Getting started
Installation
Install and configure the package using the following command :
node ace add @foadonis/shopkeeper
-
Installs the
@foadonis/shopkeeper
package using the detected package manager. -
Registers the following service provider inside the
adonisrc.ts
file.{providers: [// ...other providers() => import('@foadonis/shopkeeper/providers/shopkeeper')]} -
Creates the
config/shopkeeper.ts
file. -
Defines the environment variables to store
STRIPE_KEY
,STRIPE_SECRET
andSTRIPE_WEBHOOK_SECRET
. -
Creates the database migrations files for the tables
users
,suscriptions
andsubscription_items
.
Then migrate your database:
node ace migration:run
Shopkeeper's migrations will add several columns to your users
table. They will also create a new subscriptions
table to hold all of your customer's subscriptions and a subscription_items table for subscriptions with multiple prices.
Lastly, to ensure Shopkeeper properly handles all Stripe events, remember to configure Shopkeeper's webhook handling.
Configuration
Billable Model
Before using Shopkeeper, add the Billable
mixin to your billable model definition. Typically, this will be the User
model. This trait provides various methods to allow you to perform common billing tasks, such as creating subscriptions, applying coupons, and updating payment method information:
import { compose } from '@adonisjs/core/helpers'
import { BaseModel } from '@adonisjs/lucid/orm'
import { Billable } from '@foadonis/shopkeeper/mixins'
export default class User extends compose(BaseModel, Billable) {}
In your Shopkeeper configuration file, define your User as the Customer model:
import { defineConfig } from '@foadonis/shopkeeper'
export default defineConfig({
customerModel: () => import('#models/user')
...
})
When using a model with a different name than User
, make sure to change the table name in the generated migration.
API Keys
Next, you should configure your Stripe API keys in your application's .env
file. You can retrieve your Stripe API keys from the Stripe control panel:
STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret
STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secret
[!WARNING]
You should ensure that theSTRIPE_WEBHOOK_SECRET
environment variable is defined in your application's.env
file, as this variable is used to ensure that incoming webhooks are actually from Stripe.
Currency Configuration
The default Shopkeeper currency is United States Dollars (USD). You can change the default currency by setting the SHOPKEEPER_CURRENCY
environment variable within your application's .env
file:
SHOPKEEPER_CURRENCY=eur
In addition to configuring Shopkeeper's currency, you may also specify a locale to be used when formatting money values for display on invoices. Internally, Shopkeeper utilizes Intl.NumberFormat
to set the currency locale:
SHOPKEEPER_CURRENCY_LOCALE=de-DE
Tax Configuration
Thanks to Stripe Tax, it's possible to automatically calculate taxes for all invoices generated by Stripe. You can enable automatic tax calculation by setting calculateTaxes
option to true in the Shopkeeper's configuration file:
import { defineConfig } from '@foadonis/shopkeeper'
export default defineConfig({
calculateTaxes: true
...
})
Once tax calculation has been enabled, any new subscriptions and any one-off invoices that are generated will receive automatic tax calculation.
For this feature to work properly, your customer's billing details, such as the customer's name, address, and tax ID, need to be synced to Stripe. You may use the customer data synchronization and Tax ID methods offered by Shopkeeper to accomplish this.
Using custom models
You are free to extend the models used internally by Shopkeeper by defining your own model and extending the corresponding Shopkeeper model:
import { Subscription as ShopkeeperSubscription } from '@foadonis/shopkeeper/models'
export default class Subscription extends ShopkeeperSubscription {
// ...
}
After defining your model, you may instruct Shopkeeper to use your custom model via the configuration file:
import { defineConfig } from '@foadonis/shopkeeper'
export default defineConfig({
subscriptionModel: () => import('#models/subscription')
subscriptionItemModel: () => import('#models/subscription_item')
...
})