From 61b6ff518626a0d89d1b417ae9002bf73cae8d2c Mon Sep 17 00:00:00 2001 From: VitaliiShpital Date: Thu, 26 Mar 2020 15:34:16 +0200 Subject: [PATCH] web/satellite: available credits amount added on billing page Change-Id: I9d9c18ad08cf150ceba078356e39132a602558d4 --- web/satellite/src/api/auth.ts | 7 +- web/satellite/src/api/payments.ts | 11 ++- .../account/billing/BillingArea.vue | 8 +- .../EstimatedCostsAndCredits.vue | 92 ++++++++++++------ ...ChargeItem.vue => UsageAndChargesItem.vue} | 40 ++++---- .../billing/paymentMethods/PaymentMethods.vue | 2 +- .../paymentMethods/TokenDepositSelection.vue | 11 ++- .../ProjectSelectionDropdown.vue | 2 +- .../components/project/NewProjectPopup.vue | 2 +- web/satellite/src/store/modules/payments.ts | 95 +++++++++++++++---- web/satellite/src/types/payments.ts | 8 +- web/satellite/src/views/DashboardArea.vue | 6 +- .../views/forgotPassword/ForgotPassword.vue | 9 +- .../EstimatedCostsAndCredits.spec.ts | 64 +++++++++++-- ...em.spec.ts => UsageAndChargesItem.spec.ts} | 16 ++-- .../EstimatedCostsAndCredits.spec.ts.snap | 80 +++++++++++++++- .../UsageAndChargesItem.spec.ts.snap | 64 +++++++++++++ .../UsageChargeItem.spec.ts.snap | 64 ------------- web/satellite/tests/unit/mock/api/payments.ts | 4 +- 19 files changed, 405 insertions(+), 180 deletions(-) rename web/satellite/src/components/account/billing/estimatedCostsAndCredits/{UsageChargeItem.vue => UsageAndChargesItem.vue} (80%) rename web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/{UsageChargeItem.spec.ts => UsageAndChargesItem.spec.ts} (71%) create mode 100644 web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/__snapshots__/UsageAndChargesItem.spec.ts.snap delete mode 100644 web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/__snapshots__/UsageChargeItem.spec.ts.snap diff --git a/web/satellite/src/api/auth.ts b/web/satellite/src/api/auth.ts index c707448b4..423695056 100644 --- a/web/satellite/src/api/auth.ts +++ b/web/satellite/src/api/auth.ts @@ -84,7 +84,12 @@ export class AuthHttpApi { */ public async forgotPassword(email: string): Promise { const path = `${this.ROOT_PATH}/forgot-password/${email}`; - await this.http.post(path, email); + const response = await this.http.post(path, email); + if (response.ok) { + return; + } + + throw new Error('There is no such email'); } /** diff --git a/web/satellite/src/api/payments.ts b/web/satellite/src/api/payments.ts index 52401849e..9ed74319a 100644 --- a/web/satellite/src/api/payments.ts +++ b/web/satellite/src/api/payments.ts @@ -2,7 +2,7 @@ // See LICENSE for copying information. import { ErrorUnauthorized } from '@/api/errors/ErrorUnauthorized'; -import { BillingHistoryItem, CreditCard, PaymentsApi, ProjectCharge, TokenDeposit } from '@/types/payments'; +import { BillingHistoryItem, CreditCard, PaymentsApi, ProjectUsageAndCharges, TokenDeposit } from '@/types/payments'; import { HttpClient } from '@/utils/httpClient'; import { toUnixTimestamp } from '@/utils/time'; @@ -56,9 +56,9 @@ export class PaymentsHttpApi implements PaymentsApi { } /** - * projectsCharges returns how much money current user will be charged for each project which he owns. + * projectsUsageAndCharges returns usage and how much money current user will be charged for each project which he owns. */ - public async projectsCharges(start: Date, end: Date): Promise { + public async projectsUsageAndCharges(start: Date, end: Date): Promise { const since = toUnixTimestamp(start).toString(); const before = toUnixTimestamp(end).toString(); const path = `${this.ROOT_PATH}/account/charges?from=${since}&to=${before}`; @@ -75,7 +75,7 @@ export class PaymentsHttpApi implements PaymentsApi { const charges = await response.json(); if (charges) { return charges.map(charge => - new ProjectCharge( + new ProjectUsageAndCharges( new Date(charge.since), new Date(charge.before), charge.egress, @@ -84,7 +84,8 @@ export class PaymentsHttpApi implements PaymentsApi { charge.projectId, charge.storagePrice, charge.egressPrice, - charge.objectPrice), + charge.objectPrice, + ), ); } diff --git a/web/satellite/src/components/account/billing/BillingArea.vue b/web/satellite/src/components/account/billing/BillingArea.vue index 81d695005..e14c9c5c8 100644 --- a/web/satellite/src/components/account/billing/BillingArea.vue +++ b/web/satellite/src/components/account/billing/BillingArea.vue @@ -152,7 +152,7 @@ export default class BillingArea extends Vue { */ public async beforeRouteLeave(to, from, next): Promise { try { - await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES_CURRENT_ROLLUP); + await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP); } catch (error) { await this.$notify.error(error.message); } @@ -220,7 +220,7 @@ export default class BillingArea extends Vue { start_date: this.dateRange.startDate, end_date: this.dateRange.endDate, }); - await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES_CURRENT_ROLLUP); + await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP); } catch (error) { await this.$notify.error(`Unable to fetch project charges. ${error.message}`); } @@ -239,7 +239,7 @@ export default class BillingArea extends Vue { start_date: this.dateRange.startDate, end_date: this.dateRange.endDate, }); - await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES_PREVIOUS_ROLLUP); + await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP); } catch (error) { await this.$notify.error(`Unable to fetch project charges. ${error.message}`); } @@ -274,7 +274,7 @@ export default class BillingArea extends Vue { const dateRange: DateRange = new DateRange(startDate, endDate); try { - await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES, dateRange); + await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES, dateRange); } catch (error) { await this.$notify.error(`Unable to fetch project charges. ${error.message}`); } diff --git a/web/satellite/src/components/account/billing/estimatedCostsAndCredits/EstimatedCostsAndCredits.vue b/web/satellite/src/components/account/billing/estimatedCostsAndCredits/EstimatedCostsAndCredits.vue index 4a0945979..a41fe3703 100644 --- a/web/satellite/src/components/account/billing/estimatedCostsAndCredits/EstimatedCostsAndCredits.vue +++ b/web/satellite/src/components/account/billing/estimatedCostsAndCredits/EstimatedCostsAndCredits.vue @@ -5,26 +5,26 @@

