Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating usage endpoints for organizations and subscriptions #4506

Merged
merged 34 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
acf7c1d
add monthly counts for NLP usage to /api/v2/service_usage
LMNTL May 17, 2023
d26df60
update usage frontend to be even with API
LMNTL May 17, 2023
730c791
get usage data by organization in api/v2/service_usage
LMNTL May 24, 2023
522c73a
clarify variable names
LMNTL May 24, 2023
a62e3d1
update NLP usage counter to track by day
LMNTL May 31, 2023
77ca025
track NLP usage daily instead of monthly
LMNTL Jun 9, 2023
9cb6859
get tests passing
LMNTL Jun 12, 2023
8de282e
rename MonthlyNLPUsageCounter to NLPUsageCounter
LMNTL Jun 13, 2023
a7cd93e
Merge branch 'feature/usage-limits' into feature/usage-limits-api
LMNTL Jun 13, 2023
3811d18
fix broken migration on trackers
LMNTL Jun 13, 2023
32040f4
add yearly NLP usage to asset_usage and get nlp totals by subscriptio…
LMNTL Jun 14, 2023
59eee58
remove deprecated nlp_tracking function
LMNTL Jun 14, 2023
01148ab
add yearly count to submissions
LMNTL Jun 15, 2023
0faae9d
update API documentation
LMNTL Jun 15, 2023
dcb97bc
refactor NLPUsageCounter migration to not iterate
LMNTL Jun 20, 2023
9ae9a21
refactor ServiceUsageSerializer to make fewer queries
LMNTL Jun 20, 2023
170d781
Merge branch 'feature/usage-limits' into feature/usage-limits-api
LMNTL Jun 21, 2023
0013796
get test_api_service_usage passing
LMNTL Jun 21, 2023
f3d70c3
reuse Xforms and daily counters isntead of instantiating new ones
LMNTL Jun 21, 2023
dbfcb24
format changed files
LMNTL Jun 22, 2023
3a728b5
squash migrations for trackers
LMNTL Jun 22, 2023
87b2386
fix broken test for trackers
LMNTL Jun 23, 2023
7245072
use chained queries for each usage type, code cleanup
LMNTL Jun 23, 2023
75cc413
unsquash migrations to prevent a postgres error
LMNTL Jun 28, 2023
ddec1ba
get tests passing
LMNTL Jul 5, 2023
2d36ed0
update api documentation
LMNTL Jul 5, 2023
511cace
fix broken test
LMNTL Jul 5, 2023
857920e
flesh out some test cases
LMNTL Jul 5, 2023
2f5f484
move active stripe statuses to constant
LMNTL Jul 5, 2023
202533f
move frontend active stripe statuses to constants.ts
LMNTL Jul 5, 2023
2793a63
remove unused import
LMNTL Jul 10, 2023
64ad2a8
add active_subscription property to Organization
LMNTL Jul 10, 2023
95c1144
make service_usage use organization.active_subscription
LMNTL Jul 10, 2023
e442ef0
refactor active_subscription to remove djstripe dependency
LMNTL Jul 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 22 additions & 19 deletions jsapp/js/account/plan.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import Button from 'js/components/common/button';
import classnames from 'classnames';
import LoadingSpinner from 'js/components/common/loadingSpinner';
import {notify} from 'js/utils';
import {BaseProduct} from "js/account/subscriptionStore";
import {ACTIVE_STRIPE_STATUSES} from 'js/constants';

