satellite/compensation: add offline status tracking
Change-Id: I52e615d3db186416ee95029dc72df626f0e69ad7
This commit is contained in:
parent
cafa7a5f0b
commit
42f63c6538
@ -81,18 +81,19 @@ func generateInvoicesCSV(ctx context.Context, period compensation.Period, out io
|
|||||||
}
|
}
|
||||||
|
|
||||||
nodeInfo := compensation.NodeInfo{
|
nodeInfo := compensation.NodeInfo{
|
||||||
ID: usage.NodeID,
|
ID: usage.NodeID,
|
||||||
CreatedAt: node.CreatedAt,
|
CreatedAt: node.CreatedAt,
|
||||||
Disqualified: node.Disqualified,
|
LastContactSuccess: node.Reputation.LastContactSuccess,
|
||||||
GracefulExit: gracefulExit,
|
Disqualified: node.Disqualified,
|
||||||
UsageAtRest: usage.AtRestTotal,
|
GracefulExit: gracefulExit,
|
||||||
UsageGet: usage.GetTotal,
|
UsageAtRest: usage.AtRestTotal,
|
||||||
UsagePut: usage.PutTotal,
|
UsageGet: usage.GetTotal,
|
||||||
UsageGetRepair: usage.GetRepairTotal,
|
UsagePut: usage.PutTotal,
|
||||||
UsagePutRepair: usage.PutRepairTotal,
|
UsageGetRepair: usage.GetRepairTotal,
|
||||||
UsageGetAudit: usage.GetAuditTotal,
|
UsagePutRepair: usage.PutRepairTotal,
|
||||||
TotalHeld: withheldAmounts.TotalHeld,
|
UsageGetAudit: usage.GetAuditTotal,
|
||||||
TotalDisposed: withheldAmounts.TotalDisposed,
|
TotalHeld: withheldAmounts.TotalHeld,
|
||||||
|
TotalDisposed: withheldAmounts.TotalDisposed,
|
||||||
}
|
}
|
||||||
|
|
||||||
invoice := compensation.Invoice{
|
invoice := compensation.Invoice{
|
||||||
|
@ -26,13 +26,17 @@ const (
|
|||||||
|
|
||||||
// GracefulExit is included if the node has gracefully exited.
|
// GracefulExit is included if the node has gracefully exited.
|
||||||
GracefulExit Code = "X"
|
GracefulExit Code = "X"
|
||||||
|
|
||||||
|
// Offline is included if the node's last contact success is before the starting
|
||||||
|
// period.
|
||||||
|
Offline Code = "O"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CodeFromString parses the string into a Code.
|
// CodeFromString parses the string into a Code.
|
||||||
func CodeFromString(s string) (Code, error) {
|
func CodeFromString(s string) (Code, error) {
|
||||||
code := Code(s)
|
code := Code(s)
|
||||||
switch code {
|
switch code {
|
||||||
case Disqualified, Sanctioned, No1099, InWithholding, GracefulExit:
|
case Disqualified, Sanctioned, No1099, InWithholding, GracefulExit, Offline:
|
||||||
return code, nil
|
return code, nil
|
||||||
default:
|
default:
|
||||||
return "", Error.New("no such code %q", code)
|
return "", Error.New("no such code %q", code)
|
||||||
|
@ -36,18 +36,19 @@ var (
|
|||||||
// NodeInfo contains all of the information about a node and the operations
|
// NodeInfo contains all of the information about a node and the operations
|
||||||
// it performed in some period.
|
// it performed in some period.
|
||||||
type NodeInfo struct {
|
type NodeInfo struct {
|
||||||
ID storj.NodeID
|
ID storj.NodeID
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
Disqualified *time.Time
|
LastContactSuccess time.Time
|
||||||
GracefulExit *time.Time
|
Disqualified *time.Time
|
||||||
UsageAtRest float64
|
GracefulExit *time.Time
|
||||||
UsageGet int64
|
UsageAtRest float64
|
||||||
UsagePut int64
|
UsageGet int64
|
||||||
UsageGetRepair int64
|
UsagePut int64
|
||||||
UsagePutRepair int64
|
UsageGetRepair int64
|
||||||
UsageGetAudit int64
|
UsagePutRepair int64
|
||||||
TotalHeld currency.MicroUnit
|
UsageGetAudit int64
|
||||||
TotalDisposed currency.MicroUnit
|
TotalHeld currency.MicroUnit
|
||||||
|
TotalDisposed currency.MicroUnit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statement is the computed amounts and codes from a node.
|
// Statement is the computed amounts and codes from a node.
|
||||||
@ -98,6 +99,7 @@ type PeriodInfo struct {
|
|||||||
|
|
||||||
// GenerateStatements generates all of the Statements for the given PeriodInfo.
|
// GenerateStatements generates all of the Statements for the given PeriodInfo.
|
||||||
func GenerateStatements(info PeriodInfo) ([]Statement, error) {
|
func GenerateStatements(info PeriodInfo) ([]Statement, error) {
|
||||||
|
startDate := info.Period.StartDate()
|
||||||
endDate := info.Period.EndDateExclusive()
|
endDate := info.Period.EndDateExclusive()
|
||||||
|
|
||||||
rates := info.Rates
|
rates := info.Rates
|
||||||
@ -150,6 +152,11 @@ func GenerateStatements(info PeriodInfo) ([]Statement, error) {
|
|||||||
codes = append(codes, GracefulExit)
|
codes = append(codes, GracefulExit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
offline := node.LastContactSuccess.Before(startDate)
|
||||||
|
if offline {
|
||||||
|
codes = append(codes, Offline)
|
||||||
|
}
|
||||||
|
|
||||||
withheldPercent, inWithholding := NodeWithheldPercent(withheldPercents, node.CreatedAt, endDate)
|
withheldPercent, inWithholding := NodeWithheldPercent(withheldPercents, node.CreatedAt, endDate)
|
||||||
held := PercentOf(total, decimal.NewFromInt(int64(withheldPercent)))
|
held := PercentOf(total, decimal.NewFromInt(int64(withheldPercent)))
|
||||||
owed := total.Sub(held)
|
owed := total.Sub(held)
|
||||||
@ -177,7 +184,7 @@ func GenerateStatements(info PeriodInfo) ([]Statement, error) {
|
|||||||
owed = owed.Add(disposed)
|
owed = owed.Add(disposed)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the node is disqualified nothing is owed/held/disposed.
|
// If the node is disqualified but not gracefully exited, nothing is owed/held/disposed.
|
||||||
if node.Disqualified != nil && node.Disqualified.Before(endDate) && !gracefullyExited {
|
if node.Disqualified != nil && node.Disqualified.Before(endDate) && !gracefullyExited {
|
||||||
codes = append(codes, Disqualified)
|
codes = append(codes, Disqualified)
|
||||||
disposed = decimal.Zero
|
disposed = decimal.Zero
|
||||||
@ -185,6 +192,13 @@ func GenerateStatements(info PeriodInfo) ([]Statement, error) {
|
|||||||
owed = decimal.Zero
|
owed = decimal.Zero
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the node is offline, nothing is owed/held/disposed.
|
||||||
|
if offline {
|
||||||
|
disposed = decimal.Zero
|
||||||
|
held = decimal.Zero
|
||||||
|
owed = decimal.Zero
|
||||||
|
}
|
||||||
|
|
||||||
var overflowErrs errs.Group
|
var overflowErrs errs.Group
|
||||||
toMicroUnit := func(v decimal.Decimal) currency.MicroUnit {
|
toMicroUnit := func(v decimal.Decimal) currency.MicroUnit {
|
||||||
m, err := currency.MicroUnitFromDecimal(v)
|
m, err := currency.MicroUnitFromDecimal(v)
|
||||||
|
@ -52,14 +52,15 @@ func TestGenerateStatements(t *testing.T) {
|
|||||||
name: "within withholding",
|
name: "within withholding",
|
||||||
surgePercent: 0,
|
surgePercent: 0,
|
||||||
node: compensation.NodeInfo{
|
node: compensation.NodeInfo{
|
||||||
ID: nodeID,
|
ID: nodeID,
|
||||||
CreatedAt: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
LastContactSuccess: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||||
UsageAtRest: 1 * GB,
|
CreatedAt: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||||
UsageGet: 2 * TB,
|
UsageAtRest: 1 * GB,
|
||||||
UsagePut: 3 * TB,
|
UsageGet: 2 * TB,
|
||||||
UsageGetRepair: 4 * TB,
|
UsagePut: 3 * TB,
|
||||||
UsagePutRepair: 5 * TB,
|
UsageGetRepair: 4 * TB,
|
||||||
UsageGetAudit: 6 * TB,
|
UsagePutRepair: 5 * TB,
|
||||||
|
UsageGetAudit: 6 * TB,
|
||||||
},
|
},
|
||||||
statement: compensation.Statement{
|
statement: compensation.Statement{
|
||||||
NodeID: nodeID,
|
NodeID: nodeID,
|
||||||
@ -79,15 +80,16 @@ func TestGenerateStatements(t *testing.T) {
|
|||||||
name: "just out of withheld",
|
name: "just out of withheld",
|
||||||
surgePercent: 0,
|
surgePercent: 0,
|
||||||
node: compensation.NodeInfo{
|
node: compensation.NodeInfo{
|
||||||
ID: nodeID,
|
ID: nodeID,
|
||||||
CreatedAt: time.Date(2019, 11, 1, 0, 0, 0, 0, time.UTC),
|
LastContactSuccess: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||||
UsageAtRest: 1 * GB,
|
CreatedAt: time.Date(2019, 11, 1, 0, 0, 0, 0, time.UTC),
|
||||||
UsageGet: 2 * TB,
|
UsageAtRest: 1 * GB,
|
||||||
UsagePut: 3 * TB,
|
UsageGet: 2 * TB,
|
||||||
UsageGetRepair: 4 * TB,
|
UsagePut: 3 * TB,
|
||||||
UsagePutRepair: 5 * TB,
|
UsageGetRepair: 4 * TB,
|
||||||
UsageGetAudit: 6 * TB,
|
UsagePutRepair: 5 * TB,
|
||||||
TotalHeld: D(40),
|
UsageGetAudit: 6 * TB,
|
||||||
|
TotalHeld: D(40),
|
||||||
},
|
},
|
||||||
statement: compensation.Statement{
|
statement: compensation.Statement{
|
||||||
NodeID: nodeID,
|
NodeID: nodeID,
|
||||||
@ -106,16 +108,17 @@ func TestGenerateStatements(t *testing.T) {
|
|||||||
name: "out of withheld and already disposed",
|
name: "out of withheld and already disposed",
|
||||||
surgePercent: 0,
|
surgePercent: 0,
|
||||||
node: compensation.NodeInfo{
|
node: compensation.NodeInfo{
|
||||||
ID: nodeID,
|
ID: nodeID,
|
||||||
CreatedAt: time.Date(2019, 6, 12, 0, 0, 0, 0, time.UTC),
|
LastContactSuccess: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||||
UsageAtRest: 1 * GB,
|
CreatedAt: time.Date(2019, 6, 12, 0, 0, 0, 0, time.UTC),
|
||||||
UsageGet: 2 * TB,
|
UsageAtRest: 1 * GB,
|
||||||
UsagePut: 3 * TB,
|
UsageGet: 2 * TB,
|
||||||
UsageGetRepair: 4 * TB,
|
UsagePut: 3 * TB,
|
||||||
UsagePutRepair: 5 * TB,
|
UsageGetRepair: 4 * TB,
|
||||||
UsageGetAudit: 6 * TB,
|
UsagePutRepair: 5 * TB,
|
||||||
TotalHeld: D(40),
|
UsageGetAudit: 6 * TB,
|
||||||
TotalDisposed: D(24),
|
TotalHeld: D(40),
|
||||||
|
TotalDisposed: D(24),
|
||||||
},
|
},
|
||||||
statement: compensation.Statement{
|
statement: compensation.Statement{
|
||||||
NodeID: nodeID,
|
NodeID: nodeID,
|
||||||
@ -134,17 +137,18 @@ func TestGenerateStatements(t *testing.T) {
|
|||||||
name: "graceful exit within period",
|
name: "graceful exit within period",
|
||||||
surgePercent: 0,
|
surgePercent: 0,
|
||||||
node: compensation.NodeInfo{
|
node: compensation.NodeInfo{
|
||||||
ID: nodeID,
|
ID: nodeID,
|
||||||
CreatedAt: time.Date(2018, 6, 12, 0, 0, 0, 0, time.UTC),
|
LastContactSuccess: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||||
GracefulExit: timePtr(time.Date(2019, 11, 30, 23, 59, 59, 0, time.UTC)),
|
CreatedAt: time.Date(2018, 6, 12, 0, 0, 0, 0, time.UTC),
|
||||||
UsageAtRest: 1 * GB,
|
GracefulExit: timePtr(time.Date(2019, 11, 30, 23, 59, 59, 0, time.UTC)),
|
||||||
UsageGet: 2 * TB,
|
UsageAtRest: 1 * GB,
|
||||||
UsagePut: 3 * TB,
|
UsageGet: 2 * TB,
|
||||||
UsageGetRepair: 4 * TB,
|
UsagePut: 3 * TB,
|
||||||
UsagePutRepair: 5 * TB,
|
UsageGetRepair: 4 * TB,
|
||||||
UsageGetAudit: 6 * TB,
|
UsagePutRepair: 5 * TB,
|
||||||
TotalHeld: D(40),
|
UsageGetAudit: 6 * TB,
|
||||||
TotalDisposed: D(24),
|
TotalHeld: D(40),
|
||||||
|
TotalDisposed: D(24),
|
||||||
},
|
},
|
||||||
statement: compensation.Statement{
|
statement: compensation.Statement{
|
||||||
NodeID: nodeID,
|
NodeID: nodeID,
|
||||||
@ -160,6 +164,34 @@ func TestGenerateStatements(t *testing.T) {
|
|||||||
Disposed: D(16),
|
Disposed: D(16),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "offline",
|
||||||
|
surgePercent: 0,
|
||||||
|
node: compensation.NodeInfo{
|
||||||
|
ID: nodeID,
|
||||||
|
LastContactSuccess: time.Date(2019, 10, 2, 0, 0, 0, 0, time.UTC),
|
||||||
|
CreatedAt: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||||
|
UsageAtRest: 1 * GB,
|
||||||
|
UsageGet: 2 * TB,
|
||||||
|
UsagePut: 3 * TB,
|
||||||
|
UsageGetRepair: 4 * TB,
|
||||||
|
UsagePutRepair: 5 * TB,
|
||||||
|
UsageGetAudit: 6 * TB,
|
||||||
|
},
|
||||||
|
statement: compensation.Statement{
|
||||||
|
NodeID: nodeID,
|
||||||
|
Codes: compensation.Codes{compensation.Offline, compensation.InWithholding},
|
||||||
|
AtRest: D(2),
|
||||||
|
Get: D(6),
|
||||||
|
Put: D(15),
|
||||||
|
GetRepair: D(28),
|
||||||
|
PutRepair: D(55),
|
||||||
|
GetAudit: D(78),
|
||||||
|
Owed: D(0),
|
||||||
|
Held: D(0),
|
||||||
|
Disposed: D(0),
|
||||||
|
},
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
tt := tt
|
tt := tt
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user