Estimated Costs for This Billing Period

- {{ chargesSummary | centsToDollars }} + {{ priceSummary | centsToDollars }}

DETAILS

-
- - +
+ +
Usage Charges
- Estimated total {{ chargesSummary | centsToDollars }} + Estimated total {{ priceSummary | centsToDollars }}
-
- +
@@ -40,6 +40,14 @@ {{ balance | centsToDollars }}
+
+
+ Available Credits +
+ + {{ availableBalance | centsToDollars }} + +
@@ -47,19 +55,19 @@ diff --git a/web/satellite/src/components/account/billing/estimatedCostsAndCredits/UsageChargeItem.vue b/web/satellite/src/components/account/billing/estimatedCostsAndCredits/UsageAndChargesItem.vue similarity index 80% rename from web/satellite/src/components/account/billing/estimatedCostsAndCredits/UsageChargeItem.vue rename to web/satellite/src/components/account/billing/estimatedCostsAndCredits/UsageAndChargesItem.vue index 5f921b3a5..5e2fcac99 100644 --- a/web/satellite/src/components/account/billing/estimatedCostsAndCredits/UsageChargeItem.vue +++ b/web/satellite/src/components/account/billing/estimatedCostsAndCredits/UsageAndChargesItem.vue @@ -2,49 +2,49 @@ // See LICENSE for copying information. @@ -52,19 +52,19 @@ diff --git a/web/satellite/src/components/header/projectSelection/ProjectSelectionDropdown.vue b/web/satellite/src/components/header/projectSelection/ProjectSelectionDropdown.vue index ba0a4da94..95b180efe 100644 --- a/web/satellite/src/components/header/projectSelection/ProjectSelectionDropdown.vue +++ b/web/satellite/src/components/header/projectSelection/ProjectSelectionDropdown.vue @@ -50,7 +50,7 @@ export default class ProjectSelectionDropdown extends Vue { await this.$store.dispatch(PM_ACTIONS.SET_SEARCH_QUERY, ''); try { - await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES_CURRENT_ROLLUP); + await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP); } catch (error) { await this.$notify.error(`Unable to fetch project usage. ${error.message}`); } diff --git a/web/satellite/src/components/project/NewProjectPopup.vue b/web/satellite/src/components/project/NewProjectPopup.vue index c74480657..15a32a740 100644 --- a/web/satellite/src/components/project/NewProjectPopup.vue +++ b/web/satellite/src/components/project/NewProjectPopup.vue @@ -159,7 +159,7 @@ export default class NewProjectPopup extends Vue { try { await this.$store.dispatch(PAYMENTS_ACTIONS.GET_BILLING_HISTORY); await this.$store.dispatch(PAYMENTS_ACTIONS.GET_BALANCE); - await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES_CURRENT_ROLLUP); + await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP); await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, this.createdProjectId); } catch (error) { await this.$notify.error(error.message); diff --git a/web/satellite/src/store/modules/payments.ts b/web/satellite/src/store/modules/payments.ts index e580bf5ec..31f6225ef 100644 --- a/web/satellite/src/store/modules/payments.ts +++ b/web/satellite/src/store/modules/payments.ts @@ -9,7 +9,7 @@ import { CreditCard, DateRange, PaymentsApi, - ProjectCharge, + ProjectUsageAndCharges, TokenDeposit, } from '@/types/payments'; @@ -21,7 +21,10 @@ export const PAYMENTS_MUTATIONS = { UPDATE_CARDS_SELECTION: 'UPDATE_CARDS_SELECTION', UPDATE_CARDS_DEFAULT: 'UPDATE_CARDS_DEFAULT', SET_BILLING_HISTORY: 'SET_BILLING_HISTORY', - SET_PROJECT_CHARGES: 'SET_PROJECT_CHARGES', + SET_PROJECT_USAGE_AND_CHARGES: 'SET_PROJECT_USAGE_AND_CHARGES', + SET_CURRENT_ROLLUP_PRICE: 'SET_CURRENT_ROLLUP_PRICE', + SET_PREVIOUS_ROLLUP_PRICE: 'SET_PREVIOUS_ROLLUP_PRICE', + SET_PRICE_SUMMARY: 'SET_PRICE_SUMMARY', }; export const PAYMENTS_ACTIONS = { @@ -36,9 +39,9 @@ export const PAYMENTS_ACTIONS = { REMOVE_CARD: 'removeCard', GET_BILLING_HISTORY: 'getBillingHistory', MAKE_TOKEN_DEPOSIT: 'makeTokenDeposit', - GET_PROJECT_CHARGES: 'getProjectCharges', - GET_PROJECT_CHARGES_CURRENT_ROLLUP: 'getProjectChargesCurrentRollup', - GET_PROJECT_CHARGES_PREVIOUS_ROLLUP: 'getProjectChargesPreviousRollup', + GET_PROJECT_USAGE_AND_CHARGES: 'getProjectUsageAndCharges', + GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP: 'getProjectUsageAndChargesCurrentRollup', + GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP: 'getProjectUsageAndChargesPreviousRollup', }; const { @@ -49,7 +52,10 @@ const { UPDATE_CARDS_SELECTION, UPDATE_CARDS_DEFAULT, SET_BILLING_HISTORY, - SET_PROJECT_CHARGES, + SET_PROJECT_USAGE_AND_CHARGES, + SET_CURRENT_ROLLUP_PRICE, + SET_PREVIOUS_ROLLUP_PRICE, + SET_PRICE_SUMMARY, } = PAYMENTS_MUTATIONS; const { @@ -64,9 +70,9 @@ const { REMOVE_CARD, GET_BILLING_HISTORY, MAKE_TOKEN_DEPOSIT, - GET_PROJECT_CHARGES, - GET_PROJECT_CHARGES_CURRENT_ROLLUP, - GET_PROJECT_CHARGES_PREVIOUS_ROLLUP, + GET_PROJECT_USAGE_AND_CHARGES, + GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP, + GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP, } = PAYMENTS_ACTIONS; export class PaymentsState { @@ -76,7 +82,10 @@ export class PaymentsState { public balance: number = 0; public creditCards: CreditCard[] = []; public billingHistory: BillingHistoryItem[] = []; - public charges: ProjectCharge[] = []; + public usageAndCharges: ProjectUsageAndCharges[] = []; + public priceSummary: number = 0; + public currentRollupPrice: number = 0; + public previousRollupPrice: number = 0; public startDate: Date = new Date(); public endDate: Date = new Date(); } @@ -129,12 +138,36 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule [SET_BILLING_HISTORY](state: PaymentsState, billingHistory: BillingHistoryItem[]): void { state.billingHistory = billingHistory; }, - [SET_PROJECT_CHARGES](state: PaymentsState, charges: ProjectCharge[]): void { - state.charges = charges; + [SET_PROJECT_USAGE_AND_CHARGES](state: PaymentsState, usageAndCharges: ProjectUsageAndCharges[]): void { + state.usageAndCharges = usageAndCharges; + }, + [SET_CURRENT_ROLLUP_PRICE](state: PaymentsState): void { + state.currentRollupPrice = state.priceSummary; + }, + [SET_PREVIOUS_ROLLUP_PRICE](state: PaymentsState): void { + state.previousRollupPrice = state.priceSummary; + }, + [SET_PRICE_SUMMARY](state: PaymentsState, charges: ProjectUsageAndCharges[]): void { + if (charges.length === 0) { + state.priceSummary = 0; + + return; + } + + const usageItemSummaries = charges.map(item => item.summary()); + + state.priceSummary = usageItemSummaries.reduce((accumulator, current) => accumulator + current); }, [CLEAR](state: PaymentsState) { state.balance = 0; + state.billingHistory = []; + state.usageAndCharges = []; + state.priceSummary = 0; + state.previousRollupPrice = 0; + state.currentRollupPrice = 0; state.creditCards = []; + state.startDate = new Date(); + state.endDate = new Date(); }, }, actions: { @@ -185,7 +218,7 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule [MAKE_TOKEN_DEPOSIT]: async function({commit}: any, amount: number): Promise { return await api.makeTokenDeposit(amount); }, - [GET_PROJECT_CHARGES]: async function({commit}: any, dateRange: DateRange): Promise { + [GET_PROJECT_USAGE_AND_CHARGES]: async function({commit}: any, dateRange: DateRange): Promise { const now = new Date(); let beforeUTC = new Date(Date.UTC(dateRange.endDate.getUTCFullYear(), dateRange.endDate.getUTCMonth(), dateRange.endDate.getUTCDate(), 23, 59)); @@ -196,30 +229,35 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule } const sinceUTC = new Date(Date.UTC(dateRange.startDate.getUTCFullYear(), dateRange.startDate.getUTCMonth(), dateRange.startDate.getUTCDate(), 0, 0)); - const charges: ProjectCharge[] = await api.projectsCharges(sinceUTC, beforeUTC); + const usageAndCharges: ProjectUsageAndCharges[] = await api.projectsUsageAndCharges(sinceUTC, beforeUTC); commit(SET_DATE, dateRange); - commit(SET_PROJECT_CHARGES, charges); + commit(SET_PROJECT_USAGE_AND_CHARGES, usageAndCharges); + commit(SET_PRICE_SUMMARY, usageAndCharges); }, - [GET_PROJECT_CHARGES_CURRENT_ROLLUP]: async function({commit}: any): Promise { + [GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP]: async function({commit}: any): Promise { const now = new Date(); const endUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes())); const startUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1, 0, 0)); - const charges: ProjectCharge[] = await api.projectsCharges(startUTC, endUTC); + const usageAndCharges: ProjectUsageAndCharges[] = await api.projectsUsageAndCharges(startUTC, endUTC); commit(SET_DATE, new DateRange(startUTC, endUTC)); - commit(SET_PROJECT_CHARGES, charges); + commit(SET_PROJECT_USAGE_AND_CHARGES, usageAndCharges); + commit(SET_PRICE_SUMMARY, usageAndCharges); + commit(SET_CURRENT_ROLLUP_PRICE); }, - [GET_PROJECT_CHARGES_PREVIOUS_ROLLUP]: async function({commit}: any): Promise { + [GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP]: async function({commit}: any): Promise { const now = new Date(); const startUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - 1, 1, 0, 0)); const endUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 0, 23, 59, 59)); - const charges: ProjectCharge[] = await api.projectsCharges(startUTC, endUTC); + const usageAndCharges: ProjectUsageAndCharges[] = await api.projectsUsageAndCharges(startUTC, endUTC); commit(SET_DATE, new DateRange(startUTC, endUTC)); - commit(SET_PROJECT_CHARGES, charges); + commit(SET_PROJECT_USAGE_AND_CHARGES, usageAndCharges); + commit(SET_PRICE_SUMMARY, usageAndCharges); + commit(SET_PREVIOUS_ROLLUP_PRICE); }, }, getters: { @@ -229,6 +267,21 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule && billingItem.status === BillingHistoryItemStatus.Completed; }) || state.creditCards.length > 0; }, + isInvoiceForPreviousRollup: (state: PaymentsState): boolean => { + const now = new Date(); + + return state.billingHistory.some((billingItem: BillingHistoryItem) => { + if (now.getUTCMonth() === 0) { + return billingItem.type === BillingHistoryItemType.Invoice + && billingItem.start.getUTCFullYear() === now.getUTCFullYear() - 1 + && billingItem.start.getUTCMonth() === 11; + } + + return billingItem.type === BillingHistoryItemType.Invoice + && billingItem.start.getUTCFullYear() === now.getUTCFullYear() + && billingItem.start.getUTCMonth() === now.getUTCMonth() - 1; + }); + }, }, }; } diff --git a/web/satellite/src/types/payments.ts b/web/satellite/src/types/payments.ts index b3761b5a6..85cf52476 100644 --- a/web/satellite/src/types/payments.ts +++ b/web/satellite/src/types/payments.ts @@ -21,9 +21,9 @@ export interface PaymentsApi { getBalance(): Promise; /** - * projectsCharges returns how much money current user will be charged for each project which he owns. + * projectsUsagesAndCharges returns usage and how much money current user will be charged for each project which he owns. */ - projectsCharges(since: Date, before: Date): Promise; + projectsUsageAndCharges(since: Date, before: Date): Promise; /** * Add credit card @@ -177,9 +177,9 @@ class Amount { } /** - * ProjectCharge shows how much money current project will charge in the end of the month. + * ProjectUsageAndCharges shows usage and how much money current project will charge in the end of the month. */ -export class ProjectCharge { +export class ProjectUsageAndCharges { public constructor( public since: Date = new Date(), public before: Date = new Date(), diff --git a/web/satellite/src/views/DashboardArea.vue b/web/satellite/src/views/DashboardArea.vue index 65b2c4b68..1426f5e4e 100644 --- a/web/satellite/src/views/DashboardArea.vue +++ b/web/satellite/src/views/DashboardArea.vue @@ -81,7 +81,8 @@ const { GET_BALANCE, GET_CREDIT_CARDS, GET_BILLING_HISTORY, - GET_PROJECT_CHARGES_CURRENT_ROLLUP, + GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP, + GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP, } = PAYMENTS_ACTIONS; @Component({ @@ -126,7 +127,8 @@ export default class DashboardArea extends Vue { balance = await this.$store.dispatch(GET_BALANCE); creditCards = await this.$store.dispatch(GET_CREDIT_CARDS); await this.$store.dispatch(GET_BILLING_HISTORY); - await this.$store.dispatch(GET_PROJECT_CHARGES_CURRENT_ROLLUP); + await this.$store.dispatch(GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP); + await this.$store.dispatch(GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP); } catch (error) { await this.$notify.error(error.message); } diff --git a/web/satellite/src/views/forgotPassword/ForgotPassword.vue b/web/satellite/src/views/forgotPassword/ForgotPassword.vue index 32127f81b..5d750906a 100644 --- a/web/satellite/src/views/forgotPassword/ForgotPassword.vue +++ b/web/satellite/src/views/forgotPassword/ForgotPassword.vue @@ -52,21 +52,24 @@ export default class ForgotPassword extends Vue { try { await this.auth.forgotPassword(this.email); - await this.$notify.success('Please look for instructions at your email'); } catch (error) { await this.$notify.error(error.message); + + return; } + + await this.$notify.success('Please look for instructions at your email'); } /** * Changes location to Login route. */ public onBackToLoginClick(): void { - this.$router.push(RouteConfig.Login.path); + this.$router.push(RouteConfig.Login.path); } public onLogoClick(): void { - location.reload(); + location.reload(); } private validateFields(): boolean { diff --git a/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/EstimatedCostsAndCredits.spec.ts b/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/EstimatedCostsAndCredits.spec.ts index ddc429448..6b55bf955 100644 --- a/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/EstimatedCostsAndCredits.spec.ts +++ b/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/EstimatedCostsAndCredits.spec.ts @@ -8,7 +8,7 @@ import EstimatedCostsAndCredits from '@/components/account/billing/estimatedCost import { makePaymentsModule, PAYMENTS_MUTATIONS } from '@/store/modules/payments'; import { makeProjectsModule, PROJECTS_MUTATIONS } from '@/store/modules/projects'; import { makeUsersModule, USER_MUTATIONS } from '@/store/modules/users'; -import { ProjectCharge } from '@/types/payments'; +import { BillingHistoryItem, BillingHistoryItemType, ProjectUsageAndCharges } from '@/types/payments'; import { Project } from '@/types/projects'; import { User } from '@/types/users'; import { createLocalVue, mount } from '@vue/test-utils'; @@ -34,10 +34,19 @@ const store = new Vuex.Store({ modules: { usersModule, projectsModule, paymentsM const project = new Project('id', 'projectName', 'projectDescription', 'test', 'testOwnerId', true); const user = new User('testOwnerId'); const date = new Date(1970, 1, 1); -const projectCharge = new ProjectCharge(date, date, 100, 100, 100, 'id', 100, 100, 100); +const projectCharge = new ProjectUsageAndCharges(date, date, 100, 100, 100, 'id', 100, 100, 100); +const { + SET_BALANCE, + CLEAR, + SET_BILLING_HISTORY, + SET_PROJECT_USAGE_AND_CHARGES, + SET_CURRENT_ROLLUP_PRICE, + SET_PREVIOUS_ROLLUP_PRICE, + SET_PRICE_SUMMARY, +} = PAYMENTS_MUTATIONS; describe('EstimatedCostsAndCredits', () => { - it('renders correctly with project and no project charges', () => { + it('renders correctly with project and no project usage and charges', () => { store.commit(USER_MUTATIONS.SET_USER, user); store.commit(PROJECTS_MUTATIONS.ADD, project); @@ -49,9 +58,52 @@ describe('EstimatedCostsAndCredits', () => { expect(wrapper).toMatchSnapshot(); }); - it('renders correctly with project and project charges', () => { - store.commit(PAYMENTS_MUTATIONS.SET_BALANCE, 5500); - store.commit(PAYMENTS_MUTATIONS.SET_PROJECT_CHARGES, [projectCharge]); + it('renders correctly with project and project usage and charges', () => { + store.commit(SET_BALANCE, 5500); + store.commit(SET_PROJECT_USAGE_AND_CHARGES, [projectCharge]); + store.commit(SET_PRICE_SUMMARY, [projectCharge]); + store.commit(SET_CURRENT_ROLLUP_PRICE); + store.commit(SET_PREVIOUS_ROLLUP_PRICE); + + const wrapper = mount(EstimatedCostsAndCredits, { + store, + localVue, + }); + + expect(wrapper).toMatchSnapshot(); + }); + + it('renders correctly with project and project usage and charges with previous rollup invoice', () => { + const now = new Date(); + let billingHistoryItem = new BillingHistoryItem('id', 'description', 300, 300, 'paid', 'test', new Date(now.getUTCFullYear(), now.getUTCMonth() - 1, 15), now, BillingHistoryItemType.Invoice); + + if (now.getUTCMonth() === 0) { + billingHistoryItem = new BillingHistoryItem('id', 'description', 300, 300, 'paid', 'test', new Date(now.getUTCFullYear() - 1, 11, 15), now, BillingHistoryItemType.Invoice); + } + + store.commit(CLEAR); + store.commit(SET_BALANCE, 600); + store.commit(SET_PROJECT_USAGE_AND_CHARGES, [projectCharge]); + store.commit(SET_PRICE_SUMMARY, [projectCharge]); + store.commit(SET_CURRENT_ROLLUP_PRICE); + store.commit(SET_BILLING_HISTORY, [billingHistoryItem]); + + const wrapper = mount(EstimatedCostsAndCredits, { + store, + localVue, + }); + + expect(wrapper).toMatchSnapshot(); + }); + + it('renders correctly with project and project usage and charges with price bigger than balance amount', () => { + store.commit(CLEAR); + store.commit(SET_BALANCE, 500); + store.commit(SET_PROJECT_USAGE_AND_CHARGES, [projectCharge]); + store.commit(SET_PRICE_SUMMARY, [projectCharge]); + store.commit(SET_CURRENT_ROLLUP_PRICE); + store.commit(SET_PREVIOUS_ROLLUP_PRICE); + store.commit(SET_BILLING_HISTORY, []); const wrapper = mount(EstimatedCostsAndCredits, { store, diff --git a/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/UsageChargeItem.spec.ts b/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/UsageAndChargesItem.spec.ts similarity index 71% rename from web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/UsageChargeItem.spec.ts rename to web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/UsageAndChargesItem.spec.ts index 9010b2e2e..787e274c5 100644 --- a/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/UsageChargeItem.spec.ts +++ b/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/UsageAndChargesItem.spec.ts @@ -3,11 +3,11 @@ import Vuex from 'vuex'; -import UsageChargeItem from '@/components/account/billing/estimatedCostsAndCredits/UsageChargeItem.vue'; +import UsageAndChargesItem from '@/components/account/billing/estimatedCostsAndCredits/UsageAndChargesItem.vue'; import { makePaymentsModule } from '@/store/modules/payments'; import { makeProjectsModule } from '@/store/modules/projects'; -import { ProjectCharge } from '@/types/payments'; +import { ProjectUsageAndCharges } from '@/types/payments'; import { Project } from '@/types/projects'; import { createLocalVue, shallowMount } from '@vue/test-utils'; @@ -26,14 +26,14 @@ const paymentsApi = new PaymentsMock(); const paymentsModule = makePaymentsModule(paymentsApi); const store = new Vuex.Store({ modules: { projectsModule, paymentsModule }}); -describe('UsageChargeItem', () => { +describe('UsageAndChargesItem', () => { const project = new Project('id', 'projectName', 'projectDescription', 'test', 'testOwnerId', true); projectsApi.setMockProjects([project]); const date = new Date(Date.UTC(1970, 1, 1)); - const projectCharge = new ProjectCharge(date, date, 100, 100, 100, 'id', 100, 100, 100); + const projectCharge = new ProjectUsageAndCharges(date, date, 100, 100, 100, 'id', 100, 100, 100); it('renders correctly', () => { - const wrapper = shallowMount(UsageChargeItem, { + const wrapper = shallowMount(UsageAndChargesItem, { store, localVue, }); @@ -42,7 +42,7 @@ describe('UsageChargeItem', () => { }); it('toggling dropdown works correctly', async () => { - const wrapper = shallowMount(UsageChargeItem, { + const wrapper = shallowMount(UsageAndChargesItem, { store, localVue, propsData: { @@ -50,11 +50,11 @@ describe('UsageChargeItem', () => { }, }); - await wrapper.find('.usage-charge-item-container__summary').trigger('click'); + await wrapper.find('.usage-charges-item-container__summary').trigger('click'); expect(wrapper).toMatchSnapshot(); - await wrapper.find('.usage-charge-item-container__summary').trigger('click'); + await wrapper.find('.usage-charges-item-container__summary').trigger('click'); expect(wrapper).toMatchSnapshot(); }); diff --git a/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/__snapshots__/EstimatedCostsAndCredits.spec.ts.snap b/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/__snapshots__/EstimatedCostsAndCredits.spec.ts.snap index c80471cd0..59ba9881a 100644 --- a/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/__snapshots__/EstimatedCostsAndCredits.spec.ts.snap +++ b/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/__snapshots__/EstimatedCostsAndCredits.spec.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`EstimatedCostsAndCredits renders correctly with project and no project charges 1`] = ` +exports[`EstimatedCostsAndCredits renders correctly with project and no project usage and charges 1`] = `

