mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 04:40:32 +00:00
feat: Payment system with voucher cards.
feat: Design with inversion dependency injection architecture. feat: Prettier http middleware. feat: Re-write items categories with preferred accounts.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
|
||||
exports.up = function(knex) {
|
||||
return knex.schema.createTable('subscription_plans', table => {
|
||||
table.increments();
|
||||
table.string('slug');
|
||||
table.string('name');
|
||||
table.string('desc');
|
||||
table.boolean('active');
|
||||
|
||||
table.decimal('price').unsigned();
|
||||
table.string('currency', 3);
|
||||
|
||||
table.decimal('trial_period').nullable();
|
||||
table.string('trial_interval').nullable();
|
||||
|
||||
table.decimal('invoice_period').nullable();
|
||||
table.string('invoice_interval').nullable();
|
||||
|
||||
table.integer('index').unsigned();
|
||||
|
||||
table.timestamps();
|
||||
}).then(() => {
|
||||
return knex.seed.run({
|
||||
specific: 'seed_subscriptions_plans.js',
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(knex) {
|
||||
return knex.schema.dropTableIfExists('subscription_plans')
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
exports.up = function(knex) {
|
||||
return knex.schema.createTable('subscription_plan_features', table => {
|
||||
table.increments();
|
||||
|
||||
table.integer('plan_id').unsigned();
|
||||
table.string('slug');
|
||||
table.string('name');
|
||||
table.string('description');
|
||||
|
||||
table.timestamps();
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(knex) {
|
||||
return knex.schema.dropTableIfExists('subscription_plan_features');
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
exports.up = function(knex) {
|
||||
return knex.schema.createTable('subscription_plan_subscriptions', table => {
|
||||
table.increments('id');
|
||||
table.string('slug');
|
||||
|
||||
table.integer('plan_id').unsigned();
|
||||
table.integer('tenant_id').unsigned();
|
||||
|
||||
table.dateTime('trial_started_at').nullable();
|
||||
table.dateTime('trial_ends_at').nullable();
|
||||
|
||||
table.dateTime('starts_at').nullable();
|
||||
table.dateTime('ends_at').nullable();
|
||||
|
||||
table.dateTime('cancels_at').nullable();
|
||||
table.dateTime('canceled_at').nullable();
|
||||
|
||||
table.timestamps();
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(knex) {
|
||||
return knex.schema.dropTableIfExists('subscription_plan_subscriptions');
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
exports.up = function(knex) {
|
||||
return knex.schema.createTable('subscription_vouchers', table => {
|
||||
table.increments();
|
||||
|
||||
table.string('voucher_code').unique();
|
||||
table.integer('plan_id').unsigned();
|
||||
|
||||
table.integer('voucher_period').unsigned();
|
||||
table.string('period_interval');
|
||||
|
||||
table.boolean('sent').defaultTo(false);
|
||||
table.boolean('disabled').defaultTo(false);
|
||||
table.boolean('used').defaultTo(false);
|
||||
|
||||
table.dateTime('sent_at');
|
||||
table.dateTime('disabled_at');
|
||||
table.dateTime('used_at');
|
||||
|
||||
table.timestamps();
|
||||
})
|
||||
};
|
||||
|
||||
exports.down = function(knex) {
|
||||
return knex.schema.dropTableIfExists('subscription_vouchers');
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
import { Model, mixin } from 'objection';
|
||||
import SystemModel from '@/system/models/SystemModel';
|
||||
import DateSession from '@/models/DateSession';
|
||||
import UserSubscription from '@/services/Subscription/UserSubscription';
|
||||
|
||||
|
||||
export default class SubscriptionLicense extends mixin(SystemModel, [DateSession, UserSubscription]) {
|
||||
/**
|
||||
* Table name.
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'subscription_licences';
|
||||
}
|
||||
|
||||
markAsUsed() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import SystemModel from '@/system/models/SystemModel';
|
||||
|
||||
export default class SubscriptionUsage extends SystemModel {
|
||||
/**
|
||||
* Table name
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'subscriptions_usage';
|
||||
}
|
||||
}
|
||||
94
server/src/system/models/Subscriptions/Plan.js
Normal file
94
server/src/system/models/Subscriptions/Plan.js
Normal file
@@ -0,0 +1,94 @@
|
||||
import { Model, mixin } from 'objection';
|
||||
import SystemModel from '@/system/models/SystemModel';
|
||||
import { PlanSubscription } from '..';
|
||||
|
||||
export default class Plan extends mixin(SystemModel) {
|
||||
/**
|
||||
* Table name.
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'subscription_plans';
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamps columns.
|
||||
*/
|
||||
static get timestamps() {
|
||||
return ['createdAt', 'updatedAt'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Defined virtual attributes.
|
||||
*/
|
||||
static get virtualAttributes() {
|
||||
return ['isFree', 'hasTrial'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Model modifiers.
|
||||
*/
|
||||
static get modifiers() {
|
||||
return {
|
||||
getFeatureBySlug(builder, featureSlug) {
|
||||
builder.where('slug', featureSlug);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Relationship mapping.
|
||||
*/
|
||||
static get relationMappings() {
|
||||
const PlanFeature = require('@/system/models/Subscriptions/PlanFeature');
|
||||
|
||||
return {
|
||||
/**
|
||||
* The plan may have many features.
|
||||
*/
|
||||
features: {
|
||||
relation: Model.BelongsToOneRelation,
|
||||
modelClass: PlanFeature.default,
|
||||
join: {
|
||||
from: 'subscriptions_plans.id',
|
||||
to: 'subscriptions_plan_features.planId',
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* The plan may have many subscriptions.
|
||||
*/
|
||||
subscriptions: {
|
||||
relation: Model.HasManyRelation,
|
||||
modelClass: PlanSubscription.default,
|
||||
join: {
|
||||
from: 'subscription_plans.id',
|
||||
to: 'subscription_plans.planId',
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plan is free.
|
||||
* @return {boolean}
|
||||
*/
|
||||
isFree() {
|
||||
return this.price <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plan is paid.
|
||||
* @return {boolean}
|
||||
*/
|
||||
isPaid() {
|
||||
return !this.isFree();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plan has trial.
|
||||
* @return {boolean}
|
||||
*/
|
||||
hasTrial() {
|
||||
return this.trialPeriod && this.trialInterval;
|
||||
}
|
||||
}
|
||||
36
server/src/system/models/Subscriptions/PlanFeature.js
Normal file
36
server/src/system/models/Subscriptions/PlanFeature.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Model, mixin } from 'objection';
|
||||
import SystemModel from '@/system/models/SystemModel';
|
||||
|
||||
export default class PlanFeature extends mixin(SystemModel) {
|
||||
/**
|
||||
* Table name.
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'subscriptions.plan_features';
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamps columns.
|
||||
*/
|
||||
static get timestamps() {
|
||||
return ['createdAt', 'updatedAt'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Relationship mapping.
|
||||
*/
|
||||
static get relationMappings() {
|
||||
const Plan = require('@/system/models/Subscriptions/Plan');
|
||||
|
||||
return {
|
||||
plan: {
|
||||
relation: Model.BelongsToOneRelation,
|
||||
modelClass: Plan.default,
|
||||
join: {
|
||||
from: 'subscriptions.plan_features.planId',
|
||||
to: 'subscriptions.plans.id',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
170
server/src/system/models/Subscriptions/PlanSubscription.js
Normal file
170
server/src/system/models/Subscriptions/PlanSubscription.js
Normal file
@@ -0,0 +1,170 @@
|
||||
import { Model, mixin } from 'objection';
|
||||
import SystemModel from '@/system/models/SystemModel';
|
||||
import moment from 'moment';
|
||||
import SubscriptionPeriod from '@/services/Subscription/SubscriptionPeriod';
|
||||
|
||||
export default class PlanSubscription extends mixin(SystemModel) {
|
||||
/**
|
||||
* Table name.
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'subscription_plan_subscriptions';
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamps columns.
|
||||
*/
|
||||
static get timestamps() {
|
||||
return ['createdAt', 'updatedAt'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Defined virtual attributes.
|
||||
*/
|
||||
static get virtualAttributes() {
|
||||
return ['active', 'inactive', 'ended', 'onTrial'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifiers queries.
|
||||
*/
|
||||
static get modifiers() {
|
||||
return {
|
||||
activeSubscriptions(builder) {
|
||||
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
|
||||
const now = moment().format(dateFormat);
|
||||
|
||||
builder.where('ends_at', '>', now);
|
||||
builder.where('trial_ends_at', '>', now);
|
||||
},
|
||||
|
||||
inactiveSubscriptions() {
|
||||
builder.modify('endedTrial');
|
||||
builder.modify('endedPeriod');
|
||||
},
|
||||
|
||||
subscriptionBySlug(builder, subscriptionSlug) {
|
||||
builder.where('slug', subscriptionSlug);
|
||||
},
|
||||
|
||||
endedTrial(builder) {
|
||||
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
|
||||
const endDate = moment().format(dateFormat);
|
||||
|
||||
builder.where('ends_at', '<=', endDate);
|
||||
},
|
||||
|
||||
endedPeriod(builder) {
|
||||
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
|
||||
const endDate = moment().format(dateFormat);
|
||||
|
||||
builder.where('trial_ends_at', '<=', endDate);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Relations mappings.
|
||||
*/
|
||||
static get relationMappings() {
|
||||
const Tenant = require('@/system/Models/Tenant');
|
||||
const Plan = require('@/system/Models/Subscriptions/Plan');
|
||||
|
||||
return {
|
||||
/**
|
||||
* Plan subscription belongs to tenant.
|
||||
*/
|
||||
tenant: {
|
||||
relation: Model.BelongsToOneRelation,
|
||||
modelClass: this.relationBindKnex(Tenant.default),
|
||||
join: {
|
||||
from: 'subscription_plan_subscriptions.tenantId',
|
||||
to: 'tenants.id'
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Plan description belongs to plan.
|
||||
*/
|
||||
plan: {
|
||||
relation: Model.BelongsToOneRelation,
|
||||
modelClass: this.relationBindKnex(Plan.default),
|
||||
join: {
|
||||
from: 'subscription_plan_subscriptions.planId',
|
||||
to: 'subscription_plans.id',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if subscription is active.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
active() {
|
||||
return !this.ended() || this.onTrial();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if subscription is inactive.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
inactive() {
|
||||
return !this.active();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if subscription period has ended.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
ended() {
|
||||
return this.endsAt ? moment().isAfter(this.endsAt) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if subscription is currently on trial.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
onTrial() {
|
||||
return this.trailEndsAt ? moment().isAfter(this.trailEndsAt) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set new period from the given details.
|
||||
* @param {string} invoiceInterval
|
||||
* @param {number} invoicePeriod
|
||||
* @param {string} start
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
setNewPeriod(invoiceInterval, invoicePeriod, start) {
|
||||
let _invoiceInterval = invoiceInterval;
|
||||
let _invoicePeriod = invoicePeriod;
|
||||
|
||||
if (!invoiceInterval) {
|
||||
_invoiceInterval = this.plan.invoiceInterval;
|
||||
}
|
||||
if (!invoicePeriod) {
|
||||
_invoicePeriod = this.plan.invoicePeriod;
|
||||
}
|
||||
const period = new SubscriptionPeriod(_invoiceInterval, _invoicePeriod, start);
|
||||
|
||||
const startsAt = period.getStartDate();
|
||||
const endsAt = period.getEndDate();
|
||||
|
||||
return { startsAt, endsAt };
|
||||
}
|
||||
|
||||
/**
|
||||
* Renews subscription period.
|
||||
* @Promise
|
||||
*/
|
||||
renew(plan) {
|
||||
const { invoicePeriod, invoiceInterval } = plan;
|
||||
const patch = { ...this.setNewPeriod(invoiceInterval, invoicePeriod) };
|
||||
patch.cancelsAt = null;
|
||||
patch.planId = plan.id;
|
||||
|
||||
return this.$query().patch(patch);
|
||||
}
|
||||
}
|
||||
141
server/src/system/models/Subscriptions/Voucher.ts
Normal file
141
server/src/system/models/Subscriptions/Voucher.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { Model, mixin } from 'objection';
|
||||
import moment from 'moment';
|
||||
import SystemModel from '@/system/models/SystemModel';
|
||||
import { IVouchersFilter } from '@/interfaces';
|
||||
|
||||
export default class Voucher extends mixin(SystemModel) {
|
||||
/**
|
||||
* Table name.
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'subscription_vouchers';
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamps columns.
|
||||
*/
|
||||
get timestamps() {
|
||||
return ['createdAt', 'updatedAt'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Model modifiers.
|
||||
*/
|
||||
static get modifiers() {
|
||||
return {
|
||||
// Filters active vouchers.
|
||||
filterActiveVoucher(query) {
|
||||
query.where('disabled', false);
|
||||
query.where('used', false);
|
||||
query.where('sent', false);
|
||||
},
|
||||
|
||||
// Find voucher by its code or id.
|
||||
findByCodeOrId(query, id, code) {
|
||||
if (id) {
|
||||
query.where('id', id);
|
||||
}
|
||||
if (code) {
|
||||
query.where('voucher_code', code);
|
||||
}
|
||||
},
|
||||
|
||||
// Filters vouchers list.
|
||||
filter(builder, vouchersFilter: IVouchersFilter) {
|
||||
if (vouchersFilter.active) {
|
||||
builder.modify('filterActiveVoucher')
|
||||
}
|
||||
if (vouchersFilter.disabled) {
|
||||
builder.where('disabled', true);
|
||||
}
|
||||
if (vouchersFilter.used) {
|
||||
builder.where('used', true);
|
||||
}
|
||||
if (vouchersFilter.sent) {
|
||||
builder.where('sent', true);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Relationship mapping.
|
||||
*/
|
||||
static get relationMappings() {
|
||||
const Plan = require('@/system/models/Subscriptions/Plan');
|
||||
|
||||
return {
|
||||
plan: {
|
||||
relation: Model.BelongsToOneRelation,
|
||||
modelClass: Plan.default,
|
||||
join: {
|
||||
from: 'subscription_vouchers.planId',
|
||||
to: 'subscriptions_plans.id',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given voucher code from the storage.
|
||||
* @param {string} voucherCode
|
||||
* @return {Promise}
|
||||
*/
|
||||
static deleteVoucher(voucherCode: string, viaAttribute: string = 'voucher_code') {
|
||||
return this.query()
|
||||
.where(viaAttribute, voucherCode)
|
||||
.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the given voucher code as disabled on the storage.
|
||||
* @param {string} voucherCode
|
||||
* @return {Promise}
|
||||
*/
|
||||
static markVoucherAsDisabled(voucherCode: string, viaAttribute: string = 'voucher_code') {
|
||||
return this.query()
|
||||
.where(viaAttribute, voucherCode)
|
||||
.patch({
|
||||
disabled: true,
|
||||
disabled_at: moment().toMySqlDateTime(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the given voucher code as sent on the storage.
|
||||
* @param {string} voucherCode
|
||||
*/
|
||||
static markVoucherAsSent(voucherCode: string, viaAttribute: string = 'voucher_code') {
|
||||
return this.query()
|
||||
.where(viaAttribute, voucherCode)
|
||||
.patch({
|
||||
sent: true,
|
||||
sent_at: moment().toMySqlDateTime(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the given voucher code as used on the storage.
|
||||
* @param {string} voucherCode
|
||||
* @return {Promise}
|
||||
*/
|
||||
static markVoucherAsUsed(voucherCode: string, viaAttribute: string = 'voucher_code') {
|
||||
return this.query()
|
||||
.where(viaAttribute, voucherCode)
|
||||
.patch({
|
||||
used: true,
|
||||
used_at: moment().toMySqlDateTime()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {IIPlan} plan
|
||||
* @return {boolean}
|
||||
*/
|
||||
isEqualPlanPeriod(plan) {
|
||||
return (this.invoicePeriod === plan.invoiceInterval &&
|
||||
voucher.voucherPeriod === voucher.periodInterval);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
import { Model, mixin } from 'objection';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import SystemModel from '@/system/models/SystemModel';
|
||||
import UserSubscription from '@/services/Subscription/UserSubscription';
|
||||
|
||||
|
||||
export default class SystemUser extends mixin(SystemModel, [UserSubscription]) {
|
||||
export default class SystemUser extends mixin(SystemModel) {
|
||||
/**
|
||||
* Table name.
|
||||
*/
|
||||
@@ -24,7 +23,6 @@ export default class SystemUser extends mixin(SystemModel, [UserSubscription]) {
|
||||
*/
|
||||
static get relationMappings() {
|
||||
const Tenant = require('@/system/models/Tenant');
|
||||
const SubscriptionUsage = require('@/system/models/SubscriptionUsage');
|
||||
|
||||
return {
|
||||
tenant: {
|
||||
@@ -35,15 +33,6 @@ export default class SystemUser extends mixin(SystemModel, [UserSubscription]) {
|
||||
to: 'tenants.id',
|
||||
},
|
||||
},
|
||||
|
||||
subscriptionUsage: {
|
||||
relation: Model.BelongsToOneRelation,
|
||||
modelClass: SubscriptionUsage.default,
|
||||
join: {
|
||||
from: 'users.id',
|
||||
to: 'subscriptions_usage.user_id',
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import BaseModel from '@/models/Model';
|
||||
import { Model } from 'objection';
|
||||
import SubscriptionPeriod from '@/services/Subscription/SubscriptionPeriod';
|
||||
|
||||
export default class Tenant extends BaseModel {
|
||||
/**
|
||||
@@ -7,4 +9,63 @@ export default class Tenant extends BaseModel {
|
||||
static get tableName() {
|
||||
return 'tenants';
|
||||
}
|
||||
|
||||
/**
|
||||
* Query modifiers.
|
||||
*/
|
||||
static modifiers() {
|
||||
return {
|
||||
subscriptions(builder) {
|
||||
builder.withGraphFetched('subscriptions');
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Relations mappings.
|
||||
*/
|
||||
static get relationMappings() {
|
||||
const PlanSubscription = require('./Subscriptions/PlanSubscription');
|
||||
|
||||
return {
|
||||
subscriptions: {
|
||||
relation: Model.HasManyRelation,
|
||||
modelClass: this.relationBindKnex(PlanSubscription.default),
|
||||
join: {
|
||||
from: 'tenants.id',
|
||||
to: 'subscription_plan_subscriptions.tenantId',
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the subscribed plans ids.
|
||||
* @return {number[]}
|
||||
*/
|
||||
async subscribedPlansIds() {
|
||||
const { subscriptions } = this;
|
||||
return chain(subscriptions).map('planId').unq();
|
||||
}
|
||||
|
||||
/**
|
||||
* Records a new subscription for the associated tenant.
|
||||
* @param {string} subscriptionSlug
|
||||
* @param {IPlan} plan
|
||||
*/
|
||||
newSubscription(subscriptionSlug, plan) {
|
||||
const trial = new SubscriptionPeriod(plan.trialInterval, plan.trialPeriod)
|
||||
const period = new SubscriptionPeriod(plan.invoiceInterval, plan.invoicePeriod, trial.getEndDate());
|
||||
|
||||
return this.$relatedQuery('subscriptions').insert({
|
||||
slug: subscriptionSlug,
|
||||
planId: plan.id,
|
||||
|
||||
trialStartedAt: trial.getStartDate(),
|
||||
trialEndsAt: trial.getEndDate(),
|
||||
|
||||
startsAt: period.getStartDate(),
|
||||
endsAt: period.getEndDate(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
14
server/src/system/models/index.js
Normal file
14
server/src/system/models/index.js
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
import Plan from './Subscriptions/Plan';
|
||||
import PlanFeature from './Subscriptions/PlanFeature';
|
||||
import PlanSubscription from './Subscriptions/PlanSubscription';
|
||||
import Voucher from './Subscriptions/Voucher';
|
||||
import Tenant from './Tenant';
|
||||
|
||||
export {
|
||||
Plan,
|
||||
PlanFeature,
|
||||
PlanSubscription,
|
||||
Voucher,
|
||||
Tenant,
|
||||
}
|
||||
26
server/src/system/seeds/seed_subscriptions_plans.js
Normal file
26
server/src/system/seeds/seed_subscriptions_plans.js
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
exports.seed = (knex) => {
|
||||
// Deletes ALL existing entries
|
||||
return knex('subscription_plans').del()
|
||||
.then(() => {
|
||||
// Inserts seed entries
|
||||
return knex('subscription_plans').insert([
|
||||
{
|
||||
id: 1,
|
||||
name: 'free',
|
||||
slug: 'free',
|
||||
price: 0,
|
||||
active: true,
|
||||
currency: 'LYD',
|
||||
|
||||
trial_period: 15,
|
||||
trial_interval: 'days',
|
||||
|
||||
invoice_period: 3,
|
||||
invoice_interval: 'month',
|
||||
|
||||
index: 1,
|
||||
}
|
||||
]);
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user