interface PlanState {
subscribedProduct: null | BaseSubscription;
Expand All @@ -53,12 +53,6 @@ const initialState = {
featureTypes: ['support', 'advanced', 'addons'],
};

/*
Stripe Subscription statuses that are shown as active in the UI.
Subscriptions with a status in this array will show an option to 'Manage'.
*/
const activeSubscriptionStatuses = ['active', 'past_due', 'trialing'];

const subscriptionUpgradeMessageDuration = 8000;

function planReducer(state: PlanState, action: DataUpdates) {
Expand Down Expand Up @@ -100,8 +94,11 @@ export default function Plan() {
[state.products, state.organization, state.subscribedProduct]
);

const hasManageableStatus = useCallback((subscription: BaseSubscription) =>
activeSubscriptionStatuses.includes(subscription.status), []);
const hasManageableStatus = useCallback(
(subscription: BaseSubscription) =>
ACTIVE_STRIPE_STATUSES.includes(subscription.status),
[]
);

const hasActiveSubscription = useMemo(() => {
if (state.subscribedProduct) {
Expand All @@ -113,9 +110,7 @@ export default function Plan() {
}, [state.subscribedProduct]);

useMemo(() => {
if (
state.subscribedProduct?.length > 0
) {
if (state.subscribedProduct?.length > 0) {
const subscribedFilter =
state.subscribedProduct?.[0].items[0].price.recurring?.interval;
if (!hasManageableStatus(state.subscribedProduct)) {
Expand Down Expand Up @@ -207,7 +202,10 @@ export default function Plan() {
const filterAmount = state.products.map((product: Product) => {
const filteredPrices = product.prices.filter((price: BasePrice) => {
const interval = price.recurring?.interval;
return interval === state.intervalFilter && product.metadata.product_type === 'plan';
return (
interval === state.intervalFilter &&
product.metadata.product_type === 'plan'
);
});

return {
Expand All @@ -216,8 +214,12 @@ export default function Plan() {
};
});

return filterAmount.filter((product: Product) => product.prices)
.sort((priceA: Price, priceB: Price) => priceA.prices.unit_amount > priceB.prices.unit_amount);
return filterAmount
.filter((product: Product) => product.prices)
.sort(
(priceA: Price, priceB: Price) =>
priceA.prices.unit_amount > priceB.prices.unit_amount
);
}
return [];
}, [state.products, state.intervalFilter]);
Expand All @@ -244,9 +246,10 @@ export default function Plan() {
const subscriptions = getSubscriptionsForProductId(product.id);

if (subscriptions.length > 0) {
return subscriptions.some((subscription: BaseSubscription) =>
subscription.items[0].price.id === product.prices.id &&
hasManageableStatus(subscription)
return subscriptions.some(
(subscription: BaseSubscription) =>
subscription.items[0].price.id === product.prices.id &&
hasManageableStatus(subscription)
);
}
return false;
Expand All @@ -262,7 +265,7 @@ export default function Plan() {
}

return subscriptions.some((subscription: BaseSubscription) =>
hasManageableStatus(subscription)
hasManageableStatus(subscription)
);
},
[state.subscribedProduct]
Expand Down
25 changes: 17 additions & 8 deletions jsapp/js/account/usage.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,27 @@ interface AssetUsage {
asset__name: string;
submission_count_current_month: number;
submission_count_all_time: number;
nlp_usage_current_month: unknown,
nlp_usage_all_time: unknown,
nlp_usage_current_month: unknown;
nlp_usage_all_time: unknown;
storage_bytes: number;
}

interface UsageResponse {
per_asset_usage: AssetUsage[],
total_submission_count_current_month: number,
total_submission_count_all_time: number,
total_storage_bytes: number,
total_nlp_asr_seconds: number,
total_nlp_mt_characters: number,
per_asset_usage: AssetUsage[];
total_submission_count: {
current_month: number;
current_year: number;
all_time: number;
};
total_storage_bytes: number;
total_nlp_usage: {
asr_seconds_current_month: number;
mt_characters_current_month: number;
asr_seconds_current_year: number;
mt_characters_current_year: number;
asr_seconds_all_time: number;
mt_characters_all_time: number;
};
}

const USAGE_URL = '/api/v2/service_usage/';
Expand Down
21 changes: 12 additions & 9 deletions jsapp/js/account/usage.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ import Button from '../components/common/button';
interface UsageState {
storage: number;
monthlySubmissions: number;
transcriptionMinutes: number;
translationChars: number;
monthlyTranscriptionMinutes: number;
monthlyTranslationChars: number;
}

export default function Usage() {
const [usage, setUsage] = useState<UsageState>({
storage: 0,
monthlySubmissions: 0,
transcriptionMinutes: 0,
translationChars: 0,
monthlyTranscriptionMinutes: 0,
monthlyTranslationChars: 0,
});

function truncate(decimal: number) {
Expand All @@ -30,9 +30,12 @@ export default function Usage() {
setUsage({
...usage,
storage: truncate(data.total_storage_bytes / 1000000000), // bytes to GB
monthlySubmissions: data.total_submission_count_current_month,
transcriptionMinutes: Math.floor(truncate(data.total_nlp_asr_seconds / 60)), // seconds to minutes
translationChars: data.total_nlp_mt_characters,
monthlySubmissions: data.total_submission_count['current_month'],
monthlyTranscriptionMinutes: Math.floor(
truncate(data.total_nlp_usage['asr_seconds_current_month'] / 60)
), // seconds to minutes
monthlyTranslationChars:
data.total_nlp_usage['mt_characters_current_month'],
});
});
}, []);
Expand Down Expand Up @@ -67,7 +70,7 @@ export default function Usage() {
</div>
<div className={styles.usage}>
<strong className={styles.description}>{t('Monthly use')}</strong>
<strong>{usage.transcriptionMinutes}</strong>
<strong>{usage.monthlyTranscriptionMinutes}</strong>
</div>
</div>
<div className={styles.box}>
Expand All @@ -79,7 +82,7 @@ export default function Usage() {
</div>
<div className={styles.usage}>
<strong className={styles.description}>{t('Monthly use')}</strong>
<strong>{usage.translationChars}</strong>
<strong>{usage.monthlyTranslationChars}</strong>
</div>
</div>
</div>
Expand Down