Estimated Costs for This Billing Period

USD $0.00 @@ -19,11 +19,16 @@ exports[`EstimatedCostsAndCredits renders correctly with project and no project USD $0.00
+
+
Available Credits
+ USD $0.00 + +
`; -exports[`EstimatedCostsAndCredits renders correctly with project and project charges 1`] = ` +exports[`EstimatedCostsAndCredits renders correctly with project and project usage and charges 1`] = `

Estimated Costs for This Billing Period

USD $3.00 @@ -35,9 +40,7 @@ exports[`EstimatedCostsAndCredits renders correctly with project and project cha
- - -
Usage Charges +
Usage Charges
Estimated total USD $3.00
@@ -47,6 +50,73 @@ exports[`EstimatedCostsAndCredits renders correctly with project and project cha USD $55.00 +
+
Available Credits
+ USD $49.00 + +
+ + +`; + +exports[`EstimatedCostsAndCredits renders correctly with project and project usage and charges with previous rollup invoice 1`] = ` +
+
+

Estimated Costs for This Billing Period

USD $3.00 +
+
+

DETAILS

+
+
+
+
+ +
Usage Charges +
Estimated total USD $3.00 +
+ +
+
+
Earned Credits
+ USD $6.00 + +
+
+
Available Credits
+ USD $3.00 + +
+
+
+`; + +exports[`EstimatedCostsAndCredits renders correctly with project and project usage and charges with price bigger than balance amount 1`] = ` +
+
+

Estimated Costs for This Billing Period

USD $3.00 +
+
+

DETAILS

+
+
+
+
+ +
Usage Charges +
Estimated total USD $3.00 +
+ +
+
+
Earned Credits
+ USD $5.00 + +
+
+
Available Credits
+ USD $0.00 + +
`; diff --git a/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/__snapshots__/UsageAndChargesItem.spec.ts.snap b/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/__snapshots__/UsageAndChargesItem.spec.ts.snap new file mode 100644 index 000000000..04831dc73 --- /dev/null +++ b/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/__snapshots__/UsageAndChargesItem.spec.ts.snap @@ -0,0 +1,64 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`UsageAndChargesItem renders correctly 1`] = ` +
+
+
+ + +
+ +
+ +
+`; + +exports[`UsageAndChargesItem toggling dropdown works correctly 1`] = ` +
+
+
+ + +
+ +
+
+
RESOURCE PERIOD USAGE COST
+
+
+

Storage ($0.010 per Gigabyte-Month)

+

Egress ($0.045 per GB)

+

Objects ($0.0000022 per Object-Month)

+
+
+

Feb 1 - Feb 1

+

Feb 1 - Feb 1

+

Feb 1 - Feb 1

+
+
+

0.00 Gigabyte-month

+

0.10 KB

+

0.14 Object-month

+
+
+

USD $1.00

+

USD $1.00

+

USD $1.00

+
+
USD $3.00 +
+
+`; + +exports[`UsageAndChargesItem toggling dropdown works correctly 2`] = ` +
+
+
+ + +
+ +
+ +
+`; diff --git a/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/__snapshots__/UsageChargeItem.spec.ts.snap b/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/__snapshots__/UsageChargeItem.spec.ts.snap deleted file mode 100644 index bc542f7f4..000000000 --- a/web/satellite/tests/unit/account/billing/estimatedCostsAndCredits/__snapshots__/UsageChargeItem.spec.ts.snap +++ /dev/null @@ -1,64 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`UsageChargeItem renders correctly 1`] = ` -
-
-
- - -
- -
- -
-`; - -exports[`UsageChargeItem toggling dropdown works correctly 1`] = ` -
-
-
- - -
- -
-
-
RESOURCE PERIOD USAGE COST
-
-
-

Storage ($0.010 per Gigabyte-Month)

-

Egress ($0.045 per GB)

-

Objects ($0.0000022 per Object-Month)

-
-
-

Feb 1 - Feb 1

-

Feb 1 - Feb 1

-

Feb 1 - Feb 1

-
-
-

0.00 Gigabyte-month

-

0.10 KB

-

0.14 Object-month

-
-
-

USD $1.00

-

USD $1.00

-

USD $1.00

-
-
USD $3.00 -
-
-`; - -exports[`UsageChargeItem toggling dropdown works correctly 2`] = ` -
-
-
- - -
- -
- -
-`; diff --git a/web/satellite/tests/unit/mock/api/payments.ts b/web/satellite/tests/unit/mock/api/payments.ts index e0b8ad58e..aef568850 100644 --- a/web/satellite/tests/unit/mock/api/payments.ts +++ b/web/satellite/tests/unit/mock/api/payments.ts @@ -1,7 +1,7 @@ // Copyright (C) 2019 Storj Labs, Inc. // See LICENSE for copying information. -import { BillingHistoryItem, CreditCard, PaymentsApi, ProjectCharge, TokenDeposit } from '@/types/payments'; +import { BillingHistoryItem, CreditCard, PaymentsApi, ProjectUsageAndCharges, TokenDeposit } from '@/types/payments'; /** * Mock for PaymentsApi @@ -15,7 +15,7 @@ export class PaymentsMock implements PaymentsApi { return Promise.resolve(0); } - projectsCharges(): Promise { + projectsUsageAndCharges(): Promise { return Promise.resolve([]); }