diff --git a/src/lib/sdk/billing.ts b/src/lib/sdk/billing.ts index 68db777fb..1c19a21fe 100644 --- a/src/lib/sdk/billing.ts +++ b/src/lib/sdk/billing.ts @@ -82,6 +82,25 @@ export type EstimationItem = { value: number; }; +export type EstimationOrganization = { + amount: number; + grossAmount: number; + credits: number; + discount: number; + items: EstimationItem[]; + discounts: EstimationItem[]; + usage: { + name: string; + value: number /* service over the limit*/; + amount: number /* price of service over the limit*/; + rate: number; + desc: string; + }[]; + trialDays: number; + trialEndDate: string | undefined; + error: string | undefined; +}; + export type EstimationDeleteOrganization = { amount: number; grossAmount: number; @@ -485,6 +504,14 @@ export class Billing { }); } + async estimationGetOrganization(organizationId: string): Promise { + const path = `/organizations/${organizationId}/estimations`; + const uri = new URL(this.client.config.endpoint + path); + return await this.client.call('get', uri, { + 'content-type': 'application/json' + }); + } + async getOrganizationPlan(organizationId: string): Promise { const path = `/organizations/${organizationId}/plan`; const uri = new URL(this.client.config.endpoint + path); diff --git a/src/routes/(console)/organization-[organization]/billing/+page.svelte b/src/routes/(console)/organization-[organization]/billing/+page.svelte index 2d3772358..b555be065 100644 --- a/src/routes/(console)/organization-[organization]/billing/+page.svelte +++ b/src/routes/(console)/organization-[organization]/billing/+page.svelte @@ -118,10 +118,8 @@ Billing + estimation={data?.estimationOrganization} + currentPlan={data?.aggregationBillingPlan} /> diff --git a/src/routes/(console)/organization-[organization]/billing/+page.ts b/src/routes/(console)/organization-[organization]/billing/+page.ts index b72e98ea0..009b9a724 100644 --- a/src/routes/(console)/organization-[organization]/billing/+page.ts +++ b/src/routes/(console)/organization-[organization]/billing/+page.ts @@ -39,32 +39,29 @@ export const load: PageLoad = async ({ parent, depends }) => { // ignore error } - let billingInvoice = null; - try { - billingInvoice = await sdk.forConsole.billing.getInvoice( - organization.$id, - (organization as Organization)?.billingInvoiceId - ); - } catch (e) { - // ignore error - } - - const [paymentMethods, addressList, billingAddress, creditList, aggregationBillingPlan] = - await Promise.all([ - sdk.forConsole.billing.listPaymentMethods(), - sdk.forConsole.billing.listAddresses(), - billingAddressPromise, - sdk.forConsole.billing.listCredits(organization.$id), - sdk.forConsole.billing.getPlan(billingAggregation?.plan ?? organization.billingPlan) - ]); + const [ + estimationOrganization, + paymentMethods, + addressList, + billingAddress, + creditList, + aggregationBillingPlan + ] = await Promise.all([ + sdk.forConsole.billing.estimationGetOrganization(organization.$id), + sdk.forConsole.billing.listPaymentMethods(), + sdk.forConsole.billing.listAddresses(), + billingAddressPromise, + sdk.forConsole.billing.listCredits(organization.$id), + sdk.forConsole.billing.getPlan(billingAggregation?.plan ?? organization.billingPlan) + ]); return { + estimationOrganization, paymentMethods, addressList, billingAddress, aggregationBillingPlan, creditList, - billingAggregation, - billingInvoice + billingAggregation }; }; diff --git a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte index 1e08e5190..fcba8161b 100644 --- a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte +++ b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte @@ -3,9 +3,9 @@ import { Card, CardGrid, Collapsible, CollapsibleItem, Heading } from '$lib/components'; import { Button } from '$lib/elements/forms'; import { toLocaleDate } from '$lib/helpers/date'; - import { plansInfo, upgradeURL } from '$lib/stores/billing'; + import { upgradeURL } from '$lib/stores/billing'; import { organization } from '$lib/stores/organization'; - import type { Aggregation, CreditList, Invoice, Plan } from '$lib/sdk/billing'; + import type { EstimationOrganization, Plan } from '$lib/sdk/billing'; import { abbreviateNumber, formatCurrency, formatNumberWithCommas } from '$lib/helpers/numbers'; import { humanFileSize } from '$lib/helpers/sizeConvertion'; import { BillingPlan } from '$lib/constants'; @@ -13,19 +13,14 @@ import { tooltip } from '$lib/actions/tooltip'; import CancelDowngradeModel from './cancelDowngradeModal.svelte'; + export let estimation: EstimationOrganization; export let currentPlan: Plan; - export let creditList: CreditList; - export let currentInvoice: Invoice | undefined = undefined; - export let currentAggregation: Aggregation | undefined = undefined; let showCancel: boolean = false; - const availableCredit = creditList.available; - const today = new Date(); - const isTrial = - new Date($organization?.billingStartDate).getTime() - today.getTime() > 0 && - $plansInfo.get($organization.billingPlan)?.trialDays; - const extraUsage = currentInvoice ? currentInvoice.amount - currentPlan?.price : 0; + const extraUsage = estimation.usage.length + ? estimation.usage.reduce((total, usage) => total + usage.amount, 0) + : 0; {#if $organization} @@ -43,26 +38,19 @@
-
- {currentPlan.name} plan -
- {isTrial || - $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION - ? formatCurrency(0) - : currentPlan - ? formatCurrency(currentPlan?.price) - : ''} + {#each estimation.items as item} +
+ {item.label} +
+ {formatCurrency(item.value)} +
-
- - {#if currentPlan.budgeting && extraUsage > 0} + {/each} + {#if estimation.usage.length} Add-ons{currentAggregation.additionalMembers > 0 - ? currentInvoice.usage.length + 1 - : currentInvoice.usage.length} + class="inline-tag">{estimation.usage.length}
@@ -70,106 +58,84 @@
- {formatCurrency(extraUsage >= 0 ? extraUsage : 0)} + {formatCurrency(extraUsage)}
    - {#if currentAggregation.additionalMembers} + {#each estimation.usage as excess}
  • -
    -
    - Additional members -
    -
    - {formatCurrency( - currentAggregation.additionalMemberAmount - )} + {#if ['storage', 'bandwidth'].includes(excess.name)} + {@const excessValue = humanFileSize(excess.value)} +
    +
    + {excess.name} +
    + {formatCurrency(excess.amount)}
    -
    -
    - {currentAggregation.additionalMembers} + class="body-text-2 u-stretch u-color-text-offline" + title={formatNumberWithCommas( + excess.value ?? 0 + ) + 'bytes'}> + {excessValue.value ?? 0}{excessValue.unit}
    -
    + {:else if excess.name === 'member'} +
    +
    + Additional members +
    + {formatCurrency(excess.amount)} +
    +
    + {excess.value} +
    + {:else} +
    +
    + {excess.name} +
    + {formatCurrency(excess.amount)} +
    +
    + {abbreviateNumber(excess.value)} +
    + {/if}
  • - {/if} - {#if currentInvoice?.usage} - {#each currentInvoice.usage as excess, i} -
  • 0 || - currentAggregation.additionalMembers > 0}> - {#if ['storage', 'bandwidth'].includes(excess.name)} - {@const excessValue = humanFileSize( - excess.value - )} -
    -
    - {excess.name} -
    - {formatCurrency(excess.amount)} -
    -
    - {excessValue.value ?? 0}{excessValue.unit} -
    - {:else if excess.name !== 'member'} -
    -
    - {excess.name} -
    - {formatCurrency(excess.amount)} -
    -
    - {abbreviateNumber(excess.value)} -
    - {/if} -
  • - {/each} - {/if} + {/each}
{/if} - {#if currentPlan.supportsCredits && availableCredit > 0} + {#if estimation.discounts.length} - - - - Credits to be applied + {#each estimation.discounts as discount} + + + + {discount.label} -
- -{formatCurrency( - Math.min(availableCredit, currentInvoice?.amount ?? 0) - )} -
+
+ -{formatCurrency(discount.value)} +
+ {/each}
{/if} @@ -190,16 +156,7 @@ }}>
- {formatCurrency( - Math.max( - (currentInvoice?.amount ?? 0) - - Math.min( - availableCredit, - currentInvoice?.amount ?? 0 - ), - 0 - ) - )} + {formatCurrency(estimation.grossAmount)}
{/if}