mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-02 12:08:01 +00:00
feat: Upgrade page instead of banner (#11202)
# Pull Request Template ## Description This PR will replace the upgrade banner with an upgrade page view. ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## How Has This Been Tested? ### Loom video https://www.loom.com/share/0f2b4b09acdd4404bf3211184a470227?sid=7ed60a99-0299-4642-b907-2af8c4dcc643 ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Pranav <pranavrajs@gmail.com>
This commit is contained in:
@@ -18,4 +18,8 @@ module BillingHelper
|
|||||||
def non_web_inboxes(account)
|
def non_web_inboxes(account)
|
||||||
account.inboxes.where.not(channel_type: Channel::WebWidget.to_s).count
|
account.inboxes.where.not(channel_type: Channel::WebWidget.to_s).count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def agents(account)
|
||||||
|
account.users.count
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import AddAccountModal from '../dashboard/components/layout/sidebarComponents/Ad
|
|||||||
import LoadingState from './components/widgets/LoadingState.vue';
|
import LoadingState from './components/widgets/LoadingState.vue';
|
||||||
import NetworkNotification from './components/NetworkNotification.vue';
|
import NetworkNotification from './components/NetworkNotification.vue';
|
||||||
import UpdateBanner from './components/app/UpdateBanner.vue';
|
import UpdateBanner from './components/app/UpdateBanner.vue';
|
||||||
import UpgradeBanner from './components/app/UpgradeBanner.vue';
|
|
||||||
import PaymentPendingBanner from './components/app/PaymentPendingBanner.vue';
|
import PaymentPendingBanner from './components/app/PaymentPendingBanner.vue';
|
||||||
import PendingEmailVerificationBanner from './components/app/PendingEmailVerificationBanner.vue';
|
import PendingEmailVerificationBanner from './components/app/PendingEmailVerificationBanner.vue';
|
||||||
import vueActionCable from './helper/actionCable';
|
import vueActionCable from './helper/actionCable';
|
||||||
@@ -31,7 +30,6 @@ export default {
|
|||||||
UpdateBanner,
|
UpdateBanner,
|
||||||
PaymentPendingBanner,
|
PaymentPendingBanner,
|
||||||
WootSnackbarBox,
|
WootSnackbarBox,
|
||||||
UpgradeBanner,
|
|
||||||
PendingEmailVerificationBanner,
|
PendingEmailVerificationBanner,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
@@ -146,7 +144,6 @@ export default {
|
|||||||
<template v-if="currentAccountId">
|
<template v-if="currentAccountId">
|
||||||
<PendingEmailVerificationBanner v-if="hideOnOnboardingView" />
|
<PendingEmailVerificationBanner v-if="hideOnOnboardingView" />
|
||||||
<PaymentPendingBanner v-if="hideOnOnboardingView" />
|
<PaymentPendingBanner v-if="hideOnOnboardingView" />
|
||||||
<UpgradeBanner />
|
|
||||||
</template>
|
</template>
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade" mode="out-in">
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
{
|
{
|
||||||
"GENERAL_SETTINGS": {
|
"GENERAL_SETTINGS": {
|
||||||
|
"LIMIT_MESSAGES": {
|
||||||
|
"CONVERSATION": "You have exceeded the conversation limit. Hacker plan allows only 500 conversations.",
|
||||||
|
"INBOXES": "You have exceeded the inbox limit. Hacker plan only supports website live-chat. Additional inboxes like email, WhatsApp etc. require a paid plan.",
|
||||||
|
"AGENTS": "You have exceeded the agent limit. Hacker plan allows only 2 agents.",
|
||||||
|
"NON_ADMIN": "Please contact your administrator to upgrade the plan and continue using all features."
|
||||||
|
},
|
||||||
"TITLE": "Account settings",
|
"TITLE": "Account settings",
|
||||||
"SUBMIT": "Update settings",
|
"SUBMIT": "Update settings",
|
||||||
"BACK": "Back",
|
"BACK": "Back",
|
||||||
@@ -51,6 +57,7 @@
|
|||||||
"UPDATE_CHATWOOT": "An update {latestChatwootVersion} for Chatwoot is available. Please update your instance.",
|
"UPDATE_CHATWOOT": "An update {latestChatwootVersion} for Chatwoot is available. Please update your instance.",
|
||||||
"LEARN_MORE": "Learn more",
|
"LEARN_MORE": "Learn more",
|
||||||
"PAYMENT_PENDING": "Your payment is pending. Please update your payment information to continue using Chatwoot",
|
"PAYMENT_PENDING": "Your payment is pending. Please update your payment information to continue using Chatwoot",
|
||||||
|
"UPGRADE": "Upgrade to continue using Chatwoot",
|
||||||
"LIMITS_UPGRADE": "Your account has exceeded the usage limits, please upgrade your plan to continue using Chatwoot",
|
"LIMITS_UPGRADE": "Your account has exceeded the usage limits, please upgrade your plan to continue using Chatwoot",
|
||||||
"OPEN_BILLING": "Open billing"
|
"OPEN_BILLING": "Open billing"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import { defineAsyncComponent, ref } from 'vue';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { defineAsyncComponent } from 'vue';
|
|
||||||
|
|
||||||
import NextSidebar from 'next/sidebar/Sidebar.vue';
|
import NextSidebar from 'next/sidebar/Sidebar.vue';
|
||||||
import WootKeyShortcutModal from 'dashboard/components/widgets/modal/WootKeyShortcutModal.vue';
|
import WootKeyShortcutModal from 'dashboard/components/widgets/modal/WootKeyShortcutModal.vue';
|
||||||
@@ -8,6 +8,7 @@ import AddAccountModal from 'dashboard/components/layout/sidebarComponents/AddAc
|
|||||||
import AccountSelector from 'dashboard/components/layout/sidebarComponents/AccountSelector.vue';
|
import AccountSelector from 'dashboard/components/layout/sidebarComponents/AccountSelector.vue';
|
||||||
import AddLabelModal from 'dashboard/routes/dashboard/settings/labels/AddLabel.vue';
|
import AddLabelModal from 'dashboard/routes/dashboard/settings/labels/AddLabel.vue';
|
||||||
import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue';
|
import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue';
|
||||||
|
import UpgradePage from 'dashboard/routes/dashboard/upgrade/UpgradePage.vue';
|
||||||
|
|
||||||
import { useUISettings } from 'dashboard/composables/useUISettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import { useAccount } from 'dashboard/composables/useAccount';
|
import { useAccount } from 'dashboard/composables/useAccount';
|
||||||
@@ -35,8 +36,10 @@ export default {
|
|||||||
AccountSelector,
|
AccountSelector,
|
||||||
AddLabelModal,
|
AddLabelModal,
|
||||||
NotificationPanel,
|
NotificationPanel,
|
||||||
|
UpgradePage,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
|
const upgradePageRef = ref(null);
|
||||||
const { uiSettings, updateUISettings } = useUISettings();
|
const { uiSettings, updateUISettings } = useUISettings();
|
||||||
const { accountId } = useAccount();
|
const { accountId } = useAccount();
|
||||||
|
|
||||||
@@ -44,6 +47,7 @@ export default {
|
|||||||
uiSettings,
|
uiSettings,
|
||||||
updateUISettings,
|
updateUISettings,
|
||||||
accountId,
|
accountId,
|
||||||
|
upgradePageRef,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -64,6 +68,16 @@ export default {
|
|||||||
currentRoute() {
|
currentRoute() {
|
||||||
return ' ';
|
return ' ';
|
||||||
},
|
},
|
||||||
|
showUpgradePage() {
|
||||||
|
return this.upgradePageRef?.shouldShowUpgradePage;
|
||||||
|
},
|
||||||
|
bypassUpgradePage() {
|
||||||
|
return [
|
||||||
|
'billing_settings_index',
|
||||||
|
'settings_inbox_list',
|
||||||
|
'agent_list',
|
||||||
|
].includes(this.$route.name);
|
||||||
|
},
|
||||||
isSidebarOpen() {
|
isSidebarOpen() {
|
||||||
const { show_secondary_sidebar: showSecondarySidebar } = this.uiSettings;
|
const { show_secondary_sidebar: showSecondarySidebar } = this.uiSettings;
|
||||||
return showSecondarySidebar;
|
return showSecondarySidebar;
|
||||||
@@ -197,8 +211,25 @@ export default {
|
|||||||
@show-add-label-popup="showAddLabelPopup"
|
@show-add-label-popup="showAddLabelPopup"
|
||||||
/>
|
/>
|
||||||
<main class="flex flex-1 h-full min-h-0 px-0 overflow-hidden">
|
<main class="flex flex-1 h-full min-h-0 px-0 overflow-hidden">
|
||||||
<router-view />
|
<UpgradePage
|
||||||
<CommandBar />
|
v-show="showUpgradePage"
|
||||||
|
ref="upgradePageRef"
|
||||||
|
:bypass-upgrade-page="bypassUpgradePage"
|
||||||
|
/>
|
||||||
|
<template v-if="!showUpgradePage">
|
||||||
|
<router-view />
|
||||||
|
<CommandBar />
|
||||||
|
<NotificationPanel
|
||||||
|
v-if="isNotificationPanel"
|
||||||
|
@close="closeNotificationPanel"
|
||||||
|
/>
|
||||||
|
<woot-modal
|
||||||
|
v-model:show="showAddLabelModal"
|
||||||
|
:on-close="hideAddLabelPopup"
|
||||||
|
>
|
||||||
|
<AddLabelModal @close="hideAddLabelPopup" />
|
||||||
|
</woot-modal>
|
||||||
|
</template>
|
||||||
<AccountSelector
|
<AccountSelector
|
||||||
:show-account-modal="showAccountModal"
|
:show-account-modal="showAccountModal"
|
||||||
@close-account-modal="toggleAccountModal"
|
@close-account-modal="toggleAccountModal"
|
||||||
@@ -213,16 +244,6 @@ export default {
|
|||||||
@close="closeKeyShortcutModal"
|
@close="closeKeyShortcutModal"
|
||||||
@clickaway="closeKeyShortcutModal"
|
@clickaway="closeKeyShortcutModal"
|
||||||
/>
|
/>
|
||||||
<NotificationPanel
|
|
||||||
v-if="isNotificationPanel"
|
|
||||||
@close="closeNotificationPanel"
|
|
||||||
/>
|
|
||||||
<woot-modal
|
|
||||||
v-model:show="showAddLabelModal"
|
|
||||||
:on-close="hideAddLabelPopup"
|
|
||||||
>
|
|
||||||
<AddLabelModal @close="hideAddLabelPopup" />
|
|
||||||
</woot-modal>
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, computed, defineExpose, defineProps } from 'vue';
|
||||||
|
import { useStore } from 'dashboard/composables/store';
|
||||||
|
import { useMapGetter } from 'dashboard/composables/store.js';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { useAccount } from 'dashboard/composables/useAccount';
|
||||||
|
import { differenceInDays } from 'date-fns';
|
||||||
|
import { useAdmin } from 'dashboard/composables/useAdmin';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import NextButton from 'dashboard/components-next/button/Button.vue';
|
||||||
|
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
bypassUpgradePage: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const store = useStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { accountId, currentAccount } = useAccount();
|
||||||
|
const { isAdmin } = useAdmin();
|
||||||
|
|
||||||
|
const isOnChatwootCloud = useMapGetter('globalConfig/isOnChatwootCloud');
|
||||||
|
|
||||||
|
const testLimit = ({ allowed, consumed }) => {
|
||||||
|
return consumed > allowed;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isTrialAccount = computed(() => {
|
||||||
|
// check if account is less than 15 days old
|
||||||
|
const account = currentAccount.value;
|
||||||
|
if (!account) return false;
|
||||||
|
|
||||||
|
const createdAt = new Date(account.created_at);
|
||||||
|
const diffDays = differenceInDays(new Date(), createdAt);
|
||||||
|
|
||||||
|
return diffDays <= 15;
|
||||||
|
});
|
||||||
|
|
||||||
|
const limitExceededMessage = computed(() => {
|
||||||
|
const account = currentAccount.value;
|
||||||
|
if (!account?.limits) return '';
|
||||||
|
|
||||||
|
const {
|
||||||
|
conversation,
|
||||||
|
non_web_inboxes: nonWebInboxes,
|
||||||
|
agents,
|
||||||
|
} = account.limits;
|
||||||
|
|
||||||
|
let message = '';
|
||||||
|
|
||||||
|
if (testLimit(conversation)) {
|
||||||
|
message = t('GENERAL_SETTINGS.LIMIT_MESSAGES.CONVERSATION');
|
||||||
|
} else if (testLimit(nonWebInboxes)) {
|
||||||
|
message = t('GENERAL_SETTINGS.LIMIT_MESSAGES.INBOXES');
|
||||||
|
} else if (testLimit(agents)) {
|
||||||
|
message = t('GENERAL_SETTINGS.LIMIT_MESSAGES.AGENTS');
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
});
|
||||||
|
|
||||||
|
const isLimitExceeded = computed(() => {
|
||||||
|
const account = currentAccount.value;
|
||||||
|
if (!account?.limits) return false;
|
||||||
|
|
||||||
|
const {
|
||||||
|
conversation,
|
||||||
|
non_web_inboxes: nonWebInboxes,
|
||||||
|
agents,
|
||||||
|
} = account.limits;
|
||||||
|
|
||||||
|
return (
|
||||||
|
testLimit(conversation) || testLimit(nonWebInboxes) || testLimit(agents)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const shouldShowUpgradePage = computed(() => {
|
||||||
|
// Skip upgrade page in Billing, Inbox, and Agent pages
|
||||||
|
if (props.bypassUpgradePage) return false;
|
||||||
|
if (!isOnChatwootCloud.value) return false;
|
||||||
|
if (isTrialAccount.value) return false;
|
||||||
|
return isLimitExceeded.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchLimits = () => {
|
||||||
|
store.dispatch('accounts/limits');
|
||||||
|
};
|
||||||
|
|
||||||
|
const routeToBilling = () => {
|
||||||
|
router.push({
|
||||||
|
name: 'billing_settings_index',
|
||||||
|
params: { accountId: accountId.value },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => fetchLimits());
|
||||||
|
|
||||||
|
defineExpose({ shouldShowUpgradePage });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<template v-if="shouldShowUpgradePage">
|
||||||
|
<div class="mx-auto h-full pt-[clamp(3rem,15vh,12rem)]">
|
||||||
|
<div
|
||||||
|
class="flex flex-col gap-4 max-w-md px-8 py-6 shadow-lg bg-n-solid-1 rounded-xl outline outline-1 outline-n-container"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="flex items-center w-full gap-2">
|
||||||
|
<span
|
||||||
|
class="flex items-center justify-center w-6 h-6 rounded-full bg-n-solid-blue"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
class="flex-shrink-0 text-n-brand size-[14px]"
|
||||||
|
icon="i-lucide-lock-keyhole"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span class="text-base font-medium text-n-slate-12">
|
||||||
|
{{ $t('GENERAL_SETTINGS.UPGRADE') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm font-normal text-n-slate-11 mb-3">
|
||||||
|
{{ limitExceededMessage }}
|
||||||
|
</p>
|
||||||
|
<p v-if="!isAdmin">
|
||||||
|
{{ t('GENERAL_SETTINGS.LIMIT_MESSAGES.NON_ADMIN') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<NextButton
|
||||||
|
v-if="isAdmin"
|
||||||
|
:label="$t('GENERAL_SETTINGS.OPEN_BILLING')"
|
||||||
|
icon="i-lucide-credit-card"
|
||||||
|
@click="routeToBilling()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else />
|
||||||
|
</template>
|
||||||
@@ -8,7 +8,7 @@ class AccountPolicy < ApplicationPolicy
|
|||||||
end
|
end
|
||||||
|
|
||||||
def limits?
|
def limits?
|
||||||
@account_user.administrator?
|
@account_user.administrator? || @account_user.agent?
|
||||||
end
|
end
|
||||||
|
|
||||||
def update?
|
def update?
|
||||||
|
|||||||
@@ -13,24 +13,24 @@ class Enterprise::Api::V1::AccountsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def limits
|
def limits
|
||||||
limits = {
|
limits = if default_plan?(@account)
|
||||||
'conversation' => {},
|
{
|
||||||
'non_web_inboxes' => {},
|
'conversation' => {
|
||||||
'captain' => @account.usage_limits[:captain]
|
'allowed' => 500,
|
||||||
}
|
'consumed' => conversations_this_month(@account)
|
||||||
|
},
|
||||||
if default_plan?(@account)
|
'non_web_inboxes' => {
|
||||||
limits = {
|
'allowed' => 0,
|
||||||
'conversation' => {
|
'consumed' => non_web_inboxes(@account)
|
||||||
'allowed' => 500,
|
},
|
||||||
'consumed' => conversations_this_month(@account)
|
'agents' => {
|
||||||
},
|
'allowed' => 2,
|
||||||
'non_web_inboxes' => {
|
'consumed' => agents(@account)
|
||||||
'allowed' => 0,
|
}
|
||||||
'consumed' => non_web_inboxes(@account)
|
}
|
||||||
}
|
else
|
||||||
}
|
default_limits
|
||||||
end
|
end
|
||||||
|
|
||||||
# include id in response to ensure that the store can be updated on the frontend
|
# include id in response to ensure that the store can be updated on the frontend
|
||||||
render json: { id: @account.id, limits: limits }, status: :ok
|
render json: { id: @account.id, limits: limits }, status: :ok
|
||||||
@@ -49,6 +49,15 @@ class Enterprise::Api::V1::AccountsController < Api::BaseController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def default_limits
|
||||||
|
{
|
||||||
|
'conversation' => {},
|
||||||
|
'non_web_inboxes' => {},
|
||||||
|
'agents' => {},
|
||||||
|
'captain' => @account.usage_limits[:captain]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def fetch_account
|
def fetch_account
|
||||||
@account = current_user.accounts.find(params[:id])
|
@account = current_user.accounts.find(params[:id])
|
||||||
@current_account_user = @account.account_users.find_by(user_id: current_user.id)
|
@current_account_user = @account.account_users.find_by(user_id: current_user.id)
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ require 'rails_helper'
|
|||||||
|
|
||||||
RSpec.describe 'Enterprise Billing APIs', type: :request do
|
RSpec.describe 'Enterprise Billing APIs', type: :request do
|
||||||
let(:account) { create(:account) }
|
let(:account) { create(:account) }
|
||||||
let(:admin) { create(:user, account: account, role: :administrator) }
|
let!(:admin) { create(:user, account: account, role: :administrator) }
|
||||||
let(:agent) { create(:user, account: account, role: :agent) }
|
let!(:agent) { create(:user, account: account, role: :agent) }
|
||||||
|
|
||||||
describe 'POST /enterprise/api/v1/accounts/{account.id}/subscription' do
|
describe 'POST /enterprise/api/v1/accounts/{account.id}/subscription' do
|
||||||
context 'when it is an unauthenticated user' do
|
context 'when it is an unauthenticated user' do
|
||||||
@@ -121,13 +121,36 @@ RSpec.describe 'Enterprise Billing APIs', type: :request do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context 'when it is an authenticated user' do
|
context 'when it is an authenticated user' do
|
||||||
|
before do
|
||||||
|
InstallationConfig.where(name: 'DEPLOYMENT_ENV').first_or_create(value: 'cloud')
|
||||||
|
InstallationConfig.where(name: 'CHATWOOT_CLOUD_PLANS').first_or_create(value: [{ 'name': 'Hacker' }])
|
||||||
|
end
|
||||||
|
|
||||||
context 'when it is an agent' do
|
context 'when it is an agent' do
|
||||||
it 'returns unauthorized' do
|
it 'returns unauthorized' do
|
||||||
get "/enterprise/api/v1/accounts/#{account.id}/limits",
|
get "/enterprise/api/v1/accounts/#{account.id}/limits",
|
||||||
headers: agent.create_new_auth_token,
|
headers: agent.create_new_auth_token,
|
||||||
as: :json
|
as: :json
|
||||||
|
|
||||||
expect(response).to have_http_status(:unauthorized)
|
expect(response).to have_http_status(:success)
|
||||||
|
json_response = JSON.parse(response.body)
|
||||||
|
expect(json_response['id']).to eq(account.id)
|
||||||
|
expect(json_response['limits']).to eq(
|
||||||
|
{
|
||||||
|
'conversation' => {
|
||||||
|
'allowed' => 500,
|
||||||
|
'consumed' => 0
|
||||||
|
},
|
||||||
|
'non_web_inboxes' => {
|
||||||
|
'allowed' => 0,
|
||||||
|
'consumed' => 0
|
||||||
|
},
|
||||||
|
'agents' => {
|
||||||
|
'allowed' => 2,
|
||||||
|
'consumed' => 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -155,6 +178,10 @@ RSpec.describe 'Enterprise Billing APIs', type: :request do
|
|||||||
'non_web_inboxes' => {
|
'non_web_inboxes' => {
|
||||||
'allowed' => 0,
|
'allowed' => 0,
|
||||||
'consumed' => 1
|
'consumed' => 1
|
||||||
|
},
|
||||||
|
'agents' => {
|
||||||
|
'allowed' => 2,
|
||||||
|
'consumed' => 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,18 +199,11 @@ RSpec.describe 'Enterprise Billing APIs', type: :request do
|
|||||||
expected_response = {
|
expected_response = {
|
||||||
'id' => account.id,
|
'id' => account.id,
|
||||||
'limits' => {
|
'limits' => {
|
||||||
|
'agents' => {},
|
||||||
'conversation' => {},
|
'conversation' => {},
|
||||||
'captain' => {
|
'captain' => {
|
||||||
'documents' => {
|
'documents' => { 'consumed' => 0, 'current_available' => ChatwootApp.max_limit, 'total_count' => ChatwootApp.max_limit },
|
||||||
'consumed' => 0,
|
'responses' => { 'consumed' => 0, 'current_available' => ChatwootApp.max_limit, 'total_count' => ChatwootApp.max_limit }
|
||||||
'current_available' => ChatwootApp.max_limit,
|
|
||||||
'total_count' => ChatwootApp.max_limit
|
|
||||||
},
|
|
||||||
'responses' => {
|
|
||||||
'consumed' => 0,
|
|
||||||
'current_available' => ChatwootApp.max_limit,
|
|
||||||
'total_count' => ChatwootApp.max_limit
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
'non_web_inboxes' => {}
|
'non_web_inboxes' => {}
|
||||||
}
|
}
|
||||||
@@ -208,6 +228,10 @@ RSpec.describe 'Enterprise Billing APIs', type: :request do
|
|||||||
'non_web_inboxes' => {
|
'non_web_inboxes' => {
|
||||||
'allowed' => 0,
|
'allowed' => 0,
|
||||||
'consumed' => 1
|
'consumed' => 1
|
||||||
|
},
|
||||||
|
'agents' => {
|
||||||
|
'allowed' => 2,
|
||||||
|
'consumed' => 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user