Chore: Remove dead code related to billing (#935)

- remove subscription model
- remove billing-related code
This commit is contained in:
Sojan Jose 2020-06-07 20:31:48 +05:30 committed by GitHub
parent 051871a3cd
commit 52d28105e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
84 changed files with 27 additions and 1240 deletions

View file

@ -89,15 +89,6 @@ TWITTER_ENVIRONMENT=
## Mobile app env variables
IOS_APP_ID=6C953F3RX2.com.chatwoot.app
#### This environment variables are only required in hosted version which has billing
ENABLE_BILLING=
## chargebee settings
CHARGEBEE_API_KEY=
CHARGEBEE_SITE=
CHARGEBEE_WEBHOOK_USERNAME=
CHARGEBEE_WEBHOOK_PASSWORD=
## Push Notification
## generate a new key value here : https://d3v.one/vapid-key-generator/
# VAPID_PUBLIC_KEY=

View file

@ -65,7 +65,6 @@ Style/GuardClause:
- 'app/builders/account_builder.rb'
- 'app/models/attachment.rb'
- 'app/models/message.rb'
- 'lib/webhooks/chargebee.rb'
- 'db/migrate/20190819005836_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb'
Metrics/AbcSize:
Exclude:

View file

@ -88,7 +88,6 @@ Naming/MemoizedInstanceVariableName:
- 'app/controllers/application_controller.rb'
- 'app/models/message.rb'
- 'lib/integrations/widget/outgoing_message_builder.rb'
- 'lib/webhooks/chargebee.rb'
# Offense count: 4
# Cop supports --auto-correct.
@ -187,7 +186,6 @@ Rails/EnumHash:
- 'app/models/attachment.rb'
- 'app/models/conversation.rb'
- 'app/models/message.rb'
- 'app/models/subscription.rb'
- 'app/models/user.rb'
# Offense count: 1
@ -226,7 +224,6 @@ Rails/Output:
Rails/TimeZone:
Exclude:
- 'app/builders/report_builder.rb'
- 'app/models/subscription.rb'
- 'lib/reports/update_account_identity.rb'
- 'lib/reports/update_agent_identity.rb'
- 'lib/reports/update_identity.rb'

View file

@ -56,9 +56,6 @@ gem 'administrate'
# https://karolgalanciak.com/blog/2019/11/30/from-activerecord-callbacks-to-publish-slash-subscribe-pattern-and-event-driven-design/
gem 'wisper', '2.0.0'
##--- gems for billing ---##
gem 'chargebee'
##--- gems for channels ---##
gem 'facebook-messenger'
gem 'telegram-bot-ruby'

View file

@ -138,9 +138,6 @@ GEM
bundler (>= 1.2.0, < 3)
thor (~> 0.18)
byebug (11.1.3)
chargebee (2.7.5)
json_pure (~> 2.1)
rest-client (>= 1.8, < 3.0)
coderay (1.1.2)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
@ -249,7 +246,6 @@ GEM
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (2.3.0)
json_pure (2.3.0)
jwt (2.2.1)
kaminari (1.2.1)
activesupport (>= 4.1.0)
@ -542,7 +538,6 @@ DEPENDENCIES
bullet
bundle-audit
byebug
chargebee
devise
devise_token_auth
dotenv-rails

View file

@ -10,8 +10,4 @@ class Api::BaseController < ApplicationController
def authenticate_by_access_token?
request.headers[:api_access_token].present? || request.headers[:HTTP_API_ACCESS_TOKEN].present?
end
def check_billing_enabled
raise ActionController::RoutingError, 'Not Found' unless ENV['BILLING_ENABLED']
end
end

View file

@ -1,13 +0,0 @@
class Api::V1::Accounts::SubscriptionsController < Api::V1::Accounts::BaseController
skip_before_action :check_subscription
before_action :check_billing_enabled
def index
render json: Current.account.subscription_data
end
def status
render json: Current.account.subscription.summary
end
end

View file

@ -2,7 +2,7 @@ class Api::V1::AccountsController < Api::BaseController
include AuthHelper
skip_before_action :verify_authenticity_token, only: [:create]
skip_before_action :authenticate_user!, :set_current_user, :check_subscription, :handle_with_exception,
skip_before_action :authenticate_user!, :set_current_user, :handle_with_exception,
only: [:create], raise: false
before_action :check_signup_enabled, only: [:create]
before_action :fetch_account, except: [:create]

View file

@ -1,6 +1,5 @@
class Api::V1::AgentBotsController < Api::BaseController
skip_before_action :authenticate_user!
skip_before_action :check_subscription
def index
render json: AgentBot.all

View file

@ -1,18 +1,6 @@
class Api::V1::WebhooksController < ApplicationController
skip_before_action :authenticate_user!, raise: false
skip_before_action :set_current_user
skip_before_action :check_subscription
before_action :login_from_basic_auth, only: [:chargebee]
before_action :check_billing_enabled, only: [:chargebee]
def chargebee
chargebee_consumer.consume
head :ok
rescue StandardError => e
Raven.capture_exception(e)
head :ok
end
def twitter_crc
render json: { response_token: "sha256=#{twitter_client.generate_crc(params[:crc_token])}" }
@ -34,16 +22,6 @@ class Api::V1::WebhooksController < ApplicationController
end
end
def login_from_basic_auth
authenticate_or_request_with_http_basic do |username, password|
username == ENV['CHARGEBEE_WEBHOOK_USERNAME'] && password == ENV['CHARGEBEE_WEBHOOK_PASSWORD']
end
end
def chargebee_consumer
@chargebee_consumer ||= ::Webhooks::Chargebee.new(params)
end
def twitter_consumer
@twitter_consumer ||= ::Webhooks::Twitter.new(params)
end

View file

@ -1,6 +1,5 @@
class ApiController < ApplicationController
skip_before_action :set_current_user, only: [:index]
skip_before_action :check_subscription, only: [:index]
def index
render json: { version: Chatwoot.config[:version], timestamp: Time.now.utc.to_formatted_s(:db) }

View file

@ -5,7 +5,6 @@ class ApplicationController < ActionController::Base
protect_from_forgery with: :null_session
before_action :set_current_user, unless: :devise_controller?
before_action :check_subscription, unless: :devise_controller?
around_action :handle_with_exception, unless: :devise_controller?
# after_action :verify_authorized
@ -68,18 +67,6 @@ class ApplicationController < ActionController::Base
I18n.locale = locale || I18n.default_locale
end
def check_subscription
# This block is left over from the initial version of chatwoot
# We might reuse this later in the hosted version of chatwoot.
return if !ENV['BILLING_ENABLED'] || !current_user
if current_subscription.trial? && current_subscription.expiry < Date.current
render json: { error: 'Trial Expired' }, status: :trial_expired
elsif current_subscription.cancelled?
render json: { error: 'Account Suspended' }, status: :account_suspended
end
end
def pundit_user
{
user: Current.user,

View file

@ -10,7 +10,6 @@ class AsyncDispatcher < BaseDispatcher
def listeners
listeners = [EventListener.instance, WebhookListener.instance]
listeners << SubscriptionListener.instance if ENV['BILLING_ENABLED']
listeners
end
end

View file

@ -1,2 +0,0 @@
module Api::V1::SubscriptionsHelper
end

View file

@ -1,20 +0,0 @@
/* global axios */
import endPoints from './endPoints';
export default {
getSubscription() {
const urlData = endPoints('subscriptions').get();
const fetchPromise = new Promise((resolve, reject) => {
axios
.get(urlData.url)
.then(response => {
resolve(response);
})
.catch(error => {
reject(error);
});
});
return fetchPromise;
},
};

View file

@ -33,14 +33,6 @@ const endPoints = {
},
params: { omniauth_token: '' },
},
subscriptions: {
get() {
return {
url: '/api/v1/subscriptions',
};
},
},
};
export default page => {

View file

@ -3,7 +3,6 @@
@import 'animations';
@import 'foundation-custom';
@import 'widgets/billing';
@import 'widgets/buttons';
@import 'widgets/conv-header';
@import 'widgets/conversation-card';

View file

@ -1,75 +0,0 @@
.billing {
@include full-height;
.row {
@include full-height;
}
.billing__stats {
@include flex;
}
.billing__form {
@include thin-border($color-border-light);
@include margin($zero - $space-micro);
@include full-height;
background: $color-white;
iframe {
@include full-height;
border: 0;
width: 100%;
}
}
.account-row {
@include padding($space-normal);
@include flex;
flex-direction: column;
// @include thin-border($color-border-light);
// @include margin(-$space-micro $zero);
background: $color-white;
font-size: $font-size-small;
.title {
color: $color-heading;
font-weight: $font-weight-medium;
}
.value {
font-size: $font-size-mega;
font-weight: $font-weight-light;
text-transform: capitalize;
}
}
}
.account-locked {
@include background-gray;
@include margin(0);
}
.lock-message {
@include flex;
@include full-height;
flex-direction: column;
@include flex-align(center, middle);
div {
@include flex;
@include full-height;
flex-direction: column;
@include flex-align(center, middle);
img {
@include margin($space-normal);
width: 10rem;
}
span {
font-size: $font-size-small;
font-weight: $font-weight-medium;
text-align: center;
}
}
}

View file

@ -21,18 +21,6 @@
</transition-group>
</div>
<!-- this block is only required in the hosted version with billing enabled -->
<transition name="fade" mode="out-in">
<woot-status-bar
v-if="shouldShowStatusBox"
:message="trialMessage"
:button-text="$t('APP_GLOBAL.TRAIL_BUTTON')"
:button-route="{ name: 'billing' }"
:type="statusBarClass"
:show-button="isAdmin"
/>
</transition>
<div class="bottom-nav">
<transition name="menu-slide">
<div
@ -108,7 +96,6 @@ import { mixin as clickaway } from 'vue-clickaway';
import adminMixin from '../../mixins/isAdmin';
import Auth from '../../api/auth';
import SidebarItem from './SidebarItem';
import WootStatusBar from '../widgets/StatusBar';
import { frontendURL } from '../../helper/URLHelper';
import Thumbnail from '../widgets/Thumbnail';
import { getSidebarItems } from '../../i18n/default-sidebar';
@ -116,7 +103,6 @@ import { getSidebarItems } from '../../i18n/default-sidebar';
export default {
components: {
SidebarItem,
WootStatusBar,
Thumbnail,
},
mixins: [clickaway, adminMixin],
@ -138,7 +124,6 @@ export default {
daysLeft: 'getTrialLeft',
globalConfig: 'globalConfig/get',
inboxes: 'inboxes/getInboxes',
subscriptionData: 'getSubscription',
accountId: 'getCurrentAccountId',
currentRole: 'getCurrentRole',
}),
@ -160,10 +145,6 @@ export default {
}
}
if (!window.chatwootConfig.billingEnabled) {
menuItems = this.filterBillingRoutes(menuItems);
}
return this.filterMenuItemsByRole(menuItems);
},
currentRoute() {
@ -193,35 +174,11 @@ export default {
dashboardPath() {
return frontendURL(`accounts/${this.accountId}/dashboard`);
},
shouldShowStatusBox() {
return (
window.chatwootConfig.billingEnabled &&
(this.subscriptionData.state === 'trial' ||
this.subscriptionData.state === 'cancelled')
);
},
statusBarClass() {
if (this.subscriptionData.state === 'trial') {
return 'warning';
}
if (this.subscriptionData.state === 'cancelled') {
return 'danger';
}
return '';
},
trialMessage() {
return `${this.daysLeft} ${this.$t('APP_GLOBAL.TRIAL_MESSAGE')}`;
},
},
mounted() {
this.$store.dispatch('inboxes/get');
},
methods: {
filterBillingRoutes(menuItems) {
return menuItems.filter(
menuItem => !menuItem.toState.includes('billing')
);
},
filterMenuItemsByRole(menuItems) {
if (!this.currentRole) {
return [];

View file

@ -1,24 +0,0 @@
<template>
<div class="status-bar" :class="type">
<p class="message">{{message}}</p>
<router-link
:to="buttonRoute"
class="button small warning nice"
v-if="showButton"
>
{{buttonText}}
</router-link>
</div>
</template>
<script>
export default {
props: {
message: String,
buttonRoute: Object,
buttonText: String,
showButton: Boolean,
type: String, // Danger, Info, Success, Warning
},
};
</script>

View file

@ -1,15 +1,8 @@
/* eslint no-console: 0 */
import constants from '../constants';
import Auth from '../api/auth';
import router from '../routes';
const parseErrorCode = error => {
const errorStatus = error.response ? error.response.status : undefined;
// 901, 902 are used to identify billing related issues
if ([901, 902].includes(errorStatus)) {
const name = Auth.isAdmin() ? 'billing' : 'billing_deactivated';
router.push({ name });
}
return Promise.reject(error);
};

View file

@ -8,7 +8,6 @@ export const getSidebarItems = accountId => ({
'inbox_conversation',
'conversation_through_inbox',
'settings_account_reports',
'billing_deactivated',
'profile_settings',
'profile_settings_index',
],
@ -51,7 +50,6 @@ export const getSidebarItems = accountId => ({
'settings_inboxes_page_channel',
'settings_inboxes_add_agents',
'settings_inbox_finish',
'billing',
'settings_integrations',
'settings_integrations_webhook',
'general_settings',
@ -88,13 +86,6 @@ export const getSidebarItems = accountId => ({
),
toStateName: 'canned_list',
},
billing: {
icon: 'ion-card',
label: 'BILLING',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/billing`),
toStateName: 'billing',
},
settings_integrations: {
icon: 'ion-flash',
label: 'INTEGRATIONS',

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Facturació",
"LOADING": "S'estan obtenin les suscripcions",
"ACCOUNT_STATE": "Estat del compte",
"AGENT_COUNT": "Compte d'agent",
"PER_AGENT_COST": "Per cost d'agent",
"TOTAL_COST": "Cost total",
"BUTTON": {
"ADD": "Afegir mètode de pagament",
"EDIT": "EDITAR Mètode de pagament"
},
"TRIAL": {
"TITLE": "S'ha acabat el període de prova",
"MESSAGE": "Afegiu un mètode de pagament per continuar utilitzant Chatwoot."
},
"ACCOUNT_LOCKED": "El seu compte no està disponible de moment. <br>Poseu-vos en contacte amb l'administrador per reactivar-lo."
}
}

View file

@ -1,6 +1,5 @@
/* eslint-disable */
import { default as _agentMgmt } from './agentMgmt.json';
import { default as _billing } from './billing.json';
import { default as _cannedMgmt } from './cannedMgmt.json';
import { default as _chatlist } from './chatlist.json';
import { default as _contact } from './contact.json';
@ -17,7 +16,6 @@ import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
..._billing,
..._cannedMgmt,
..._chatlist,
..._contact,

View file

@ -87,7 +87,6 @@
"AGENTS": "Agents",
"INBOXES": "Safates d'entrada",
"CANNED_RESPONSES": "Respostes Predeterminades",
"BILLING": "Facturació",
"INTEGRATIONS": "Integracions",
"ACCOUNT_SETTINGS": "Configuració del compte"
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Fakturace",
"LOADING": "Načítání předplatného",
"ACCOUNT_STATE": "Stav účtu",
"AGENT_COUNT": "Počet agentů",
"PER_AGENT_COST": "Náklady na jednoho agenta",
"TOTAL_COST": "Celkové náklady",
"BUTTON": {
"ADD": "Přidat způsob platby",
"EDIT": "Metoda platby EDIT"
},
"TRIAL": {
"TITLE": "Vaše zkušební období skončilo",
"MESSAGE": "Přidejte platební metodu a pokračujte v používání Chatwoot."
},
"ACCOUNT_LOCKED": "Váš účet není momentálně k dispozici. <br>Obraťte se na správce pro opětovné aktivaci."
}
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Abrechnung",
"LOADING": "Abonnements abrufen",
"ACCOUNT_STATE": "Kontostatus",
"AGENT_COUNT": "Anzahl der Agenten",
"PER_AGENT_COST": "Kosten pro Agent",
"TOTAL_COST": "Gesamtkosten",
"BUTTON": {
"ADD": "Zahlungsmethode hinzufügen",
"EDIT": "Zahlungsmethode BEARBEITEN"
},
"TRIAL": {
"TITLE": "Ihre Probezeit ist vorbei",
"MESSAGE": "Fügen Sie eine Zahlungsmethode hinzu, um Chatwoot weiterhin zu verwenden."
},
"ACCOUNT_LOCKED": "Ihr Konto ist derzeit nicht verfügbar. <br> Bitte wenden Sie sich zur Reaktivierung an Ihren Administrator."
}
}

View file

@ -1,6 +1,5 @@
/* eslint-disable */
import { default as _agentMgmt } from './agentMgmt.json';
import { default as _billing } from './billing.json';
import { default as _cannedMgmt } from './cannedMgmt.json';
import { default as _chatlist } from './chatlist.json';
import { default as _contact } from './contact.json';
@ -17,7 +16,6 @@ import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
..._billing,
..._cannedMgmt,
..._chatlist,
..._contact,

View file

@ -90,7 +90,6 @@
"AGENTS": "Agenten",
"INBOXES": "Posteingänge",
"CANNED_RESPONSES": "Vorgefertigte Antworten",
"BILLING": "Abrechnung",
"INTEGRATIONS": "Integrationen",
"ACCOUNT_SETTINGS": "Kontoeinstellungen"
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Χρεώσεις",
"LOADING": "Λήψη Συνδρομών",
"ACCOUNT_STATE": "Κατάσταση Λογαριασμού",
"AGENT_COUNT": "Αριθμός Πρακτόρων",
"PER_AGENT_COST": "Κόστος ανά πράκτορα",
"TOTAL_COST": "Συνολικό κόστος",
"BUTTON": {
"ADD": "Προσθήκη μεθόδου πληρωμής",
"EDIT": "Επεξεργασία μεθόδου πληρωμής"
},
"TRIAL": {
"TITLE": "Η δοκιμαστική περίοδος ολοκληρώθηκε",
"MESSAGE": "Προσθέστε μια μέθοδο πληρωμής για να συνεχίσετε την χρήση του Chatwoot."
},
"ACCOUNT_LOCKED": "O Λογαριασμός σας δεν είναι ενεργός αυτήν τη στιγμή. <br>Παρακαλώ απευθυνθείτε στον διαχειριστή για ενεργοποίηση."
}
}

View file

@ -1,6 +1,5 @@
/* eslint-disable */
import { default as _agentMgmt } from './agentMgmt.json';
import { default as _billing } from './billing.json';
import { default as _cannedMgmt } from './cannedMgmt.json';
import { default as _chatlist } from './chatlist.json';
import { default as _contact } from './contact.json';
@ -17,7 +16,6 @@ import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
..._billing,
..._cannedMgmt,
..._chatlist,
..._contact,

View file

@ -102,7 +102,6 @@
"AGENTS": "Πράκτορες",
"INBOXES": "Κιβώτια Εισερχομένων",
"CANNED_RESPONSES": "Έτοιμες Απαντήσεις",
"BILLING": "Χρεώσεις",
"INTEGRATIONS": "Ενοποιήσεις",
"ACCOUNT_SETTINGS": "Ρυθμίσεις Λογαριασμού"
}

View file

@ -3,7 +3,7 @@
"HEADER": "Agents",
"HEADER_BTN_TXT": "Add Agent",
"LOADING": "Fetching Agent List",
"SIDEBAR_TXT": "<p><b>Agents</b></p> <p> An <b>Agent</b> is a member of your Customer Support team. </p><p> Agents will be able to view and reply to messages from your users. The list shows all agents currently in your account. </p><p> Click on <b>Add Agent</b> to add a new agent. Agent you add will receive an email with a confirmation link to activate their account, after which they can access Chatwoot and respond to messages. </p><p> Access to Chatwoot's features are based on following roles. </p><p> <b>Agent</b> - Agents with this role can only access inboxes, reports and conversations. They can assign conversations to other agents or themselves and resolve conversations.</p><p> <b>Administrator</b> - Administrator will have access to all Chatwoot features enabled for your account, including settings and billing, along with all of a normal agents' privileges.</p>",
"SIDEBAR_TXT": "<p><b>Agents</b></p> <p> An <b>Agent</b> is a member of your Customer Support team. </p><p> Agents will be able to view and reply to messages from your users. The list shows all agents currently in your account. </p><p> Click on <b>Add Agent</b> to add a new agent. Agent you add will receive an email with a confirmation link to activate their account, after which they can access Chatwoot and respond to messages. </p><p> Access to Chatwoot's features are based on following roles. </p><p> <b>Agent</b> - Agents with this role can only access inboxes, reports and conversations. They can assign conversations to other agents or themselves and resolve conversations.</p><p> <b>Administrator</b> - Administrator will have access to all Chatwoot features enabled for your account, including settings, along with all of a normal agents' privileges.</p>",
"AGENT_TYPES": [
{
"name": "administrator",

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Billing",
"LOADING": "Fetching Subscriptions",
"ACCOUNT_STATE": "Account State",
"AGENT_COUNT": "Agent Count",
"PER_AGENT_COST": "Per Agent Cost",
"TOTAL_COST": "Total Cost",
"BUTTON": {
"ADD": "Add Payment Method",
"EDIT": "EDIT Payment Method"
},
"TRIAL": {
"TITLE": "Your Trial period is over",
"MESSAGE": "Add a payment method to continue using Chatwoot."
},
"ACCOUNT_LOCKED": "Your account is not available at the moment. <br>Please contact your administrator for reactivation."
}
}

View file

@ -1,6 +1,5 @@
/* eslint-disable */
import { default as _agentMgmt } from './agentMgmt.json';
import { default as _billing } from './billing.json';
import { default as _cannedMgmt } from './cannedMgmt.json';
import { default as _chatlist } from './chatlist.json';
import { default as _contact } from './contact.json';
@ -17,7 +16,6 @@ import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
..._billing,
..._cannedMgmt,
..._chatlist,
..._contact,

View file

@ -102,7 +102,6 @@
"AGENTS": "Agents",
"INBOXES": "Inboxes",
"CANNED_RESPONSES": "Canned Responses",
"BILLING": "Billing",
"INTEGRATIONS": "Integrations",
"ACCOUNT_SETTINGS": "Account Settings"
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Facturación",
"LOADING": "Obteniendo suscripciones",
"ACCOUNT_STATE": "Estado de cuenta",
"AGENT_COUNT": "Contador de agentes",
"PER_AGENT_COST": "Coste por agente",
"TOTAL_COST": "Coste total",
"BUTTON": {
"ADD": "Añadir método de pago",
"EDIT": "Método de pago EDIT"
},
"TRIAL": {
"TITLE": "Su período de prueba ha terminado",
"MESSAGE": "Añadir un método de pago para seguir usando Chatwoot."
},
"ACCOUNT_LOCKED": "Su cuenta no está disponible en este momento. <br>Póngase en contacto con su administrador para reactivación."
}
}

View file

@ -1,6 +1,5 @@
/* eslint-disable */
import { default as _agentMgmt } from './agentMgmt.json';
import { default as _billing } from './billing.json';
import { default as _cannedMgmt } from './cannedMgmt.json';
import { default as _chatlist } from './chatlist.json';
import { default as _contact } from './contact.json';
@ -17,7 +16,6 @@ import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
..._billing,
..._cannedMgmt,
..._chatlist,
..._contact,

View file

@ -102,7 +102,6 @@
"AGENTS": "Agentes",
"INBOXES": "Entradas",
"CANNED_RESPONSES": "Respuestas predefinidas",
"BILLING": "Facturación",
"INTEGRATIONS": "Integraciones",
"ACCOUNT_SETTINGS": "Configuración de la cuenta"
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Facturation",
"LOADING": "Récupération des abonnements",
"ACCOUNT_STATE": "État du compte",
"AGENT_COUNT": "Nombre d'agents",
"PER_AGENT_COST": "Coût par agent",
"TOTAL_COST": "Coût total",
"BUTTON": {
"ADD": "Ajouter une méthode de paiement",
"EDIT": "MODIFIER la méthode de paiement"
},
"TRIAL": {
"TITLE": "Votre période d'essai est terminée",
"MESSAGE": "Ajoutez une méthode de paiement pour continuer à utiliser Chatwoot."
},
"ACCOUNT_LOCKED": "Votre compte n'est pas disponible pour le moment. <br>Veuillez contacter votre administrateur pour la réactivation."
}
}

View file

@ -1,6 +1,5 @@
/* eslint-disable */
import { default as _agentMgmt } from './agentMgmt.json';
import { default as _billing } from './billing.json';
import { default as _cannedMgmt } from './cannedMgmt.json';
import { default as _chatlist } from './chatlist.json';
import { default as _contact } from './contact.json';
@ -17,7 +16,6 @@ import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
..._billing,
..._cannedMgmt,
..._chatlist,
..._contact,

View file

@ -102,7 +102,6 @@
"AGENTS": "Agents",
"INBOXES": "Boîtes de réception",
"CANNED_RESPONSES": "Réponses standardisées",
"BILLING": "Facturation",
"INTEGRATIONS": "Intégrations",
"ACCOUNT_SETTINGS": "Paramètres du compte"
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Fatturazione",
"LOADING": "Recupero Iscrizioni",
"ACCOUNT_STATE": "Stato del conto",
"AGENT_COUNT": "Conteggio Agente",
"PER_AGENT_COST": "Costo per agente",
"TOTAL_COST": "Costo totale",
"BUTTON": {
"ADD": "Aggiungi metodo di pagamento",
"EDIT": "Metodo di pagamento EDIT"
},
"TRIAL": {
"TITLE": "Il tuo periodo di prova è finito",
"MESSAGE": "Aggiungi un metodo di pagamento per continuare a utilizzare Chatwoot."
},
"ACCOUNT_LOCKED": "Il tuo account non è al momento disponibile. <br>Si prega di contattare l'amministratore per la riattivazione."
}
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "ബില്ലിംഗ്",
"LOADING": "സബ്സ്ക്രിപ്ഷനുകൾ ലഭ്യമാക്കുന്നു",
"ACCOUNT_STATE": "അക്കൗണ്ടിന്റെ അവസ്ഥ",
"AGENT_COUNT": "ഏജന്റിന്റെ എണ്ണം ",
"PER_AGENT_COST": "ഓരോ ഏജന്റിന്റെ വില",
"TOTAL_COST": "ആകെ ചെലവ്",
"BUTTON": {
"ADD": "പേയ്‌മെന്റ് രീതി ചേർക്കുക",
"EDIT": "പേയ്‌മെന്റ് രീതി എഡിറ്റുചെയ്യുക"
},
"TRIAL": {
"TITLE": "നിങ്ങളുടെ ട്രയൽ കാലയളവ് അവസാനിച്ചു",
"MESSAGE": "ചാറ്റ് വൂട്ട് ഉപയോഗിക്കുന്നത് തുടരാൻ ഒരു പേയ്‌മെന്റ് രീതി ചേർക്കുക."
},
"ACCOUNT_LOCKED": "നിങ്ങളുടെ അക്കൗണ്ട് ഇപ്പോൾ ലഭ്യമല്ല. <br> വീണ്ടും സജീവമാക്കുന്നതിന് ദയവായി നിങ്ങളുടെ അഡ്മിനിസ്ട്രേറ്ററുമായി ബന്ധപ്പെടുക."
}
}

View file

@ -1,6 +1,5 @@
/* eslint-disable */
import { default as _agentMgmt } from './agentMgmt.json';
import { default as _billing } from './billing.json';
import { default as _cannedMgmt } from './cannedMgmt.json';
import { default as _chatlist } from './chatlist.json';
import { default as _contact } from './contact.json';
@ -17,7 +16,6 @@ import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
..._billing,
..._cannedMgmt,
..._chatlist,
..._contact,

View file

@ -90,7 +90,6 @@
"AGENTS": "ഏജന്റുമാർ",
"INBOXES": "ഇൻബോക്സുകൾ",
"CANNED_RESPONSES": "ക്യാൻഡ് പ്രതികരണങ്ങൾ",
"BILLING": "ബില്ലിംഗ്",
"INTEGRATIONS": "സംയോജനങ്ങൾ",
"ACCOUNT_SETTINGS": "അക്കൗണ്ട് ക്രമീകരണങ്ങൾ"
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Facturatie",
"LOADING": "Ophalen Abonnementen",
"ACCOUNT_STATE": "Accountstatus",
"AGENT_COUNT": "Aantal Medewerkers",
"PER_AGENT_COST": "Kosten per medewerker",
"TOTAL_COST": "Totale kosten",
"BUTTON": {
"ADD": "Betaalmethode toevoegen",
"EDIT": "Betalingsmethode bewerken"
},
"TRIAL": {
"TITLE": "Uw proefperiode is voorbij",
"MESSAGE": "Voeg een betaalmethode toe om Chatwoot te blijven gebruiken."
},
"ACCOUNT_LOCKED": "Uw account is op dit moment niet beschikbaar. <br>Neem contact op met uw beheerder voor heractivatie."
}
}

View file

@ -1,6 +1,5 @@
/* eslint-disable */
import { default as _agentMgmt } from './agentMgmt.json';
import { default as _billing } from './billing.json';
import { default as _cannedMgmt } from './cannedMgmt.json';
import { default as _chatlist } from './chatlist.json';
import { default as _contact } from './contact.json';
@ -17,7 +16,6 @@ import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
..._billing,
..._cannedMgmt,
..._chatlist,
..._contact,

View file

@ -102,7 +102,6 @@
"AGENTS": "Medewerkers",
"INBOXES": "Inboxen",
"CANNED_RESPONSES": "Standaard antwoorden",
"BILLING": "Facturatie",
"INTEGRATIONS": "Integraties",
"ACCOUNT_SETTINGS": "Accountinstellingen"
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Płatność",
"LOADING": "Pobieranie subskrypcji",
"ACCOUNT_STATE": "Stan konta",
"AGENT_COUNT": "Liczba agentów",
"PER_AGENT_COST": "Koszt za agenta",
"TOTAL_COST": "Całkowity koszt",
"BUTTON": {
"ADD": "Dodaj metodę płatności",
"EDIT": "Metoda płatności EDIT"
},
"TRIAL": {
"TITLE": "Twój okres próbny minął",
"MESSAGE": "Dodaj metodę płatności, aby kontynuować korzystanie z Chatwoot."
},
"ACCOUNT_LOCKED": "Twoje konto nie jest obecnie dostępne. <br>Skontaktuj się z administratorem, aby reaktywować."
}
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Faturamento",
"LOADING": "Buscando Assinaturas",
"ACCOUNT_STATE": "Estado do cliente",
"AGENT_COUNT": "Número de Representantes",
"PER_AGENT_COST": "Custo por agente",
"TOTAL_COST": "Custo Total",
"BUTTON": {
"ADD": "Adicionar método de pagamento",
"EDIT": "EDIT Método de Pagamento"
},
"TRIAL": {
"TITLE": "Seu período de avaliação terminou",
"MESSAGE": "Adicione um método de pagamento para continuar usando o Chatwoot."
},
"ACCOUNT_LOCKED": "Sua conta não está disponível no momento. <br>Por favor, entre em contato com o administrador para reativação."
}
}

View file

@ -1,6 +1,5 @@
/* eslint-disable */
import { default as _agentMgmt } from './agentMgmt.json';
import { default as _billing } from './billing.json';
import { default as _cannedMgmt } from './cannedMgmt.json';
import { default as _chatlist } from './chatlist.json';
import { default as _contact } from './contact.json';
@ -17,7 +16,6 @@ import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
..._billing,
..._cannedMgmt,
..._chatlist,
..._contact,

View file

@ -67,7 +67,6 @@
"AGENTS": "Agentes",
"INBOXES": "Caixas de entrada",
"CANNED_RESPONSES": "Respostas Enlatadas",
"BILLING": "Faturamento",
"INTEGRATIONS": "Integrações",
"ACCOUNT_SETTINGS": "Configurações da conta"
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Faturamento",
"LOADING": "Buscando Assinaturas",
"ACCOUNT_STATE": "Estado do cliente",
"AGENT_COUNT": "Número de Agente",
"PER_AGENT_COST": "Custo por agente",
"TOTAL_COST": "Custo Total",
"BUTTON": {
"ADD": "Adicionar Forma de Pagamento",
"EDIT": "Editar Forma de Pagamento"
},
"TRIAL": {
"TITLE": "Seu período de avaliação terminou",
"MESSAGE": "Adicione um método de pagamento para continuar usando o Chatwoot."
},
"ACCOUNT_LOCKED": "Sua conta não está disponível no momento. <br>Por favor, entre em contato com o administrador para reativação."
}
}

View file

@ -1,6 +1,5 @@
/* eslint-disable */
import { default as _agentMgmt } from './agentMgmt.json';
import { default as _billing } from './billing.json';
import { default as _cannedMgmt } from './cannedMgmt.json';
import { default as _chatlist } from './chatlist.json';
import { default as _contact } from './contact.json';
@ -17,7 +16,6 @@ import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
..._billing,
..._cannedMgmt,
..._chatlist,
..._contact,

View file

@ -100,7 +100,6 @@
"AGENTS": "Agentes",
"INBOXES": "Caixas de Entrada",
"CANNED_RESPONSES": "Atalhos",
"BILLING": "Faturamento",
"INTEGRATIONS": "Integrações",
"ACCOUNT_SETTINGS": "Configurações da conta"
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Facturare",
"LOADING": "Preluare abonamente",
"ACCOUNT_STATE": "Stare cont",
"AGENT_COUNT": "Număr de agenți",
"PER_AGENT_COST": "Cost per Agent",
"TOTAL_COST": "Cost total",
"BUTTON": {
"ADD": "Adaugă metodă de plată",
"EDIT": "Adaugă metodă de plată"
},
"TRIAL": {
"TITLE": "Perioada de evaluare s-a încheiat",
"MESSAGE": "Adaugă o metodă de plată pentru a continua să folosești Chatwoot."
},
"ACCOUNT_LOCKED": "Contul dvs. nu este disponibil momentan. <br>Vă rugăm să contactaţi administratorul pentru reactivare."
}
}

View file

@ -1,5 +1,4 @@
import { default as _agentMgmt } from './agentMgmt.json';
import { default as _billing } from './billing.json';
import { default as _cannedMgmt } from './cannedMgmt.json';
import { default as _chatlist } from './chatlist.json';
import { default as _contact } from './contact.json';
@ -16,7 +15,6 @@ import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
..._billing,
..._cannedMgmt,
..._chatlist,
..._contact,

View file

@ -102,7 +102,6 @@
"AGENTS": "Agenți",
"INBOXES": "Căsuțe",
"CANNED_RESPONSES": "Răspunsuri predefinite",
"BILLING": "Facturare",
"INTEGRATIONS": "Integrări",
"ACCOUNT_SETTINGS": "Setările contului"
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Fakturering",
"LOADING": "Hämtar prenumerationer",
"ACCOUNT_STATE": "Kontots status",
"AGENT_COUNT": "Agentkommando Antal",
"PER_AGENT_COST": "Per agent: kostnad",
"TOTAL_COST": "Total kostnad",
"BUTTON": {
"ADD": "Lägg till betalningsmetod",
"EDIT": "EDIT betalningsmetod"
},
"TRIAL": {
"TITLE": "Din provperiod är över",
"MESSAGE": "Lägg till en betalningsmetod för att fortsätta använda Chatwoot."
},
"ACCOUNT_LOCKED": "Ditt konto är inte tillgängligt just nu. <br>Kontakta administratören för återaktivering."
}
}

View file

@ -1,19 +0,0 @@
{
"BILLING": {
"HEADER": "Оплата",
"LOADING": "Отримання підписок",
"ACCOUNT_STATE": "Стан облікового запису",
"AGENT_COUNT": "Кількість агентів",
"PER_AGENT_COST": "Вартість одного агента",
"TOTAL_COST": "Загальна вартість",
"BUTTON": {
"ADD": "Додати спосіб оплати",
"EDIT": "РЕДАГУВАТИ спосіб оплати"
},
"TRIAL": {
"TITLE": "Пробний період закінчився",
"MESSAGE": "Додайте спосіб оплати, щоб продовжити використовувати Chatwoot."
},
"ACCOUNT_LOCKED": "На даний момент ваш обліковий запис недоступний. <br>Зверніться до свого адміністратора для повторної активації."
}
}

View file

@ -1,22 +0,0 @@
<template>
<div class="column content-box account-locked">
<div class="lock-message">
<!-- No inboxes attached -->
<div>
<img src="~dashboard/assets/images/lock.svg" alt="Lock" />
<span v-html="$t('BILLING.ACCOUNT_LOCKED')">
</span>
</div>
</div>
</div>
</template>
<script>
/* eslint no-console: 0 */
/* global bus */
export default {
props: ['state'],
};
</script>

View file

@ -1,124 +0,0 @@
<template>
<div class="column content-box billing">
<woot-loading-state v-if="fetchStatus" :message="$t('BILLING.LOADING')" />
<div v-if="billingDetails" class="row">
<div class="small-12 columns billing__stats">
<div class="account-row column">
<span class="title">{{ $t('BILLING.ACCOUNT_STATE') }}</span>
<span class="value">{{ billingDetails.state }} </span>
</div>
<div class="account-row column">
<span class="title">{{ $t('BILLING.AGENT_COUNT') }}</span>
<span class="value">{{ billingDetails.agents_count }} </span>
</div>
<div class="account-row column">
<span class="title">{{ $t('BILLING.PER_AGENT_COST') }}</span>
<span class="value">${{ billingDetails.per_agent_cost }} </span>
</div>
<div class="account-row column">
<span class="title">{{ $t('BILLING.TOTAL_COST') }}</span>
<span class="value">${{ billingDetails.total_cost }} </span>
</div>
</div>
<div class="small-12 columns billing__form">
<iframe
v-if="iframeUrl && !isShowEmptyState"
:src="billingDetails.iframe_url"
></iframe>
<div v-if="isShowEmptyState">
<empty-state :title="emptyStateTitle" :message="emptyStateMessage">
<div class="medium-12 columns text-center">
<button class="button success nice" @click="billingButtonClick()">
{{ buttonText }}
</button>
</div>
</empty-state>
</div>
</div>
</div>
</div>
</template>
<script>
/* eslint no-console: 0 */
/* global bus */
import { mapGetters } from 'vuex';
import EmptyState from '../../../../components/widgets/EmptyState';
export default {
components: {
EmptyState,
},
props: ['state'],
data() {
return {
is_adding_source: false,
};
},
computed: {
...mapGetters({
billingDetails: 'getBillingDetails',
fetchStatus: 'billingFetchStatus',
daysLeft: 'getTrialLeft',
subscriptionData: 'getSubscription',
}),
redirectMessage() {
if (!this.state) {
return '';
}
if (this.state === 'succeeded') {
return this.$t('BILLING.STATUS.SUCCESS');
}
return this.$t('BILLING.STATUS.ERROR');
},
iframeUrl() {
return typeof this.billingDetails.iframe_url === 'string';
},
isShowEmptyState() {
if (this.billingDetails !== null) {
if (this.is_adding_source) {
return false;
}
}
return true;
},
buttonText() {
if (this.billingDetails !== null) {
return this.billingDetails.payment_source_added
? this.$t('BILLING.BUTTON.EDIT')
: this.$t('BILLING.BUTTON.ADD');
}
return this.$t('BILLING.BUTTON.ADD');
},
emptyStateTitle() {
if (this.daysLeft <= 0 || this.subscriptionData.state === 'cancelled') {
return this.$t('BILLING.TRIAL.TITLE');
}
return '';
},
emptyStateMessage() {
if (this.daysLeft <= 0 || this.subscriptionData.state === 'cancelled') {
return this.$t('BILLING.TRIAL.MESSAGE');
}
return '';
},
},
mounted() {
if (this.state) {
bus.$emit('newToastMessage', this.redirectMessage);
}
this.$store.dispatch('fetchSubscription');
},
methods: {
billingButtonClick() {
this.is_adding_source = true;
},
},
};
</script>

View file

@ -1,32 +0,0 @@
import Index from './Index';
import SettingsContent from '../Wrapper';
import AccountLocked from './AccountLocked';
import { frontendURL } from '../../../../helper/URLHelper';
export default {
routes: [
{
path: frontendURL('accounts/:accountId/settings/billing'),
component: SettingsContent,
props: {
headerTitle: 'BILLING.HEADER',
icon: 'ion-card',
},
children: [
{
path: '',
name: 'billing',
component: Index,
roles: ['administrator'],
props: route => ({ state: route.query.state }),
},
],
},
{
path: '/deactivated',
name: 'billing_deactivated',
component: AccountLocked,
roles: ['agent'],
},
],
};

View file

@ -1,6 +1,5 @@
import { frontendURL } from '../../../helper/URLHelper';
import agent from './agents/agent.routes';
import billing from './billing/billing.routes';
import canned from './canned/canned.routes';
import inbox from './inbox/inbox.routes';
import profile from './profile/profile.routes';
@ -23,7 +22,6 @@ export default {
},
},
...agent.routes,
...billing.routes,
...canned.routes,
...inbox.routes,
...profile.routes,

View file

@ -4,7 +4,6 @@ import Vuex from 'vuex';
import accounts from './modules/accounts';
import agents from './modules/agents';
import auth from './modules/auth';
import billing from './modules/billing';
import cannedResponse from './modules/cannedResponse';
import Channel from './modules/channels';
import contactConversations from './modules/contactConversations';
@ -27,7 +26,6 @@ export default new Vuex.Store({
accounts,
agents,
auth,
billing,
cannedResponse,
Channel,
contactConversations,

View file

@ -1,60 +0,0 @@
/* eslint no-console: 0 */
/* eslint no-param-reassign: 0 */
/* eslint no-shadow: 0 */
import * as types from '../mutation-types';
import Billing from '../../api/billing';
const state = {
fetchingStatus: false,
billingDetails: {},
status: null,
};
const getters = {
getBillingDetails(_state) {
return _state.billingDetails;
},
billingFetchStatus(_state) {
return _state.fetchingStatus;
},
};
const actions = {
fetchSubscription({ commit }) {
commit(types.default.TOGGLE_SUBSCRIPTION_LOADING, true);
Billing.getSubscription()
.then(billingDetails => {
commit(types.default.SET_SUBSCRIPTION, billingDetails.data);
commit(
types.default.TOGGLE_SUBSCRIPTION_LOADING,
false,
billingDetails.status
);
})
.catch(error => {
const { response } = error;
commit(
types.default.TOGGLE_SUBSCRIPTION_LOADING,
false,
response.status
);
});
},
};
const mutations = {
[types.default.SET_SUBSCRIPTION](_state, billingDetails) {
_state.billingDetails = billingDetails;
},
[types.default.TOGGLE_SUBSCRIPTION_LOADING](_state, flag, apiStatus) {
_state.fetchingStatus = flag;
_state.status = apiStatus;
},
};
export default {
state,
getters,
actions,
mutations,
};

View file

@ -93,10 +93,6 @@ export default {
SET_ACCOUNT_SUMMARY: 'SET_ACCOUNT_SUMMARY',
TOGGLE_ACCOUNT_REPORT_LOADING: 'TOGGLE_ACCOUNT_REPORT_LOADING',
// Billings
SET_SUBSCRIPTION: 'SET_SUBSCRIPTION',
TOGGLE_SUBSCRIPTION_LOADING: 'TOGGLE_SUBSCRIPTION_LOADING',
// Conversation Metadata
SET_CONVERSATION_METADATA: 'SET_CONVERSATION_METADATA',

View file

@ -1,35 +0,0 @@
# This listener is left over from the initial version of chatwoot
# We might reuse this later in the hosted version of chatwoot.
class SubscriptionListener < BaseListener
def subscription_created(event)
subscription = event.data[:subscription]
account = subscription.account
Subscription::ChargebeeService.create_subscription(account)
end
def account_destroyed(event)
account = event.data[:account]
Subscription::ChargebeeService.cancel_subscription(account)
end
def agent_added(event)
account = event.data[:account]
Subscription::ChargebeeService.update_subscription(account)
end
def agent_removed(event)
account = event.data[:account]
Subscription::ChargebeeService.update_subscription(account)
end
def subscription_reactivated(event)
account = event.data[:account]
Subscription::ChargebeeService.reactivate_subscription(account)
end
def subscription_deactivated(event)
account = event.data[:account]
Subscription::ChargebeeService.deactivate_subscription(account)
end
end

View file

@ -46,13 +46,11 @@ class Account < ApplicationRecord
has_many :canned_responses, dependent: :destroy
has_many :webhooks, dependent: :destroy
has_many :labels, dependent: :destroy
has_one :subscription, dependent: :destroy
has_many :notification_settings, dependent: :destroy
has_flags ACCOUNT_SETTINGS_FLAGS.merge(column: 'settings_flags').merge(DEFAULT_QUERY_SETTING)
enum locale: LANGUAGES_CONFIG.map { |key, val| [val[:iso_639_1_code], key] }.to_h
after_create :create_subscription
after_create :notify_creation
after_destroy :notify_deletion
@ -74,22 +72,6 @@ class Account < ApplicationRecord
.map { |_| _.tag.name }
end
def subscription_data
agents_count = users.count
per_agent_price = Plan.paid_plan.price
{
state: subscription.state,
expiry: subscription.expiry.to_i,
agents_count: agents_count,
per_agent_cost: per_agent_price,
total_cost: (per_agent_price * agents_count),
iframe_url: Subscription::ChargebeeService.hosted_page_url(self),
trial_expired: subscription.trial_expired?,
account_suspended: subscription.suspended?,
payment_source_added: subscription.payment_source_added
}
end
def webhook_data
{
id: id,
@ -99,11 +81,6 @@ class Account < ApplicationRecord
private
def create_subscription
subscription = build_subscription
subscription.save
end
def notify_creation
Rails.configuration.dispatcher.dispatch(ACCOUNT_CREATED, Time.zone.now, account: self)
end

View file

@ -3,7 +3,6 @@
# Table name: channel_web_widgets
#
# id :integer not null, primary key
# agent_away_message :string
# website_token :string
# website_url :string
# welcome_tagline :string

View file

@ -1,57 +0,0 @@
# == Schema Information
#
# Table name: subscriptions
#
# id :integer not null, primary key
# billing_plan :string default("trial")
# expiry :datetime
# payment_source_added :boolean default(FALSE)
# pricing_version :string
# state :integer default("trial")
# created_at :datetime not null
# updated_at :datetime not null
# account_id :integer
# stripe_customer_id :string
#
class Subscription < ApplicationRecord
include Events::Types
belongs_to :account
before_create :set_default_billing_params
after_create :notify_creation
enum state: [:trial, :active, :cancelled]
def payment_source_added!
self.payment_source_added = true
save
end
def trial_expired?
(trial? && expiry < Date.current) ||
(cancelled? && !payment_source_added)
end
def suspended?
cancelled? && payment_source_added
end
def summary
{
state: state,
expiry: expiry.to_i
}
end
private
def set_default_billing_params
self.expiry = Time.now + Plan.default_trial_period
self.pricing_version = Plan.default_pricing_version
end
def notify_creation
Rails.configuration.dispatcher.dispatch(SUBSCRIPTION_CREATED, Time.zone.now, subscription: self)
end
end

View file

@ -118,7 +118,6 @@ class User < ApplicationRecord
def serializable_hash(options = nil)
serialized_user = super(options).merge(confirmed: confirmed?)
serialized_user.merge(subscription: account.try(:subscription).try(:summary)) if ENV['BILLING_ENABLED']
serialized_user
end

View file

@ -1,70 +0,0 @@
class Subscription::ChargebeeService
class << self
def create_subscription(account)
result = ChargeBee::Subscription.create(
plan_id: Plan.paid_plan.id,
customer: {
email: account.users.administrator.try(:first).try(:email),
first_name: account.name,
company: account.name
}
)
subscription = account.subscription
subscription.stripe_customer_id = result.subscription.customer_id
subscription.save
rescue StandardError => e
Raven.capture_exception(e)
end
def update_subscription(account)
subscription = account.subscription
agents_count = account.users.count
ChargeBee::Subscription.update(subscription.stripe_customer_id, plan_quantity: agents_count)
rescue StandardError => e
Raven.capture_exception(e)
end
def cancel_subscription(account)
subscription = account.subscription
ChargeBee::Subscription.delete(subscription.stripe_customer_id)
rescue StandardError => e
Raven.capture_exception(e)
end
def reactivate_subscription(account)
subscription = account.subscription
ChargeBee::Subscription.reactivate(subscription.stripe_customer_id)
subscription.active!
rescue StandardError => e
Raven.capture_exception(e)
end
def deactivate_subscription(account)
subscription = account.subscription
ChargeBee::Subscription.cancel(subscription.stripe_customer_id)
subscription.cancelled!
rescue StandardError => e
Raven.capture_exception(e)
end
def hosted_page_url(account)
subscription = account.subscription
# result = ChargeBee::HostedPage.checkout_existing({
# :subscription => {
# :id => subscription.stripe_customer_id,
# :plan_id => Plan.paid_plan.id
# }
# })
result = ChargeBee::HostedPage.update_payment_method(
customer: {
id: subscription.stripe_customer_id
}
)
result.hosted_page.url
rescue StandardError => e
Raven.capture_exception(e)
end
end
end

View file

@ -31,7 +31,6 @@
window.chatwootConfig = {
hostURL: '<%= ENV.fetch('FRONTEND_URL', '') %>',
fbAppId: '<%= ENV.fetch('FB_APP_ID', nil) %>',
billingEnabled: <%= ActiveModel::Type::Boolean.new.cast(ENV.fetch('BILLING_ENABLED', false)) %>,
signupEnabled: '<%= ENV.fetch('ENABLE_ACCOUNT_SIGNUP', true) %>',
<% if ENV['VAPID_PUBLIC_KEY'] %>
vapidPublicKey: new Uint8Array(<%= Base64.urlsafe_decode64(ENV['VAPID_PUBLIC_KEY']).bytes %>),

View file

@ -1,2 +0,0 @@
PLAN_CONFIG = YAML.load_file(File.join(Rails.root, 'config', 'plans.yml'))
$chargebee = ChargeBee.configure(site: ENV['CHARGEBEE_SITE'], api_key: ENV['CHARGEBEE_API_KEY'])

View file

@ -1,17 +0,0 @@
active:
v1:
paid:
name: 'Platinum'
id: 'v1-platinum'
price: 29
trial:
name: 'Trial'
id: 'v1Trial'
price: 0
inactive:
v0:
free:
name: 'Free'
price: 0
trial_period: 365
default_pricing_version: 'v1'

View file

@ -83,13 +83,6 @@ Rails.application.routes.draw do
resources :notifications, only: [:index, :update]
resource :notification_settings, only: [:show, :update]
# this block is only required if subscription via chargebee is enabled
resources :subscriptions, only: [:index] do
collection do
get :summary
end
end
resources :webhooks, except: [:show]
end
end
@ -114,12 +107,6 @@ Rails.application.routes.draw do
resources :inbox_members, only: [:index]
resources :labels, only: [:create, :destroy]
end
resources :webhooks, only: [] do
collection do
post :chargebee
end
end
end
namespace :v2 do

View file

@ -0,0 +1,15 @@
class RemoveSubscriptions < ActiveRecord::Migration[6.0]
def change
drop_table :subscriptions do |t|
t.string 'pricing_version'
t.integer 'account_id'
t.datetime 'expiry'
t.string 'billing_plan', default: 'trial'
t.string 'stripe_customer_id'
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
t.integer 'state', default: 0
t.boolean 'payment_source_added', default: false
end
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_06_06_132552) do
ActiveRecord::Schema.define(version: 2020_06_07_140737) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_stat_statements"
@ -328,18 +328,6 @@ ActiveRecord::Schema.define(version: 2020_06_06_132552) do
t.index ["user_id"], name: "index_notifications_on_user_id"
end
create_table "subscriptions", id: :serial, force: :cascade do |t|
t.string "pricing_version"
t.integer "account_id"
t.datetime "expiry"
t.string "billing_plan", default: "trial"
t.string "stripe_customer_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "state", default: 0
t.boolean "payment_source_added", default: false
end
create_table "super_admins", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false

View file

@ -1,86 +0,0 @@
# frozen_string_literal: true
class Webhooks::Chargebee
SUPPORTED_EVENTS = [:subscription_created, :subscription_trial_end_reminder,
:subscription_activated, :subscription_cancelled,
:subscription_reactivated, :subscription_deleted,
:subscription_renewed, :payment_source_added, :subscription_changed].freeze
attr_accessor :params, :account
def initialize(params)
@params = params
end
def consume
send(event_name) if supported_event?
end
private
def event_name
@params[:event_type]
end
def customer_id
@params[:content][:customer][:id]
end
def trial_ends_on
trial_end = @params[:content][:subscription][:trial_end]
DateTime.strptime(trial_end, '%s')
end
def supported_event?
SUPPORTED_EVENTS.include?(event_name.to_sym)
end
def subscription
@subscriptiom ||= Subscription.find_by(stripe_customer_id: customer_id)
end
def subscription_created
Raven.capture_message("subscription created for #{customer_id}")
end
def subscription_changed
if subscription.expiry != trial_ends_on
subscription.expiry = trial_ends_on
subscription.save
subscription.trial!
end
end
def subscription_trial_end_reminder
# Raven.capture_message("subscription trial end reminder for #{customer_id}")
end
def subscription_activated
subscription.active!
Raven.capture_message("subscription activated for #{customer_id}")
end
def subscription_cancelled
# if there is a reason field in response. Then cancellation is due to payment failure
subscription.cancelled!
Raven.capture_message("subscription cancelled for #{customer_id}")
end
def subscription_reactivated
# TODO: send mail to user that account is reactivated
subscription.active!
Raven.capture_message("subscription reactivated for #{customer_id}")
end
def subscription_renewed
# TODO: Needs this to show payment history.
Raven.capture_message("subscription renewed for #{customer_id}")
end
def subscription_deleted; end
def payment_source_added
Raven.capture_message("payment source added for #{customer_id}")
subscription.payment_source_added!
end
end

View file

@ -1,46 +0,0 @@
require 'rails_helper'
RSpec.describe 'Subscriptions API', type: :request do
let(:account) { create(:account) }
describe 'GET /api/v1/accounts/{account.id}/subscriptions' do
context 'when it is an unauthenticated user' do
it 'returns unauthorized' do
ENV['BILLING_ENABLED'] = 'true'
get "/api/v1/accounts/#{account.id}/subscriptions"
expect(response).to have_http_status(:unauthorized)
ENV['BILLING_ENABLED'] = nil
end
end
context 'when it is an authenticated user' do
let(:agent) { create(:user, account: account, role: :agent) }
it 'returns all subscriptions' do
ENV['BILLING_ENABLED'] = 'true'
get "/api/v1/accounts/#{account.id}/subscriptions",
headers: agent.create_new_auth_token,
as: :json
expect(response).to have_http_status(:success)
expect(JSON.parse(response.body)).to eq(account.subscription_data.as_json)
ENV['BILLING_ENABLED'] = nil
end
it 'throws 404 error if env variable is not set' do
ENV['BILLING_ENABLED'] = nil
get "/api/v1/accounts/#{account.id}/subscriptions",
headers: agent.create_new_auth_token,
as: :json
expect(response).to have_http_status(:not_found)
end
end
end
end

View file

@ -1,15 +0,0 @@
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
pricing_version: MyString
account_id: 1
expiry: 2017-04-24 22:47:08
billing_plan: MyString
stripe_customer_id: MyString
two:
pricing_version: MyString
account_id: 1
expiry: 2017-04-24 22:47:08
billing_plan: MyString
stripe_customer_id: MyString

View file

@ -14,7 +14,6 @@ RSpec.describe Account do
it { is_expected.to have_many(:canned_responses).dependent(:destroy) }
it { is_expected.to have_many(:facebook_pages).class_name('::Channel::FacebookPage').dependent(:destroy) }
it { is_expected.to have_many(:web_widgets).class_name('::Channel::WebWidget').dependent(:destroy) }
it { is_expected.to have_one(:subscription).dependent(:destroy) }
it { is_expected.to have_many(:webhooks).dependent(:destroy) }
it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
it { is_expected.to have_many(:events) }