Scenario: A customer can refer a client to another customer.
Each referral needs to be stored in a DB table row. The customer receiving the referral should see a notification for the event.
Create a new referral and dispatch the event:
$totalRefers = [];
foreach ($array as $to) {
$refer = new ClientReferral;
$refer->user_id = $user_id;
$refer->by = $by;
$refer->to = $to;
$refer->save();
array_push($totalRefers, $refer);
ReferralSent::dispatch($refer); // Here is the Event
}
return response()->json([
'status' => 'Success',
'message' => 'Client referred successfully to selected professionals.',
'data' => $totalRefers
], 200);
The event broadcastOn() method:
public function broadcastOn() {
return new PrivateChannel('referral.' . $this->referral->id);
}
The channel:
Broadcast::channel('referral.{id}', function ($user, $id) {
// let's say it's true for the time being
return true;
});
And the request is an Ajax POST so in the success callback:
console.log('referral created');
res.data.forEach(function(entry) {
// window.custom.userId is the authenticated user ID:
if (entry.refer_to == window.custom.userId) {
window.Echo.private('referral.' + entry.id).listen('ReferralSent', ({data}) => {
console.log('You have received a new referral');
});
}
});
Now the issue with the current code is that the receiver cannot subscribe to this channel because the event is created dynamically, and I cannot make the channel name static because the referral came in at run time.
How can a receiver subscribe and listen to dynamic events?
With this logic, I want to get that specific referral and its data to show it in the notification tray in HTML.
How can I achieve this?
The event shown in the question broadcasts to a channel for that specific referral entity only. However, the receiver that subscribes to this channel should receive events for all referral entities referred to them.
Instead of creating the channel context for the referral entity itself, publish to a channel designated for the user that receives the referral. I'm guessing that $referral->to contains that user's ID:
public function broadcastOn()
{
return new PrivateChannel('referral.' . $this->referral->to);
}
Update the channel to authorize the current user based on the ID of the user that receives the referral:
Broadcast::channel('referral.{refereeId}', function ($user, $refereeId) {
return $user->id == $refereeId;
});
And, on the client-side, listen on the same channel:
window.Echo.private('referral.' + window.custom.userId)
.listen(e => console.log(e.referral));
Because we're not listening for a specific referral ID anymore, we can initialize the Echo subscriber during the page load instead of in the AJAX response callback.
Broadcast events are designed to be useful for real-time actions outside the normal request/response cycle (including AJAX requests). In the case of this question, we want to start Echo listeners for every customer when the page loads—not after a specific request—so that they can receive notifications any time another customer refers a client to them.
The flow looks like this:
Customer 1 and Customer 2 both open the app, which starts Echo on the client-side.
Customer 1 creates a referral for Customer 2.
Customer 1's browser sends an AJAX request to save the referral.
Laravel publishes the event to Customer 2's channel.
Customer 2's browser receives the event through Echo, which is listening on that channel.
The code you wrote to handle that event creates a notification in Customer 2's browser.
Related
What I'm trying to do here is to implement a callback function in a Laravel 5.4 controller. This uses Authorize.net to process a credit card transaction, then inserts a bunch of stuff into the database, sends some messages, makes an invoice and airbill, and so on.
What I WANT to happen is:
Hit the "Submit" button, sends AJAX request
Processes the Authorize.net transaction
If good, then call a callback function to do all the gruntwork but return a transaction response.
4) Notify the user
The reason I wanna do it this way is that I want the user to wait the minimum amount of time to see the result of their payment processing without having to wait another 5 seconds or so staring at a spinning wheel waiting to go to the order complete page.
Can a callback function help me do this?
Thanks
My current implementation results in a 500 error, and I'm not quite sure what I should do from here...
[ route in web.config ]
// AJAX call to process the transaction, insert the new order, inform the user of success/failure
Route::post('/shop/processtransaction', 'OrderCheckoutController#processTransaction');
[ function processTransaction in OrderCheckoutController.php ]
public function processTransaction(Request $request) {
return self::processPaymentAndOrderInsertion($request, 'createOrder');
}
[ function processPaymentAndOrderInsertion in OrderCheckoutController.php ]
public function processPaymentAndOrderInsertion(Request $request, callable $createOrderCallback = null) {
$order_proc = new OrderProcessingTools;
$transaction_response = $order_proc->processTransaction($request);
if($transaction_response['success'] === true) {
self::$createOrderCallback($request, $transaction_response);
}
return json_encode($transaction_response);
}
[ my callback function ]
public function createOrder(Request $request, $transaction_response) {
$order_proc = new OrderProcessingTools;
$new_order = $order_proc->insertNewOrder($request);
$new_order->payment_status_id = $transaction_response['response_data']['order_payment_status_id'];
$new_order->save();
// record the payment transaction
$order_proc->insertOrderPaymentData($new_order, $transaction_response);
// insert the travelers for this order
$travelers = $order_proc->insertOrderTravelers($new_order);
// insert order inbound shipment record
$order_proc->insertInboundOrderShipping($new_order->id);
// generate inbound shipping airbill
$order_proc->generateInboundShippingAirbill($new_order->id);
/// generate the invoive
$order_proc->generateInvoice($new_order);
// send new order notification to the user
$order_proc->sendNewOrderNotificationToUser($new_order);
// send new order notification to admin
$order_proc->sendNewOrderNotificationToAdmin($new_order);
// finally kill the session variable
$_SESSION['travelers'] = [];
}
[ my previous non-asynchronous implementation looks like this...]
public function processTransaction(Request $request) {
// :: POST
// Process the Authorize.net transaction, insert the order, generate invoices
// and airbills, send notifications
$order_proc = new OrderProcessingTools;
$transaction_response = $order_proc->processTransaction($request);
if($transaction_response['success'] === true) {
// insert a new order
$new_order = $order_proc->insertNewOrder($request);
$new_order->payment_status_id = $transaction_response['response_data']['order_payment_status_id'];
$new_order->save();
// record the payment transaction
$order_proc->insertOrderPaymentData($new_order, $transaction_response);
// insert the travelers for this order
$travelers = $order_proc->insertOrderTravelers($new_order);
// insert order inbound shipment record
$order_proc->insertInboundOrderShipping($new_order->id);
// generate inbound shipping airbill
$order_proc->generateInboundShippingAirbill($new_order->id);
/// generate the invoive
$order_proc->generateInvoice($new_order);
// send new order notification to the user
$order_proc->sendNewOrderNotificationToUser($new_order);
// send new order notification to admin
$order_proc->sendNewOrderNotificationToAdmin($new_order);
// finally kill the session variable
$_SESSION['travelers'] = [];
}
// either good news or bad news at this point..
return json_encode($transaction_response);
}
When I try it this way, this is the error that is returned...
xception: "Symfony\Component\Debug\Exception\FatalThrowableError"
file: "F:\wamp64\www\uspassports\public_html\app\Http\Controllers\OrderCheckoutController.php"
line: 105
message: "Argument 2 passed to App\Http\Controllers\OrderCheckoutController::processPaymentAndOrderInsertion() must be callable or null, string given
You need to pass a callable type, but passing just the string name of the method won't work as PHP will only check if it's a global function.
You need to pass an array, with the first parameter being the object to call the method on, and the second the name of the function, like so:
return self::processPaymentAndOrderInsertion($request, [$this, 'createOrder']);
Documentation: https://www.php.net/manual/en/language.types.callable.php
Im using this laravel package "https://github.com/kanazaca/easypay" to create a MB reference using the Easypay API.
I have this method to create the reference:
public function generateReference()
{
$amount = Session::get('total');
$payment_info = [
't_value' => $amount,
'o_obs' => '',
't_key' => 1
];
$easypay = new EasyPay($payment_info);
$reference = $easypay->createReference();
Session::put('entity', $reference['ep_entity']);
Session::put('reference', $reference['ep_reference']);
Session::put('value', $reference['ep_value']);
}
And it works fine with this code I get some reference codes which can be payed using MB or credit-card.
Then, when a payment is made, easypay will call a "Notification URL".
that we should configure on easypay's backoffice under "URL Configurations".
Because when the easypay service receives the payment they will call the URL that we provided. So I defined a url in the easypay´s backoffice and created a route in the project:
Route::get('/easypay/notification-callback', [
'uses' => 'PaymentController#receiveNotifications',
'as' =>'mb.notifications'
]);
In the api backoffice there is a button that simulates a payment, after this button is clicked nothing happens and if I manually access "http://....ngrok.io/easypay/notification-callback" it appears an empty array:
[]
But in the documentation (https://docs.easypay.pt/workflow/payment-notification) says that when Easypay calls this endpoint, it comes with a few parameters: "ep_cin", "ep_user" and "ep_doc" that will be necessary in the process. So it should not appear an empty array.
Do you know what can be the issue? Im a beginner uing API´s so Im not understnading what the issue can be.
PaymentController receiveNotifications() method:
public function receiveNotifications(Request $request)
{
dd($request->all());
//$easypay = new EasyPay($payment_info);
//$xml = $easypay->processPaymentInfo();
//return \Response::make($xml, '200')->header('Content-Type', 'text/xml'); //must return in text/xml for easypay
}
receiveNotifications() method with log:
public function receiveNotifications(Request $request)
{
//dd($request->all());
Log::info('Showing info: ' .var_export($request->all(),true));
$payment_info = [
'ep_cin' => $request->ep_cin,
'ep_user' => $request->ep_user,
'ep_doc' => $request->ep_doc
];
Log::info('Showing info: ' .var_export($payment_info,true));
//dd($payment_info);
$easypay = new EasyPay($payment_info);
$xml = $easypay->processPaymentInfo();
return \Response::make($xml, '200')->header('Content-Type', 'text/xml'); //must return in text/xml for easypay
}
The session is saved in the session file of the user that visits your website that initiates the payment.
The receiveNotifications would call data from the session file that belongs to the payment gateway server if you were doing anything there. The data isn't matched because the two don't know about each other.
Also, you might not have a Session::save() somewhere in your request handling which writes the session data to file.
Store the reference in a database. Create a model for storing this data, so you can then query that model for the correct reference ID to verify/do stuff.
When the request comes back from the payment gateway use the variables ep_cin, ep_user and ep_doc to get the data from the model.
When you manually request that data you are requesting it with a GET request, which doesn't send the above data along.
The request made by the payment provider will get the result of the DD but that's logged nowhere, so nothing happens.
Log your data for requests triggered by remote api's to see what happens.
I have login page which is working fine. Once the customer logs into account account he will be redirected to "HomePage" now HomePage will have all the data of customer. Below is My loginPage.ts file code which is working fine:
this.auth.login(this.loginCredentials).subscribe(data => {
if(data){
this.customerdata = data;
if(this.customerdata['status_code'] == '200'){
this.navCtrl.setRoot(HomePage,{customerdata: this.customerdata});
}else if(this.customerdata['status_code'] == '000'){
this.navCtrl.setRoot(LoginPage);
}
}
})
Problem is, I have one more page "MyDetailsPage.ts" I want above same data in this page also. I am moving to this page through SIDE-MENU section. So I cannot use PUSH function and send data.
So please help me out.
Thank you,
By using NavParams and Events you can do that
Events is a publish-subscribe style event system for sending and responding to application-level events across your app.
NavParams are an object that exists on a page and can contain data for that particular view.
import { Events } from 'ionic-angular';
first page (publish an event when a user is created)
constructor(public events: Events) {}
createUser(user) {
console.log('User created!')
this.events.publish('user:created', user, Date.now());
}
second page (listen for the user created event after function is called)
constructor(public events: Events) {
events.subscribe('user:created', (user, time) => {
user and time are the same arguments passed in `events.publish(user, time)`
console.log('Welcome', user, 'at', time);
});
}
Refer link https://ionicframework.com/docs/api/util/Events/
Or try with params
constructor(public navParams: NavParams){
// userParams is an object we have in our nav-parameters
this.customerdata=this.navParams.get('customerdata');
}
I'm creating a managed account in Stripe and for some reason, when I create an account it creates two in my dashboard.
This is in Laravel. Here is my code:
$user = Auth::user();
//create them a connect account
$account = \Stripe\Account::create(
array(
"country" => "GB",
"managed" => true,
"external_account" => request('stripeToken'),
"legal_entity[type]" => $user->legal_entity_type,
"legal_entity[first_name]" => $user->name,
"legal_entity[last_name]" => $user->last_name,
"tos_acceptance[date]" => $user->tos_acceptance_date,
"tos_acceptance[ip]" => $user->tos_acceptance_ip,
"legal_entity[dob][day]" => $user->dob_day,
"legal_entity[dob][month]" => $user->dob_month,
"legal_entity[dob][year]" => $user->dob_year,
"legal_entity[address][city]" => $user->address_city,
"legal_entity[address][line1]" => $user->address_line1,
"legal_entity[address][postal_code]" => $user->address_postal_code,
)
);
//grab the stripe users ID, secret key and publishable key
$acc_id = $account->id;
$secret_key = $account->keys->secret;
$publishable = $account->keys->publishable;
//update the users table to reflect the changes
$user->stripe_id=$acc_id;
$user->stripe_secret=$secret_key;
$user->stripe_key=$publishable;
$user->save();
return redirect()->action('HomeController#index');
I create the managed account with all the required information (including bank token created from previous form and submitted) then update my users tables with the stripe id etc and save it.
However when I go to my Stripe dashboard I have two entries with different account ID's but all the same details.
Any advice where I'm going wrong would be great
When I die and dump the account ID it's always the second account ID.
Edit: The first account never receives the External Account attribute, but the second account in the dashboard does, and that's the one that ends up being attributed in the users table as the stripe_id
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script>
Stripe.setPublishableKey('{{ config('services.stripe.key') }}');
function stripeResponseHandler(status, response) {
// Grab the form:
var $form = $('#bank-account-form');
if (response.error) { // Problem!
// Show the errors on the form:
$form.find('.bank-errors').text(response.error.message);
$form.find('button').prop('disabled', false); // Re-enable submission
} else { // Token created!
// Get the token ID:
var token = response.id;
// Insert the token into the form so it gets submitted to the server:
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
// Submit the form:
$form.get(0).submit();
}
}
$(document).ready(function () {
$("#bank-account-form").submit(function (event) {
// disable the submit button to prevent repeated clicks
$('.submit-button').attr("disabled", "disabled");
// bank account parameters
var bankAccountParams = {
country: $('.country').val(),
currency: $('.currency').val(),
//routing_number: $('.routing-number').val(),
account_number: $('.account-number').val(),
account_holder_name: $('.account-holder-name').val(),
account_holder_type: $('.account-holder-type').val()
}
if ($('.routing-number').val() != '') {
bankAccountParams['routing_number'] = $('.routing-number').val();
}
// createToken returns immediately - the supplied callback submits the form if there are no errors
Stripe.bankAccount.createToken(bankAccountParams, stripeResponseHandler);
});
});
</script>
Thanks,
Your backend code for creating the managed account is being called twice, once without the stripeToken POST parameter and once with it.
My guess is that you have a client-side form using Stripe.js to collect the user's bank account information, and there is an issue with the form where the browser submits it twice, once without the token and once with it.
In your form's event handler, make sure that you disable the default submission by calling preventDefault(); on the submit event and/or returning false in the handler.
The form should only be submitted by Stripe.js' own callback, when the token has been created.
Check if your browser network request see if its sending multiple requests. Any javascript error or redirection could be cause of the issue, as php code looks ok.
Hi guys I am having a problem with twilio currently setting an assignment to a worker and i need to pass the worker to the conference. My problem is that i cant use session to retrieve the id in the session and the id will be the conference name of the conference to be able to have a unique conference name for a worker.
This is my callback in twilio
This is my code to get the task. And the id will be passed on forward_queue_conference.
public function assignment()
{
id = $this->session->userdata('user_id');
$TaskAttributes = $_POST['TaskAttributes'];
$json = json_decode($TaskAttributes, true);
$this->Mytwilio->SetAssignment($json['from'], AFTERTALK, HTTP_BASE_URL."agent/call_controls/forward_queue_conference?data=".$id);
}
This is my code on forward_queue_conference to retrieve the pass data
public function forward_queue_conference()
{
roomName = $_GET['data'];
$this->Mytwilio->CallerToQueue($roomName);
}
MyTwilio is a library that i made for twilio functions.
function CallerToQueue($roomName)
{
$response = new Services_Twilio_Twiml;
$dial = $response->dial();
$dial->conference($roomName, array(
'startConferenceOnEnter' => 'true',
'endConferenceOnExit' => 'true',
'muted' => 'false',
'record' => 'record-from-start',
'waitUrl' => 'http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient',
));
print $response;
}
And this is my whole process my problem is that i cant get the session data to become the conference room.
Twilio developer evangelist here.
When Twilio makes a callback to a URL on your website, it does not share the same session as your logged in user. It is therefore impossible to get the current user ID from the session.
However, your workers have an ID in the Twilio system. And that ID is sent as part of the parameters for the webhook. So, I recommend using the WorkerSid as the conference room instead of your own ID. Or alternatively, you could map between your worker ID and the user ID in your system.