In the previous segment we set up the Stripe webhooks so that Stripe can interact with our system asynchronously. Today we implement Stripe customers in our platform. For all source code check here. In the next post we introduce recurring billing.
In this second part of the tutorial (here is part one) I show you how to work with Stripe webhooks, create a manifest.json file and implement push notifications. The full source code is listed below here. An important part of any point of sales system, is alerting you when you have successful transactions among other things. Stripe has a wonderful webhook system that allows us to interact with the system with events. A full list of events can be found here if you want to expand the source code. In part 3 I will show you how to add customers to your POS platform and what can be done by doing so. Don’t forget to like the video and subscribe to my Youtube channel!
Creating web apps for the fun of it is cool, but we all need to get paid right?! This new series explores how to create a point of sales system with Laravel, Vue.js and the Stripe API. A point of sales system (or POS) is software solution that allows you to process money. In this case we will use Stripe to process credit/debit cards as well as manage inventory. Using a fullstack Laravel and Vue.js application we can collect money, send invoices and get paid all in one location. By the time this series is over you will have used:
Laravel Passport
Laravel Socialite
Stripe Charge API
Stripe Product API
Stripe Subscription API
All of the source code is available at https://github.com/mastashake08/laravel-vue-pos. In part one I explain what it is we are building today as well as setting up the ground work for the future. Watch the video below and don’t forget to subscribe to the channel and share the video! Lastly don’t forget to check out the live version right here! Now on to part 2.
In part one we created a point of sales system using Laravel and Vue (if you haven’t done part 1 here is the source code). It had very basic functionality but it got the job done, you could charge debit/credit cards. The basic design looked like this
In part two we will add email invoice functionality so that we can email our customers and they can pay without us having to know their account information. For this we will be using Laravel’s notification framework on the backend and utilizing the web payment request API with Vue.js on the front end.
The Invoice Model
In the command line we will create a new model to represent our invoices type in the following command to generate your model and migration
php artisan make:model -m Invoice
Once the model and migration are made, open up migration and edit accordingly:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateInvoicesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('invoices', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->longText('description');
$table->integer('amount');
$table->string('email');
$table->string('charge_id');
$table->boolean('is_paid')->default(false);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('invoices');
}
}
As you can see there are only a few fields
name of person being invoiced
description of the invoice
amount to be invoiced
email address for invoice to be mailed to
stripe charge id
boolean indicating whether or not the invoice has been paid
Open up the Invoice.php model and add the following to the $fillable array
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;
class Invoice extends Model
{
use Notifiable;
//
protected $fillable = ['name','amount','email','description','charge_id'];
}
Next we need to create some api routes and a RESTful controller. Let’s start with the routes, open up routes/api.php and add the following routes
Open up the controller and replace with the following
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Invoice;
class InvoiceController extends Controller
{
public function __construct(){
\Stripe\Stripe::setApiKey(env('STRIPE_SECRET'));
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
$invoices = Invoice::where('is_paid',true)->get();
return response()->json([
'invoices' => $invoices
]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
$invoice = Invoice::Create($request->all());
$invoice->notify(new \App\Notifications\InvoiceCreated());
return response()->json([
'invoice' => $invoice
]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
$invoice = Invoice::findOrFail($id);
$invoice->fill($request->all())->save();
return response()->json([
'invoice' => $invoice
]);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
return response()->json([
'success' => Invoice::findOrFail($id)->delete()
]);
}
function getPayInvoice($id){
return view('invoice')->with([
'invoice' => Invoice::findOrFail($id)
]);
}
function payInvoice(Request $request,$id){
$invoice = Invoice::findOrFail($id);
try {
// Use Stripe's library to make requests...
$token = \Stripe\Token::create(array(
"card" => array(
"number" => $request->details['cardNumber'],
"exp_month" => $request->details['expiryMonth'],
"exp_year" => $request->details['expiryYear'],
"cvc" => $request->details['cardSecurityCode']
)
));
\Stripe\Charge::create(array(
"amount" => $invoice->amount,
"currency" => "usd",
"source" => $token, // obtained with Stripe.js
"description" => $invoice->description,
"receipt_email" => $invoice->email
));
return response()->json([
'success' => true
]);
} catch(\Stripe\Error\Card $e) {
// Since it's a decline, \Stripe\Error\Card will be caught
return response()->json($e->getJsonBody());
} catch (\Stripe\Error\RateLimit $e) {
// Too many requests made to the API too quickly
return response()->json($e->getJsonBody());
} catch (\Stripe\Error\InvalidRequest $e) {
// Invalid parameters were supplied to Stripe's API
return response()->json($e->getJsonBody());
} catch (\Stripe\Error\Authentication $e) {
// Authentication with Stripe's API failed
// (maybe you changed API keys recently)
return response()->json($e->getJsonBody());
} catch (\Stripe\Error\ApiConnection $e) {
// Network communication with Stripe failed
return response()->json($e->getJsonBody());
} catch (\Stripe\Error\Base $e) {
// Display a very generic error to the user, and maybe send
// yourself an email
return response()->json($e->getJsonBody());
} catch (Exception $e) {
// Something else happened, completely unrelated to Stripe
return response()->json($e->getJsonBody());
}
}
}
Most of the CRUD operations are simple, in the create method we are calling a notification on the invoice (we will create the notification next don’t worry), and we have the charge method which is really just copy and paste from the other charge method except the amount comes from the invoice.
The last thing needed on the back end is the notification. Let’s go ahead and create that.
php artisan make:notification InvoiceCreated
In the notification file we just send an email with a link to pay
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class InvoiceCreated extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->subject('You Have A New Invoice Due')
->line('Pay NOW or suffer the consequences!')
->action('Pay UP!', url('/invoice/pay/'.$notifiable->id))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
The Front End
We are going to create 2 components and a new page so people can pay their invoice. Create a new component in your vue application name it InvoiceComponent and replace with the following
Drop that new component in your home.blade file and your page should look like this
Create another component call it InvoicePayController and place the following
We are making use of the Payment Request API to gather all user card data to simplify the checkout process, you can read up more about it here. Create a new blade view file and call it Invoice.blade.php and put this new component there
Now your customers can pay invoices sent to them via email! Please don’t forget to subscribe to my Youtube Channel and like the video and post! Also don’t forget if you want to support this blog pre-orders for my new e-book are open now until the end of month!
Using this Web Speech JavaScript API you can enable your web apps to handle voice data. The API is broken down into two parts SpeechSynthesis and SpeechRecognition. SpeechSynthesis also known as text-to-speech allows your web app to read text aloud from your speakers. SpeechRecognition allows your web app to convert voice data from your microphone into text.
What Are We Building?
To adequately demonstrate the power of the web speech API I decided to break the project up into steps. Step one is a simple voice dictated note taking app. The premise is very simple, you create an account and on the dashboard you have a list of your notes as well as a button to add a new note. Once that button is pressed you are prompted to allow access to your microphone. The SpeechRecognition API will transcribe your speech and when complete saves it to the database. In case you missed the livestream here is a link to the source code as well as a link to the live app.
What Are The Next Steps?
As you can see there isn’t much coding or difficulty setting up the API. Bear in mind I barely scratched the surface of what SpeechRecognition can do (for a more detail examination I suggest reading here). In my next livestream I will expand on this app and add SpeechSynthesis functionality into the program. You will be able to pick different voices, adjust the pitch and rate of speech and allow the browser to read your notes back to you! I hope to see you all on the next stream, if you haven’t already subscribe to my channel and to this blog. If you have any questions or concerns please drop them in the comment section below until next time happy hacking!
Well for my platform it is anyway, whenever I create a new app or website Twitter is the first social network that I turn to. It’s fast, the analytics are on point, and it’s easy to use, my only issue is that I am busy coding and whatnot to Tweet as much as I would like or need to in order to optimize my reach. This leaves me with two options:
Pay someone to manage my account for me
Learn the Twitter API and write my own automation program to manage it myself
The idea of paying another person to manage my social media just made my stomach and my wallet hurt so the OBVIOUS choice is to use the API. Now let me tell you thisn API is DENSE there is a lot you can do with it (click here for the docs) so I will only focus on one aspect in this tutorial, sending posts. The first basic application that I wrote was a simple post scheduler, it allows me to create as many posts as I want, set a date-time to post at, then a Laravel job executes at the desired time, then deletes the entry from the database. This basic application has saved me tremendous time because now I can just schedule all my important tweets weeks or months early!
Registering Your Twitter App
Before you can do any actual coding you need to register your app on Twitter, head over to the developer portal and create your app. The home page will show a list of your Twitter apps, if this is your first time then you won’t have any apps, click on create new app.
Fill out all the mandatory fields then proceed you should see a screen that shows you your Consume Key and Consumer Secret. Copy those down and also create some access tokens. These access tokens are for writing Twitter apps that only interact with your OWN account. Copy down the access token and the access token secret and that’s all you have to do. Now let’s code!
App Components
The main page will be a Vue.js app that allows you to add new tweets, and an area below to edit and delete them. In a traditional SPA manner the app will interact with an API for all it’s calls. The backend will consist of one model (Tweet), one controller (TweetController), and one Job ProcessTweet, pretty simple stuff let’s begin. Start by creating your Laravel application.
laravel new tweeter && cd tweeter && php artisan make:auth
Now create the Tweet model along with it’s migration
php artisan make:model -m Tweet
The Tweet model only has two attributes a string that holds the content that is limited to 140 characters and a timestamp for when you want the tweet to be published.
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTweetsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('tweets', function (Blueprint $table) {
$table->increments('id');
$table->string('content',140);
$table->timestamp('publish_timestamp');
$table->timestamps();
});
}/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('tweets');
}
}
The Tweet model is pretty bare bones
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tweet extends Model
{
//
public $fillable = [
'content',
'publish_timestamp'
];
}
Go ahead and run your migrations we are done with models, now to make our RESTful controller.
The controller is basic I purposely left out validation and such as a homework exercise for you, but the gist is basic CRUD operations that return JSON
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Tweet;
use App\Jobs\ProcessTweet;
class TweetController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
return response()->json(Tweet::all());
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//create the tweet
$tweet = Tweet::Create([
'content' => $request->content,
'publish_timestamp' => \Carbon\Carbon::parse($request->publish_timestamp)
]);
//Add tweet to the queue
ProcessTweet::dispatch($tweet)->delay(\Carbon\Carbon::parse($request->publish_timestamp,'America/New_York')->diffInSeconds(\Carbon\Carbon::now('America/New_York')));
//return json
return response()->json($tweet);
}/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
return response()->json(Tweet::findOrFail($id));
}/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
$tweet = Tweet::findOrFail($id);
$tweet->fill([
'content' => $request->content,
'publish_timestamp' => \Carbon\Carbon::parse($request->publish_timestamp)
]);
//return json
return response()->json($tweet);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
Tweet::destroy($id);
}
}
Notice the ProcessTweet job? We will implement that next but for now open up the routes/api.php file and add the following resource route
<?php
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::resource('/tweet','TweetController');
Now our Vue application (patience it’s coming) can interact with our backend. Now let’s add our ProcessTweet job and we will be finished on the backend.
ProcessTweet Job
In order to schedule the tweets to post at any given time you must utilize Laravel Jobs this will allow you to schedule your events to fire at a certain point in time. If you aren’t familiar with jobs and queues please look at my previous post because I will not be covering setting up queues in this tutorial, otherwise create a new job
php artisan make:job ProcessTweet
In the handle method we simply call the Twitter API and send the tweet then delete it from the database
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Twitter;
class ProcessTweet implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tweet;
/** * Create a new job instance.
*
* @return void
*/
public function __construct(\App\Tweet $tweet)
{
//
$this->tweet = $tweet;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
//post the tweet
Twitter::postTweet(['status' => $this->tweet->content, 'format' => 'json']);
//delete the tweet from database
\App\Tweet::destroy($this->tweet->id);
}
}
Your backend is now functioning run your queue worker and test around with it or continue to creating the Vue application.
Getting The Front End Together
We need to add vue-resource to call our api so let’s add that first
npm install --save vue-resource
Also update the resources/js/app.js file
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
const resource = require('vue-resource');
Vue.use(resource);
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('tweet-component', require('./components/TweetComponent.vue'));
const app = new Vue({
el: '#app'
});
As you can see the example-component has been replaced with the tweet-component rename your ExampleComponent.vue to TweetComponent.vue and update it with the following contents
Run your npm build script as well as your queue worker and start tweeting! You can get the full source code here, and as always please subscribe to my blog via email or push notifications, share, and leave your comment below! If you would like to add a real-time nodejs microservice to your app then read here!