web/storagenode: frontend refactoring

WHAT:
separation of domain and presentation entities

WHY:
to have ability to easily reuse logic

Change-Id: I48f7d1831c217dec999ff1b678034bb2c10cfbaa
This commit is contained in:
NickolaiYurchenko 2020-09-08 20:39:16 +03:00 committed by Nikolay Yurchenko
parent 7db5794c16
commit 9a627b22e8
39 changed files with 2311 additions and 749 deletions

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@
"@vue/cli-service": "4.1.1",
"@vue/test-utils": "1.0.0-beta.30",
"babel-core": "7.0.0-bridge.0",
"compression-webpack-plugin": "3.0.1",
"compression-webpack-plugin": "6.0.0",
"core-js": "3.6.5",
"jest-fetch-mock": "3.0.0",
"node-sass": "4.14.1",

View File

@ -530,6 +530,7 @@ export default class SNOContentFilling extends Vue {
flex-direction: row;
align-items: center;
justify-content: flex-end;
text-decoration: none;
&__text {
font-size: 16px;

View File

@ -184,7 +184,7 @@ export default class SNOHeader extends Vue {
await this.$store.dispatch(APPSTATE_ACTIONS.SET_LOADING, false);
try {
await this.$store.dispatch(PAYOUT_ACTIONS.GET_HELD_INFO, selectedSatellite);
await this.$store.dispatch(PAYOUT_ACTIONS.GET_PAYOUT_INFO, selectedSatellite);
await this.$store.dispatch(PAYOUT_ACTIONS.GET_TOTAL);
} catch (error) {
console.error(error.message);

View File

@ -31,8 +31,9 @@ import SuspensionIcon from '@/../static/images/suspend.svg';
import { APPSTATE_ACTIONS } from '@/app/store/modules/appState';
import { NODE_ACTIONS } from '@/app/store/modules/node';
import { PAYOUT_ACTIONS } from '@/app/store/modules/payout';
import { PayoutInfoRange, PayoutPeriod } from '@/app/types/payout';
import { PayoutInfoRange } from '@/app/types/payout';
import { SatelliteInfo } from '@/storagenode/dashboard';
import { PayoutPeriod } from '@/storagenode/payouts/payouts';
@Component({
components: {

View File

@ -37,11 +37,11 @@ import SingleInfo from '@/app/components/payments/SingleInfo.vue';
})
export default class TotalPayoutArea extends Vue {
public get totalEarnings(): number {
return this.$store.state.payoutModule.totalEarnings;
return this.$store.state.payoutModule.totalHeldAndPaid.paid;
}
public get totalHeld(): number {
return this.$store.state.payoutModule.totalHeldAmount;
return this.$store.state.payoutModule.totalHeldAndPaid.held;
}
public get currentEarnings(): number {

View File

@ -5,8 +5,8 @@
<div class="notification-popup-container">
<div class="notification-popup-container__header">
<p class="notification-popup-container__header__title">Notifications</p>
<router-link :to="notificationsPath">
<p class="notification-popup-container__header__link">See All</p>
<router-link :to="notificationsPath" class="notification-popup-container__header__link">
<p>See All</p>
</router-link>
</div>
<div
@ -92,6 +92,7 @@ export default class NotificationsPopup extends Vue {
font-size: 14px;
color: var(--navigation-link-color);
margin-right: 20px;
text-decoration: none;
}
}

View File

@ -7,6 +7,8 @@ import { Component, Vue } from 'vue-property-decorator';
import BlueHideIcon from '@/../static/images/common/BlueMinus.svg';
import BlueExpandIcon from '@/../static/images/common/BluePlus.svg';
import { SatelliteHeldHistory } from '@/storagenode/payouts/payouts';
@Component({
components: {
BlueExpandIcon,
@ -14,6 +16,13 @@ import BlueExpandIcon from '@/../static/images/common/BluePlus.svg';
},
})
export default class BaseSmallHeldHistoryTable extends Vue {
/**
* Indicates if held info should be rendered.
*/
public get allSatellitesHeldHistory(): SatelliteHeldHistory[] {
return this.$store.state.payoutModule.heldHistory;
}
/**
* Indicates if held info should be rendered.
*/

View File

@ -81,7 +81,7 @@
</div>
</div>
<div class="estimation-table-container__held-area">
<p class="estimation-table-container__held-area__text">Held back</p>
<p class="estimation-table-container__held-area__text">Held Back</p>
<p class="estimation-table-container__held-area__text">-{{ held | centsToDollars }}</p>
</div>
<div class="estimation-table-container__held-area" v-if="!isCurrentPeriod && disposed > 0">
@ -104,9 +104,9 @@
<p class="estimation-table-container__net-total-area__text">{{ totalPayout | centsToDollars }}</p>
</div>
</div>
<div class="estimation-table-container__total-area" v-if="!isCurrentPeriod && !isLastPeriodWithoutPaystub && heldInfo.surgePercent">
<div class="estimation-table-container__total-area" v-if="!isCurrentPeriod && !isLastPeriodWithoutPaystub && totalPaystubForPeriod.surgePercent">
<p class="estimation-table-container__total-area__text">Total + Surge {{ surgePercent }}</p>
<p class="estimation-table-container__total-area__text">{{ heldInfo.paid | centsToDollars }}</p>
<p class="estimation-table-container__total-area__text">{{ totalPaystubForPeriod.paid | centsToDollars }}</p>
</div>
</div>
<div class="no-data-container" v-else>
@ -129,13 +129,11 @@ import {
DISK_SPACE_PRICE_PER_TB, PAYOUT_ACTIONS,
} from '@/app/store/modules/payout';
import {
EstimatedPayout,
HeldInfo,
monthNames,
PayoutInfoRange,
PayoutPeriod,
} from '@/app/types/payout';
import { formatBytes, TB } from '@/app/utils/converter';
import { formatBytes } from '@/app/utils/converter';
import { EstimatedPayout, PayoutPeriod, TotalPaystubForPeriod } from '@/storagenode/payouts/payouts';
/**
* Describes table row data item.
@ -213,7 +211,7 @@ export default class EstimationArea extends Vue {
* Returns surge percent if single month selected.
*/
public get surgePercent(): string {
return !this.$store.state.payoutModule.periodRange.start ? `(${this.heldInfo.surgePercent}%)` : '';
return !this.$store.state.payoutModule.periodRange.start ? `(${this.totalPaystubForPeriod.surgePercent}%)` : '';
}
/**
@ -224,10 +222,10 @@ export default class EstimationArea extends Vue {
}
/**
* Returns held info from store.
* Returns payout info from store.
*/
public get heldInfo(): HeldInfo {
return this.$store.state.payoutModule.heldInfo;
public get totalPaystubForPeriod(): TotalPaystubForPeriod {
return this.$store.state.payoutModule.totalPaystubForPeriod;
}
/**
@ -242,7 +240,7 @@ export default class EstimationArea extends Vue {
*/
public get held(): number {
if (!this.isCurrentPeriod && !this.isLastPeriodWithoutPaystub) {
return this.heldInfo.held;
return this.totalPaystubForPeriod.held;
}
return this.estimatedHeld();
@ -252,7 +250,7 @@ export default class EstimationArea extends Vue {
* Returns calculated or stored returned held amount.
*/
public get disposed(): number {
return this.heldInfo.disposed;
return this.totalPaystubForPeriod.disposed;
}
/**
@ -260,7 +258,7 @@ export default class EstimationArea extends Vue {
*/
public get totalPayout(): number {
if (!this.isCurrentPeriod && !this.isLastPeriodWithoutPaystub) {
return this.heldInfo.paid;
return this.totalPaystubForPeriod.paid;
}
return this.grossTotal;
@ -281,7 +279,7 @@ export default class EstimationArea extends Vue {
return formatBytes(this.currentDiskSpace);
}
return formatBytes(this.heldInfo.usageAtRest);
return formatBytes(this.totalPaystubForPeriod.usageAtRest);
}
/**
@ -292,7 +290,7 @@ export default class EstimationArea extends Vue {
return formatBytes((this.currentBandwidthAuditAndRepair + this.currentBandwidthDownload));
}
const bandwidthSum = this.heldInfo.usageGet + this.heldInfo.usageGetRepair + this.heldInfo.usageGetAudit;
const bandwidthSum = this.totalPaystubForPeriod.usageGet + this.totalPaystubForPeriod.usageGetRepair + this.totalPaystubForPeriod.usageGetAudit;
return formatBytes(bandwidthSum);
}
@ -324,9 +322,9 @@ export default class EstimationArea extends Vue {
public get tableData(): EstimationTableRow[] {
if (!this.isCurrentPeriod && !this.isLastPeriodWithoutPaystub) {
return [
new EstimationTableRow('Download', 'Egress', `$${BANDWIDTH_DOWNLOAD_PRICE_PER_TB / 100} / TB`, '--', formatBytes(this.heldInfo.usageGet), this.heldInfo.compGet),
new EstimationTableRow('Repair & Audit', 'Egress', `$${BANDWIDTH_REPAIR_PRICE_PER_TB / 100} / TB`, '--', formatBytes(this.heldInfo.usageGetRepair + this.heldInfo.usageGetAudit), this.heldInfo.compGetRepair + this.heldInfo.compGetAudit),
new EstimationTableRow('Disk Average Month', 'Storage', `$${DISK_SPACE_PRICE_PER_TB / 100} / TBm`, formatBytes(this.heldInfo.usageAtRest) + 'm', '--', this.heldInfo.compAtRest),
new EstimationTableRow('Download', 'Egress', `$${BANDWIDTH_DOWNLOAD_PRICE_PER_TB / 100} / TB`, '--', formatBytes(this.totalPaystubForPeriod.usageGet), this.totalPaystubForPeriod.compGet),
new EstimationTableRow('Repair & Audit', 'Egress', `$${BANDWIDTH_REPAIR_PRICE_PER_TB / 100} / TB`, '--', formatBytes(this.totalPaystubForPeriod.usageGetRepair + this.totalPaystubForPeriod.usageGetAudit), this.totalPaystubForPeriod.compGetRepair + this.totalPaystubForPeriod.compGetAudit),
new EstimationTableRow('Disk Average Month', 'Storage', `$${DISK_SPACE_PRICE_PER_TB / 100} / TBm`, formatBytes(this.totalPaystubForPeriod.usageAtRest) + 'm', '--', this.totalPaystubForPeriod.compAtRest),
];
}

View File

@ -18,10 +18,10 @@
<p class="held-history-table-container--large__labels-area__text">Held Returned</p>
</div>
</div>
<div v-for="item in allStats" class="held-history-table-container--large__info-area" :key="item.satelliteID">
<div v-for="item in allSatellitesHeldHistory" class="held-history-table-container--large__info-area" :key="item.satelliteID">
<div class="justify-start column-1">
<p class="held-history-table-container--large__info-area__text">{{ item.satelliteName }}</p>
<p class="held-history-table-container--large__info-area__months">{{ item.age }} month</p>
<p class="held-history-table-container--large__info-area__months">{{ item.monthsWithNode }} month</p>
</div>
<div class="column justify-end column-2">
<p class="held-history-table-container--large__info-area__text">{{ item.joinedAt.toISOString().split('T')[0] }}</p>
@ -36,7 +36,7 @@
</div>
<div class="held-history-table-container--small">
<HeldHistoryAllStatsTableItemSmall
v-for="item in allStats"
v-for="item in allSatellitesHeldHistory"
:held-history-item="item"
:key="item.satelliteID"
/>
@ -50,7 +50,7 @@ import { Component } from 'vue-property-decorator';
import BaseHeldHistoryTable from '@/app/components/payments/BaseHeldHistoryTable.vue';
import HeldHistoryAllStatsTableItemSmall from '@/app/components/payments/HeldHistoryAllStatsTableItemSmall.vue';
import { HeldHistoryAllStatItem } from '@/app/types/payout';
import { SatelliteHeldHistory } from '@/storagenode/payouts/payouts';
@Component({
components: {
@ -61,8 +61,8 @@ export default class HeldHistoryAllStatsTable extends BaseHeldHistoryTable {
/**
* Returns list of satellite held history items by periods from store.
*/
public get allStats(): HeldHistoryAllStatItem[] {
return this.$store.state.payoutModule.heldHistory.allStats;
public get allSatellitesHeldHistory(): SatelliteHeldHistory[] {
return this.$store.state.payoutModule.heldHistory;
}
}
</script>

View File

@ -6,7 +6,7 @@
<div class="held-history-table-container--small__item__satellite-info">
<div>
<p class="held-history-table-container--small__item__satellite-info__name">{{ heldHistoryItem.satelliteName }}</p>
<p class="held-history-table-container--small__item__satellite-info__months">{{ heldHistoryItem.age }} month</p>
<p class="held-history-table-container--small__item__satellite-info__months">{{ heldHistoryItem.monthsWithNode }} month</p>
</div>
<div class="held-history-table-container--small__item__satellite-info__button">
<div class="icon hide" @click="hide" v-if="isExpanded">
@ -41,11 +41,11 @@ import { Component, Prop } from 'vue-property-decorator';
import BaseSmallHeldHistoryTable from '@/app/components/payments/BaseSmallHeldHistoryTable.vue';
import { HeldHistoryAllStatItem } from '@/app/types/payout';
import { SatelliteHeldHistory } from '@/storagenode/payouts/payouts';
@Component
export default class HeldHistoryAllStatsTableSmall extends BaseSmallHeldHistoryTable {
@Prop({default: () => new HeldHistoryAllStatItem()})
public readonly heldHistoryItem: HeldHistoryAllStatItem;
@Prop({default: () => new SatelliteHeldHistory()})
public readonly heldHistoryItem: SatelliteHeldHistory;
}
</script>

View File

@ -18,10 +18,10 @@
<p class="held-history-table-container--large__labels-area__text">Month 7-9</p>
</div>
</div>
<div v-for="item in monthlyBreakdown" class="held-history-table-container--large__info-area" :key="item.satelliteID">
<div v-for="item in allSatellitesHeldHistory" class="held-history-table-container--large__info-area" :key="item.satelliteID">
<div class="justify-start column-1">
<p class="held-history-table-container--large__info-area__text">{{ item.satelliteName }}</p>
<p class="held-history-table-container--large__info-area__months">{{ item.age }} month</p>
<p class="held-history-table-container--large__info-area__months">{{ item.monthsWithNode }} month</p>
</div>
<div class="column justify-end column-2">
<p class="held-history-table-container--large__info-area__text">{{ item.firstPeriod | centsToDollars }}</p>
@ -36,7 +36,7 @@
</div>
<div class="held-history-table-container--small">
<HeldHistoryMonthlyBreakdownTableItemSmall
v-for="item in monthlyBreakdown"
v-for="item in allSatellitesHeldHistory"
:held-history-item="item"
:key="item.satelliteID"
/>
@ -50,7 +50,7 @@ import { Component, Vue } from 'vue-property-decorator';
import BaseHeldHistoryTable from '@/app/components/payments/BaseHeldHistoryTable.vue';
import HeldHistoryMonthlyBreakdownTableItemSmall from '@/app/components/payments/HeldHistoryMonthlyBreakdownTableItemSmall.vue';
import { HeldHistoryMonthlyBreakdownItem } from '@/app/types/payout';
import { SatelliteHeldHistory } from '@/storagenode/payouts/payouts';
@Component({
components: {
@ -61,8 +61,8 @@ export default class HeldHistoryMonthlyBreakdownTable extends BaseHeldHistoryTab
/**
* Returns list of satellite held history items by periods from store.
*/
public get monthlyBreakdown(): HeldHistoryMonthlyBreakdownItem[] {
return this.$store.state.payoutModule.heldHistory.monthlyBreakdown;
public get allSatellitesHeldHistory(): SatelliteHeldHistory[] {
return this.$store.state.payoutModule.heldHistory;
}
}
</script>

View File

@ -6,7 +6,7 @@
<div class="held-history-table-container--small__item__satellite-info">
<div>
<p class="held-history-table-container--small__item__satellite-info__name">{{ heldHistoryItem.satelliteName }}</p>
<p class="held-history-table-container--small__item__satellite-info__months">{{ heldHistoryItem.age }} month</p>
<p class="held-history-table-container--small__item__satellite-info__months">{{ heldHistoryItem.monthsWithNode }} month</p>
</div>
<div class="held-history-table-container--small__item__satellite-info__button">
<div class="icon hide" @click="hide" v-if="isExpanded">
@ -41,11 +41,11 @@ import { Component, Prop } from 'vue-property-decorator';
import BaseSmallHeldHistoryTable from '@/app/components/payments/BaseSmallHeldHistoryTable.vue';
import { HeldHistoryMonthlyBreakdownItem } from '@/app/types/payout';
import { SatelliteHeldHistory } from '@/storagenode/payouts/payouts';
@Component
export default class HeldHistoryMonthlyBreakdownTableSmall extends BaseSmallHeldHistoryTable {
@Prop({default: () => new HeldHistoryMonthlyBreakdownItem()})
public readonly heldHistoryItem: HeldHistoryMonthlyBreakdownItem;
@Prop({default: () => new SatelliteHeldHistory()})
public readonly heldHistoryItem: SatelliteHeldHistory;
}
</script>

View File

@ -31,7 +31,7 @@ import PayoutHistoryPeriodDropdown from '@/app/components/payments/PayoutHistory
import PayoutHistoryTableItem from '@/app/components/payments/PayoutHistoryTableItem.vue';
import { PAYOUT_ACTIONS } from '@/app/store/modules/payout';
import { PayoutHistoryItem } from '@/app/types/payout';
import { SatellitePayoutForPeriod } from '@/storagenode/payouts/payouts';
@Component ({
components: {
@ -40,7 +40,7 @@ import { PayoutHistoryItem } from '@/app/types/payout';
},
})
export default class PayoutHistoryTable extends Vue {
public get payoutHistory(): PayoutHistoryItem[] {
public get payoutHistory(): SatellitePayoutForPeriod[] {
return this.$store.state.payoutModule.payoutHistory;
}
@ -62,7 +62,7 @@ export default class PayoutHistoryTable extends Vue {
return;
}
const lastPeriod = payoutPeriods[0];
const lastPeriod = payoutPeriods[payoutPeriods.length - 1];
await this.$store.dispatch(PAYOUT_ACTIONS.SET_PAYOUT_HISTORY_PERIOD, lastPeriod.period);
try {

View File

@ -81,7 +81,14 @@
<div class="payout-history-item__expanded-area__right-area__divider"></div>
<div class="payout-history-item__expanded-area__right-area__footer">
<div class="payout-history-item__expanded-area__right-area__footer__transaction" v-if="historyItem.receipt">
<a :href="historyItem.receipt" target="_blank" rel="noreferrer noopener">Transaction</a>
<a
class="payout-history-item__expanded-area__right-area__footer__transaction__link"
:href="historyItem.receipt"
target="_blank"
rel="noreferrer noopener"
>
Transaction
</a>
<ShareIcon class="payout-history-item__expanded-area__right-area__footer__transaction__icon" />
</div>
<p class="payout-history-item__expanded-area__right-area__footer__total">{{ historyItem.paid | centsToDollars }}</p>
@ -100,7 +107,7 @@ import DisqualifyIcon from '@/../static/images/largeDisqualify.svg';
import OKIcon from '@/../static/images/payments/OKIcon.svg';
import ShareIcon from '@/../static/images/payments/Share.svg';
import { PayoutHistoryItem } from '@/app/types/payout';
import { SatellitePayoutForPeriod } from '@/storagenode/payouts/payouts';
@Component ({
components: {
@ -111,8 +118,8 @@ import { PayoutHistoryItem } from '@/app/types/payout';
},
})
export default class PayoutHistoryTableItem extends Vue {
@Prop({default: () => new PayoutHistoryItem()})
public readonly historyItem: PayoutHistoryItem;
@Prop({default: () => new SatellitePayoutForPeriod()})
public readonly historyItem: SatellitePayoutForPeriod;
/**
* Indicates if payout info should be rendered.
@ -291,18 +298,18 @@ export default class PayoutHistoryTableItem extends Vue {
display: flex;
align-items: center;
justify-content: flex-end;
color: var(--link-color);
color: var(--navigation-link-color);
cursor: pointer;
a:visited {
color: var(--link-color);
color: var(--navigation-link-color);
}
&__icon {
margin-left: 7px;
path {
stroke: var(--link-color);
stroke: var(--navigation-link-color);
}
}
}

View File

@ -44,9 +44,9 @@ import {
MonthButton,
monthNames,
PayoutInfoRange,
PayoutPeriod,
StoredMonthsByYear,
} from '@/app/types/payout';
import { PayoutPeriod } from '@/storagenode/payouts/payouts';
@Component({
components: {
@ -95,7 +95,7 @@ export default class PayoutPeriodCalendar extends Vue {
);
try {
await this.$store.dispatch(PAYOUT_ACTIONS.GET_HELD_INFO, this.$store.state.node.selectedSatellite.id);
await this.$store.dispatch(PAYOUT_ACTIONS.GET_PAYOUT_INFO, this.$store.state.node.selectedSatellite.id);
await this.$store.dispatch(APPSTATE_ACTIONS.SET_NO_PAYOUT_DATA, false);
} catch (error) {
const lastMonthDate = new Date();

View File

@ -9,12 +9,14 @@ import { makePayoutModule } from '@/app/store/modules/payout';
import { NotificationsHttpApi } from '@/storagenode/api/notifications';
import { PayoutHttpApi } from '@/storagenode/api/payout';
import { SNOApi } from '@/storagenode/api/storagenode';
import { PayoutService } from '@/storagenode/payouts/service';
import { appStateModule } from './modules/appState';
import { makeNodeModule } from './modules/node';
const notificationsApi = new NotificationsHttpApi();
const payoutApi = new PayoutHttpApi();
const payoutService = new PayoutService(payoutApi);
const nodeApi = new SNOApi();
Vue.use(Vuex);
@ -27,7 +29,7 @@ export const store = new Vuex.Store({
node: makeNodeModule(nodeApi),
appStateModule,
notificationsModule: makeNotificationsModule(notificationsApi),
payoutModule: makePayoutModule(payoutApi),
payoutModule: makePayoutModule(payoutApi, payoutService),
},
});

View File

@ -2,22 +2,24 @@
// See LICENSE for copying information.
import {
EstimatedPayout,
HeldHistory,
HeldInfo,
PaymentInfoParameters,
PayoutApi,
PayoutHistoryItem,
PayoutInfoRange,
PayoutPeriod,
PayoutState,
TotalPayoutInfo,
} from '@/app/types/payout';
import { TB } from '@/app/utils/converter';
import { getHeldPercentage } from '@/app/utils/payout';
import {
EstimatedPayout,
PayoutApi,
PayoutPeriod,
SatelliteHeldHistory,
SatellitePayoutForPeriod,
TotalHeldAndPaid,
TotalPaystubForPeriod,
} from '@/storagenode/payouts/payouts';
import { PayoutService } from '@/storagenode/payouts/service';
export const PAYOUT_MUTATIONS = {
SET_HELD_INFO: 'SET_HELD_INFO',
SET_PAYOUT_INFO: 'SET_PAYOUT_INFO',
SET_RANGE: 'SET_RANGE',
SET_TOTAL: 'SET_TOTAL',
SET_HELD_PERCENT: 'SET_HELD_PERCENT',
@ -29,7 +31,7 @@ export const PAYOUT_MUTATIONS = {
};
export const PAYOUT_ACTIONS = {
GET_HELD_INFO: 'GET_HELD_INFO',
GET_PAYOUT_INFO: 'GET_PAYOUT_INFO',
SET_PERIODS_RANGE: 'SET_PERIODS_RANGE',
GET_TOTAL: 'GET_TOTAL',
GET_HELD_HISTORY: 'GET_HELD_HISTORY',
@ -39,6 +41,7 @@ export const PAYOUT_ACTIONS = {
SET_PAYOUT_HISTORY_PERIOD: 'SET_PAYOUT_HISTORY_PERIOD',
};
// TODO: move to config in storagenode/payouts
export const BANDWIDTH_DOWNLOAD_PRICE_PER_TB = 2000;
export const BANDWIDTH_REPAIR_PRICE_PER_TB = 1000;
export const DISK_SPACE_PRICE_PER_TB = 150;
@ -47,18 +50,18 @@ export const DISK_SPACE_PRICE_PER_TB = 150;
* creates notifications module with all dependencies
*
* @param api - payments api
* @param service - payments service
*/
export function makePayoutModule(api: PayoutApi) {
export function makePayoutModule(api: PayoutApi, service: PayoutService) {
return {
state: new PayoutState(),
mutations: {
[PAYOUT_MUTATIONS.SET_HELD_INFO](state: PayoutState, heldInfo: HeldInfo): void {
state.heldInfo = heldInfo;
[PAYOUT_MUTATIONS.SET_PAYOUT_INFO](state: PayoutState, totalPaystubForPeriod: TotalPaystubForPeriod): void {
state.totalPaystubForPeriod = totalPaystubForPeriod;
},
[PAYOUT_MUTATIONS.SET_TOTAL](state: PayoutState, totalPayoutInfo: TotalPayoutInfo): void {
state.totalEarnings = totalPayoutInfo.totalEarnings;
state.totalHeldAmount = totalPayoutInfo.totalHeldAmount;
state.currentMonthEarnings = totalPayoutInfo.currentMonthEarnings;
[PAYOUT_MUTATIONS.SET_TOTAL](state: PayoutState, totalHeldAndPaid: TotalHeldAndPaid): void {
state.totalHeldAndPaid = totalHeldAndPaid;
state.currentMonthEarnings = totalHeldAndPaid.currentMonthEarnings;
},
[PAYOUT_MUTATIONS.SET_RANGE](state: PayoutState, periodRange: PayoutInfoRange): void {
state.periodRange = periodRange;
@ -66,7 +69,7 @@ export function makePayoutModule(api: PayoutApi) {
[PAYOUT_MUTATIONS.SET_HELD_PERCENT](state: PayoutState, heldPercentage: number): void {
state.heldPercentage = heldPercentage;
},
[PAYOUT_MUTATIONS.SET_HELD_HISTORY](state: PayoutState, heldHistory: HeldHistory): void {
[PAYOUT_MUTATIONS.SET_HELD_HISTORY](state: PayoutState, heldHistory: SatelliteHeldHistory[]): void {
state.heldHistory = heldHistory;
},
[PAYOUT_MUTATIONS.SET_ESTIMATION](state: PayoutState, estimatedInfo: EstimatedPayout): void {
@ -75,7 +78,7 @@ export function makePayoutModule(api: PayoutApi) {
[PAYOUT_MUTATIONS.SET_PERIODS](state: PayoutState, periods: PayoutPeriod[]): void {
state.payoutPeriods = periods;
},
[PAYOUT_MUTATIONS.SET_PAYOUT_HISTORY](state: PayoutState, payoutHistory: PayoutHistoryItem[]): void {
[PAYOUT_MUTATIONS.SET_PAYOUT_HISTORY](state: PayoutState, payoutHistory: SatellitePayoutForPeriod[]): void {
state.payoutHistory = payoutHistory;
},
[PAYOUT_MUTATIONS.SET_PAYOUT_HISTORY_PERIOD](state: PayoutState, period: string): void {
@ -83,28 +86,24 @@ export function makePayoutModule(api: PayoutApi) {
},
},
actions: {
[PAYOUT_ACTIONS.GET_HELD_INFO]: async function ({ commit, state, rootState }: any, satelliteId: string = ''): Promise<void> {
const heldInfo = state.periodRange.start ? await api.getHeldInfoByPeriod(new PaymentInfoParameters(
[PAYOUT_ACTIONS.GET_PAYOUT_INFO]: async function ({ commit, state, rootState }: any, satelliteId: string = ''): Promise<void> {
const totalPaystubForPeriod = await service.paystubSummaryForPeriod(
state.periodRange.start,
state.periodRange.end,
satelliteId,
)) : await api.getHeldInfoByMonth(new PaymentInfoParameters(
null,
state.periodRange.end,
satelliteId,
));
);
commit(PAYOUT_MUTATIONS.SET_HELD_PERCENT, getHeldPercentage(rootState.node.selectedSatellite.joinDate));
commit(PAYOUT_MUTATIONS.SET_HELD_INFO, heldInfo);
commit(PAYOUT_MUTATIONS.SET_PAYOUT_INFO, totalPaystubForPeriod);
},
[PAYOUT_ACTIONS.GET_TOTAL]: async function ({ commit, rootState }: any, satelliteId: string = ''): Promise<void> {
const now = new Date();
const totalPayoutInfo = await api.getTotal(new PaymentInfoParameters(
new PayoutPeriod(rootState.node.selectedSatellite.joinDate.getUTCFullYear(), rootState.node.selectedSatellite.joinDate.getUTCMonth()),
new PayoutPeriod(now.getUTCFullYear(), now.getUTCMonth()),
satelliteId,
));
const start = new PayoutPeriod(rootState.node.selectedSatellite.joinDate.getUTCFullYear(), rootState.node.selectedSatellite.joinDate.getUTCMonth());
const end = new PayoutPeriod(now.getUTCFullYear(), now.getUTCMonth());
const totalHeldAndPaid = await service.totalHeldAndPaid(start, end, satelliteId);
// TODO: move to service
const currentBandwidthDownload = (rootState.node.egressChartData || [])
.map(data => data.egress.usage)
.reduce((previous, current) => previous + current, 0);
@ -122,29 +121,31 @@ export function makePayoutModule(api: PayoutApi) {
+ currentBandwidthAuditAndRepair * BANDWIDTH_REPAIR_PRICE_PER_TB
+ currentDiskSpace * DISK_SPACE_PRICE_PER_TB) / TB;
totalHeldAndPaid.setCurrentMonthEarnings(thisMonthEarnings);
commit(PAYOUT_MUTATIONS.SET_HELD_PERCENT, getHeldPercentage(rootState.node.selectedSatellite.joinDate));
commit(PAYOUT_MUTATIONS.SET_TOTAL, new TotalPayoutInfo(totalPayoutInfo.totalHeldAmount, totalPayoutInfo.totalEarnings, thisMonthEarnings));
commit(PAYOUT_MUTATIONS.SET_TOTAL, totalHeldAndPaid);
},
[PAYOUT_ACTIONS.SET_PERIODS_RANGE]: function ({ commit }: any, periodRange: PayoutInfoRange): void {
commit(PAYOUT_MUTATIONS.SET_RANGE, periodRange);
},
[PAYOUT_ACTIONS.GET_HELD_HISTORY]: async function ({ commit }: any): Promise<void> {
const heldHistory = await api.getHeldHistory();
const heldHistory = await service.allSatellitesHeldHistory();
commit(PAYOUT_MUTATIONS.SET_HELD_HISTORY, heldHistory);
},
[PAYOUT_ACTIONS.GET_PERIODS]: async function ({commit}: any, satelliteId: string = ''): Promise<void> {
const periods = await api.getPayoutPeriods(satelliteId);
const periods = await service.availablePeriods(satelliteId);
commit(PAYOUT_MUTATIONS.SET_PERIODS, periods);
},
[PAYOUT_ACTIONS.GET_ESTIMATION]: async function ({ commit }: any, satelliteId: string = ''): Promise<void> {
const estimatedInfo = await api.getEstimatedInfo(satelliteId);
const estimatedInfo = await service.estimatedPayout(satelliteId);
commit(PAYOUT_MUTATIONS.SET_ESTIMATION, estimatedInfo);
},
[PAYOUT_ACTIONS.GET_PAYOUT_HISTORY]: async function ({ commit, state }: any): Promise<void> {
const payoutHistory = await api.getPayoutHistory(state.payoutHistoryPeriod);
const payoutHistory = await service.payoutHistory(state.payoutHistoryPeriod);
commit(PAYOUT_MUTATIONS.SET_PAYOUT_HISTORY, payoutHistory);
},

View File

@ -1,69 +1,13 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
// TODO: move comp division from api.
const PRICE_DIVIDER: number = 10000;
/**
* Holds request arguments for payout information.
*/
export class PaymentInfoParameters {
public constructor(
public start: PayoutPeriod | null = null,
public end: PayoutPeriod = new PayoutPeriod(),
public satelliteId: string = '',
) {}
}
/**
* Holds payout information.
*/
export class HeldInfo {
public constructor(
public usageAtRest: number = 0,
public usageGet: number = 0,
public usagePut: number = 0,
public usageGetRepair: number = 0,
public usagePutRepair: number = 0,
public usageGetAudit: number = 0,
public compAtRest: number = 0,
public compGet: number = 0,
public compPut: number = 0,
public compGetRepair: number = 0,
public compPutRepair: number = 0,
public compGetAudit: number = 0,
public surgePercent: number = 0,
public held: number = 0,
public owed: number = 0,
public disposed: number = 0,
public paid: number = 0,
public paidWithoutSurge: number = 0,
) {}
}
/**
* Represents payout period month and year.
*/
export class PayoutPeriod {
public constructor(
public year: number = new Date().getUTCFullYear(),
public month: number = new Date().getUTCMonth(),
) {}
public get period(): string {
return this.month < 9 ? `${this.year}-0${this.month + 1}` : `${this.year}-${this.month + 1}`;
}
/**
* Parses PayoutPeriod from string.
* @param period string
*/
public static fromString(period: string): PayoutPeriod {
const periodArray = period.split('-');
return new PayoutPeriod(parseInt(periodArray[0]), parseInt(periodArray[1]) - 1);
}
}
import {
EstimatedPayout,
PayoutPeriod,
SatelliteHeldHistory, SatellitePayoutForPeriod,
TotalHeldAndPaid,
TotalPaystubForPeriod,
} from '@/storagenode/payouts/payouts';
/**
* Holds 'start' and 'end' of payout period range.
@ -75,183 +19,24 @@ export class PayoutInfoRange {
) {}
}
/**
* Holds accumulated held and earned payouts.
*/
export class TotalPayoutInfo {
public constructor(
public totalHeldAmount: number = 0,
public totalEarnings: number = 0,
public currentMonthEarnings: number = 0,
) {}
}
/**
* Holds all payout module state.
*/
export class PayoutState {
public constructor (
public heldInfo: HeldInfo = new HeldInfo(),
public totalPaystubForPeriod: TotalPaystubForPeriod = new TotalPaystubForPeriod(),
public periodRange: PayoutInfoRange = new PayoutInfoRange(),
public totalHeldAmount: number = 0,
public totalEarnings: number = 0,
public totalHeldAndPaid: TotalHeldAndPaid = new TotalHeldAndPaid(),
public currentMonthEarnings: number = 0,
public heldPercentage: number = 0,
public payoutPeriods: PayoutPeriod[] = [],
public heldHistory: HeldHistory = new HeldHistory(),
public payoutHistory: PayoutHistoryItem[] = [],
public heldHistory: SatelliteHeldHistory[] = [],
public payoutHistory: SatellitePayoutForPeriod[] = [],
public payoutHistoryPeriod: string = '',
public estimation: EstimatedPayout = new EstimatedPayout(),
) {}
}
/**
* Exposes all payout-related functionality.
*/
export interface PayoutApi {
/**
* Fetches held amount information by selected period.
* @throws Error
*/
getHeldInfoByPeriod(paymentInfoParameters: PaymentInfoParameters): Promise<HeldInfo>;
/**
* Fetches held amount information by selected month.
* @throws Error
*/
getHeldInfoByMonth(paymentInfoParameters: PaymentInfoParameters): Promise<HeldInfo>;
/**
* Fetches available payout periods.
* @throws Error
*/
getPayoutPeriods(id: string): Promise<PayoutPeriod[]>;
/**
* Fetches total payout information.
* @throws Error
*/
getTotal(paymentInfoParameters: PaymentInfoParameters): Promise<TotalPayoutInfo>;
/**
* Fetches held history for all satellites.
* @throws Error
*/
getHeldHistory(): Promise<HeldHistory>;
/**
* Fetch estimated payout information.
* @throws Error
*/
getEstimatedInfo(satelliteId: string): Promise<EstimatedPayout>;
/**
* Fetches payout history for all satellites.
* @throws Error
*/
getPayoutHistory(period: string): Promise<PayoutHistoryItem[]>;
}
/**
* Holds held history information for all satellites.
*/
export class HeldHistory {
public constructor(
public monthlyBreakdown: HeldHistoryMonthlyBreakdownItem[] = [],
public allStats: HeldHistoryAllStatItem[] = [],
) {}
}
/**
* Contains held amounts of satellite grouped by periods.
*/
export class HeldHistoryMonthlyBreakdownItem {
public constructor(
public satelliteID: string = '',
public satelliteName: string = '',
public age: number = 1,
public firstPeriod: number = 0,
public secondPeriod: number = 0,
public thirdPeriod: number = 0,
) {
this.firstPeriod = this.firstPeriod / PRICE_DIVIDER;
this.secondPeriod = this.secondPeriod / PRICE_DIVIDER;
this.thirdPeriod = this.thirdPeriod / PRICE_DIVIDER;
}
}
/**
* Contains held information summary of satellite grouped by periods.
*/
export class HeldHistoryAllStatItem {
public constructor(
public satelliteID: string = '',
public satelliteName: string = '',
public age: number = 1,
public totalHeld: number = 0,
public totalDisposed: number = 0,
public joinedAt: Date = new Date(),
) {
this.totalHeld = this.totalHeld / PRICE_DIVIDER;
this.totalDisposed = this.totalDisposed / PRICE_DIVIDER;
}
}
/**
* Contains estimated payout information for current and last periods.
*/
export class EstimatedPayout {
public constructor(
public currentMonth: PreviousMonthEstimatedPayout = new PreviousMonthEstimatedPayout(),
public previousMonth: PreviousMonthEstimatedPayout = new PreviousMonthEstimatedPayout(),
) {}
}
/**
* Contains last month estimated payout information.
*/
export class PreviousMonthEstimatedPayout {
public constructor(
public egressBandwidth: number = 0,
public egressBandwidthPayout: number = 0,
public egressRepairAudit: number = 0,
public egressRepairAuditPayout: number = 0,
public diskSpace: number = 0,
public diskSpacePayout: number = 0,
public heldRate: number = 0,
public payout: number = 0,
public held: number = 0,
) {}
}
/**
* Contains payout information for payout history table.
*/
export class PayoutHistoryItem {
public constructor(
public satelliteID: string = '',
public satelliteName: string = '',
public age: number = 1,
public earned: number = 0,
public surge: number = 0,
public surgePercent: number = 0,
public held: number = 0,
public afterHeld: number = 0,
public disposed: number = 0,
public paid: number = 0,
public receipt: string = '',
public isExitComplete: boolean = false,
public heldPercent: number = 0,
) {
this.earned = this.earned / PRICE_DIVIDER;
this.surge = this.surge / PRICE_DIVIDER;
this.held = this.held / PRICE_DIVIDER;
this.afterHeld = this.afterHeld / PRICE_DIVIDER;
this.disposed = this.disposed / PRICE_DIVIDER;
this.paid = this.paid / PRICE_DIVIDER;
}
}
export interface StoredMonthsByYear {
[key: number]: MonthButton[];
}

View File

@ -54,8 +54,8 @@ import { NODE_ACTIONS } from '@/app/store/modules/node';
import { NOTIFICATIONS_ACTIONS } from '@/app/store/modules/notifications';
import { PAYOUT_ACTIONS } from '@/app/store/modules/payout';
import { NotificationsCursor } from '@/app/types/notifications';
import { PayoutPeriod } from '@/app/types/payout';
import { SatelliteInfo } from '@/storagenode/dashboard';
import { PayoutPeriod } from '@/storagenode/payouts/payouts';
@Component ({
components: {
@ -111,7 +111,7 @@ export default class PayoutArea extends Vue {
}
public get totalHeld(): number {
return this.$store.state.payoutModule.totalHeldAmount;
return this.$store.state.payoutModule.totalHeldAndPaid.held;
}
public get heldPercentage(): number {

View File

@ -3,74 +3,31 @@
import {
EstimatedPayout,
HeldHistory,
HeldHistoryAllStatItem,
HeldHistoryMonthlyBreakdownItem,
HeldInfo,
PaymentInfoParameters,
PayoutApi, PayoutHistoryItem,
PayoutApi,
PayoutPeriod,
Paystub,
PreviousMonthEstimatedPayout,
TotalPayoutInfo,
} from '@/app/types/payout';
SatelliteHeldHistory,
SatellitePayoutForPeriod,
} from '@/storagenode/payouts/payouts';
import { HttpClient } from '@/storagenode/utils/httpClient';
/**
* NotificationsHttpApi is a http implementation of Notifications API.
* Exposes all notifications-related functionality
* PayoutHttpApi is a http implementation of Payout API.
* Exposes all payout-related functionality
*/
export class PayoutHttpApi implements PayoutApi {
private readonly client: HttpClient = new HttpClient();
private readonly ROOT_PATH: string = '/api/heldamount';
private PRICE_DIVIDER: number = 10000;
/**
* Fetch held amount information by selected period.
* Fetch paystubs for selected period.
*
* @returns held amount information
* @returns paystubs for given period
* @throws Error
*/
public async getHeldInfoByPeriod(paymentInfoParameters: PaymentInfoParameters): Promise<HeldInfo> {
let path = `${this.ROOT_PATH}/paystubs/`;
if (paymentInfoParameters.start) {
path += paymentInfoParameters.start.period + '/';
}
path += paymentInfoParameters.end.period;
if (paymentInfoParameters.satelliteId) {
path += '?id=' + paymentInfoParameters.satelliteId;
}
return await this.getHeld(path);
}
/**
* Fetch held amount information by selected month.
*
* @returns held amount information
* @throws Error
*/
public async getHeldInfoByMonth(paymentInfoParameters: PaymentInfoParameters): Promise<HeldInfo> {
let path = `${this.ROOT_PATH}/paystubs/`;
path += paymentInfoParameters.end.period;
if (paymentInfoParameters.satelliteId) {
path += '?id=' + paymentInfoParameters.satelliteId;
}
return await this.getHeld(path);
}
/**
* Fetch total payout information.
*
* @returns total payout information
* @throws Error
*/
public async getTotal(paymentInfoParameters: PaymentInfoParameters): Promise<TotalPayoutInfo> {
public async getPaystubsForPeriod(paymentInfoParameters: PaymentInfoParameters): Promise<Paystub[]> {
let path = `${this.ROOT_PATH}/paystubs/`;
if (paymentInfoParameters.start) {
@ -86,28 +43,32 @@ export class PayoutHttpApi implements PayoutApi {
const response = await this.client.get(path);
if (!response.ok) {
throw new Error('can not get total payout information');
throw new Error('can not get held information');
}
const data: any = await response.json() || [];
const data: any[] = await response.json() || [];
if (!Array.isArray(data)) {
return new TotalPayoutInfo(data.held, data.paid);
}
let held: number = 0;
let paid: number = 0;
data.forEach((paystub: any) => {
held += (paystub.held - paystub.disposed) / this.PRICE_DIVIDER;
paid += paystub.paid / this.PRICE_DIVIDER;
});
return new TotalPayoutInfo(
held,
paid,
0,
return data.map((paystubJson: any) => {
return new Paystub(
paystubJson.usageAtRest,
paystubJson.usageGet,
paystubJson.usagePut,
paystubJson.usageGetRepair,
paystubJson.usagePutRepair,
paystubJson.usageGetAudit,
paystubJson.compAtRest,
paystubJson.compGet,
paystubJson.compPut,
paystubJson.compGetRepair,
paystubJson.compPutRepair,
paystubJson.compGetAudit,
paystubJson.surgePercent,
paystubJson.held,
paystubJson.owed,
paystubJson.disposed,
paystubJson.paid,
);
});
}
/**
@ -142,7 +103,7 @@ export class PayoutHttpApi implements PayoutApi {
* @returns payout information
* @throws Error
*/
public async getPayoutHistory(period): Promise<PayoutHistoryItem[]> {
public async getPayoutHistory(period): Promise<SatellitePayoutForPeriod[]> {
const path = `${this.ROOT_PATH}/payout-history/${period}`;
const response = await this.client.get(path);
@ -154,7 +115,7 @@ export class PayoutHttpApi implements PayoutApi {
const data: any = await response.json() || [];
return data.map((payoutHistoryItem: any) => {
return new PayoutHistoryItem(
return new SatellitePayoutForPeriod(
payoutHistoryItem.satelliteID,
payoutHistoryItem.satelliteURL,
payoutHistoryItem.age,
@ -178,7 +139,7 @@ export class PayoutHttpApi implements PayoutApi {
* @returns total payout information
* @throws Error
*/
public async getHeldHistory(): Promise<HeldHistory> {
public async getHeldHistory(): Promise<SatelliteHeldHistory[]> {
const path = `${this.ROOT_PATH}/held-history/`;
const response = await this.client.get(path);
@ -189,29 +150,18 @@ export class PayoutHttpApi implements PayoutApi {
const data: any = await response.json() || [];
const monthlyBreakdown = data.map((historyItem: any) => {
return new HeldHistoryMonthlyBreakdownItem(
return data.map((historyItem: any) => {
return new SatelliteHeldHistory(
historyItem.satelliteID,
historyItem.satelliteName,
historyItem.age,
historyItem.firstPeriod,
historyItem.secondPeriod,
historyItem.thirdPeriod,
);
});
const allStats = data.map((historyItem: any) => {
return new HeldHistoryAllStatItem(
historyItem.satelliteID,
historyItem.satelliteName,
historyItem.age,
historyItem.totalHeld,
historyItem.totalDisposed,
new Date(historyItem.joinedAt),
);
});
return new HeldHistory(monthlyBreakdown, allStats);
}
/**
@ -220,7 +170,7 @@ export class PayoutHttpApi implements PayoutApi {
* @returns estimated payout information
* @throws Error
*/
public async getEstimatedInfo(satelliteId: string): Promise<EstimatedPayout> {
public async getEstimatedPayout(satelliteId: string): Promise<EstimatedPayout> {
let path = '/api/sno/estimated-payout';
if (satelliteId) {
@ -233,7 +183,7 @@ export class PayoutHttpApi implements PayoutApi {
throw new Error('can not get estimated payout information');
}
const data: any = await response.json() || [];
const data: any = await response.json() || new EstimatedPayout();
return new EstimatedPayout(
new PreviousMonthEstimatedPayout(
@ -260,87 +210,4 @@ export class PayoutHttpApi implements PayoutApi {
),
);
}
/**
* Fetch total payout information depends on month.
*
* @returns total payout information
* @throws Error
*/
public async getHeld(path): Promise<HeldInfo> {
const response = await this.client.get(path);
if (!response.ok) {
throw new Error('can not get held information');
}
const data: any[] = await response.json();
if (!data || data.length === 0) {
throw new Error('no payout data for selected period');
}
let usageAtRest: number = 0;
let usageGet: number = 0;
let usagePut: number = 0;
let usageGetRepair: number = 0;
let usagePutRepair: number = 0;
let usageGetAudit: number = 0;
let compAtRest: number = 0;
let compGet: number = 0;
let compPut: number = 0;
let compGetRepair: number = 0;
let compPutRepair: number = 0;
let compGetAudit: number = 0;
let held: number = 0;
let owed: number = 0;
let disposed: number = 0;
let paid: number = 0;
let surgePercent: number = 0;
let paidWithoutSurge: number = 0;
data.forEach((paystub: any) => {
const surge = paystub.surgePercent === 0 ? 1 : paystub.surgePercent / 100;
usageAtRest += paystub.usageAtRest;
usageGet += paystub.usageGet;
usagePut += paystub.usagePut;
usageGetRepair += paystub.usageGetRepair;
usagePutRepair += paystub.usagePutRepair;
usageGetAudit += paystub.usageGetAudit;
compAtRest += paystub.compAtRest / this.PRICE_DIVIDER;
compGet += paystub.compGet / this.PRICE_DIVIDER;
compPut += paystub.compPut / this.PRICE_DIVIDER;
compGetRepair += paystub.compGetRepair / this.PRICE_DIVIDER;
compPutRepair += paystub.compPutRepair / this.PRICE_DIVIDER;
compGetAudit += paystub.compGetAudit / this.PRICE_DIVIDER;
held += paystub.held / this.PRICE_DIVIDER;
owed += paystub.owed / this.PRICE_DIVIDER;
disposed += paystub.disposed / this.PRICE_DIVIDER;
paid += paystub.paid / this.PRICE_DIVIDER;
surgePercent = paystub.surgePercent;
paidWithoutSurge += paystub.paid / this.PRICE_DIVIDER / surge;
});
return new HeldInfo(
usageAtRest,
usageGet,
usagePut,
usageGetRepair,
usagePutRepair,
usageGetAudit,
compAtRest,
compGet,
compPut,
compGetRepair,
compPutRepair,
compGetAudit,
surgePercent,
held,
owed,
disposed,
paid,
paidWithoutSurge,
);
}
}

View File

@ -0,0 +1,276 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
import { getMonthsBeforeNow } from '@/app/utils/payout';
/**
* Exposes all payout-related functionality.
*/
export interface PayoutApi {
/**
* Fetches paystubs by selected period.
* @throws Error
*/
getPaystubsForPeriod(paymentInfoParameters: PaymentInfoParameters): Promise<Paystub[]>;
/**
* Fetches available payout periods.
* @throws Error
*/
getPayoutPeriods(id: string): Promise<PayoutPeriod[]>;
/**
* Fetches held history for all satellites.
* @throws Error
*/
getHeldHistory(): Promise<SatelliteHeldHistory[]>;
/**
* Fetch estimated payout information.
* @throws Error
*/
getEstimatedPayout(satelliteId: string): Promise<EstimatedPayout>;
/**
* Fetches payout history for all satellites.
* @throws Error
*/
getPayoutHistory(period: string): Promise<SatellitePayoutForPeriod[]>;
}
// TODO: move to config.
/**
* Divider to convert payout amounts to cents.
*/
const PRICE_DIVIDER: number = 10000;
/**
* Represents payout period month and year.
*/
export class PayoutPeriod {
public constructor(
public year: number = new Date().getUTCFullYear(),
public month: number = new Date().getUTCMonth(),
) {}
public get period(): string {
return this.month < 9 ? `${this.year}-0${this.month + 1}` : `${this.year}-${this.month + 1}`;
}
/**
* Parses PayoutPeriod from string.
* @param period string
*/
public static fromString(period: string): PayoutPeriod {
const periodArray = period.split('-');
return new PayoutPeriod(parseInt(periodArray[0]), parseInt(periodArray[1]) - 1);
}
}
/**
* Holds request arguments for payout information.
*/
export class PaymentInfoParameters {
public constructor(
public start: PayoutPeriod | null = null,
public end: PayoutPeriod = new PayoutPeriod(),
public satelliteId: string = '',
) {}
}
/**
* PayStub is an entity that holds usage and cash amounts that will be paid to storagenode operator after for month period.
*/
export class Paystub {
public constructor(
public usageAtRest: number = 0,
public usageGet: number = 0,
public usagePut: number = 0,
public usageGetRepair: number = 0,
public usagePutRepair: number = 0,
public usageGetAudit: number = 0,
public compAtRest: number = 0,
public compGet: number = 0,
public compPut: number = 0,
public compGetRepair: number = 0,
public compPutRepair: number = 0,
public compGetAudit: number = 0,
public surgePercent: number = 0,
public held: number = 0,
public owed: number = 0,
public disposed: number = 0,
public paid: number = 0,
) {}
/**
* Returns payout amount multiplier.
*/
public get surgeMultiplier(): number {
// 0 in backend uses instead of "without multiplier"
return this.surgePercent === 0 ? 1 : this.surgePercent / 100;
}
}
/**
* Summary of paystubs by period.
* Payout amounts converted to cents.
*/
export class TotalPaystubForPeriod {
public usageAtRest: number = 0;
public usageGet: number = 0;
public usagePut: number = 0;
public usageGetRepair: number = 0;
public usagePutRepair: number = 0;
public usageGetAudit: number = 0;
public compAtRest: number = 0;
public compGet: number = 0;
public compPut: number = 0;
public compGetRepair: number = 0;
public compPutRepair: number = 0;
public compGetAudit: number = 0;
public surgePercent: number = 0;
public held: number = 0;
public owed: number = 0;
public disposed: number = 0;
public paid: number = 0;
public paidWithoutSurge: number = 0;
public constructor(
paystubs: Paystub[] = [],
) {
paystubs.forEach(paystub => {
this.usageAtRest += paystub.usageAtRest;
this.usageGet += paystub.usageGet;
this.usagePut += paystub.usagePut;
this.usageGetRepair += paystub.usageGetRepair;
this.usagePutRepair += paystub.usagePutRepair;
this.usageGetAudit += paystub.usageGetAudit;
this.compAtRest += this.convertToCents(paystub.compAtRest);
this.compGet += this.convertToCents(paystub.compGet);
this.compPut += this.convertToCents(paystub.compPut);
this.compGetRepair += this.convertToCents(paystub.compGetRepair);
this.compPutRepair += this.convertToCents(paystub.compPutRepair);
this.compGetAudit += this.convertToCents(paystub.compGetAudit);
this.held += this.convertToCents(paystub.held);
this.owed += this.convertToCents(paystub.owed);
this.disposed += this.convertToCents(paystub.disposed);
this.paid += this.convertToCents(paystub.paid);
this.surgePercent = this.convertToCents(paystub.surgePercent);
this.paidWithoutSurge += this.convertToCents(paystub.paid) / paystub.surgeMultiplier;
});
}
private convertToCents(value: number): number {
return value / PRICE_DIVIDER;
}
}
/**
* Holds accumulated held and earned payouts.
*/
export class TotalHeldAndPaid {
public held: number = 0;
public paid: number = 0;
// TODO: remove
public currentMonthEarnings: number = 0;
public constructor(
paystubs: Paystub[] = [],
) {
paystubs.forEach(paystub => {
this.held += this.convertToCents(paystub.held - paystub.disposed);
this.paid += this.convertToCents(paystub.paid);
});
}
public setCurrentMonthEarnings(value: number): void {
this.currentMonthEarnings = value;
}
private convertToCents(value: number): number {
return value / PRICE_DIVIDER;
}
}
/**
* Holds held history information for all satellites.
*/
export class SatelliteHeldHistory {
public constructor(
public satelliteID: string = '',
public satelliteName: string = '',
public firstPeriod: number = 0,
public secondPeriod: number = 0,
public thirdPeriod: number = 0,
public totalHeld: number = 0,
public totalDisposed: number = 0,
public joinedAt: Date = new Date(),
) {
this.totalHeld = this.totalHeld / PRICE_DIVIDER;
this.totalDisposed = this.totalDisposed / PRICE_DIVIDER;
this.firstPeriod = this.firstPeriod / PRICE_DIVIDER;
this.secondPeriod = this.secondPeriod / PRICE_DIVIDER;
this.thirdPeriod = this.thirdPeriod / PRICE_DIVIDER;
}
public get monthsWithNode(): number {
return getMonthsBeforeNow(this.joinedAt);
}
}
/**
* Contains estimated payout information for current and last periods.
*/
export class EstimatedPayout {
public constructor(
public currentMonth: PreviousMonthEstimatedPayout = new PreviousMonthEstimatedPayout(),
public previousMonth: PreviousMonthEstimatedPayout = new PreviousMonthEstimatedPayout(),
) {}
}
/**
* Contains last month estimated payout information.
*/
export class PreviousMonthEstimatedPayout {
public constructor(
public egressBandwidth: number = 0,
public egressBandwidthPayout: number = 0,
public egressRepairAudit: number = 0,
public egressRepairAuditPayout: number = 0,
public diskSpace: number = 0,
public diskSpacePayout: number = 0,
public heldRate: number = 0,
public payout: number = 0,
public held: number = 0,
) {}
}
/**
* Contains payout information for payout history table.
*/
export class SatellitePayoutForPeriod {
public constructor(
public satelliteID: string = '',
public satelliteName: string = '',
public age: number = 1,
public earned: number = 0,
public surge: number = 0,
public surgePercent: number = 0,
public held: number = 0,
public afterHeld: number = 0,
public disposed: number = 0,
public paid: number = 0,
public receipt: string = '',
public isExitComplete: boolean = false,
public heldPercent: number = 0,
) {
this.earned = this.earned / PRICE_DIVIDER;
this.surge = this.surge / PRICE_DIVIDER;
this.held = this.held / PRICE_DIVIDER;
this.afterHeld = this.afterHeld / PRICE_DIVIDER;
this.disposed = this.disposed / PRICE_DIVIDER;
this.paid = this.paid / PRICE_DIVIDER;
}
}

View File

@ -0,0 +1,82 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
import {
EstimatedPayout,
PaymentInfoParameters,
PayoutApi,
PayoutPeriod,
Paystub,
SatelliteHeldHistory,
SatellitePayoutForPeriod,
TotalHeldAndPaid,
TotalPaystubForPeriod,
} from '@/storagenode/payouts/payouts';
/**
* PayoutService is used to store and handle node paystub information.
* PayoutService exposes a business logic related to payouts.
*/
export class PayoutService {
private readonly payouts: PayoutApi;
public constructor(api: PayoutApi) {
this.payouts = api;
}
/**
* Gets summary of paystubs for given period.
* @param start period start
* @param end period end
* @param satelliteId
*/
public async paystubSummaryForPeriod(start: PayoutPeriod, end: PayoutPeriod, satelliteId?: string): Promise<TotalPaystubForPeriod> {
const paystubs: Paystub[] = await this.payouts.getPaystubsForPeriod(new PaymentInfoParameters(start, end, satelliteId));
return new TotalPaystubForPeriod(paystubs);
}
/**
* Gets held and paid summary for given period.
* @param start period start
* @param end period end
* @param satelliteId
*/
public async totalHeldAndPaid(start: PayoutPeriod, end: PayoutPeriod, satelliteId: string): Promise<TotalHeldAndPaid> {
const paystubs: Paystub[] = await this.payouts.getPaystubsForPeriod(new PaymentInfoParameters(start, end, satelliteId));
return new TotalHeldAndPaid(paystubs);
}
/**
* Gets list of payout periods that have paystubs for selected satellite.
* If satelliteId is not provided returns periods for all satellites.
* @param satelliteId
*/
public async availablePeriods(satelliteId: string): Promise<PayoutPeriod[]> {
return await this.payouts.getPayoutPeriods(satelliteId);
}
/**
* Gets list of payout history items for given period by satellites.
* @param payoutHistoryPeriod year and month representation
*/
public async payoutHistory(payoutHistoryPeriod: string): Promise<SatellitePayoutForPeriod[]> {
return await this.payouts.getPayoutHistory(payoutHistoryPeriod);
}
/**
* Gets list of held history for all satellites.
*/
public async allSatellitesHeldHistory(): Promise<SatelliteHeldHistory[]> {
return await this.payouts.getHeldHistory();
}
/**
* Gets estimated payout when no data in paystub.
* @param satelliteId
*/
public async estimatedPayout(satelliteId: string): Promise<EstimatedPayout> {
return await this.payouts.getEstimatedPayout(satelliteId);
}
}

View File

@ -6,8 +6,9 @@ import Vuex from 'vuex';
import HeldHistoryAllStatsTable from '@/app/components/payments/HeldHistoryAllStatsTable.vue';
import { makePayoutModule, PAYOUT_MUTATIONS } from '@/app/store/modules/payout';
import { HeldHistory, HeldHistoryAllStatItem } from '@/app/types/payout';
import { PayoutHttpApi } from '@/storagenode/api/payout';
import { SatelliteHeldHistory } from '@/storagenode/payouts/payouts';
import { PayoutService } from '@/storagenode/payouts/service';
import { createLocalVue, shallowMount } from '@vue/test-utils';
const localVue = createLocalVue();
@ -18,7 +19,8 @@ localVue.filter('centsToDollars', (cents: number): string => {
});
const payoutApi = new PayoutHttpApi();
const payoutModule = makePayoutModule(payoutApi);
const payoutService = new PayoutService(payoutApi);
const payoutModule = makePayoutModule(payoutApi, payoutService);
const store = new Vuex.Store({ modules: { payoutModule }});
@ -30,14 +32,13 @@ describe('HeldHistoryAllStatsTable', (): void => {
});
const testJoinAt = new Date(Date.UTC(2020, 0, 30));
const testHeldHistory = [
new SatelliteHeldHistory('1', 'name1', 1, 50000, 0, 0, 1, testJoinAt),
new SatelliteHeldHistory('2', 'name2', 5, 50000, 422280, 0, 0, testJoinAt),
new SatelliteHeldHistory('3', 'name3', 6, 50000, 7333880, 7852235, 0, testJoinAt),
];
await store.commit(PAYOUT_MUTATIONS.SET_HELD_HISTORY, new HeldHistory(
[],
[
new HeldHistoryAllStatItem('1', 'name1', 1, 50000, 20000, testJoinAt),
new HeldHistoryAllStatItem('2', 'name2', 5, 40000, 30000, testJoinAt),
],
));
await store.commit(PAYOUT_MUTATIONS.SET_HELD_HISTORY, testHeldHistory);
expect(wrapper).toMatchSnapshot();
});

View File

@ -3,7 +3,7 @@
import HeldHistoryAllStatsTableItemSmall from '@/app/components/payments/HeldHistoryAllStatsTableItemSmall.vue';
import { HeldHistoryAllStatItem } from '@/app/types/payout';
import { SatelliteHeldHistory } from '@/storagenode/payouts/payouts';
import { createLocalVue, shallowMount } from '@vue/test-utils';
const localVue = createLocalVue();
@ -18,12 +18,14 @@ describe('HeldHistoryAllStatsTableItemSmall', (): void => {
const wrapper = shallowMount(HeldHistoryAllStatsTableItemSmall, {
propsData: {
heldHistoryItem: new HeldHistoryAllStatItem(
heldHistoryItem: new SatelliteHeldHistory(
'1',
'name1',
7,
45000,
8000,
6,
50000,
7333880,
7852235,
757576,
testJoinAt,
),
},

View File

@ -7,13 +7,15 @@ import HeldHistoryArea from '@/app/components/payments/HeldHistoryArea.vue';
import { makePayoutModule } from '@/app/store/modules/payout';
import { PayoutHttpApi } from '@/storagenode/api/payout';
import { PayoutService } from '@/storagenode/payouts/service';
import { createLocalVue, shallowMount } from '@vue/test-utils';
const localVue = createLocalVue();
localVue.use(Vuex);
const payoutApi = new PayoutHttpApi();
const payoutModule = makePayoutModule(payoutApi);
const payoutService = new PayoutService(payoutApi);
const payoutModule = makePayoutModule(payoutApi, payoutService);
const store = new Vuex.Store({ modules: { payoutModule }});

View File

@ -6,8 +6,9 @@ import Vuex from 'vuex';
import HeldHistoryMonthlyBreakdownTable from '@/app/components/payments/HeldHistoryMonthlyBreakdownTable.vue';
import { makePayoutModule, PAYOUT_MUTATIONS } from '@/app/store/modules/payout';
import { HeldHistory, HeldHistoryMonthlyBreakdownItem } from '@/app/types/payout';
import { PayoutHttpApi } from '@/storagenode/api/payout';
import { SatelliteHeldHistory } from '@/storagenode/payouts/payouts';
import { PayoutService } from '@/storagenode/payouts/service';
import { createLocalVue, shallowMount } from '@vue/test-utils';
const localVue = createLocalVue();
@ -18,7 +19,8 @@ localVue.filter('centsToDollars', (cents: number): string => {
});
const payoutApi = new PayoutHttpApi();
const payoutModule = makePayoutModule(payoutApi);
const payoutService = new PayoutService(payoutApi);
const payoutModule = makePayoutModule(payoutApi, payoutService);
const store = new Vuex.Store({ modules: { payoutModule }});
@ -29,11 +31,13 @@ describe('HeldHistoryMonthlyBreakdownTable', (): void => {
localVue,
});
await store.commit(PAYOUT_MUTATIONS.SET_HELD_HISTORY, new HeldHistory([
new HeldHistoryMonthlyBreakdownItem('1', 'name1', 1, 50000, 0, 0),
new HeldHistoryMonthlyBreakdownItem('2', 'name2', 5, 50000, 422280, 0),
new HeldHistoryMonthlyBreakdownItem('3', 'name3', 6, 50000, 7333880, 7852235),
]));
const testJoinedAt = new Date(2020, 1, 20);
await store.commit(PAYOUT_MUTATIONS.SET_HELD_HISTORY, [
new SatelliteHeldHistory('1', 'name1', 1, 50000, 0, 0, 0, testJoinedAt),
new SatelliteHeldHistory('2', 'name2', 5, 50000, 422280, 0, 0 , testJoinedAt),
new SatelliteHeldHistory('3', 'name3', 6, 50000, 7333880, 7852235, 0, testJoinedAt),
]);
expect(wrapper).toMatchSnapshot();
});

View File

@ -3,7 +3,7 @@
import HeldHistoryMonthlyBreakdownTableItemSmall from '@/app/components/payments/HeldHistoryMonthlyBreakdownTableItemSmall.vue';
import { HeldHistoryMonthlyBreakdownItem } from '@/app/types/payout';
import { SatelliteHeldHistory } from '@/storagenode/payouts/payouts';
import { createLocalVue, shallowMount } from '@vue/test-utils';
const localVue = createLocalVue();
@ -16,13 +16,15 @@ describe('HeldHistoryMonthlyBreakdownTableSmall', (): void => {
it('renders correctly with actual values', async (): Promise<void> => {
const wrapper = shallowMount(HeldHistoryMonthlyBreakdownTableItemSmall, {
propsData: {
heldHistoryItem: new HeldHistoryMonthlyBreakdownItem(
heldHistoryItem: new SatelliteHeldHistory(
'1',
'name1',
6,
50000,
7333880,
7852235,
757576,
new Date(2020, 1, 20),
),
},
localVue,

View File

@ -12,6 +12,7 @@ import { makeNodeModule, NODE_MUTATIONS } from '@/app/store/modules/node';
import { makePayoutModule, PAYOUT_MUTATIONS } from '@/app/store/modules/payout';
import { PayoutHttpApi } from '@/storagenode/api/payout';
import { SNOApi } from '@/storagenode/api/storagenode';
import { PayoutService } from '@/storagenode/payouts/service';
import { Satellites } from '@/storagenode/satellite';
import { createLocalVue, shallowMount } from '@vue/test-utils';
@ -40,7 +41,8 @@ localVue.directive('click-outside', {
});
const payoutApi = new PayoutHttpApi();
const payoutModule = makePayoutModule(payoutApi);
const payoutService = new PayoutService(payoutApi);
const payoutModule = makePayoutModule(payoutApi, payoutService);
const nodeApi = new SNOApi();
const nodeModule = makeNodeModule(nodeApi);

View File

@ -6,8 +6,9 @@ import Vuex from 'vuex';
import PayoutHistoryTable from '@/app/components/payments/PayoutHistoryTable.vue';
import { makePayoutModule, PAYOUT_MUTATIONS } from '@/app/store/modules/payout';
import { PayoutHistoryItem } from '@/app/types/payout';
import { PayoutHttpApi } from '@/storagenode/api/payout';
import { SatellitePayoutForPeriod } from '@/storagenode/payouts/payouts';
import { PayoutService } from '@/storagenode/payouts/service';
import { createLocalVue, shallowMount } from '@vue/test-utils';
const localVue = createLocalVue();
@ -18,17 +19,18 @@ localVue.filter('centsToDollars', (cents: number): string => {
});
const payoutApi = new PayoutHttpApi();
const payoutModule = makePayoutModule(payoutApi);
const payoutService = new PayoutService(payoutApi);
const payoutModule = makePayoutModule(payoutApi, payoutService);
const store = new Vuex.Store({ modules: { payoutModule }});
describe('PayoutHistoryTable', (): void => {
it('renders correctly with actual values', async (): Promise<void> => {
await store.commit(PAYOUT_MUTATIONS.SET_PAYOUT_HISTORY, [
new PayoutHistoryItem('1', 'name1', 1, 100000, 1200000, 140,
new SatellitePayoutForPeriod('1', 'name1', 1, 100000, 1200000, 140,
500000, 600000, 200000, 800000, 'receipt1', false,
),
new PayoutHistoryItem('2', 'name2', 16, 100000, 1200000, 140,
new SatellitePayoutForPeriod('2', 'name2', 16, 100000, 1200000, 140,
500000, 600000, 200000, 800000, 'receipt2', true,
),
]);

View File

@ -6,8 +6,9 @@ import Vuex from 'vuex';
import PayoutHistoryTableItem from '@/app/components/payments/PayoutHistoryTableItem.vue';
import { makePayoutModule } from '@/app/store/modules/payout';
import { PayoutHistoryItem } from '@/app/types/payout';
import { PayoutHttpApi } from '@/storagenode/api/payout';
import { SatellitePayoutForPeriod } from '@/storagenode/payouts/payouts';
import { PayoutService } from '@/storagenode/payouts/service';
import { createLocalVue, shallowMount } from '@vue/test-utils';
const localVue = createLocalVue();
@ -18,7 +19,8 @@ localVue.filter('centsToDollars', (cents: number): string => {
});
const payoutApi = new PayoutHttpApi();
const payoutModule = makePayoutModule(payoutApi);
const payoutService = new PayoutService(payoutApi);
const payoutModule = makePayoutModule(payoutApi, payoutService);
const store = new Vuex.Store({ modules: { payoutModule }});
@ -28,7 +30,7 @@ describe('PayoutHistoryTableItem', (): void => {
store,
localVue,
propsData: {
historyItem: new PayoutHistoryItem('1', 'name1', 1, 100000, 1200000, 140,
historyItem: new SatellitePayoutForPeriod('1', 'name1', 1, 100000, 1200000, 140,
500000, 600000, 200000, 800000, 'receipt1', false, 75,
),
},

View File

@ -6,8 +6,9 @@ import Vuex from 'vuex';
import TotalPayoutArea from '@/app/components/TotalPayoutArea.vue';
import { makePayoutModule, PAYOUT_MUTATIONS } from '@/app/store/modules/payout';
import { TotalPayoutInfo } from '@/app/types/payout';
import { PayoutHttpApi } from '@/storagenode/api/payout';
import { Paystub, TotalHeldAndPaid } from '@/storagenode/payouts/payouts';
import { PayoutService } from '@/storagenode/payouts/service';
import { createLocalVue, shallowMount } from '@vue/test-utils';
const localVue = createLocalVue();
@ -18,11 +19,12 @@ localVue.filter('centsToDollars', (cents: number): string => {
});
const payoutApi = new PayoutHttpApi();
const payoutModule = makePayoutModule(payoutApi);
const payoutService = new PayoutService(payoutApi);
const payoutModule = makePayoutModule(payoutApi, payoutService);
const store = new Vuex.Store({ modules: { payoutModule }});
describe('TotalPayoutInfo', (): void => {
describe('TotalPayoutArea', (): void => {
it('renders correctly', (): void => {
const wrapper = shallowMount(TotalPayoutArea, {
store,
@ -37,8 +39,21 @@ describe('TotalPayoutInfo', (): void => {
store,
localVue,
});
const paystub = new Paystub();
paystub.held = 600000;
paystub.disposed = 100000;
paystub.paid = 1000000;
await store.commit(PAYOUT_MUTATIONS.SET_TOTAL, new TotalPayoutInfo(2100, 5000, 8000));
const totalHeldAndPaid = new TotalHeldAndPaid([paystub]);
totalHeldAndPaid.setCurrentMonthEarnings(40000);
await store.commit(PAYOUT_MUTATIONS.SET_TOTAL, totalHeldAndPaid);
expect(wrapper).toMatchSnapshot();
totalHeldAndPaid.held = 400000;
await store.commit(PAYOUT_MUTATIONS.SET_TOTAL, totalHeldAndPaid);
expect(wrapper).toMatchSnapshot();
});

View File

@ -20,37 +20,53 @@ exports[`HeldHistoryAllStatsTable renders correctly with actual values 1`] = `
<div class="held-history-table-container--large__info-area">
<div class="justify-start column-1">
<p class="held-history-table-container--large__info-area__text">name1</p>
<p class="held-history-table-container--large__info-area__months">1 month</p>
<p class="held-history-table-container--large__info-area__months">9 month</p>
</div>
<div class="column justify-end column-2">
<p class="held-history-table-container--large__info-area__text">2020-01-30</p>
</div>
<div class="column justify-end column-3">
<p class="held-history-table-container--large__info-area__text">$0.05</p>
<p class="held-history-table-container--large__info-area__text">$0.00</p>
</div>
<div class="column justify-end column-4">
<p class="held-history-table-container--large__info-area__text">$0.02</p>
<p class="held-history-table-container--large__info-area__text">$0.00</p>
</div>
</div>
<div class="held-history-table-container--large__info-area">
<div class="justify-start column-1">
<p class="held-history-table-container--large__info-area__text">name2</p>
<p class="held-history-table-container--large__info-area__months">5 month</p>
<p class="held-history-table-container--large__info-area__months">9 month</p>
</div>
<div class="column justify-end column-2">
<p class="held-history-table-container--large__info-area__text">2020-01-30</p>
</div>
<div class="column justify-end column-3">
<p class="held-history-table-container--large__info-area__text">$0.04</p>
<p class="held-history-table-container--large__info-area__text">$0.00</p>
</div>
<div class="column justify-end column-4">
<p class="held-history-table-container--large__info-area__text">$0.03</p>
<p class="held-history-table-container--large__info-area__text">$0.00</p>
</div>
</div>
<div class="held-history-table-container--large__info-area">
<div class="justify-start column-1">
<p class="held-history-table-container--large__info-area__text">name3</p>
<p class="held-history-table-container--large__info-area__months">9 month</p>
</div>
<div class="column justify-end column-2">
<p class="held-history-table-container--large__info-area__text">2020-01-30</p>
</div>
<div class="column justify-end column-3">
<p class="held-history-table-container--large__info-area__text">$7.85</p>
</div>
<div class="column justify-end column-4">
<p class="held-history-table-container--large__info-area__text">$0.00</p>
</div>
</div>
</div>
<div class="held-history-table-container--small">
<heldhistoryallstatstableitemsmall-stub heldhistoryitem="[object Object]"></heldhistoryallstatstableitemsmall-stub>
<heldhistoryallstatstableitemsmall-stub heldhistoryitem="[object Object]"></heldhistoryallstatstableitemsmall-stub>
<heldhistoryallstatstableitemsmall-stub heldhistoryitem="[object Object]"></heldhistoryallstatstableitemsmall-stub>
</div>
</div>
`;

View File

@ -5,7 +5,7 @@ exports[`HeldHistoryAllStatsTableItemSmall renders correctly with actual values
<div class="held-history-table-container--small__item__satellite-info">
<div>
<p class="held-history-table-container--small__item__satellite-info__name">name1</p>
<p class="held-history-table-container--small__item__satellite-info__months">7 month</p>
<p class="held-history-table-container--small__item__satellite-info__months">9 month</p>
</div>
<div class="held-history-table-container--small__item__satellite-info__button">
<div class="icon expand">
@ -24,7 +24,7 @@ exports[`HeldHistoryAllStatsTableItemSmall renders correctly with actual values
<div class="held-history-table-container--small__item__satellite-info">
<div>
<p class="held-history-table-container--small__item__satellite-info__name">name1</p>
<p class="held-history-table-container--small__item__satellite-info__months">7 month</p>
<p class="held-history-table-container--small__item__satellite-info__months">9 month</p>
</div>
<div class="held-history-table-container--small__item__satellite-info__button">
<div class="icon hide">
@ -40,11 +40,11 @@ exports[`HeldHistoryAllStatsTableItemSmall renders correctly with actual values
</div>
<div class="held-history-table-container--small__item__held-info__item">
<p class="held-history-table-container--small__item__held-info__item__label">Held Total</p>
<p class="held-history-table-container--small__item__held-info__item__value">$0.04</p>
<p class="held-history-table-container--small__item__held-info__item__value">$7.85</p>
</div>
<div class="held-history-table-container--small__item__held-info__item">
<p class="held-history-table-container--small__item__held-info__item__label">Held Returned</p>
<p class="held-history-table-container--small__item__held-info__item__value">$0.01</p>
<p class="held-history-table-container--small__item__held-info__item__value">$0.76</p>
</div>
</div>
</transition-stub>
@ -56,7 +56,7 @@ exports[`HeldHistoryAllStatsTableItemSmall renders correctly with actual values
<div class="held-history-table-container--small__item__satellite-info">
<div>
<p class="held-history-table-container--small__item__satellite-info__name">name1</p>
<p class="held-history-table-container--small__item__satellite-info__months">7 month</p>
<p class="held-history-table-container--small__item__satellite-info__months">9 month</p>
</div>
<div class="held-history-table-container--small__item__satellite-info__button">
<div class="icon expand">

View File

@ -20,13 +20,13 @@ exports[`HeldHistoryMonthlyBreakdownTable renders correctly with actual values 1
<div class="held-history-table-container--large__info-area">
<div class="justify-start column-1">
<p class="held-history-table-container--large__info-area__text">name1</p>
<p class="held-history-table-container--large__info-area__months">1 month</p>
<p class="held-history-table-container--large__info-area__months">8 month</p>
</div>
<div class="column justify-end column-2">
<p class="held-history-table-container--large__info-area__text">$0.05</p>
<p class="held-history-table-container--large__info-area__text">$0.00</p>
</div>
<div class="column justify-end column-3">
<p class="held-history-table-container--large__info-area__text">$0.00</p>
<p class="held-history-table-container--large__info-area__text">$0.05</p>
</div>
<div class="column justify-end column-4">
<p class="held-history-table-container--large__info-area__text">$0.00</p>
@ -35,31 +35,31 @@ exports[`HeldHistoryMonthlyBreakdownTable renders correctly with actual values 1
<div class="held-history-table-container--large__info-area">
<div class="justify-start column-1">
<p class="held-history-table-container--large__info-area__text">name2</p>
<p class="held-history-table-container--large__info-area__months">5 month</p>
<p class="held-history-table-container--large__info-area__months">8 month</p>
</div>
<div class="column justify-end column-2">
<p class="held-history-table-container--large__info-area__text">$0.05</p>
<p class="held-history-table-container--large__info-area__text">$0.00</p>
</div>
<div class="column justify-end column-3">
<p class="held-history-table-container--large__info-area__text">$0.42</p>
<p class="held-history-table-container--large__info-area__text">$0.05</p>
</div>
<div class="column justify-end column-4">
<p class="held-history-table-container--large__info-area__text">$0.00</p>
<p class="held-history-table-container--large__info-area__text">$0.42</p>
</div>
</div>
<div class="held-history-table-container--large__info-area">
<div class="justify-start column-1">
<p class="held-history-table-container--large__info-area__text">name3</p>
<p class="held-history-table-container--large__info-area__months">6 month</p>
<p class="held-history-table-container--large__info-area__months">8 month</p>
</div>
<div class="column justify-end column-2">
<p class="held-history-table-container--large__info-area__text">$0.05</p>
<p class="held-history-table-container--large__info-area__text">$0.00</p>
</div>
<div class="column justify-end column-3">
<p class="held-history-table-container--large__info-area__text">$7.33</p>
<p class="held-history-table-container--large__info-area__text">$0.05</p>
</div>
<div class="column justify-end column-4">
<p class="held-history-table-container--large__info-area__text">$7.85</p>
<p class="held-history-table-container--large__info-area__text">$7.33</p>
</div>
</div>
</div>

View File

@ -5,7 +5,7 @@ exports[`HeldHistoryMonthlyBreakdownTableSmall renders correctly with actual val
<div class="held-history-table-container--small__item__satellite-info">
<div>
<p class="held-history-table-container--small__item__satellite-info__name">name1</p>
<p class="held-history-table-container--small__item__satellite-info__months">6 month</p>
<p class="held-history-table-container--small__item__satellite-info__months">8 month</p>
</div>
<div class="held-history-table-container--small__item__satellite-info__button">
<div class="icon expand">
@ -24,7 +24,7 @@ exports[`HeldHistoryMonthlyBreakdownTableSmall renders correctly with actual val
<div class="held-history-table-container--small__item__satellite-info">
<div>
<p class="held-history-table-container--small__item__satellite-info__name">name1</p>
<p class="held-history-table-container--small__item__satellite-info__months">6 month</p>
<p class="held-history-table-container--small__item__satellite-info__months">8 month</p>
</div>
<div class="held-history-table-container--small__item__satellite-info__button">
<div class="icon hide">
@ -36,15 +36,15 @@ exports[`HeldHistoryMonthlyBreakdownTableSmall renders correctly with actual val
<div class="held-history-table-container--small__item__held-info">
<div class="held-history-table-container--small__item__held-info__item">
<p class="held-history-table-container--small__item__held-info__item__label">Month 1-3</p>
<p class="held-history-table-container--small__item__held-info__item__value">$0.05</p>
<p class="held-history-table-container--small__item__held-info__item__value">$0.00</p>
</div>
<div class="held-history-table-container--small__item__held-info__item">
<p class="held-history-table-container--small__item__held-info__item__label">Month 4-6</p>
<p class="held-history-table-container--small__item__held-info__item__value">$7.33</p>
<p class="held-history-table-container--small__item__held-info__item__value">$0.05</p>
</div>
<div class="held-history-table-container--small__item__held-info__item">
<p class="held-history-table-container--small__item__held-info__item__label">Month 7-9</p>
<p class="held-history-table-container--small__item__held-info__item__value">$7.85</p>
<p class="held-history-table-container--small__item__held-info__item__value">$7.33</p>
</div>
</div>
</transition-stub>
@ -56,7 +56,7 @@ exports[`HeldHistoryMonthlyBreakdownTableSmall renders correctly with actual val
<div class="held-history-table-container--small__item__satellite-info">
<div>
<p class="held-history-table-container--small__item__satellite-info__name">name1</p>
<p class="held-history-table-container--small__item__satellite-info__months">6 month</p>
<p class="held-history-table-container--small__item__satellite-info__months">8 month</p>
</div>
<div class="held-history-table-container--small__item__satellite-info__button">
<div class="icon expand">

View File

@ -76,7 +76,9 @@ exports[`PayoutHistoryTableItem renders correctly with actual values 2`] = `
</div>
<div class="payout-history-item__expanded-area__right-area__divider"></div>
<div class="payout-history-item__expanded-area__right-area__footer">
<div class="payout-history-item__expanded-area__right-area__footer__transaction"><a href="receipt1" target="_blank" rel="noreferrer noopener">Transaction</a>
<div class="payout-history-item__expanded-area__right-area__footer__transaction"><a href="receipt1" target="_blank" rel="noreferrer noopener" class="payout-history-item__expanded-area__right-area__footer__transaction__link">
Transaction
</a>
<shareicon-stub class="payout-history-item__expanded-area__right-area__footer__transaction__icon"></shareicon-stub>
</div>
<p class="payout-history-item__expanded-area__right-area__footer__total">$0.80</p>

View File

@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TotalPayoutInfo renders correctly 1`] = `
exports[`TotalPayoutArea renders correctly 1`] = `
<section class="total-payout-area">
<div class="total-payout-area__united-info-area">
<div class="total-payout-area__united-info-area__item">
@ -24,26 +24,50 @@ exports[`TotalPayoutInfo renders correctly 1`] = `
</section>
`;
exports[`TotalPayoutInfo renders correctly with actual values 1`] = `
exports[`TotalPayoutArea renders correctly with actual values 1`] = `
<section class="total-payout-area">
<div class="total-payout-area__united-info-area">
<div class="total-payout-area__united-info-area__item">
<p class="total-payout-area__united-info-area__item__label">Current Month Earnings</p>
<p class="total-payout-area__united-info-area__item__amount">$80.00</p>
<p class="total-payout-area__united-info-area__item__amount">$400.00</p>
</div>
<div class="total-payout-area__united-info-area__item align-center">
<p class="total-payout-area__united-info-area__item__label">Total Earned</p>
<p class="total-payout-area__united-info-area__item__amount">$50.00</p>
<p class="total-payout-area__united-info-area__item__amount">$1.00</p>
</div>
<div class="total-payout-area__united-info-area__item align-end">
<p class="total-payout-area__united-info-area__item__label">Total Held Amount</p>
<p class="total-payout-area__united-info-area__item__amount">$21.00</p>
<p class="total-payout-area__united-info-area__item__amount">$0.50</p>
</div>
</div>
<div class="total-payout-area__info-area">
<singleinfo-stub width="100%" label="Current Month Earnings" value="$80.00"></singleinfo-stub>
<singleinfo-stub width="100%" label="Total Earnings" value="$50.00"></singleinfo-stub>
<singleinfo-stub width="100%" label="Total Held Amount" value="$21.00"></singleinfo-stub>
<singleinfo-stub width="100%" label="Current Month Earnings" value="$400.00"></singleinfo-stub>
<singleinfo-stub width="100%" label="Total Earnings" value="$1.00"></singleinfo-stub>
<singleinfo-stub width="100%" label="Total Held Amount" value="$0.50"></singleinfo-stub>
</div>
</section>
`;
exports[`TotalPayoutArea renders correctly with actual values 2`] = `
<section class="total-payout-area">
<div class="total-payout-area__united-info-area">
<div class="total-payout-area__united-info-area__item">
<p class="total-payout-area__united-info-area__item__label">Current Month Earnings</p>
<p class="total-payout-area__united-info-area__item__amount">$400.00</p>
</div>
<div class="total-payout-area__united-info-area__item align-center">
<p class="total-payout-area__united-info-area__item__label">Total Earned</p>
<p class="total-payout-area__united-info-area__item__amount">$1.00</p>
</div>
<div class="total-payout-area__united-info-area__item align-end">
<p class="total-payout-area__united-info-area__item__label">Total Held Amount</p>
<p class="total-payout-area__united-info-area__item__amount">$4000.00</p>
</div>
</div>
<div class="total-payout-area__info-area">
<singleinfo-stub width="100%" label="Current Month Earnings" value="$400.00"></singleinfo-stub>
<singleinfo-stub width="100%" label="Total Earnings" value="$1.00"></singleinfo-stub>
<singleinfo-stub width="100%" label="Total Held Amount" value="$4000.00"></singleinfo-stub>
</div>
</section>
`;

View File

@ -5,26 +5,27 @@ import Vuex from 'vuex';
import { makeNodeModule } from '@/app/store/modules/node';
import { makePayoutModule, PAYOUT_ACTIONS, PAYOUT_MUTATIONS } from '@/app/store/modules/payout';
import {
EstimatedPayout,
HeldHistory,
HeldHistoryAllStatItem,
HeldHistoryMonthlyBreakdownItem,
HeldInfo,
PayoutHistoryItem,
PayoutInfoRange,
PayoutPeriod,
PreviousMonthEstimatedPayout,
TotalPayoutInfo,
} from '@/app/types/payout';
import { PayoutInfoRange } from '@/app/types/payout';
import { getHeldPercentage, getMonthsBeforeNow } from '@/app/utils/payout';
import { PayoutHttpApi } from '@/storagenode/api/payout';
import { SNOApi } from '@/storagenode/api/storagenode';
import {
EstimatedPayout,
PayoutPeriod,
Paystub,
PreviousMonthEstimatedPayout,
SatelliteHeldHistory,
SatellitePayoutForPeriod,
TotalHeldAndPaid,
TotalPaystubForPeriod,
} from '@/storagenode/payouts/payouts';
import { PayoutService } from '@/storagenode/payouts/service';
import { createLocalVue } from '@vue/test-utils';
const Vue = createLocalVue();
const payoutApi = new PayoutHttpApi();
const payoutModule = makePayoutModule(payoutApi);
const payoutService = new PayoutService(payoutApi);
const payoutModule = makePayoutModule(payoutApi, payoutService);
const nodeApi = new SNOApi();
const nodeModule = makeNodeModule(nodeApi);
@ -40,23 +41,29 @@ describe('mutations', (): void => {
createLocalVue().use(Vuex);
});
it('sets held information', (): void => {
const heldInfo = new HeldInfo(13, 12, 11);
it('sets payout information', (): void => {
const totalPaystubForPeriod = new TotalPaystubForPeriod([new Paystub(13, 12, 11)]);
store.commit(PAYOUT_MUTATIONS.SET_HELD_INFO, heldInfo);
store.commit(PAYOUT_MUTATIONS.SET_PAYOUT_INFO, totalPaystubForPeriod);
expect(state.payoutModule.heldInfo.usageAtRest).toBe(13);
expect(state.payoutModule.heldInfo.usageGet).toBe(12);
expect(state.payoutModule.heldInfo.usagePut).toBe(11);
expect(state.payoutModule.totalPaystubForPeriod.usageAtRest).toBe(13);
expect(state.payoutModule.totalPaystubForPeriod.usageGet).toBe(12);
expect(state.payoutModule.totalPaystubForPeriod.usagePut).toBe(11);
});
it('sets total payout information', (): void => {
const totalInfo = new TotalPayoutInfo(50, 100, 22);
const paystub = new Paystub();
paystub.held = 600000;
paystub.disposed = 100000;
paystub.paid = 1000000;
store.commit(PAYOUT_MUTATIONS.SET_TOTAL, totalInfo);
const totalHeldAndPaid = new TotalHeldAndPaid([paystub]);
totalHeldAndPaid.setCurrentMonthEarnings(22);
expect(state.payoutModule.totalHeldAmount).toBe(50);
expect(state.payoutModule.totalEarnings).toBe(100);
store.commit(PAYOUT_MUTATIONS.SET_TOTAL, totalHeldAndPaid);
expect(state.payoutModule.totalHeldAndPaid.held).toBe(50);
expect(state.payoutModule.totalHeldAndPaid.paid).toBe(100);
expect(state.payoutModule.currentMonthEarnings).toBe(22);
});
@ -84,25 +91,18 @@ describe('mutations', (): void => {
it('sets held history', (): void => {
const testJoinAt = new Date(Date.UTC(2020, 0, 30));
const testHeldHistory = new HeldHistory(
[
new HeldHistoryMonthlyBreakdownItem('1', 'name1', 1, 50000, 0, 0),
new HeldHistoryMonthlyBreakdownItem('2', 'name2', 5, 50000, 422280, 0),
new HeldHistoryMonthlyBreakdownItem('3', 'name3', 6, 50000, 7333880, 7852235),
],
[
new HeldHistoryAllStatItem('1', 'name1', 1, 1000000, 0, testJoinAt),
new HeldHistoryAllStatItem('2', 'name2', 5, 300000, 20, testJoinAt),
],
);
const testHeldHistory = [
new SatelliteHeldHistory('1', 'name1', 1, 50000, 0, 0, 1, testJoinAt),
new SatelliteHeldHistory('2', 'name2', 5, 50000, 422280, 0),
new SatelliteHeldHistory('3', 'name3', 6, 50000, 7333880, 7852235),
];
store.commit(PAYOUT_MUTATIONS.SET_HELD_HISTORY, testHeldHistory);
expect(state.payoutModule.heldHistory.monthlyBreakdown.length).toBe(testHeldHistory.monthlyBreakdown.length);
expect(state.payoutModule.heldHistory.monthlyBreakdown[1].satelliteName).toBe(testHeldHistory.monthlyBreakdown[1].satelliteName);
expect(state.payoutModule.heldHistory.allStats.length).toBe(testHeldHistory.allStats.length);
expect(state.payoutModule.heldHistory.allStats[0].joinedAt).toBe(testJoinAt);
expect(state.payoutModule.heldHistory.allStats[1].totalHeld).toBe(30);
expect(state.payoutModule.heldHistory.length).toBe(testHeldHistory.length);
expect(state.payoutModule.heldHistory[1].satelliteName).toBe(testHeldHistory[1].satelliteName);
expect(state.payoutModule.heldHistory[0].joinedAt).toBe(testJoinAt);
expect(state.payoutModule.heldHistory[2].totalHeld).toBe(785.2235);
});
it('sets estimated payout information', (): void => {
@ -159,10 +159,10 @@ describe('mutations', (): void => {
it('sets payout history period', (): void => {
const payoutHistory = [
new PayoutHistoryItem('1', 'name1', 1, 10, 120, 140,
new SatellitePayoutForPeriod('1', 'name1', 1, 10, 120, 140,
50, 60, 20, 80, 'receipt1', false,
),
new PayoutHistoryItem('2', 'name2', 16, 10, 120, 140,
new SatellitePayoutForPeriod('2', 'name2', 16, 10, 120, 140,
50, 60, 20, 80, 'receipt2', true,
),
];
@ -179,82 +179,94 @@ describe('actions', () => {
jest.resetAllMocks();
});
it('success get held info by month', async (): Promise<void> => {
jest.spyOn(payoutApi, 'getHeldInfoByMonth').mockReturnValue(
Promise.resolve(new HeldInfo(1, 2 , 3, 4, 5)),
it('success get payout info by month', async (): Promise<void> => {
const paystub = new Paystub();
paystub.usagePut = 3;
paystub.held = 100000;
jest.spyOn(payoutApi, 'getPaystubsForPeriod').mockReturnValue(
Promise.resolve([paystub]),
);
const range = new PayoutInfoRange(null, new PayoutPeriod(2020, 3));
store.commit(PAYOUT_MUTATIONS.SET_RANGE, range);
await store.dispatch(PAYOUT_ACTIONS.GET_HELD_INFO);
await store.dispatch(PAYOUT_ACTIONS.GET_PAYOUT_INFO);
expect(state.payoutModule.heldInfo.usagePut).toBe(3);
expect(state.payoutModule.heldInfo.held).toBe(0);
expect(state.payoutModule.totalPaystubForPeriod.usagePut).toBe(3);
expect(state.payoutModule.totalPaystubForPeriod.held).toBe(10);
expect(state.payoutModule.heldPercentage).toBe(getHeldPercentage(new Date()));
});
it('get held info by month throws an error when api call fails', async (): Promise<void> => {
jest.spyOn(payoutApi, 'getHeldInfoByMonth').mockImplementation(() => { throw new Error(); });
it('get payout info by month throws an error when api call fails', async (): Promise<void> => {
jest.spyOn(payoutApi, 'getPaystubsForPeriod').mockImplementation(() => { throw new Error(); });
try {
await store.dispatch(PAYOUT_ACTIONS.GET_HELD_INFO);
await store.dispatch(PAYOUT_ACTIONS.GET_PAYOUT_INFO);
expect(true).toBe(false);
} catch (error) {
expect(state.payoutModule.heldInfo.usagePut).toBe(3);
expect(state.payoutModule.heldInfo.held).toBe(0);
expect(state.payoutModule.totalPaystubForPeriod.usagePut).toBe(3);
expect(state.payoutModule.totalPaystubForPeriod.held).toBe(10);
}
});
it('success get held info by period', async (): Promise<void> => {
jest.spyOn(payoutApi, 'getHeldInfoByPeriod').mockReturnValue(
Promise.resolve(new HeldInfo(1, 2 , 3, 4, 5)),
it('success get payout info by period', async (): Promise<void> => {
const paystub = new Paystub();
paystub.usagePut = 3;
paystub.held = 100000;
jest.spyOn(payoutApi, 'getPaystubsForPeriod').mockReturnValue(
Promise.resolve([paystub]),
);
const range = new PayoutInfoRange(new PayoutPeriod(2019, 2), new PayoutPeriod(2020, 3));
store.commit(PAYOUT_MUTATIONS.SET_RANGE, range);
await store.dispatch(PAYOUT_ACTIONS.GET_HELD_INFO);
await store.dispatch(PAYOUT_ACTIONS.GET_PAYOUT_INFO);
expect(state.payoutModule.heldInfo.usagePut).toBe(3);
expect(state.payoutModule.heldInfo.held).toBe(0);
expect(state.payoutModule.totalPaystubForPeriod.usagePut).toBe(3);
expect(state.payoutModule.totalPaystubForPeriod.held).toBe(10);
});
it('get held info by period throws an error when api call fails', async (): Promise<void> => {
jest.spyOn(payoutApi, 'getHeldInfoByPeriod').mockImplementation(() => { throw new Error(); });
it('get payout info by period throws an error when api call fails', async (): Promise<void> => {
jest.spyOn(payoutApi, 'getPaystubsForPeriod').mockImplementation(() => { throw new Error(); });
try {
await store.dispatch(PAYOUT_ACTIONS.GET_HELD_INFO);
await store.dispatch(PAYOUT_ACTIONS.GET_PAYOUT_INFO);
expect(true).toBe(false);
} catch (error) {
expect(state.payoutModule.heldInfo.usagePut).toBe(3);
expect(state.payoutModule.heldInfo.held).toBe(0);
expect(state.payoutModule.totalPaystubForPeriod.usagePut).toBe(3);
expect(state.payoutModule.totalPaystubForPeriod.held).toBe(10);
}
});
it('success get total', async (): Promise<void> => {
jest.spyOn(payoutApi, 'getTotal').mockReturnValue(
Promise.resolve(new TotalPayoutInfo(10, 20, 5)),
const paystub = new Paystub();
paystub.held = 100000;
paystub.paid = 200000;
jest.spyOn(payoutApi, 'getPaystubsForPeriod').mockReturnValue(
Promise.resolve([paystub]),
);
await store.dispatch(PAYOUT_ACTIONS.GET_TOTAL);
expect(state.payoutModule.totalHeldAmount).toBe(10);
expect(state.payoutModule.totalEarnings).toBe(20);
expect(state.payoutModule.totalHeldAndPaid.held).toBe(10);
expect(state.payoutModule.totalHeldAndPaid.paid).toBe(20);
expect(state.payoutModule.currentMonthEarnings).toBe(0);
});
it('get total throws an error when api call fails', async (): Promise<void> => {
jest.spyOn(payoutApi, 'getTotal').mockImplementation(() => { throw new Error(); });
jest.spyOn(payoutApi, 'getPaystubsForPeriod').mockImplementation(() => { throw new Error(); });
try {
await store.dispatch(PAYOUT_ACTIONS.GET_TOTAL);
expect(true).toBe(false);
} catch (error) {
expect(state.payoutModule.totalHeldAmount).toBe(10);
expect(state.payoutModule.totalEarnings).toBe(20);
expect(state.payoutModule.totalHeldAndPaid.held).toBe(10);
expect(state.payoutModule.totalHeldAndPaid.paid).toBe(20);
expect(state.payoutModule.currentMonthEarnings).toBe(0);
}
});
@ -290,28 +302,22 @@ describe('actions', () => {
it('success get held history', async (): Promise<void> => {
const testJoinAt = new Date(Date.UTC(2020, 0, 30));
const testHeldHistory = [
new SatelliteHeldHistory('1', 'name1', 1, 50000, 0, 0, 1, testJoinAt),
new SatelliteHeldHistory('2', 'name2', 5, 50000, 422280, 0),
new SatelliteHeldHistory('3', 'name3', 6, 50000, 7333880, 7852235),
];
jest.spyOn(payoutApi, 'getHeldHistory').mockReturnValue(
Promise.resolve(new HeldHistory(
[
new HeldHistoryMonthlyBreakdownItem('1', 'name1', 1, 50000, 0, 0),
new HeldHistoryMonthlyBreakdownItem('2', 'name2', 5, 50000, 422280, 0),
new HeldHistoryMonthlyBreakdownItem('3', 'name3', 6, 50000, 7333880, 7852235),
],
[
new HeldHistoryAllStatItem('1', 'name1', 1, 100, 0, testJoinAt),
new HeldHistoryAllStatItem('2', 'name2', 5, 300000, 20, testJoinAt),
],
)),
Promise.resolve(testHeldHistory),
);
await store.dispatch(PAYOUT_ACTIONS.GET_HELD_HISTORY);
expect(state.payoutModule.heldHistory.monthlyBreakdown.length).toBe(3);
expect(state.payoutModule.heldHistory.monthlyBreakdown[1].satelliteName).toBe('name2');
expect(state.payoutModule.heldHistory.allStats.length).toBe(2);
expect(state.payoutModule.heldHistory.allStats[0].joinedAt).toBe(testJoinAt);
expect(state.payoutModule.heldHistory.allStats[1].totalHeld).toBe(30);
expect(state.payoutModule.heldHistory.length).toBe(3);
expect(state.payoutModule.heldHistory[1].satelliteName).toBe('name2');
expect(state.payoutModule.heldHistory[0].joinedAt).toBe(testJoinAt);
expect(state.payoutModule.heldHistory[2].totalHeld).toBe(785.2235);
});
it('get total throws an error when api call fails', async (): Promise<void> => {
@ -321,8 +327,7 @@ describe('actions', () => {
await store.dispatch(PAYOUT_ACTIONS.GET_HELD_HISTORY);
expect(true).toBe(false);
} catch (error) {
expect(state.payoutModule.heldHistory.monthlyBreakdown.length).toBe(3);
expect(state.payoutModule.heldHistory.monthlyBreakdown[1].satelliteName).toBe('name2');
expect(state.payoutModule.heldHistory.length).toBe(3);
}
});
@ -349,7 +354,7 @@ describe('actions', () => {
it('success get payout history', async (): Promise<void> => {
jest.spyOn(payoutApi, 'getPayoutHistory').mockReturnValue(
Promise.resolve([
new PayoutHistoryItem('1', 'name1', 1, 100000, 2200000, 140,
new SatellitePayoutForPeriod('1', 'name1', 1, 100000, 2200000, 140,
500000, 600000, 200000, 800000, 'receipt1', false,
),
]),
@ -367,10 +372,10 @@ describe('getters', () => {
it('getter totalPaidForPayoutHistoryPeriod returns correct value', async (): Promise<void> => {
jest.spyOn(payoutApi, 'getPayoutHistory').mockReturnValue(
Promise.resolve([
new PayoutHistoryItem('1', 'name1', 1, 10, 120, 140,
new SatellitePayoutForPeriod('1', 'name1', 1, 10, 120, 140,
50, 60, 20, 1300000, 'receipt1', false,
),
new PayoutHistoryItem('2', 'name2', 16, 10, 120, 140,
new SatellitePayoutForPeriod('2', 'name2', 16, 10, 120, 140,
50, 60, 20, 1700000, 'receipt2', true,
),
]),
@ -382,7 +387,7 @@ describe('getters', () => {
});
it('get estimated payout information throws an error when api call fails', async (): Promise<void> => {
jest.spyOn(payoutApi, 'getEstimatedInfo').mockImplementation(() => { throw new Error(); });
jest.spyOn(payoutApi, 'getEstimatedPayout').mockImplementation(() => { throw new Error(); });
try {
await store.dispatch(PAYOUT_ACTIONS.GET_ESTIMATION);
@ -394,7 +399,7 @@ describe('getters', () => {
});
it('success get estimated payout information', async (): Promise<void> => {
jest.spyOn(payoutApi, 'getEstimatedInfo').mockReturnValue(
jest.spyOn(payoutApi, 'getEstimatedPayout').mockReturnValue(
Promise.resolve(new EstimatedPayout(
new PreviousMonthEstimatedPayout(
1,