web/storagenode: last month estimated payout

Change-Id: I8b8c96dd3b4a8112abb2dbae5f09c97941012e8c
This commit is contained in:
NickolaiYurchenko 2020-07-16 17:01:32 +03:00 committed by Nikolay Yurchenko
parent 32e1f16b48
commit 6ec7bc8b5d
9 changed files with 106 additions and 46 deletions

View File

@ -167,6 +167,12 @@ export default class SNOHeader extends Vue {
console.error(`${error.message} satellite data.`);
}
try {
await this.$store.dispatch(PAYOUT_ACTIONS.GET_ESTIMATION, this.$store.state.node.selectedSatellite.id);
} catch (error) {
console.error(error);
}
await this.$store.dispatch(APPSTATE_ACTIONS.SET_LOADING, false);
}
}

View File

@ -124,6 +124,12 @@ export default class SatelliteSelectionDropdown extends Vue {
}
}
try {
await this.$store.dispatch(PAYOUT_ACTIONS.GET_ESTIMATION, id);
} catch (error) {
console.error(error);
}
try {
await this.$store.dispatch(PAYOUT_ACTIONS.GET_TOTAL, id);
} catch (error) {

View File

@ -68,7 +68,7 @@
<p class="estimation-table-container__info-area__text">{{ item.payout | centsToDollars }}</p>
</div>
</div>
<div class="estimation-table-container__info-area" v-if="isCurrentPeriod">
<div class="estimation-table-container__info-area" v-if="isCurrentPeriod || isLastPeriodWithoutPaystub">
<div class="column justify-start column-1">
<p class="estimation-table-container__info-area__text">Gross Total</p>
</div>
@ -120,7 +120,7 @@ import {
BANDWIDTH_REPAIR_PRICE_PER_TB,
DISK_SPACE_PRICE_PER_TB, PAYOUT_ACTIONS,
} from '@/app/store/modules/payout';
import { HeldInfo, PayoutInfoRange, PayoutPeriod } from '@/app/types/payout';
import { EstimatedPayout, HeldInfo, PayoutInfoRange, PayoutPeriod } from '@/app/types/payout';
import { formatBytes, TB } from '@/app/utils/converter';
/**
@ -176,6 +176,30 @@ export default class EstimationArea extends Vue {
return !this.$store.state.payoutModule.periodRange.start && isCurrentMonthSelected;
}
/**
* Indicates if last month selected and has no data for this period.
*/
public get isLastPeriodWithoutPaystub(): boolean {
const joinedAt: Date = this.$store.state.node.selectedSatellite.joinDate;
const isNodeStartedBeforeCurrentPeriod =
joinedAt.getTime() < new Date(this.now.getUTCFullYear(), this.now.getUTCMonth(), 1 , 0, 0, 1).getTime();
if (!isNodeStartedBeforeCurrentPeriod) {
return false;
}
const lastMonthDate = new Date();
lastMonthDate.setMonth(lastMonthDate.getUTCMonth() - 1);
const selectedPeriod: PayoutInfoRange = this.$store.state.payoutModule.periodRange;
const lastMonthPayoutPeriod = new PayoutPeriod(lastMonthDate.getUTCFullYear(), lastMonthDate.getUTCMonth());
const isLastPeriodSelected: boolean = !selectedPeriod.start && selectedPeriod.end.period === lastMonthPayoutPeriod.period;
const isPaystubAvailable: boolean = this.$store.state.payoutModule.payoutPeriods.map(e => e.period).includes(lastMonthPayoutPeriod.period);
return isLastPeriodSelected && !isPaystubAvailable;
}
public get isSatelliteSelected(): boolean {
return !!this.$store.state.node.selectedSatellite.id;
}
@ -194,42 +218,47 @@ export default class EstimationArea extends Vue {
return this.$store.state.payoutModule.heldInfo;
}
/**
* Returns estimated payout information.
*/
public get estimation(): EstimatedPayout {
return this.$store.state.payoutModule.estimation;
}
/**
* Returns calculated or stored held amount.
*/
public get held(): number {
if (this.isCurrentPeriod) {
return this.currentMonthHeld();
if (!this.isCurrentPeriod && !this.isLastPeriodWithoutPaystub) {
return this.heldInfo.held;
}
return this.heldInfo.held;
return this.estimatedHeld();
}
/**
* Returns calculated or stored total payout by selected period.
*/
public get totalPayout(): number {
if (this.isCurrentPeriod) {
return this.grossTotal - this.held;
if (!this.isCurrentPeriod && !this.isLastPeriodWithoutPaystub) {
return this.heldInfo.paid;
}
return this.heldInfo.paid;
return this.grossTotal - this.held;
}
/**
* Returns calculated gross payout by selected period.
*/
public get grossTotal(): number {
return (this.currentBandwidthDownload * BANDWIDTH_DOWNLOAD_PRICE_PER_TB
+ this.currentBandwidthAuditAndRepair * BANDWIDTH_REPAIR_PRICE_PER_TB
+ this.currentDiskSpace * DISK_SPACE_PRICE_PER_TB) / TB;
return this.isLastPeriodWithoutPaystub ? this.estimation.previousMonth.payout + this.held : this.estimation.currentMonth.payout + this.held;
}
/**
* Returns calculated or stored total used disk space by selected period.
*/
public get totalDiskSpace(): string {
if (this.isCurrentPeriod) {
if (this.isCurrentPeriod || this.isLastPeriodWithoutPaystub) {
return formatBytes(this.currentDiskSpace);
}
@ -240,7 +269,7 @@ export default class EstimationArea extends Vue {
* Returns calculated or stored total used bandwidth by selected period.
*/
public get totalBandwidth(): string {
if (this.isCurrentPeriod) {
if (this.isCurrentPeriod || this.isLastPeriodWithoutPaystub) {
return formatBytes((this.currentBandwidthAuditAndRepair + this.currentBandwidthDownload));
}
@ -253,35 +282,28 @@ export default class EstimationArea extends Vue {
* Returns summary of current month audit and repair bandwidth.
*/
private get currentBandwidthAuditAndRepair(): number {
if (!this.$store.state.node.egressChartData) return 0;
return this.$store.state.node.egressChartData.map(data => data.egress.audit + data.egress.repair).reduce((previous, current) => previous + current, 0);
return this.isLastPeriodWithoutPaystub ? this.estimation.previousMonth.egressRepairAudit : this.estimation.currentMonth.egressRepairAudit;
}
/**
* Returns summary of current month download bandwidth.
*/
private get currentBandwidthDownload(): number {
if (!this.$store.state.node.egressChartData) return 0;
return this.$store.state.node.egressChartData.map(data => data.egress.usage)
.reduce((previous, current) => previous + current, 0);
return this.isLastPeriodWithoutPaystub ? this.estimation.previousMonth.egressBandwidth : this.estimation.currentMonth.egressBandwidth;
}
/**
* Returns summary of current month used disk space.
*/
private get currentDiskSpace(): number {
if (!this.$store.state.node.storageChartData) return 0;
return this.$store.state.node.storageChartData.map(data => data.atRestTotal / 720).reduce((previous, current) => previous + current, 0);
return this.isLastPeriodWithoutPaystub ? this.estimation.previousMonth.diskSpace : this.estimation.currentMonth.diskSpace;
}
/**
* Builds estimated payout table depends on selected period.
*/
public get tableData(): EstimationTableRow[] {
if (!this.isCurrentPeriod) {
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),
@ -289,30 +311,32 @@ export default class EstimationArea extends Vue {
];
}
const estimatedPayout = this.isLastPeriodWithoutPaystub ? this.estimation.previousMonth : this.estimation.currentMonth;
return [
new EstimationTableRow(
'Download',
'Egress',
`$${BANDWIDTH_DOWNLOAD_PRICE_PER_TB / 100} / TB`,
'--',
formatBytes(this.currentBandwidthDownload),
this.currentBandwidthDownload * BANDWIDTH_DOWNLOAD_PRICE_PER_TB / TB,
formatBytes(estimatedPayout.egressBandwidth),
estimatedPayout.egressBandwidthPayout,
),
new EstimationTableRow(
'Repair & Audit',
'Egress',
`$${BANDWIDTH_REPAIR_PRICE_PER_TB / 100} / TB`,
'--',
formatBytes(this.currentBandwidthAuditAndRepair),
this.currentBandwidthAuditAndRepair * BANDWIDTH_REPAIR_PRICE_PER_TB / TB,
formatBytes(estimatedPayout.egressRepairAudit),
estimatedPayout.egressRepairAuditPayout,
),
new EstimationTableRow(
'Disk Average Month',
'Storage',
`$${DISK_SPACE_PRICE_PER_TB / 100} / TBm`,
this.totalDiskSpace + 'm',
formatBytes(estimatedPayout.diskSpace) + 'm',
'--',
this.currentDiskSpace * DISK_SPACE_PRICE_PER_TB / TB,
estimatedPayout.diskSpacePayout,
),
];
}
@ -333,12 +357,12 @@ export default class EstimationArea extends Vue {
}
/**
* Returns current month held amount based on current day of month.
* Returns last or current month held amount based on current day of month.
*/
private currentMonthHeld(): number {
return this.isSatelliteSelected ?
this.grossTotal * this.$store.state.payoutModule.heldPercentage / 100 :
this.$store.state.payoutModule.estimation.currentMonth.held;
private estimatedHeld(): number {
return this.isLastPeriodWithoutPaystub ?
this.estimation.previousMonth.held :
this.estimation.currentMonth.held;
}
}
</script>

View File

@ -44,7 +44,6 @@ export default class EstimationPeriodDropdown extends Vue {
* Indicates if period selection calendar should be disabled.
*/
public get isCalendarDisabled(): boolean {
// TODO: change to available periods check after #1929 merge.
const nodeStartedAt = this.$store.state.node.selectedSatellite.joinDate;
const now = new Date();

View File

@ -124,8 +124,18 @@ export default class PayoutPeriodCalendar extends Vue {
await this.$store.dispatch(PAYOUT_ACTIONS.GET_HELD_INFO, this.$store.state.node.selectedSatellite.id);
await this.$store.dispatch(APPSTATE_ACTIONS.SET_NO_PAYOUT_DATA, false);
} catch (error) {
await this.$store.dispatch(APPSTATE_ACTIONS.SET_NO_PAYOUT_DATA, true);
console.error(error.message);
const lastMonthDate = new Date();
lastMonthDate.setMonth(lastMonthDate.getUTCMonth() - 1);
const selectedPeriod: PayoutInfoRange = this.$store.state.payoutModule.periodRange;
const lastMonthPayoutPeriod = new PayoutPeriod(lastMonthDate.getUTCFullYear(), lastMonthDate.getUTCMonth());
const isLastPeriodSelected: boolean = !selectedPeriod.start && selectedPeriod.end.period === lastMonthPayoutPeriod.period;
if (!isLastPeriodSelected) {
await this.$store.dispatch(APPSTATE_ACTIONS.SET_NO_PAYOUT_DATA, true);
console.error(error.message);
}
}
this.close();
@ -291,13 +301,22 @@ export default class PayoutPeriodCalendar extends Vue {
const months: MonthButton[] = [];
const availablePeriods: string[] = this.$store.state.payoutModule.payoutPeriods.map(payoutPeriod => payoutPeriod.period);
const lastMonthDate = new Date();
lastMonthDate.setMonth(lastMonthDate.getUTCMonth() - 1);
// Creates month entities and adds them to list.
for (let i = 0; i < 12; i++) {
const period = `${year}-${i < 9 ? '0' + (i + 1) : (i + 1)}`;
const isLastMonth: boolean = lastMonthDate.getUTCFullYear() === year && lastMonthDate.getUTCMonth() === i;
const isLastMonthActive: boolean =
isLastMonth && this.$store.state.node.selectedSatellite.joinDate.getTime() < new Date(
this.now.getUTCFullYear(), this.now.getUTCMonth(), 1 , 0, 0, 1,
).getTime();
const isMonthActive: boolean = availablePeriods.includes(period);
months.push(new MonthButton(year, i, isMonthActive, false));
months.push(new MonthButton(year, i, isMonthActive || isLastMonthActive, false));
}
this.displayedMonths[year] = months;

View File

@ -127,8 +127,8 @@ export function makePayoutModule(api: PayoutApi) {
commit(PAYOUT_MUTATIONS.SET_PERIODS, periods);
},
[PAYOUT_ACTIONS.GET_ESTIMATION]: async function ({commit}: any): Promise<void> {
const estimatedInfo = await api.getEstimatedInfo();
[PAYOUT_ACTIONS.GET_ESTIMATION]: async function ({ commit }: any, satelliteId: string = ''): Promise<void> {
const estimatedInfo = await api.getEstimatedInfo(satelliteId);
commit(PAYOUT_MUTATIONS.SET_ESTIMATION, estimatedInfo);
},

View File

@ -137,7 +137,7 @@ export interface PayoutApi {
* Fetch estimated payout information.
* @throws Error
*/
getEstimatedInfo(): Promise<EstimatedPayout>;
getEstimatedInfo(satelliteId: string): Promise<EstimatedPayout>;
}
/**

View File

@ -86,7 +86,7 @@ export default class PayoutArea extends Vue {
}
try {
await this.$store.dispatch(PAYOUT_ACTIONS.GET_ESTIMATION);
await this.$store.dispatch(PAYOUT_ACTIONS.GET_ESTIMATION, this.$store.state.node.selectedSatellite.id);
} catch (error) {
console.error(error);
}

View File

@ -8,8 +8,8 @@ import {
HeldInfo,
PaymentInfoParameters,
PayoutApi,
PreviousMonthEstimatedPayout,
PayoutPeriod,
PreviousMonthEstimatedPayout,
TotalPayoutInfo,
} from '@/app/types/payout';
import { HttpClient } from '@/storagenode/utils/httpClient';
@ -174,8 +174,14 @@ export class PayoutHttpApi implements PayoutApi {
* @returns estimated payout information
* @throws Error
*/
public async getEstimatedInfo(): Promise<EstimatedPayout> {
const response = await this.client.get('/api/sno/estimated-payout/');
public async getEstimatedInfo(satelliteId: string): Promise<EstimatedPayout> {
let path = '/api/sno/estimated-payout';
if (satelliteId) {
path += '?id=' + satelliteId;
}
const response = await this.client.get(path);
if (!response.ok) {
throw new Error('can not get estimated payout information');