Previously I wrote a post regarding to Integrate PayPal SDK into Laravel 4. And I believe now Laravel 5 is quite different from Laravel 4. Also, PayPal API also updated now.
This post involved Front End (Angular 5) & Back End (Laravel 5).
/** * Available option 'sandbox' or 'live' */ 'mode' => 'sandbox',
/** * Specify the max request time in seconds */ 'http.ConnectionTimeOut' => 30,
/** * Whether want to log to a file */ 'log.LogEnabled' => true,
/** * Specify the file that want to write on */ 'log.FileName' => storage_path() . '/logs/paypal.log',
/** * Available option 'FINE', 'INFO', 'WARN' or 'ERROR' * * Logging is most verbose in the 'FINE' level and decreases as you * proceed towards ERROR */ 'log.LogLevel' => 'FINE' ], 'webhooks' => [ 'payment_sale_completed' => env('PAYPAL_PAYMENT_SALE_COMPLETED_WEBHOOK_ID'), ], ];
$signature_verification = newVerifyWebhookSignature(); $signature_verification->setAuthAlgo($headers['PAYPAL-AUTH-ALGO'][0]); $signature_verification->setTransmissionId($headers['PAYPAL-TRANSMISSION-ID'][0]); $signature_verification->setCertUrl($headers['PAYPAL-CERT-URL'][0]); // get the webhook ID in config file $signature_verification->setWebhookId(config('paypal.webhooks.payment_sale_completed')); // Note that the Webhook ID must be a currently valid Webhook that you created with your client ID/secret. $signature_verification->setTransmissionSig($headers['PAYPAL-TRANSMISSION-SIG'][0]); $signature_verification->setTransmissionTime($headers['PAYPAL-TRANSMISSION-TIME'][0]);
// for error message, I log it into a file for debug purpose $exception_log_file = storage_path('logs/paypal-exception.log');
try { /** @var \PayPal\Api\VerifyWebhookSignatureResponse $output */ $output = $signature_verification->post($this->_api_context); } catch (\Exception$ex) { file_put_contents($exception_log_file, $ex->getMessage()); exit(1); } $status = $output->getVerificationStatus(); // 'SUCCESS' or 'FAILURE' // if the status is not success, then end here if (strtoupper($status) !== 'SUCCESS') exit(1);
$json = json_decode($request_body, 1);
// Because PayPal don't let us to add in custom data in JSON form, so I add it to a field 'custom' as encoded string. Now decode to get the data back $custom_data = json_decode($json['resource']['custom'], 1); $user = User::find($custom_data['user_id']); // to get the User
// save the payment info
// generate invoice
// email to user
echo$status; // at the end must echo the status exit(1); } }
You can see there are green tick and yellow exclamation mark. The echo $status; is to tell the PayPal server that this webhook has been processed. Otherwise it will resend the POST webhook request.
In Angular
Here is pretty simple, just need to add in the JavaScript code to the component.
ngAfterViewChecked() { this.configurePaypal(); } configurePaypal() { if (!this.didRenderPaypal) {
var userId = 2;
this.loadPaypalScript().then(() => { paypal.Button.render({ env: 'sandbox', // sandbox | production // Create a PayPal app: https://developer.paypal.com/developer/applications/create client: { sandbox: environment.services.paypal.clientId, production: environment.services.paypal.clientId }, // Show the buyer a 'Pay Now' button in the checkout flow commit: true,
// payment() is called when the button is clicked payment: function(data, actions) {
// Make a call to the REST api to create the payment return actions.payment.create({ payment: { transactions: [ { amount: { total: $('#total').val(), currency: 'MYR', details: { subtotal: $('#subtotal').val(), tax: $('#tax').val(), } }, custom: JSON.stringify({ // YOU CAN ADD CUSTOM DATA HERE user_id: userId, qty: $('#qty').val() }) } ] } }); },
// onAuthorize() is called when the buyer approves the payment onAuthorize: function(data, actions) { // Make a call to the REST api to execute the payment return actions.payment.execute().then(function() { console.log(data); window.alert('Payment Complete!'); }); }
The PayPal JavaScript file must be injected during run time.
You can see I use a lot of jQuery (e.g. $('total').val()), is because the code block inside is cannot be set a typescript variable directly, the total amount may change if user change products. Thus, jQuery can ensure it get the correct value from the form.
Now you run your Angular app, you should see a PayPal button there.
Once you make the payment, the webhook will be triggered.
Update: 2018-01-25
Let say you don’t want the payment processing part by webhooks, you can do it in the JavaScript success block.
... onAuthorize: function(data, actions) { // Make a call to the REST api to execute the payment return actions.payment.execute().then(function() { that.http .post( 'https://www.yoursite.com/api/paypal/checkout', data ) .toPromise() .then(res => { // success submit console.log(res.json()); }) .catch(res => { // POST error console.log(res); }); }); } ...