php - tag - ¿Cómo debería ser el flujo de este contexto?(¿Dónde colocar el código para procesar el pago según el método de pago seleccionado?)
tooltip title html (2)
Como en sus dudas, para estructurar mejor su código y la lógica separada (concepto DRY), debe hacer algunas cosas:
Cree
PaymentsController
con 3 funciones (para empezar, definitivamente agregará más aquí)- para procesar sus referencias
- para procesar tarjetas de crédito
- para almacenar métodos de pago (almacenar método de pago en sesión, hasta que el usuario complete el paso 3)
Usted es totalmente libre, en cómo nombra estas funciones, pero sugeriría algo como
processViaReferences
,processViaCreditCard
ystorePaymentMethod
.Será mucho más fácil de leer y validar, si los tiene separados.
Cree las rutas de publicación correspondientes para ellos y haga una referencia apropiada, en código de correo.
Cree vistas de pieza que contengan solo sus formularios.
Luego incluya estas vistas
@include
a través de@include
para separarlas en el nivel de vista. Para sus referencias en javascript / jQuery, recuerde mantener las identificaciones correctas de ellos. También puede extraer javascript, para ver otras vistas de partes o archivos js separados, si aún no lo ha hecho.Su código de vista / formulario debe ir a estas vistas de pieza ...
Tengo un formulario de varios pasos para que un usuario se registre en una conferencia, todos los pasos se encuentran en la misma página de registration.blade.php
, en el paso 1 y el paso 2 se realiza una solicitud ajax para validar los campos del formulario.
Los pasos son:
- Step1 es recopilar información sobre el usuario ( nombre y número de lata )
- El paso 2 es recoger el método de pago ( tarjeta de crédito o referencias ).
- El paso 3 es el pago.
- El paso 4 muestra un mensaje de éxito ( este paso solo aparece después de un pago exitoso con tarjeta de crédito, con el método de pago de referencias no aparece este paso, con el método de pago de referencias solo aparecen los pasos 1, 2 y 3 )
Mi duda está entre los pasos 2 y 3.
Si las referencias del método de pago seleccionado son necesarias para ejecutar el código a continuación, eso genera algunas referencias de pago y luego presenta esas referencias al usuario en el paso 3. Cuando el usuario paga, el sistema recibe una notificación y debe insertarse en la tabla de pagos el price
, payment_method_id
, registration_id
y status
( pagado ).
Código para procesar pagos con referencias:
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
}
Si el pago seleccionado era tarjeta de crédito, es necesario ejecutar el código a continuación para cargar la tarjeta de crédito y luego de eso se inserta en la tabla de pagos el price
, payment_method_id
, registration_id
y status
( pagado ). Y luego el usuario debe ser redirigido al paso 4 para mostrar un mensaje de éxito:
Código para procesar pagos con tarjeta de crédito:
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
}
Mi duda es cómo debe ser el flujo, dónde se debe colocar el código para manejar el pago con referencias y el código para manejar el pago con una tarjeta de crédito. Así es posible lograr este escenario:
Por ahora, solo tengo el paso 1 y el paso 2 funcionando correctamente. Para manejar step1 y step2 tengo el RegistrationController
. En el paso 1, la información introducida por el usuario se valida mediante una solicitud posterior ajax al método storeUserInfo()
del RegistrationController
Si el usuario devuelve 200
el usuario pasa al paso 2.
En el paso 2, el usuario selecciona el método de pago y hace clic en "ir al paso 3". También se realiza una solicitud ajax a storePaymentMethods()
del RegistrationController
para validar si el usuario seleccionó al menos 1 método de pago. Mi duda es después de este código de retorno de método 200 cómo debe ser el proceso.
Dependiendo del método de pago, es necesario ejecutar el código apropiado arriba ( código que genera referencias de pago o código para cargar la tarjeta de crédito ).
Por lo tanto, tengo dudas sobre cómo organizar este código en términos de controladores y métodos, dónde colocar ese código que debe ejecutarse según el método de pago seleccionado. ¿Sabes cómo debe ser el flujo para lograr eso?
Tal vez un enfoque puede ser algo como abajo en storePaymentMethods()
pero no parece muy correcto hacer todo con este método:
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);
}
Un resumen completo del flujo del registro con el formulario de varios pasos que tengo por ahora:
Entonces para el paso 1, está la forma:
<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>
Paso 1 imagen para explicar mejor:
cuando el usuario hace clic en el botón "Ir al paso 2" se realiza una solicitud ajax para validar los datos y, si no hay errores, se devuelve el código 200 y el usuario va al paso 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
}
});
});
Luego, en el ConferencesController hay el storeRegistrationInfo () para manejar la solicitud de ajax anterior:
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);
}
Entonces, si se devuelve el código 200, el usuario está en la forma step2:
<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>
imagen step2 para explicar mejor:
Cuando el usuario hace clic en el botón "Ir al paso 3", se realiza una solicitud de ajax para validar los datos y, si no hay errores, se devuelve el código 200 y el usuario va al paso 3, solicitud de 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
}
});
});
El ConferenceController tiene el storePayment () para manejar la solicitud de ajax anterior, valida si el usuario seleccionó un método de pago y, en caso afirmativo, devuelve el código 200
:
public function storePaymentMethods(Request $request){
$request->validate([
''payment_method'' => ''required'',
]);
return response()->json([
''success'' => true,
''message'' => ''success'',
''payment_method'' => $request->payment_method,
], 200);
}
Luego está el div step3. En el div 3 step3 aparecerá el div #credit_card_section
visible o #references_section
visible dependiendo del método de pago seleccionado en el paso anterior ( tarjeta de crédito o referencias ):
<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
imagen para explicar mejor, dependiendo del método de pago, la información que es necesaria para mostrar en el paso 3 es diferente. Si el método de pago era tarjeta de crédito también aparece un step4
muestra un mensaje de éxito después de un cargo exitoso con una tarjeta de crédito:
Luego está el div 4 del paso que debe mostrar el mensaje de éxito, después de completar el pago con una tarjeta de crédito:
<div id="step4">
<p>
<i class="fa fa-plus" aria-hidden="true"></i>
Payment and registration completed with success.
</p>
</div>
// Reanudación de los métodos del RegistrationController que tengo por ahora, el RegistrationController es el controlador que tengo que maneja el formulario de varios pasos
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);
}
}
Ruta para el step1
:
Route::post(''/conference/{id}/{slug?}/registration/storeRegistrationInfo'', [
''uses'' => ''RegistrationController@storeRegistrationInfo'',
''as'' =>''conferences.storeRegistrationInfo''
]);
Ruta para el paso 2:
Route::post(''/conference/{id}/{slug?}/registration/storePaymentMethods'', [
''uses'' => ''RegistrationController@storePaymentMethods'',
''as'' =>''conferences.storePaymentMethods''
]);
No hay instrucciones claras, debe decidir por sí mismo cómo organizar su código.
Si no puede elegir exactamente dónde colocar el código PHP responsable del pago, entonces pondré el procesamiento de ambos pagos en PaymentsController.php
Entonces, es obvio que después de elegir el método de pago necesita formar algo así como un pedido en la base de datos.
- En caso de referencias deberán estar atados a este pedido.
- En caso de utilizar tarjetas de crédito, el pago estará vinculado a este pedido.