satellite/payments: invoice creation (#3468)

This commit is contained in:
Yaroslav Vorobiov 2019-11-05 15:16:02 +02:00 committed by Yehor Butko
parent 9c59efd33d
commit 35edc2bcc3
36 changed files with 2806 additions and 110 deletions

View File

@ -12,6 +12,7 @@ import (
"os" "os"
"strconv" "strconv"
"strings" "strings"
"time"
prompt "github.com/segmentio/go-prompt" prompt "github.com/segmentio/go-prompt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -79,15 +80,36 @@ var (
Args: cobra.MinimumNArgs(4), Args: cobra.MinimumNArgs(4),
RunE: SegmentHealth, RunE: SegmentHealth,
} }
paymentsCmd = &cobra.Command{
Use: "payments",
Short: "commands for payments",
}
prepareInvoiceRecordsCmd = &cobra.Command{
Use: "prepare-invoice-records <period>",
Short: "Prepares invoice project records that will be used during invoice line items creation",
Args: cobra.MinimumNArgs(1),
RunE: prepareInvoiceRecords,
}
createInvoiceItemsCmd = &cobra.Command{
Use: "create-invoice-items",
Short: "Creates stripe invoice line items for not consumed project records",
RunE: createInvoiceItems,
}
createInvoicesCmd = &cobra.Command{
Use: "create-invoices",
Short: "Creates stripe invoices for all stripe customers known to satellite",
RunE: createInvoices,
}
) )
// Inspector gives access to overlay. // Inspector gives access to overlay.
type Inspector struct { type Inspector struct {
conn *rpc.Conn conn *rpc.Conn
identity *identity.FullIdentity identity *identity.FullIdentity
overlayclient rpc.OverlayInspectorClient overlayclient rpc.OverlayInspectorClient
irrdbclient rpc.IrreparableInspectorClient irrdbclient rpc.IrreparableInspectorClient
healthclient rpc.HealthInspectorClient healthclient rpc.HealthInspectorClient
paymentsClient rpc.PaymentsClient
} }
// NewInspector creates a new gRPC inspector client for access to overlay. // NewInspector creates a new gRPC inspector client for access to overlay.
@ -108,11 +130,12 @@ func NewInspector(address, path string) (*Inspector, error) {
} }
return &Inspector{ return &Inspector{
conn: conn, conn: conn,
identity: id, identity: id,
overlayclient: conn.OverlayInspectorClient(), overlayclient: conn.OverlayInspectorClient(),
irrdbclient: conn.IrreparableInspectorClient(), irrdbclient: conn.IrreparableInspectorClient(),
healthclient: conn.HealthInspectorClient(), healthclient: conn.HealthInspectorClient(),
paymentsClient: conn.PaymentsClient(),
}, nil }, nil
} }
@ -423,14 +446,104 @@ func sortSegments(segments []*pb.IrreparableSegment) map[string][]*pb.Irreparabl
return objects return objects
} }
func prepareInvoiceRecords(cmd *cobra.Command, args []string) error {
i, err := NewInspector(*Addr, *IdentityPath)
if err != nil {
return ErrInspectorDial.Wrap(err)
}
defer func() { err = errs.Combine(err, i.Close()) }()
period, err := parseDateString(args[0])
if err != nil {
return ErrArgs.New("invalid period specified: %v", err)
}
_, err = i.paymentsClient.PrepareInvoiceRecords(context.Background(),
&pb.PrepareInvoiceRecordsRequest{
Period: period,
},
)
if err != nil {
return err
}
fmt.Println("successfully created invoice project records")
return nil
}
func createInvoiceItems(cmd *cobra.Command, args []string) error {
i, err := NewInspector(*Addr, *IdentityPath)
if err != nil {
return ErrInspectorDial.Wrap(err)
}
defer func() { err = errs.Combine(err, i.Close()) }()
_, err = i.paymentsClient.ApplyInvoiceRecords(context.Background(), &pb.ApplyInvoiceRecordsRequest{})
if err != nil {
return err
}
fmt.Println("successfully created invoice line items")
return nil
}
func createInvoices(cmd *cobra.Command, args []string) error {
i, err := NewInspector(*Addr, *IdentityPath)
if err != nil {
return ErrInspectorDial.Wrap(err)
}
defer func() { err = errs.Combine(err, i.Close()) }()
_, err = i.paymentsClient.CreateInvoices(context.Background(), &pb.CreateInvoicesRequest{})
if err != nil {
return err
}
fmt.Println("successfully created invoices")
return nil
}
// parseDateString parses provided date string and returns corresponding time.Time.
func parseDateString(s string) (time.Time, error) {
values := strings.Split(s, "/")
if len(values) != 2 {
return time.Time{}, errs.New("invalid date format %s, use mm/yyyy", s)
}
month, err := strconv.ParseInt(values[0], 10, 64)
if err != nil {
return time.Time{}, errs.New("can not parse month: %v", err)
}
year, err := strconv.ParseInt(values[1], 10, 64)
if err != nil {
return time.Time{}, errs.New("can not parse year: %v", err)
}
date := time.Date(int(year), time.Month(month), 1, 0, 0, 0, 0, time.UTC)
if date.Year() != int(year) || date.Month() != time.Month(month) || date.Day() != 1 {
return date, errs.New("dates mismatch have %s result %s", s, date)
}
return date, nil
}
func init() { func init() {
rootCmd.AddCommand(statsCmd) rootCmd.AddCommand(statsCmd)
rootCmd.AddCommand(irreparableCmd) rootCmd.AddCommand(irreparableCmd)
rootCmd.AddCommand(healthCmd) rootCmd.AddCommand(healthCmd)
rootCmd.AddCommand(paymentsCmd)
healthCmd.AddCommand(objectHealthCmd) healthCmd.AddCommand(objectHealthCmd)
healthCmd.AddCommand(segmentHealthCmd) healthCmd.AddCommand(segmentHealthCmd)
paymentsCmd.AddCommand(prepareInvoiceRecordsCmd)
paymentsCmd.AddCommand(createInvoiceItemsCmd)
paymentsCmd.AddCommand(createInvoicesCmd)
objectHealthCmd.Flags().StringVar(&CSVPath, "csv-path", "stdout", "csv path where command output is written") objectHealthCmd.Flags().StringVar(&CSVPath, "csv-path", "stdout", "csv path where command output is written")
irreparableCmd.Flags().Int32Var(&irreparableLimit, "limit", 50, "max number of results per page") irreparableCmd.Flags().Int32Var(&irreparableLimit, "limit", 50, "max number of results per page")

528
pkg/pb/payments.pb.go Normal file
View File

@ -0,0 +1,528 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: payments.proto
package pb
import (
context "context"
fmt "fmt"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
_ "github.com/golang/protobuf/ptypes/timestamp"
grpc "google.golang.org/grpc"
math "math"
drpc "storj.io/drpc"
time "time"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
var _ = time.Kitchen
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
type PrepareInvoiceRecordsRequest struct {
Period time.Time `protobuf:"bytes,1,opt,name=period,proto3,stdtime" json:"period"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *PrepareInvoiceRecordsRequest) Reset() { *m = PrepareInvoiceRecordsRequest{} }
func (m *PrepareInvoiceRecordsRequest) String() string { return proto.CompactTextString(m) }
func (*PrepareInvoiceRecordsRequest) ProtoMessage() {}
func (*PrepareInvoiceRecordsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_a9566e6e864d2854, []int{0}
}
func (m *PrepareInvoiceRecordsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PrepareInvoiceRecordsRequest.Unmarshal(m, b)
}
func (m *PrepareInvoiceRecordsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_PrepareInvoiceRecordsRequest.Marshal(b, m, deterministic)
}
func (m *PrepareInvoiceRecordsRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_PrepareInvoiceRecordsRequest.Merge(m, src)
}
func (m *PrepareInvoiceRecordsRequest) XXX_Size() int {
return xxx_messageInfo_PrepareInvoiceRecordsRequest.Size(m)
}
func (m *PrepareInvoiceRecordsRequest) XXX_DiscardUnknown() {
xxx_messageInfo_PrepareInvoiceRecordsRequest.DiscardUnknown(m)
}
var xxx_messageInfo_PrepareInvoiceRecordsRequest proto.InternalMessageInfo
func (m *PrepareInvoiceRecordsRequest) GetPeriod() time.Time {
if m != nil {
return m.Period
}
return time.Time{}
}
type PrepareInvoiceRecordsResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *PrepareInvoiceRecordsResponse) Reset() { *m = PrepareInvoiceRecordsResponse{} }
func (m *PrepareInvoiceRecordsResponse) String() string { return proto.CompactTextString(m) }
func (*PrepareInvoiceRecordsResponse) ProtoMessage() {}
func (*PrepareInvoiceRecordsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_a9566e6e864d2854, []int{1}
}
func (m *PrepareInvoiceRecordsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PrepareInvoiceRecordsResponse.Unmarshal(m, b)
}
func (m *PrepareInvoiceRecordsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_PrepareInvoiceRecordsResponse.Marshal(b, m, deterministic)
}
func (m *PrepareInvoiceRecordsResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_PrepareInvoiceRecordsResponse.Merge(m, src)
}
func (m *PrepareInvoiceRecordsResponse) XXX_Size() int {
return xxx_messageInfo_PrepareInvoiceRecordsResponse.Size(m)
}
func (m *PrepareInvoiceRecordsResponse) XXX_DiscardUnknown() {
xxx_messageInfo_PrepareInvoiceRecordsResponse.DiscardUnknown(m)
}
var xxx_messageInfo_PrepareInvoiceRecordsResponse proto.InternalMessageInfo
type ApplyInvoiceRecordsRequest struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ApplyInvoiceRecordsRequest) Reset() { *m = ApplyInvoiceRecordsRequest{} }
func (m *ApplyInvoiceRecordsRequest) String() string { return proto.CompactTextString(m) }
func (*ApplyInvoiceRecordsRequest) ProtoMessage() {}
func (*ApplyInvoiceRecordsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_a9566e6e864d2854, []int{2}
}
func (m *ApplyInvoiceRecordsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ApplyInvoiceRecordsRequest.Unmarshal(m, b)
}
func (m *ApplyInvoiceRecordsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ApplyInvoiceRecordsRequest.Marshal(b, m, deterministic)
}
func (m *ApplyInvoiceRecordsRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ApplyInvoiceRecordsRequest.Merge(m, src)
}
func (m *ApplyInvoiceRecordsRequest) XXX_Size() int {
return xxx_messageInfo_ApplyInvoiceRecordsRequest.Size(m)
}
func (m *ApplyInvoiceRecordsRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ApplyInvoiceRecordsRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ApplyInvoiceRecordsRequest proto.InternalMessageInfo
type ApplyInvoiceRecordsResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ApplyInvoiceRecordsResponse) Reset() { *m = ApplyInvoiceRecordsResponse{} }
func (m *ApplyInvoiceRecordsResponse) String() string { return proto.CompactTextString(m) }
func (*ApplyInvoiceRecordsResponse) ProtoMessage() {}
func (*ApplyInvoiceRecordsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_a9566e6e864d2854, []int{3}
}
func (m *ApplyInvoiceRecordsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ApplyInvoiceRecordsResponse.Unmarshal(m, b)
}
func (m *ApplyInvoiceRecordsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ApplyInvoiceRecordsResponse.Marshal(b, m, deterministic)
}
func (m *ApplyInvoiceRecordsResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ApplyInvoiceRecordsResponse.Merge(m, src)
}
func (m *ApplyInvoiceRecordsResponse) XXX_Size() int {
return xxx_messageInfo_ApplyInvoiceRecordsResponse.Size(m)
}
func (m *ApplyInvoiceRecordsResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ApplyInvoiceRecordsResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ApplyInvoiceRecordsResponse proto.InternalMessageInfo
type CreateInvoicesRequest struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CreateInvoicesRequest) Reset() { *m = CreateInvoicesRequest{} }
func (m *CreateInvoicesRequest) String() string { return proto.CompactTextString(m) }
func (*CreateInvoicesRequest) ProtoMessage() {}
func (*CreateInvoicesRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_a9566e6e864d2854, []int{4}
}
func (m *CreateInvoicesRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CreateInvoicesRequest.Unmarshal(m, b)
}
func (m *CreateInvoicesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CreateInvoicesRequest.Marshal(b, m, deterministic)
}
func (m *CreateInvoicesRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_CreateInvoicesRequest.Merge(m, src)
}
func (m *CreateInvoicesRequest) XXX_Size() int {
return xxx_messageInfo_CreateInvoicesRequest.Size(m)
}
func (m *CreateInvoicesRequest) XXX_DiscardUnknown() {
xxx_messageInfo_CreateInvoicesRequest.DiscardUnknown(m)
}
var xxx_messageInfo_CreateInvoicesRequest proto.InternalMessageInfo
type CreateInvoicesResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CreateInvoicesResponse) Reset() { *m = CreateInvoicesResponse{} }
func (m *CreateInvoicesResponse) String() string { return proto.CompactTextString(m) }
func (*CreateInvoicesResponse) ProtoMessage() {}
func (*CreateInvoicesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_a9566e6e864d2854, []int{5}
}
func (m *CreateInvoicesResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CreateInvoicesResponse.Unmarshal(m, b)
}
func (m *CreateInvoicesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CreateInvoicesResponse.Marshal(b, m, deterministic)
}
func (m *CreateInvoicesResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_CreateInvoicesResponse.Merge(m, src)
}
func (m *CreateInvoicesResponse) XXX_Size() int {
return xxx_messageInfo_CreateInvoicesResponse.Size(m)
}
func (m *CreateInvoicesResponse) XXX_DiscardUnknown() {
xxx_messageInfo_CreateInvoicesResponse.DiscardUnknown(m)
}
var xxx_messageInfo_CreateInvoicesResponse proto.InternalMessageInfo
func init() {
proto.RegisterType((*PrepareInvoiceRecordsRequest)(nil), "nodestats.PrepareInvoiceRecordsRequest")
proto.RegisterType((*PrepareInvoiceRecordsResponse)(nil), "nodestats.PrepareInvoiceRecordsResponse")
proto.RegisterType((*ApplyInvoiceRecordsRequest)(nil), "nodestats.ApplyInvoiceRecordsRequest")
proto.RegisterType((*ApplyInvoiceRecordsResponse)(nil), "nodestats.ApplyInvoiceRecordsResponse")
proto.RegisterType((*CreateInvoicesRequest)(nil), "nodestats.CreateInvoicesRequest")
proto.RegisterType((*CreateInvoicesResponse)(nil), "nodestats.CreateInvoicesResponse")
}
func init() { proto.RegisterFile("payments.proto", fileDescriptor_a9566e6e864d2854) }
var fileDescriptor_a9566e6e864d2854 = []byte{
// 288 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2b, 0x48, 0xac, 0xcc,
0x4d, 0xcd, 0x2b, 0x29, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xcc, 0xcb, 0x4f, 0x49,
0x2d, 0x2e, 0x49, 0x2c, 0x29, 0x96, 0xe2, 0x4a, 0xcf, 0x4f, 0xcf, 0x87, 0x08, 0x4b, 0xc9, 0xa7,
0xe7, 0xe7, 0xa7, 0xe7, 0xa4, 0xea, 0x83, 0x79, 0x49, 0xa5, 0x69, 0xfa, 0x25, 0x99, 0xb9, 0x20,
0x65, 0xb9, 0x05, 0x10, 0x05, 0x4a, 0x31, 0x5c, 0x32, 0x01, 0x45, 0xa9, 0x05, 0x89, 0x45, 0xa9,
0x9e, 0x79, 0x65, 0xf9, 0x99, 0xc9, 0xa9, 0x41, 0xa9, 0xc9, 0xf9, 0x45, 0x29, 0xc5, 0x41, 0xa9,
0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x36, 0x5c, 0x6c, 0x05, 0xa9, 0x45, 0x99, 0xf9, 0x29, 0x12,
0x8c, 0x0a, 0x8c, 0x1a, 0xdc, 0x46, 0x52, 0x7a, 0x10, 0x13, 0xf5, 0x60, 0x26, 0xea, 0x85, 0xc0,
0x4c, 0x74, 0xe2, 0x38, 0x71, 0x4f, 0x9e, 0x61, 0xc2, 0x7d, 0x79, 0xc6, 0x20, 0xa8, 0x1e, 0x25,
0x79, 0x2e, 0x59, 0x1c, 0xa6, 0x17, 0x17, 0xe4, 0xe7, 0x15, 0xa7, 0x2a, 0xc9, 0x70, 0x49, 0x39,
0x16, 0x14, 0xe4, 0x54, 0x62, 0xb5, 0x5c, 0x49, 0x96, 0x4b, 0x1a, 0xab, 0x2c, 0x54, 0xb3, 0x38,
0x97, 0xa8, 0x73, 0x51, 0x6a, 0x62, 0x09, 0xcc, 0x70, 0xb8, 0x3e, 0x09, 0x2e, 0x31, 0x74, 0x09,
0x88, 0x16, 0xa3, 0xcd, 0x4c, 0x5c, 0x1c, 0x01, 0xd0, 0x90, 0x13, 0xca, 0xe2, 0x12, 0xc5, 0xea,
0x3a, 0x21, 0x75, 0x3d, 0x78, 0x68, 0xea, 0xe1, 0x0b, 0x1d, 0x29, 0x0d, 0xc2, 0x0a, 0x21, 0x16,
0x0b, 0xa5, 0x70, 0x09, 0x63, 0xf1, 0x8a, 0x90, 0x2a, 0x92, 0x01, 0xb8, 0x03, 0x42, 0x4a, 0x8d,
0x90, 0x32, 0xa8, 0x2d, 0xa1, 0x5c, 0x7c, 0xa8, 0x1e, 0x17, 0x52, 0x40, 0xd2, 0x89, 0x35, 0xb0,
0xa4, 0x14, 0xf1, 0xa8, 0x80, 0x18, 0xeb, 0xc4, 0x12, 0xc5, 0x54, 0x90, 0x94, 0xc4, 0x06, 0x8e,
0x72, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x99, 0xc9, 0xeb, 0xe7, 0x7b, 0x02, 0x00, 0x00,
}
type DRPCPaymentsClient interface {
DRPCConn() drpc.Conn
PrepareInvoiceRecords(ctx context.Context, in *PrepareInvoiceRecordsRequest) (*PrepareInvoiceRecordsResponse, error)
ApplyInvoiceRecords(ctx context.Context, in *ApplyInvoiceRecordsRequest) (*ApplyInvoiceRecordsResponse, error)
CreateInvoices(ctx context.Context, in *CreateInvoicesRequest) (*CreateInvoicesResponse, error)
}
type drpcPaymentsClient struct {
cc drpc.Conn
}
func NewDRPCPaymentsClient(cc drpc.Conn) DRPCPaymentsClient {
return &drpcPaymentsClient{cc}
}
func (c *drpcPaymentsClient) DRPCConn() drpc.Conn { return c.cc }
func (c *drpcPaymentsClient) PrepareInvoiceRecords(ctx context.Context, in *PrepareInvoiceRecordsRequest) (*PrepareInvoiceRecordsResponse, error) {
out := new(PrepareInvoiceRecordsResponse)
err := c.cc.Invoke(ctx, "/nodestats.Payments/PrepareInvoiceRecords", in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcPaymentsClient) ApplyInvoiceRecords(ctx context.Context, in *ApplyInvoiceRecordsRequest) (*ApplyInvoiceRecordsResponse, error) {
out := new(ApplyInvoiceRecordsResponse)
err := c.cc.Invoke(ctx, "/nodestats.Payments/ApplyInvoiceRecords", in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcPaymentsClient) CreateInvoices(ctx context.Context, in *CreateInvoicesRequest) (*CreateInvoicesResponse, error) {
out := new(CreateInvoicesResponse)
err := c.cc.Invoke(ctx, "/nodestats.Payments/CreateInvoices", in, out)
if err != nil {
return nil, err
}
return out, nil
}
type DRPCPaymentsServer interface {
PrepareInvoiceRecords(context.Context, *PrepareInvoiceRecordsRequest) (*PrepareInvoiceRecordsResponse, error)
ApplyInvoiceRecords(context.Context, *ApplyInvoiceRecordsRequest) (*ApplyInvoiceRecordsResponse, error)
CreateInvoices(context.Context, *CreateInvoicesRequest) (*CreateInvoicesResponse, error)
}
type DRPCPaymentsDescription struct{}
func (DRPCPaymentsDescription) NumMethods() int { return 3 }
func (DRPCPaymentsDescription) Method(n int) (string, drpc.Handler, interface{}, bool) {
switch n {
case 0:
return "/nodestats.Payments/PrepareInvoiceRecords",
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCPaymentsServer).
PrepareInvoiceRecords(
ctx,
in1.(*PrepareInvoiceRecordsRequest),
)
}, DRPCPaymentsServer.PrepareInvoiceRecords, true
case 1:
return "/nodestats.Payments/ApplyInvoiceRecords",
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCPaymentsServer).
ApplyInvoiceRecords(
ctx,
in1.(*ApplyInvoiceRecordsRequest),
)
}, DRPCPaymentsServer.ApplyInvoiceRecords, true
case 2:
return "/nodestats.Payments/CreateInvoices",
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCPaymentsServer).
CreateInvoices(
ctx,
in1.(*CreateInvoicesRequest),
)
}, DRPCPaymentsServer.CreateInvoices, true
default:
return "", nil, nil, false
}
}
func DRPCRegisterPayments(srv drpc.Server, impl DRPCPaymentsServer) {
srv.Register(impl, DRPCPaymentsDescription{})
}
type DRPCPayments_PrepareInvoiceRecordsStream interface {
drpc.Stream
SendAndClose(*PrepareInvoiceRecordsResponse) error
}
type drpcPaymentsPrepareInvoiceRecordsStream struct {
drpc.Stream
}
func (x *drpcPaymentsPrepareInvoiceRecordsStream) SendAndClose(m *PrepareInvoiceRecordsResponse) error {
if err := x.MsgSend(m); err != nil {
return err
}
return x.CloseSend()
}
type DRPCPayments_ApplyInvoiceRecordsStream interface {
drpc.Stream
SendAndClose(*ApplyInvoiceRecordsResponse) error
}
type drpcPaymentsApplyInvoiceRecordsStream struct {
drpc.Stream
}
func (x *drpcPaymentsApplyInvoiceRecordsStream) SendAndClose(m *ApplyInvoiceRecordsResponse) error {
if err := x.MsgSend(m); err != nil {
return err
}
return x.CloseSend()
}
type DRPCPayments_CreateInvoicesStream interface {
drpc.Stream
SendAndClose(*CreateInvoicesResponse) error
}
type drpcPaymentsCreateInvoicesStream struct {
drpc.Stream
}
func (x *drpcPaymentsCreateInvoicesStream) SendAndClose(m *CreateInvoicesResponse) error {
if err := x.MsgSend(m); err != nil {
return err
}
return x.CloseSend()
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// PaymentsClient is the client API for Payments service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type PaymentsClient interface {
PrepareInvoiceRecords(ctx context.Context, in *PrepareInvoiceRecordsRequest, opts ...grpc.CallOption) (*PrepareInvoiceRecordsResponse, error)
ApplyInvoiceRecords(ctx context.Context, in *ApplyInvoiceRecordsRequest, opts ...grpc.CallOption) (*ApplyInvoiceRecordsResponse, error)
CreateInvoices(ctx context.Context, in *CreateInvoicesRequest, opts ...grpc.CallOption) (*CreateInvoicesResponse, error)
}
type paymentsClient struct {
cc *grpc.ClientConn
}
func NewPaymentsClient(cc *grpc.ClientConn) PaymentsClient {
return &paymentsClient{cc}
}
func (c *paymentsClient) PrepareInvoiceRecords(ctx context.Context, in *PrepareInvoiceRecordsRequest, opts ...grpc.CallOption) (*PrepareInvoiceRecordsResponse, error) {
out := new(PrepareInvoiceRecordsResponse)
err := c.cc.Invoke(ctx, "/nodestats.Payments/PrepareInvoiceRecords", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *paymentsClient) ApplyInvoiceRecords(ctx context.Context, in *ApplyInvoiceRecordsRequest, opts ...grpc.CallOption) (*ApplyInvoiceRecordsResponse, error) {
out := new(ApplyInvoiceRecordsResponse)
err := c.cc.Invoke(ctx, "/nodestats.Payments/ApplyInvoiceRecords", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *paymentsClient) CreateInvoices(ctx context.Context, in *CreateInvoicesRequest, opts ...grpc.CallOption) (*CreateInvoicesResponse, error) {
out := new(CreateInvoicesResponse)
err := c.cc.Invoke(ctx, "/nodestats.Payments/CreateInvoices", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// PaymentsServer is the server API for Payments service.
type PaymentsServer interface {
PrepareInvoiceRecords(context.Context, *PrepareInvoiceRecordsRequest) (*PrepareInvoiceRecordsResponse, error)
ApplyInvoiceRecords(context.Context, *ApplyInvoiceRecordsRequest) (*ApplyInvoiceRecordsResponse, error)
CreateInvoices(context.Context, *CreateInvoicesRequest) (*CreateInvoicesResponse, error)
}
func RegisterPaymentsServer(s *grpc.Server, srv PaymentsServer) {
s.RegisterService(&_Payments_serviceDesc, srv)
}
func _Payments_PrepareInvoiceRecords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PrepareInvoiceRecordsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PaymentsServer).PrepareInvoiceRecords(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/nodestats.Payments/PrepareInvoiceRecords",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PaymentsServer).PrepareInvoiceRecords(ctx, req.(*PrepareInvoiceRecordsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Payments_ApplyInvoiceRecords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ApplyInvoiceRecordsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PaymentsServer).ApplyInvoiceRecords(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/nodestats.Payments/ApplyInvoiceRecords",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PaymentsServer).ApplyInvoiceRecords(ctx, req.(*ApplyInvoiceRecordsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Payments_CreateInvoices_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateInvoicesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PaymentsServer).CreateInvoices(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/nodestats.Payments/CreateInvoices",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PaymentsServer).CreateInvoices(ctx, req.(*CreateInvoicesRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Payments_serviceDesc = grpc.ServiceDesc{
ServiceName: "nodestats.Payments",
HandlerType: (*PaymentsServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "PrepareInvoiceRecords",
Handler: _Payments_PrepareInvoiceRecords_Handler,
},
{
MethodName: "ApplyInvoiceRecords",
Handler: _Payments_ApplyInvoiceRecords_Handler,
},
{
MethodName: "CreateInvoices",
Handler: _Payments_CreateInvoices_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "payments.proto",
}

28
pkg/pb/payments.proto Normal file
View File

@ -0,0 +1,28 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
syntax = "proto3";
option go_package = "pb";
package nodestats;
import "gogo.proto";
import "google/protobuf/timestamp.proto";
service Payments {
rpc PrepareInvoiceRecords(PrepareInvoiceRecordsRequest) returns (PrepareInvoiceRecordsResponse);
rpc ApplyInvoiceRecords(ApplyInvoiceRecordsRequest) returns (ApplyInvoiceRecordsResponse);
rpc CreateInvoices(CreateInvoicesRequest) returns (CreateInvoicesResponse);
}
message PrepareInvoiceRecordsRequest {
google.protobuf.Timestamp period = 1 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
}
message PrepareInvoiceRecordsResponse {}
message ApplyInvoiceRecordsRequest {}
message ApplyInvoiceRecordsResponse {}
message CreateInvoicesRequest {}
message CreateInvoicesResponse {}

View File

@ -44,6 +44,9 @@ type (
// OverlayInspectorClient is an alias to the drpc client interface // OverlayInspectorClient is an alias to the drpc client interface
OverlayInspectorClient = pb.DRPCOverlayInspectorClient OverlayInspectorClient = pb.DRPCOverlayInspectorClient
// PaymentsClient is an alias to the drpc client interface
PaymentsClient = pb.DRPCPaymentsClient
// PieceStoreInspectorClient is an alias to the drpc client interface // PieceStoreInspectorClient is an alias to the drpc client interface
PieceStoreInspectorClient = pb.DRPCPieceStoreInspectorClient PieceStoreInspectorClient = pb.DRPCPieceStoreInspectorClient
@ -157,6 +160,16 @@ func (c *Conn) OverlayInspectorClient() OverlayInspectorClient {
return NewOverlayInspectorClient(c.raw) return NewOverlayInspectorClient(c.raw)
} }
// NewPaymentsClient returns the drpc version of a PaymentsClient
func NewPaymentsClient(rc *RawConn) PaymentsClient {
return pb.NewDRPCPaymentsClient(rc)
}
// PaymentsClient returns a PaymentsClient for this connection
func (c *Conn) PaymentsClient() PaymentsClient {
return NewPaymentsClient(c.raw)
}
// NewPieceStoreInspectorClient returns the drpc version of a PieceStoreInspectorClient // NewPieceStoreInspectorClient returns the drpc version of a PieceStoreInspectorClient
func NewPieceStoreInspectorClient(rc *RawConn) PieceStoreInspectorClient { func NewPieceStoreInspectorClient(rc *RawConn) PieceStoreInspectorClient {
return pb.NewDRPCPieceStoreInspectorClient(rc) return pb.NewDRPCPieceStoreInspectorClient(rc)

View File

@ -45,6 +45,9 @@ type (
// OverlayInspectorClient is an alias to the grpc client interface // OverlayInspectorClient is an alias to the grpc client interface
OverlayInspectorClient = pb.OverlayInspectorClient OverlayInspectorClient = pb.OverlayInspectorClient
// PaymentsClient is an alias to the grpc client interface
PaymentsClient = pb.PaymentsClient
// PieceStoreInspectorClient is an alias to the grpc client interface // PieceStoreInspectorClient is an alias to the grpc client interface
PieceStoreInspectorClient = pb.PieceStoreInspectorClient PieceStoreInspectorClient = pb.PieceStoreInspectorClient
@ -158,6 +161,16 @@ func (c *Conn) OverlayInspectorClient() OverlayInspectorClient {
return NewOverlayInspectorClient(c.raw) return NewOverlayInspectorClient(c.raw)
} }
// NewPaymentsClient returns the grpc version of a PaymentsClient
func NewPaymentsClient(rc *RawConn) PaymentsClient {
return pb.NewPaymentsClient(rc)
}
// PaymentsClient returns a PaymentsClient for this connection
func (c *Conn) PaymentsClient() PaymentsClient {
return NewPaymentsClient(c.raw)
}
// NewPieceStoreInspectorClient returns the grpc version of a PieceStoreInspectorClient // NewPieceStoreInspectorClient returns the grpc version of a PieceStoreInspectorClient
func NewPieceStoreInspectorClient(rc *RawConn) PieceStoreInspectorClient { func NewPieceStoreInspectorClient(rc *RawConn) PieceStoreInspectorClient {
return pb.NewPieceStoreInspectorClient(rc) return pb.NewPieceStoreInspectorClient(rc)

View File

@ -5329,6 +5329,87 @@
] ]
} }
}, },
{
"protopath": "pkg:/:pb:/:payments.proto",
"def": {
"messages": [
{
"name": "PrepareInvoiceRecordsRequest",
"fields": [
{
"id": 1,
"name": "period",
"type": "google.protobuf.Timestamp",
"options": [
{
"name": "(gogoproto.stdtime)",
"value": "true"
},
{
"name": "(gogoproto.nullable)",
"value": "false"
}
]
}
]
},
{
"name": "PrepareInvoiceRecordsResponse"
},
{
"name": "ApplyInvoiceRecordsRequest"
},
{
"name": "ApplyInvoiceRecordsResponse"
},
{
"name": "CreateInvoicesRequest"
},
{
"name": "CreateInvoicesResponse"
}
],
"services": [
{
"name": "Payments",
"rpcs": [
{
"name": "PrepareInvoiceRecords",
"in_type": "PrepareInvoiceRecordsRequest",
"out_type": "PrepareInvoiceRecordsResponse"
},
{
"name": "ApplyInvoiceRecords",
"in_type": "ApplyInvoiceRecordsRequest",
"out_type": "ApplyInvoiceRecordsResponse"
},
{
"name": "CreateInvoices",
"in_type": "CreateInvoicesRequest",
"out_type": "CreateInvoicesResponse"
}
]
}
],
"imports": [
{
"path": "gogo.proto"
},
{
"path": "google/protobuf/timestamp.proto"
}
],
"package": {
"name": "nodestats"
},
"options": [
{
"name": "go_package",
"value": "pb"
}
]
}
},
{ {
"protopath": "pkg:/:pb:/:piecestore2.proto", "protopath": "pkg:/:pb:/:piecestore2.proto",
"def": { "def": {

View File

@ -109,8 +109,8 @@ type API struct {
} }
Payments struct { Payments struct {
Accounts payments.Accounts Accounts payments.Accounts
Clearing payments.Clearing Inspector *stripecoinpayments.Endpoint
} }
Console struct { Console struct {
@ -375,15 +375,14 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB, pointerDB metai
service := stripecoinpayments.NewService( service := stripecoinpayments.NewService(
peer.Log.Named("stripecoinpayments service"), peer.Log.Named("stripecoinpayments service"),
config.StripeCoinPayments, config.StripeCoinPayments,
peer.DB.Customers(), peer.DB.StripeCoinPayments(),
peer.DB.CoinpaymentsTransactions()) peer.DB.Console().Projects())
peer.Payments.Accounts = service.Accounts() peer.Payments.Accounts = service.Accounts()
peer.Payments.Clearing = stripecoinpayments.NewChore( peer.Payments.Inspector = stripecoinpayments.NewEndpoint(service)
peer.Log.Named("stripecoinpayments clearing loop"),
service, pb.RegisterPaymentsServer(peer.Server.PrivateGRPC(), peer.Payments.Inspector)
config.StripeCoinPayments.TransactionUpdateInterval, pb.DRPCRegisterPayments(peer.Server.PrivateDRPC(), peer.Payments.Inspector)
config.StripeCoinPayments.AccountBalanceUpdateInterval)
} }
} }

View File

@ -61,7 +61,7 @@ func TestGrapqhlMutation(t *testing.T) {
) )
paymentsConfig := stripecoinpayments.Config{} paymentsConfig := stripecoinpayments.Config{}
payments := stripecoinpayments.NewService(log, paymentsConfig, db.Customers(), db.CoinpaymentsTransactions()) payments := stripecoinpayments.NewService(log, paymentsConfig, db.StripeCoinPayments(), db.Console().Projects())
service, err := console.NewService( service, err := console.NewService(
log, log,

View File

@ -43,7 +43,7 @@ func TestGraphqlQuery(t *testing.T) {
) )
paymentsConfig := stripecoinpayments.Config{} paymentsConfig := stripecoinpayments.Config{}
payments := stripecoinpayments.NewService(log, paymentsConfig, db.Customers(), db.CoinpaymentsTransactions()) payments := stripecoinpayments.NewService(log, paymentsConfig, db.StripeCoinPayments(), db.Console().Projects())
service, err := console.NewService( service, err := console.NewService(
log, log,

View File

@ -28,6 +28,8 @@ type Projects interface {
Delete(ctx context.Context, id uuid.UUID) error Delete(ctx context.Context, id uuid.UUID) error
// Update is a method for updating project entity. // Update is a method for updating project entity.
Update(ctx context.Context, project *Project) error Update(ctx context.Context, project *Project) error
// List returns paginated projects, created before provided timestamp.
List(ctx context.Context, offset int64, limit int, before time.Time) (ProjectsPage, error)
} }
// Project is a database object that describes Project entity // Project is a database object that describes Project entity
@ -50,3 +52,12 @@ type ProjectInfo struct {
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
} }
// ProjectsPage returns paginated projects,
// providing next offset if there are more projects
// to retrieve.
type ProjectsPage struct {
Projects []Project
Next bool
NextOffset int64
}

View File

@ -100,7 +100,7 @@ type Core struct {
Payments struct { Payments struct {
Accounts payments.Accounts Accounts payments.Accounts
Clearing payments.Clearing Chore *stripecoinpayments.Chore
} }
GracefulExit struct { GracefulExit struct {
@ -299,11 +299,12 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB, pointerDB metainfo
service := stripecoinpayments.NewService( service := stripecoinpayments.NewService(
peer.Log.Named("stripecoinpayments service"), peer.Log.Named("stripecoinpayments service"),
config.StripeCoinPayments, config.StripeCoinPayments,
peer.DB.Customers(), peer.DB.StripeCoinPayments(),
peer.DB.CoinpaymentsTransactions()) peer.DB.Console().Projects())
peer.Payments.Accounts = service.Accounts() peer.Payments.Accounts = service.Accounts()
peer.Payments.Clearing = stripecoinpayments.NewChore(
peer.Payments.Chore = stripecoinpayments.NewChore(
peer.Log.Named("stripecoinpayments clearing loop"), peer.Log.Named("stripecoinpayments clearing loop"),
service, service,
config.StripeCoinPayments.TransactionUpdateInterval, config.StripeCoinPayments.TransactionUpdateInterval,

View File

@ -1,15 +0,0 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package payments
import "context"
// Clearing runs process of reconciling transactions deposits,
// customer balance, invoices and usages.
type Clearing interface {
// Run runs payments clearing loop.
Run(ctx context.Context) error
// Closes closes payments clearing loop.
Close() error
}

View File

@ -32,7 +32,7 @@ func (accounts *accounts) Invoices() payments.Invoices {
func (accounts *accounts) Setup(ctx context.Context, userID uuid.UUID, email string) (err error) { func (accounts *accounts) Setup(ctx context.Context, userID uuid.UUID, email string) (err error) {
defer mon.Task()(&ctx, userID, email)(&err) defer mon.Task()(&ctx, userID, email)(&err)
_, err = accounts.service.customers.GetCustomerID(ctx, userID) _, err = accounts.service.db.Customers().GetCustomerID(ctx, userID)
if err == nil { if err == nil {
return nil return nil
} }
@ -47,14 +47,14 @@ func (accounts *accounts) Setup(ctx context.Context, userID uuid.UUID, email str
} }
// TODO: delete customer from stripe, if db insertion fails // TODO: delete customer from stripe, if db insertion fails
return Error.Wrap(accounts.service.customers.Insert(ctx, userID, customer.ID)) return Error.Wrap(accounts.service.db.Customers().Insert(ctx, userID, customer.ID))
} }
// Balance returns an integer amount in cents that represents the current balance of payment account. // Balance returns an integer amount in cents that represents the current balance of payment account.
func (accounts *accounts) Balance(ctx context.Context, userID uuid.UUID) (_ int64, err error) { func (accounts *accounts) Balance(ctx context.Context, userID uuid.UUID) (_ int64, err error) {
defer mon.Task()(&ctx, userID)(&err) defer mon.Task()(&ctx, userID)(&err)
customerID, err := accounts.service.customers.GetCustomerID(ctx, userID) customerID, err := accounts.service.db.Customers().GetCustomerID(ctx, userID)
if err != nil { if err != nil {
return 0, Error.Wrap(err) return 0, Error.Wrap(err)
} }

View File

@ -21,7 +21,7 @@ type creditCards struct {
func (creditCards *creditCards) List(ctx context.Context, userID uuid.UUID) (cards []payments.CreditCard, err error) { func (creditCards *creditCards) List(ctx context.Context, userID uuid.UUID) (cards []payments.CreditCard, err error) {
defer mon.Task()(&ctx, userID)(&err) defer mon.Task()(&ctx, userID)(&err)
customerID, err := creditCards.service.customers.GetCustomerID(ctx, userID) customerID, err := creditCards.service.db.Customers().GetCustomerID(ctx, userID)
if err != nil { if err != nil {
return nil, Error.Wrap(err) return nil, Error.Wrap(err)
} }
@ -66,7 +66,7 @@ func (creditCards *creditCards) List(ctx context.Context, userID uuid.UUID) (car
func (creditCards *creditCards) Add(ctx context.Context, userID uuid.UUID, cardToken string) (err error) { func (creditCards *creditCards) Add(ctx context.Context, userID uuid.UUID, cardToken string) (err error) {
defer mon.Task()(&ctx, userID, cardToken)(&err) defer mon.Task()(&ctx, userID, cardToken)(&err)
customerID, err := creditCards.service.customers.GetCustomerID(ctx, userID) customerID, err := creditCards.service.db.Customers().GetCustomerID(ctx, userID)
if err != nil { if err != nil {
return payments.ErrAccountNotSetup.Wrap(err) return payments.ErrAccountNotSetup.Wrap(err)
} }
@ -107,7 +107,7 @@ func (creditCards *creditCards) Add(ctx context.Context, userID uuid.UUID, cardT
func (creditCards *creditCards) MakeDefault(ctx context.Context, userID uuid.UUID, cardID string) (err error) { func (creditCards *creditCards) MakeDefault(ctx context.Context, userID uuid.UUID, cardID string) (err error) {
defer mon.Task()(&ctx, userID, cardID)(&err) defer mon.Task()(&ctx, userID, cardID)(&err)
customerID, err := creditCards.service.customers.GetCustomerID(ctx, userID) customerID, err := creditCards.service.db.Customers().GetCustomerID(ctx, userID)
if err != nil { if err != nil {
return payments.ErrAccountNotSetup.Wrap(err) return payments.ErrAccountNotSetup.Wrap(err)
} }

View File

@ -5,17 +5,37 @@ package stripecoinpayments
import ( import (
"context" "context"
"time"
"github.com/skyrings/skyring-common/tools/uuid" "github.com/skyrings/skyring-common/tools/uuid"
) )
// ErrNoCustomer is error class defining that there is no customer for user.
var ErrNoCustomer = Error.New("customer doesn't exist")
// CustomersDB is interface for working with stripe customers table. // CustomersDB is interface for working with stripe customers table.
// //
// architecture: Database // architecture: Database
type CustomersDB interface { type CustomersDB interface {
// Insert inserts a stripe customer into the database. // Insert inserts a stripe customer into the database.
Insert(ctx context.Context, userID uuid.UUID, customerID string) error Insert(ctx context.Context, userID uuid.UUID, customerID string) error
// GetCustomerID return stripe customers id. // GetCustomerID return stripe customers id.
GetCustomerID(ctx context.Context, userID uuid.UUID) (string, error) GetCustomerID(ctx context.Context, userID uuid.UUID) (string, error)
// List returns page with customers ids created before specified date.
List(ctx context.Context, offset int64, limit int, before time.Time) (CustomersPage, error)
}
// Customer holds customer id and user id.
type Customer struct {
ID string
UserID uuid.UUID
}
// CustomersPage holds customers and
// indicates if there is more data available
// and provides next offset.
type CustomersPage struct {
Customers []Customer
Next bool
NextOffset int64
} }

View File

@ -4,7 +4,9 @@
package stripecoinpayments_test package stripecoinpayments_test
import ( import (
"strconv"
"testing" "testing"
"time"
"github.com/skyrings/skyring-common/tools/uuid" "github.com/skyrings/skyring-common/tools/uuid"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -12,6 +14,7 @@ import (
"storj.io/storj/internal/testcontext" "storj.io/storj/internal/testcontext"
"storj.io/storj/satellite" "storj.io/storj/satellite"
"storj.io/storj/satellite/payments/stripecoinpayments"
"storj.io/storj/satellite/satellitedb/satellitedbtest" "storj.io/storj/satellite/satellitedb/satellitedbtest"
) )
@ -20,7 +23,7 @@ func TestCustomersRepository(t *testing.T) {
ctx := testcontext.New(t) ctx := testcontext.New(t)
defer ctx.Cleanup() defer ctx.Cleanup()
customers := db.Customers() customers := db.StripeCoinPayments().Customers()
customerID := "customerID" customerID := "customerID"
userID, err := uuid.New() userID, err := uuid.New()
@ -43,3 +46,48 @@ func TestCustomersRepository(t *testing.T) {
}) })
}) })
} }
func TestCustomersRepositoryList(t *testing.T) {
satellitedbtest.Run(t, func(t *testing.T, db satellite.DB) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
customersDB := db.StripeCoinPayments().Customers()
const custLen = 5
var customers []stripecoinpayments.Customer
for i := 0; i < custLen; i++ {
userID, err := uuid.New()
require.NoError(t, err)
cus := stripecoinpayments.Customer{
ID: "customerID" + strconv.Itoa(i),
UserID: *userID,
}
err = customersDB.Insert(ctx, cus.UserID, cus.ID)
require.NoError(t, err)
customers = append(customers, cus)
}
page, err := customersDB.List(ctx, 0, custLen, time.Now())
require.NoError(t, err)
require.Equal(t, custLen, len(page.Customers))
assert.False(t, page.Next)
assert.Equal(t, int64(0), page.NextOffset)
for _, cus1 := range page.Customers {
for _, cus2 := range customers {
if cus1.ID != cus2.ID {
continue
}
assert.Equal(t, cus2.ID, cus1.ID)
assert.Equal(t, cus2.UserID, cus1.UserID)
}
}
})
}

View File

@ -0,0 +1,16 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package stripecoinpayments
// DB is stripecoinpayments DB interface.
//
// architecture: Database
type DB interface {
// Customers is getter for customers db.
Customers() CustomersDB
// Transactions is getter for transactions db.
Transactions() TransactionsDB
// ProjectRecords is getter for invoice project records db.
ProjectRecords() ProjectRecordsDB
}

View File

@ -0,0 +1,57 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package stripecoinpayments
import (
"context"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/rpc/rpcstatus"
)
// Endpoint is stripecoinpayments private RPC server payments endpoint.
type Endpoint struct {
service *Service
}
// NewEndpoint creates new endpoint.
func NewEndpoint(service *Service) *Endpoint {
return &Endpoint{service: service}
}
// PrepareInvoiceRecords creates project invoice records for all satellite projects.
func (endpoint *Endpoint) PrepareInvoiceRecords(ctx context.Context, req *pb.PrepareInvoiceRecordsRequest) (_ *pb.PrepareInvoiceRecordsResponse, err error) {
defer mon.Task()(&ctx)(&err)
err = endpoint.service.PrepareInvoiceProjectRecords(ctx, req.Period)
if err != nil {
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
}
return &pb.PrepareInvoiceRecordsResponse{}, nil
}
// ApplyInvoiceRecords creates stripe line items for all unapplied invoice project records.
func (endpoint *Endpoint) ApplyInvoiceRecords(ctx context.Context, req *pb.ApplyInvoiceRecordsRequest) (_ *pb.ApplyInvoiceRecordsResponse, err error) {
defer mon.Task()(&ctx)(&err)
err = endpoint.service.InvoiceApplyProjectRecords(ctx)
if err != nil {
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
}
return &pb.ApplyInvoiceRecordsResponse{}, nil
}
// CreateInvoices creates invoice for all user accounts on the satellite.
func (endpoint *Endpoint) CreateInvoices(ctx context.Context, req *pb.CreateInvoicesRequest) (_ *pb.CreateInvoicesResponse, err error) {
defer mon.Task()(&ctx)(&err)
err = endpoint.service.CreateInvoices(ctx)
if err != nil {
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
}
return &pb.CreateInvoicesResponse{}, nil
}

View File

@ -14,6 +14,8 @@ import (
) )
// invoices is an implementation of payments.Invoices. // invoices is an implementation of payments.Invoices.
//
// architecture: Database
type invoices struct { type invoices struct {
service *Service service *Service
} }
@ -22,7 +24,7 @@ type invoices struct {
func (invoices *invoices) List(ctx context.Context, userID uuid.UUID) (invoicesList []payments.Invoice, err error) { func (invoices *invoices) List(ctx context.Context, userID uuid.UUID) (invoicesList []payments.Invoice, err error) {
defer mon.Task()(&ctx, userID)(&err) defer mon.Task()(&ctx, userID)(&err)
customerID, err := invoices.service.customers.GetCustomerID(ctx, userID) customerID, err := invoices.service.db.Customers().GetCustomerID(ctx, userID)
if err != nil { if err != nil {
return nil, Error.Wrap(err) return nil, Error.Wrap(err)
} }

View File

@ -0,0 +1,57 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package stripecoinpayments
import (
"context"
"time"
"github.com/skyrings/skyring-common/tools/uuid"
)
// ErrProjectRecordExists is error class defining that such project record already exists.
var ErrProjectRecordExists = Error.New("invoice project record already exists")
// ProjectRecordsDB is interface for working with invoice project records.
//
// architecture: Database
type ProjectRecordsDB interface {
// Create creates new invoice project record in the DB.
Create(ctx context.Context, records []CreateProjectRecord, start, end time.Time) error
// Check checks if invoice project record for specified project and billing period exists.
Check(ctx context.Context, projectID uuid.UUID, start, end time.Time) error
// Consume consumes invoice project record.
Consume(ctx context.Context, id uuid.UUID) error
// ListUnapplied returns project records page with unapplied project records.
ListUnapplied(ctx context.Context, offset int64, limit int, before time.Time) (ProjectRecordsPage, error)
}
// CreateProjectRecord holds info needed for creation new invoice
// project record.
type CreateProjectRecord struct {
ProjectID uuid.UUID
Storage float64
Egress int64
Objects int64
}
// ProjectRecord holds project usage particular for billing period.
type ProjectRecord struct {
ID uuid.UUID
ProjectID uuid.UUID
Storage float64
Egress int64
Objects int64
PeriodStart time.Time
PeriodEnd time.Time
}
// ProjectRecordsPage holds project records and
// indicates if there is more data available
// and provides next offset.
type ProjectRecordsPage struct {
Records []ProjectRecord
Next bool
NextOffset int64
}

View File

@ -0,0 +1,127 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package stripecoinpayments_test
import (
"testing"
"time"
"github.com/skyrings/skyring-common/tools/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"storj.io/storj/internal/testcontext"
"storj.io/storj/satellite"
"storj.io/storj/satellite/payments/stripecoinpayments"
"storj.io/storj/satellite/satellitedb/satellitedbtest"
)
func TestProjectRecords(t *testing.T) {
satellitedbtest.Run(t, func(t *testing.T, db satellite.DB) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
utc := time.Now().UTC()
prjID, err := uuid.New()
require.NoError(t, err)
start := time.Date(utc.Year(), utc.Month(), 1, 0, 0, 0, 0, time.UTC)
end := time.Date(utc.Year(), utc.Month()+1, 1, 0, 0, 0, 0, time.UTC)
projectRecordsDB := db.StripeCoinPayments().ProjectRecords()
t.Run("create", func(t *testing.T) {
err = projectRecordsDB.Create(ctx,
[]stripecoinpayments.CreateProjectRecord{
{
ProjectID: *prjID,
Storage: 1,
Egress: 2,
Objects: 3,
},
},
start, end,
)
require.NoError(t, err)
})
t.Run("check", func(t *testing.T) {
err = projectRecordsDB.Check(ctx, *prjID, start, end)
require.Error(t, err)
assert.Equal(t, stripecoinpayments.ErrProjectRecordExists, err)
})
page, err := projectRecordsDB.ListUnapplied(ctx, 0, 1, time.Now())
require.NoError(t, err)
require.Equal(t, 1, len(page.Records))
t.Run("consume", func(t *testing.T) {
err = projectRecordsDB.Consume(ctx, page.Records[0].ID)
require.NoError(t, err)
})
page, err = projectRecordsDB.ListUnapplied(ctx, 0, 1, time.Now())
require.NoError(t, err)
require.Equal(t, 0, len(page.Records))
})
}
func TestProjectRecordsList(t *testing.T) {
satellitedbtest.Run(t, func(t *testing.T, db satellite.DB) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
utc := time.Now().UTC()
start := time.Date(utc.Year(), utc.Month(), 1, 0, 0, 0, 0, time.UTC)
end := time.Date(utc.Year(), utc.Month()+1, 1, 0, 0, 0, 0, time.UTC)
projectRecordsDB := db.StripeCoinPayments().ProjectRecords()
const recordsLen = 5
var createProjectRecords []stripecoinpayments.CreateProjectRecord
for i := 0; i < recordsLen; i++ {
projID, err := uuid.New()
require.NoError(t, err)
createProjectRecords = append(createProjectRecords,
stripecoinpayments.CreateProjectRecord{
ProjectID: *projID,
Storage: float64(i) + 1,
Egress: int64(i) + 2,
Objects: int64(i) + 3,
},
)
}
err := projectRecordsDB.Create(ctx, createProjectRecords, start, end)
require.NoError(t, err)
page, err := projectRecordsDB.ListUnapplied(ctx, 0, recordsLen, time.Now())
require.NoError(t, err)
require.Equal(t, recordsLen, len(page.Records))
assert.False(t, page.Next)
assert.Equal(t, int64(0), page.NextOffset)
for _, record := range page.Records {
for _, createRecord := range createProjectRecords {
if record.ProjectID != createRecord.ProjectID {
continue
}
assert.NotNil(t, record.ID)
assert.Equal(t, 16, len(record.ID))
assert.Equal(t, createRecord.ProjectID, record.ProjectID)
assert.Equal(t, createRecord.Storage, record.Storage)
assert.Equal(t, createRecord.Egress, record.Egress)
assert.Equal(t, createRecord.Objects, record.Objects)
assert.Equal(t, start, record.PeriodStart.UTC())
assert.Equal(t, end, record.PeriodEnd.UTC())
}
}
})
}

View File

@ -5,14 +5,16 @@ package stripecoinpayments
import ( import (
"context" "context"
"fmt"
"time" "time"
"github.com/stripe/stripe-go" "github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/client" "github.com/stripe/stripe-go/client"
"github.com/zeebo/errs" "github.com/zeebo/errs"
"go.uber.org/zap" "go.uber.org/zap"
monkit "gopkg.in/spacemonkeygo/monkit.v2" "gopkg.in/spacemonkeygo/monkit.v2"
"storj.io/storj/satellite/console"
"storj.io/storj/satellite/payments" "storj.io/storj/satellite/payments"
"storj.io/storj/satellite/payments/coinpayments" "storj.io/storj/satellite/payments/coinpayments"
) )
@ -37,15 +39,15 @@ type Config struct {
// //
// architecture: Service // architecture: Service
type Service struct { type Service struct {
log *zap.Logger log *zap.Logger
customers CustomersDB db DB
transactionsDB TransactionsDB projectsDB console.Projects
stripeClient *client.API stripeClient *client.API
coinPayments *coinpayments.Client coinPayments *coinpayments.Client
} }
// NewService creates a Service instance. // NewService creates a Service instance.
func NewService(log *zap.Logger, config Config, customers CustomersDB, transactionsDB TransactionsDB) *Service { func NewService(log *zap.Logger, config Config, db DB, projectsDB console.Projects) *Service {
stripeClient := client.New(config.StripeSecretKey, nil) stripeClient := client.New(config.StripeSecretKey, nil)
coinPaymentsClient := coinpayments.NewClient( coinPaymentsClient := coinpayments.NewClient(
@ -56,11 +58,11 @@ func NewService(log *zap.Logger, config Config, customers CustomersDB, transacti
) )
return &Service{ return &Service{
log: log, log: log,
customers: customers, db: db,
transactionsDB: transactionsDB, projectsDB: projectsDB,
stripeClient: stripeClient, stripeClient: stripeClient,
coinPayments: coinPaymentsClient, coinPayments: coinPaymentsClient,
} }
} }
@ -76,7 +78,7 @@ func (service *Service) updateTransactionsLoop(ctx context.Context) (err error)
const limit = 25 const limit = 25
before := time.Now() before := time.Now()
txsPage, err := service.transactionsDB.ListPending(ctx, 0, limit, before) txsPage, err := service.db.Transactions().ListPending(ctx, 0, limit, before)
if err != nil { if err != nil {
return err return err
} }
@ -90,7 +92,7 @@ func (service *Service) updateTransactionsLoop(ctx context.Context) (err error)
return err return err
} }
txsPage, err = service.transactionsDB.ListPending(ctx, txsPage.NextOffset, limit, before) txsPage, err = service.db.Transactions().ListPending(ctx, txsPage.NextOffset, limit, before)
if err != nil { if err != nil {
return err return err
} }
@ -138,7 +140,7 @@ func (service *Service) updateTransactions(ctx context.Context, ids coinpayments
} }
} }
return service.transactionsDB.Update(ctx, updates, applies) return service.db.Transactions().Update(ctx, updates, applies)
} }
// applyAccountBalanceLoop fetches all unapplied transaction in a loop, applying transaction // applyAccountBalanceLoop fetches all unapplied transaction in a loop, applying transaction
@ -149,7 +151,7 @@ func (service *Service) updateAccountBalanceLoop(ctx context.Context) (err error
const limit = 25 const limit = 25
before := time.Now() before := time.Now()
txsPage, err := service.transactionsDB.ListUnapplied(ctx, 0, limit, before) txsPage, err := service.db.Transactions().ListUnapplied(ctx, 0, limit, before)
if err != nil { if err != nil {
return err return err
} }
@ -169,7 +171,7 @@ func (service *Service) updateAccountBalanceLoop(ctx context.Context) (err error
return err return err
} }
txsPage, err := service.transactionsDB.ListUnapplied(ctx, txsPage.NextOffset, limit, before) txsPage, err := service.db.Transactions().ListUnapplied(ctx, txsPage.NextOffset, limit, before)
if err != nil { if err != nil {
return err return err
} }
@ -192,12 +194,12 @@ func (service *Service) updateAccountBalanceLoop(ctx context.Context) (err error
func (service *Service) applyTransactionBalance(ctx context.Context, tx Transaction) (err error) { func (service *Service) applyTransactionBalance(ctx context.Context, tx Transaction) (err error) {
defer mon.Task()(&ctx)(&err) defer mon.Task()(&ctx)(&err)
cusID, err := service.customers.GetCustomerID(ctx, tx.AccountID) cusID, err := service.db.Customers().GetCustomerID(ctx, tx.AccountID)
if err != nil { if err != nil {
return err return err
} }
if err = service.transactionsDB.Consume(ctx, tx.ID); err != nil { if err = service.db.Transactions().Consume(ctx, tx.ID); err != nil {
return err return err
} }
@ -216,3 +218,243 @@ func (service *Service) applyTransactionBalance(ctx context.Context, tx Transact
_, err = service.stripeClient.CustomerBalanceTransactions.New(params) _, err = service.stripeClient.CustomerBalanceTransactions.New(params)
return err return err
} }
// PrepareInvoiceProjectRecords iterates through all projects and creates invoice records if
// none exists.
func (service *Service) PrepareInvoiceProjectRecords(ctx context.Context, period time.Time) (err error) {
defer mon.Task()(&ctx)(&err)
const limit = 25
now := time.Now().UTC()
utc := period.UTC()
start := time.Date(utc.Year(), utc.Month(), 1, 0, 0, 0, 0, time.UTC)
end := time.Date(utc.Year(), utc.Month()+1, 1, 0, 0, 0, 0, time.UTC)
if end.After(now) {
return Error.New("prepare is for past periods only")
}
projsPage, err := service.projectsDB.List(ctx, 0, limit, end)
if err != nil {
return Error.Wrap(err)
}
if err = service.createProjectRecords(ctx, projsPage.Projects, start, end); err != nil {
return Error.Wrap(err)
}
for projsPage.Next {
if err = ctx.Err(); err != nil {
return Error.Wrap(err)
}
projsPage, err = service.projectsDB.List(ctx, projsPage.NextOffset, limit, end)
if err != nil {
return Error.Wrap(err)
}
if err = service.createProjectRecords(ctx, projsPage.Projects, start, end); err != nil {
return Error.Wrap(err)
}
}
return nil
}
// createProjectRecords creates invoice project record if none exists.
func (service *Service) createProjectRecords(ctx context.Context, projects []console.Project, start, end time.Time) (err error) {
defer mon.Task()(&ctx)(&err)
var records []CreateProjectRecord
for _, project := range projects {
if err = ctx.Err(); err != nil {
return err
}
if err = service.db.ProjectRecords().Check(ctx, project.ID, start, end); err != nil {
if err == ErrProjectRecordExists {
continue
}
return err
}
// TODO: account for usage data.
records = append(records,
CreateProjectRecord{
ProjectID: project.ID,
Storage: 0,
Egress: 0,
Objects: 0,
},
)
}
return service.db.ProjectRecords().Create(ctx, records, start, end)
}
// InvoiceApplyProjectRecords iterates through unapplied invoice project records and creates invoice line items
// for stripe customer.
func (service *Service) InvoiceApplyProjectRecords(ctx context.Context) (err error) {
defer mon.Task()(&ctx)(&err)
const limit = 25
before := time.Now()
recordsPage, err := service.db.ProjectRecords().ListUnapplied(ctx, 0, limit, before)
if err != nil {
return Error.Wrap(err)
}
if err = service.applyProjectRecords(ctx, recordsPage.Records); err != nil {
return Error.Wrap(err)
}
for recordsPage.Next {
if err = ctx.Err(); err != nil {
return Error.Wrap(err)
}
recordsPage, err = service.db.ProjectRecords().ListUnapplied(ctx, recordsPage.NextOffset, limit, before)
if err != nil {
return Error.Wrap(err)
}
if err = service.applyProjectRecords(ctx, recordsPage.Records); err != nil {
return Error.Wrap(err)
}
}
return nil
}
// applyProjectRecords applies invoice intents as invoice line items to stripe customer.
func (service *Service) applyProjectRecords(ctx context.Context, records []ProjectRecord) (err error) {
defer mon.Task()(&ctx)(&err)
for _, record := range records {
if err = ctx.Err(); err != nil {
return err
}
proj, err := service.projectsDB.Get(ctx, record.ProjectID)
if err != nil {
return err
}
cusID, err := service.db.Customers().GetCustomerID(ctx, proj.OwnerID)
if err != nil {
if err == ErrNoCustomer {
continue
}
return err
}
if err = service.createInvoiceItems(ctx, cusID, proj.Name, record); err != nil {
return err
}
}
return nil
}
// createInvoiceItems consumes invoice project record and creates invoice line items for stripe customer.
func (service *Service) createInvoiceItems(ctx context.Context, cusID, projName string, record ProjectRecord) (err error) {
defer mon.Task()(&ctx)(&err)
if err = service.db.ProjectRecords().Consume(ctx, record.ID); err != nil {
return err
}
// TODO: add and apply pricing.
projectItem := &stripe.InvoiceItemParams{
Amount: stripe.Int64(0),
Currency: stripe.String(string(stripe.CurrencyUSD)),
Customer: stripe.String(cusID),
Description: stripe.String(fmt.Sprintf("project %s", projName)),
Period: &stripe.InvoiceItemPeriodParams{
End: stripe.Int64(record.PeriodEnd.Unix()),
Start: stripe.Int64(record.PeriodStart.Unix()),
},
}
projectItem.AddMetadata("projectID", record.ProjectID.String())
_, err = service.stripeClient.InvoiceItems.New(projectItem)
return err
}
// CreateInvoices lists through all customers and creates invoices.
func (service *Service) CreateInvoices(ctx context.Context) (err error) {
defer mon.Task()(&ctx)(&err)
const limit = 25
before := time.Now()
cusPage, err := service.db.Customers().List(ctx, 0, limit, before)
if err != nil {
return Error.Wrap(err)
}
for _, cus := range cusPage.Customers {
if err = ctx.Err(); err != nil {
return Error.Wrap(err)
}
if err = service.createInvoice(ctx, cus.ID); err != nil {
return Error.Wrap(err)
}
}
for cusPage.Next {
if err = ctx.Err(); err != nil {
return Error.Wrap(err)
}
cusPage, err = service.db.Customers().List(ctx, cusPage.NextOffset, limit, before)
if err != nil {
return Error.Wrap(err)
}
for _, cus := range cusPage.Customers {
if err = ctx.Err(); err != nil {
return Error.Wrap(err)
}
if err = service.createInvoice(ctx, cus.ID); err != nil {
return Error.Wrap(err)
}
}
}
return nil
}
// createInvoice creates invoice for stripe customer. Returns nil error if there are no
// pending invoice line items for customer.
func (service *Service) createInvoice(ctx context.Context, cusID string) (err error) {
defer mon.Task()(&ctx)(&err)
_, err = service.stripeClient.Invoices.New(
&stripe.InvoiceParams{
Customer: stripe.String(cusID),
AutoAdvance: stripe.Bool(true),
},
)
if err != nil {
if stripeErr, ok := err.(*stripe.Error); ok {
switch stripeErr.Code {
case stripe.ErrorCodeInvoiceNoCustomerLineItems:
return nil
default:
return err
}
}
}
return nil
}

View File

@ -28,7 +28,7 @@ type storjTokens struct {
func (tokens *storjTokens) Deposit(ctx context.Context, userID uuid.UUID, amount big.Float) (_ *payments.Transaction, err error) { func (tokens *storjTokens) Deposit(ctx context.Context, userID uuid.UUID, amount big.Float) (_ *payments.Transaction, err error) {
defer mon.Task()(&ctx, userID, amount)(&err) defer mon.Task()(&ctx, userID, amount)(&err)
customerID, err := tokens.service.customers.GetCustomerID(ctx, userID) customerID, err := tokens.service.db.Customers().GetCustomerID(ctx, userID)
if err != nil { if err != nil {
return nil, Error.Wrap(err) return nil, Error.Wrap(err)
} }
@ -55,7 +55,7 @@ func (tokens *storjTokens) Deposit(ctx context.Context, userID uuid.UUID, amount
return nil, Error.Wrap(err) return nil, Error.Wrap(err)
} }
cpTX, err := tokens.service.transactionsDB.Insert(ctx, cpTX, err := tokens.service.db.Transactions().Insert(ctx,
Transaction{ Transaction{
ID: tx.ID, ID: tx.ID,
AccountID: userID, AccountID: userID,

View File

@ -22,12 +22,12 @@ import (
"storj.io/storj/satellite/satellitedb/satellitedbtest" "storj.io/storj/satellite/satellitedb/satellitedbtest"
) )
func TestInsertUpdateConsume(t *testing.T) { func TestTransactionsDB(t *testing.T) {
satellitedbtest.Run(t, func(t *testing.T, db satellite.DB) { satellitedbtest.Run(t, func(t *testing.T, db satellite.DB) {
ctx := testcontext.New(t) ctx := testcontext.New(t)
defer ctx.Cleanup() defer ctx.Cleanup()
transactions := db.CoinpaymentsTransactions() transactions := db.StripeCoinPayments().Transactions()
amount, ok := new(big.Float).SetPrec(1000).SetString("2.0000000000000000005") amount, ok := new(big.Float).SetPrec(1000).SetString("2.0000000000000000005")
require.True(t, ok) require.True(t, ok)
@ -111,7 +111,7 @@ func TestInsertUpdateConsume(t *testing.T) {
}) })
} }
func TestList(t *testing.T) { func TestTransactionsDBList(t *testing.T) {
ctx := testcontext.New(t) ctx := testcontext.New(t)
defer ctx.Cleanup() defer ctx.Cleanup()
@ -146,11 +146,11 @@ func TestList(t *testing.T) {
t.Run("pending transactions", func(t *testing.T) { t.Run("pending transactions", func(t *testing.T) {
satellitedbtest.Run(t, func(t *testing.T, db satellite.DB) { satellitedbtest.Run(t, func(t *testing.T, db satellite.DB) {
for _, tx := range txs { for _, tx := range txs {
_, err := db.CoinpaymentsTransactions().Insert(ctx, tx) _, err := db.StripeCoinPayments().Transactions().Insert(ctx, tx)
require.NoError(t, err) require.NoError(t, err)
} }
page, err := db.CoinpaymentsTransactions().ListPending(ctx, 0, transactionCount, time.Now()) page, err := db.StripeCoinPayments().Transactions().ListPending(ctx, 0, transactionCount, time.Now())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, transactionCount, len(page.Transactions)) require.Equal(t, transactionCount, len(page.Transactions))
@ -171,7 +171,7 @@ func TestList(t *testing.T) {
var applies coinpayments.TransactionIDList var applies coinpayments.TransactionIDList
for _, tx := range txs { for _, tx := range txs {
_, err := db.CoinpaymentsTransactions().Insert(ctx, tx) _, err := db.StripeCoinPayments().Transactions().Insert(ctx, tx)
require.NoError(t, err) require.NoError(t, err)
tx.Status = coinpayments.StatusReceived tx.Status = coinpayments.StatusReceived
@ -188,10 +188,10 @@ func TestList(t *testing.T) {
updatedTxs = append(updatedTxs, tx) updatedTxs = append(updatedTxs, tx)
} }
err := db.CoinpaymentsTransactions().Update(ctx, updates, applies) err := db.StripeCoinPayments().Transactions().Update(ctx, updates, applies)
require.NoError(t, err) require.NoError(t, err)
page, err := db.CoinpaymentsTransactions().ListUnapplied(ctx, 0, transactionCount, time.Now()) page, err := db.StripeCoinPayments().Transactions().ListUnapplied(ctx, 0, transactionCount, time.Now())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, transactionCount, len(page.Transactions)) require.Equal(t, transactionCount, len(page.Transactions))

View File

@ -79,10 +79,8 @@ type DB interface {
Buckets() metainfo.BucketsDB Buckets() metainfo.BucketsDB
// GracefulExit returns database for graceful exit // GracefulExit returns database for graceful exit
GracefulExit() gracefulexit.DB GracefulExit() gracefulexit.DB
// StripeCustomers returns table for storing stripe customers // StripeCoinPayments returns stripecoinpayments database.
Customers() stripecoinpayments.CustomersDB StripeCoinPayments() stripecoinpayments.DB
// CoinpaymentsTransactions returns db for storing coinpayments transactions.
CoinpaymentsTransactions() stripecoinpayments.TransactionsDB
} }
// Config is the global config satellite // Config is the global config satellite

View File

@ -15,8 +15,8 @@ import (
dbx "storj.io/storj/satellite/satellitedb/dbx" dbx "storj.io/storj/satellite/satellitedb/dbx"
) )
// ensure that coinpaymentsTransaction implements stripecoinpayments.TransactionsDB. // ensure that coinpaymentsTransactions implements stripecoinpayments.TransactionsDB.
var _ stripecoinpayments.TransactionsDB = (*coinpaymentsTransactions)(nil) var _ stripecoinpayments.TransactionsDB = (*coinPaymentsTransactions)(nil)
// applyBalanceIntentState defines states of the apply balance intents. // applyBalanceIntentState defines states of the apply balance intents.
type applyBalanceIntentState int type applyBalanceIntentState int
@ -33,15 +33,15 @@ func (intent applyBalanceIntentState) Int() int {
return int(intent) return int(intent)
} }
// coinpaymentsTransactions is Coinpayments transactions DB. // coinPaymentsTransactions is CoinPayments transactions DB.
// //
// architecture: Database // architecture: Database
type coinpaymentsTransactions struct { type coinPaymentsTransactions struct {
db *dbx.DB db *dbx.DB
} }
// Insert inserts new coinpayments transaction into DB. // Insert inserts new coinpayments transaction into DB.
func (db *coinpaymentsTransactions) Insert(ctx context.Context, tx stripecoinpayments.Transaction) (*stripecoinpayments.Transaction, error) { func (db *coinPaymentsTransactions) Insert(ctx context.Context, tx stripecoinpayments.Transaction) (*stripecoinpayments.Transaction, error) {
amount, err := tx.Amount.GobEncode() amount, err := tx.Amount.GobEncode()
if err != nil { if err != nil {
return nil, errs.Wrap(err) return nil, errs.Wrap(err)
@ -68,7 +68,7 @@ func (db *coinpaymentsTransactions) Insert(ctx context.Context, tx stripecoinpay
} }
// Update updates status and received for set of transactions. // Update updates status and received for set of transactions.
func (db *coinpaymentsTransactions) Update(ctx context.Context, updates []stripecoinpayments.TransactionUpdate, applies coinpayments.TransactionIDList) error { func (db *coinPaymentsTransactions) Update(ctx context.Context, updates []stripecoinpayments.TransactionUpdate, applies coinpayments.TransactionIDList) error {
if len(updates) == 0 { if len(updates) == 0 {
return nil return nil
} }
@ -106,7 +106,7 @@ func (db *coinpaymentsTransactions) Update(ctx context.Context, updates []stripe
} }
// Consume marks transaction as consumed, so it won't participate in apply account balance loop. // Consume marks transaction as consumed, so it won't participate in apply account balance loop.
func (db *coinpaymentsTransactions) Consume(ctx context.Context, id coinpayments.TransactionID) error { func (db *coinPaymentsTransactions) Consume(ctx context.Context, id coinpayments.TransactionID) error {
_, err := db.db.Update_StripecoinpaymentsApplyBalanceIntent_By_TxId(ctx, _, err := db.db.Update_StripecoinpaymentsApplyBalanceIntent_By_TxId(ctx,
dbx.StripecoinpaymentsApplyBalanceIntent_TxId(id.String()), dbx.StripecoinpaymentsApplyBalanceIntent_TxId(id.String()),
dbx.StripecoinpaymentsApplyBalanceIntent_Update_Fields{ dbx.StripecoinpaymentsApplyBalanceIntent_Update_Fields{
@ -117,7 +117,7 @@ func (db *coinpaymentsTransactions) Consume(ctx context.Context, id coinpayments
} }
// ListPending returns paginated list of pending transactions. // ListPending returns paginated list of pending transactions.
func (db *coinpaymentsTransactions) ListPending(ctx context.Context, offset int64, limit int, before time.Time) (stripecoinpayments.TransactionsPage, error) { func (db *coinPaymentsTransactions) ListPending(ctx context.Context, offset int64, limit int, before time.Time) (stripecoinpayments.TransactionsPage, error) {
var page stripecoinpayments.TransactionsPage var page stripecoinpayments.TransactionsPage
dbxTXs, err := db.db.Limited_CoinpaymentsTransaction_By_CreatedAt_LessOrEqual_And_Status_OrderBy_Desc_CreatedAt( dbxTXs, err := db.db.Limited_CoinpaymentsTransaction_By_CreatedAt_LessOrEqual_And_Status_OrderBy_Desc_CreatedAt(
@ -153,7 +153,7 @@ func (db *coinpaymentsTransactions) ListPending(ctx context.Context, offset int6
} }
// List Unapplied returns TransactionsPage with transactions completed transaction that should be applied to account balance. // List Unapplied returns TransactionsPage with transactions completed transaction that should be applied to account balance.
func (db *coinpaymentsTransactions) ListUnapplied(ctx context.Context, offset int64, limit int, before time.Time) (_ stripecoinpayments.TransactionsPage, err error) { func (db *coinPaymentsTransactions) ListUnapplied(ctx context.Context, offset int64, limit int, before time.Time) (_ stripecoinpayments.TransactionsPage, err error) {
query := db.db.Rebind(`SELECT query := db.db.Rebind(`SELECT
txs.id, txs.id,
txs.user_id, txs.user_id,

View File

@ -5,6 +5,8 @@ package satellitedb
import ( import (
"context" "context"
"database/sql"
"time"
"github.com/skyrings/skyring-common/tools/uuid" "github.com/skyrings/skyring-common/tools/uuid"
@ -16,6 +18,8 @@ import (
var _ stripecoinpayments.CustomersDB = (*customers)(nil) var _ stripecoinpayments.CustomersDB = (*customers)(nil)
// customers is an implementation of stripecoinpayments.CustomersDB. // customers is an implementation of stripecoinpayments.CustomersDB.
//
// architecture: Database
type customers struct { type customers struct {
db *dbx.DB db *dbx.DB
} }
@ -39,8 +43,59 @@ func (customers *customers) GetCustomerID(ctx context.Context, userID uuid.UUID)
idRow, err := customers.db.Get_StripeCustomer_CustomerId_By_UserId(ctx, dbx.StripeCustomer_UserId(userID[:])) idRow, err := customers.db.Get_StripeCustomer_CustomerId_By_UserId(ctx, dbx.StripeCustomer_UserId(userID[:]))
if err != nil { if err != nil {
if err == sql.ErrNoRows {
return "", stripecoinpayments.ErrNoCustomer
}
return "", err return "", err
} }
return idRow.CustomerId, nil return idRow.CustomerId, nil
} }
// List returns paginated customers id list, with customers created before specified date.
func (customers *customers) List(ctx context.Context, offset int64, limit int, before time.Time) (_ stripecoinpayments.CustomersPage, err error) {
defer mon.Task()(&ctx)(&err)
var page stripecoinpayments.CustomersPage
dbxCustomers, err := customers.db.Limited_StripeCustomer_By_CreatedAt_LessOrEqual_OrderBy_Desc_CreatedAt(ctx,
dbx.StripeCustomer_CreatedAt(before),
limit+1,
offset,
)
if err != nil {
return stripecoinpayments.CustomersPage{}, err
}
if len(dbxCustomers) == limit+1 {
page.Next = true
page.NextOffset = offset + int64(limit) + 1
dbxCustomers = dbxCustomers[:len(dbxCustomers)-1]
}
for _, dbxCustomer := range dbxCustomers {
cus, err := fromDBXCustomer(dbxCustomer)
if err != nil {
return stripecoinpayments.CustomersPage{}, err
}
page.Customers = append(page.Customers, *cus)
}
return page, nil
}
// fromDBXCustomer converts *dbx.StripeCustomer to *stripecoinpayments.Customer.
func fromDBXCustomer(dbxCustomer *dbx.StripeCustomer) (*stripecoinpayments.Customer, error) {
userID, err := bytesToUUID(dbxCustomer.UserId)
if err != nil {
return nil, err
}
return &stripecoinpayments.Customer{
ID: dbxCustomer.CustomerId,
UserID: userID,
}, nil
}

View File

@ -144,12 +144,7 @@ func (db *DB) GracefulExit() gracefulexit.DB {
return &gracefulexitDB{db: db.db} return &gracefulexitDB{db: db.db}
} }
// Customers returns database for dealing with stripe customers. // StripeCoinPayments returns database for stripecoinpayments.
func (db *DB) Customers() stripecoinpayments.CustomersDB { func (db *DB) StripeCoinPayments() stripecoinpayments.DB {
return &customers{db: db.db} return &stripeCoinPaymentsDB{db: db.db}
}
// CoinpaymentsTransactions returns database for dealing with coinpayments transactions.
func (db *DB) CoinpaymentsTransactions() stripecoinpayments.TransactionsDB {
return &coinpaymentsTransactions{db: db.db}
} }

View File

@ -292,6 +292,12 @@ read all (
orderby asc project.name orderby asc project.name
) )
read limitoffset (
select project
where project.created_at < ?
orderby asc project.created_at
)
model project_invoice_stamp ( model project_invoice_stamp (
key project_id start_date end_date key project_id start_date end_date
unique invoice_id unique invoice_id
@ -556,7 +562,7 @@ model peer_identity (
field node_id blob field node_id blob
field leaf_serial_number blob (updatable) field leaf_serial_number blob (updatable)
field chain blob (updatable) // x509 ASN.1 DER content field chain blob (updatable) // x509 ASN.1 DER content
field updated_at timestamp ( autoinsert, autoupdate ) field updated_at timestamp ( autoinsert, autoupdate )
) )
@ -775,14 +781,14 @@ model graceful_exit_progress (
) )
create graceful_exit_progress ( noreturn ) create graceful_exit_progress ( noreturn )
update graceful_exit_progress ( update graceful_exit_progress (
where graceful_exit_progress.node_id = ? where graceful_exit_progress.node_id = ?
noreturn noreturn
) )
delete graceful_exit_progress ( where graceful_exit_progress.node_id = ? ) delete graceful_exit_progress ( where graceful_exit_progress.node_id = ? )
read one ( read one (
select graceful_exit_progress select graceful_exit_progress
where graceful_exit_progress.node_id = ? where graceful_exit_progress.node_id = ?
) )
//--- graceful exit transfer queue ---// //--- graceful exit transfer queue ---//
@ -795,37 +801,37 @@ model graceful_exit_transfer_queue (
field path blob field path blob
field piece_num int field piece_num int
field durability_ratio float64 ( updatable ) field durability_ratio float64 ( updatable )
field queued_at utimestamp ( autoinsert ) field queued_at utimestamp ( autoinsert )
field requested_at utimestamp ( updatable, nullable ) field requested_at utimestamp ( updatable, nullable )
field last_failed_at utimestamp ( updatable, nullable ) field last_failed_at utimestamp ( updatable, nullable )
field last_failed_code int ( updatable, nullable ) field last_failed_code int ( updatable, nullable )
field failed_count int ( updatable, nullable ) field failed_count int ( updatable, nullable )
field finished_at utimestamp ( updatable, nullable ) field finished_at utimestamp ( updatable, nullable )
) )
create graceful_exit_transfer_queue ( noreturn ) create graceful_exit_transfer_queue ( noreturn )
update graceful_exit_transfer_queue ( update graceful_exit_transfer_queue (
where graceful_exit_transfer_queue.node_id = ? where graceful_exit_transfer_queue.node_id = ?
where graceful_exit_transfer_queue.path = ? where graceful_exit_transfer_queue.path = ?
where graceful_exit_transfer_queue.piece_num = ? where graceful_exit_transfer_queue.piece_num = ?
noreturn noreturn
) )
delete graceful_exit_transfer_queue ( delete graceful_exit_transfer_queue (
where graceful_exit_transfer_queue.node_id = ? where graceful_exit_transfer_queue.node_id = ?
) )
delete graceful_exit_transfer_queue ( delete graceful_exit_transfer_queue (
where graceful_exit_transfer_queue.node_id = ? where graceful_exit_transfer_queue.node_id = ?
where graceful_exit_transfer_queue.path = ? where graceful_exit_transfer_queue.path = ?
where graceful_exit_transfer_queue.piece_num = ? where graceful_exit_transfer_queue.piece_num = ?
) )
delete graceful_exit_transfer_queue ( delete graceful_exit_transfer_queue (
where graceful_exit_transfer_queue.node_id = ? where graceful_exit_transfer_queue.node_id = ?
where graceful_exit_transfer_queue.finished_at != null where graceful_exit_transfer_queue.finished_at != null
) )
read one ( read one (
select graceful_exit_transfer_queue select graceful_exit_transfer_queue
where graceful_exit_transfer_queue.node_id = ? where graceful_exit_transfer_queue.node_id = ?
where graceful_exit_transfer_queue.path = ? where graceful_exit_transfer_queue.path = ?
@ -844,10 +850,16 @@ model stripe_customer (
) )
create stripe_customer ( ) create stripe_customer ( )
read one ( read one (
select stripe_customer.customer_id select stripe_customer.customer_id
where stripe_customer.user_id = ? where stripe_customer.user_id = ?
) )
read limitoffset (
select stripe_customer
where stripe_customer.created_at <= ?
orderby desc stripe_customer.created_at
)
model coinpayments_transaction ( model coinpayments_transaction (
key id key id
@ -890,3 +902,40 @@ delete stripecoinpayments_apply_balance_intent (
where stripecoinpayments_apply_balance_intent.tx_id = ? where stripecoinpayments_apply_balance_intent.tx_id = ?
) )
model stripecoinpayments_invoice_project_record (
key id
unique project_id period_start period_end
field id blob
field project_id blob
field storage float64
field egress int64
field objects int64
field period_start timestamp
field period_end timestamp
field state int ( updatable )
field created_at timestamp ( autoinsert )
)
create stripecoinpayments_invoice_project_record ()
update stripecoinpayments_invoice_project_record (
where stripecoinpayments_invoice_project_record.id = ?
)
delete stripecoinpayments_invoice_project_record (
where stripecoinpayments_invoice_project_record.id = ?
)
read one (
select stripecoinpayments_invoice_project_record
where stripecoinpayments_invoice_project_record.project_id = ?
where stripecoinpayments_invoice_project_record.period_start = ?
where stripecoinpayments_invoice_project_record.period_end = ?
)
read limitoffset (
select stripecoinpayments_invoice_project_record
where stripecoinpayments_invoice_project_record.created_at <= ?
where stripecoinpayments_invoice_project_record.state = ?
orderby desc stripecoinpayments_invoice_project_record.created_at
)

View File

@ -476,6 +476,19 @@ CREATE TABLE stripe_customers (
PRIMARY KEY ( user_id ), PRIMARY KEY ( user_id ),
UNIQUE ( customer_id ) UNIQUE ( customer_id )
); );
CREATE TABLE stripecoinpayments_invoice_project_records (
id bytea NOT NULL,
project_id bytea NOT NULL,
storage double precision NOT NULL,
egress bigint NOT NULL,
objects bigint NOT NULL,
period_start timestamp with time zone NOT NULL,
period_end timestamp with time zone NOT NULL,
state integer NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( id ),
UNIQUE ( project_id, period_start, period_end )
);
CREATE TABLE users ( CREATE TABLE users (
id bytea NOT NULL, id bytea NOT NULL,
email text NOT NULL, email text NOT NULL,
@ -4078,6 +4091,199 @@ func (f StripeCustomer_CreatedAt_Field) value() interface{} {
func (StripeCustomer_CreatedAt_Field) _Column() string { return "created_at" } func (StripeCustomer_CreatedAt_Field) _Column() string { return "created_at" }
type StripecoinpaymentsInvoiceProjectRecord struct {
Id []byte
ProjectId []byte
Storage float64
Egress int64
Objects int64
PeriodStart time.Time
PeriodEnd time.Time
State int
CreatedAt time.Time
}
func (StripecoinpaymentsInvoiceProjectRecord) _Table() string {
return "stripecoinpayments_invoice_project_records"
}
type StripecoinpaymentsInvoiceProjectRecord_Update_Fields struct {
State StripecoinpaymentsInvoiceProjectRecord_State_Field
}
type StripecoinpaymentsInvoiceProjectRecord_Id_Field struct {
_set bool
_null bool
_value []byte
}
func StripecoinpaymentsInvoiceProjectRecord_Id(v []byte) StripecoinpaymentsInvoiceProjectRecord_Id_Field {
return StripecoinpaymentsInvoiceProjectRecord_Id_Field{_set: true, _value: v}
}
func (f StripecoinpaymentsInvoiceProjectRecord_Id_Field) value() interface{} {
if !f._set || f._null {
return nil
}
return f._value
}
func (StripecoinpaymentsInvoiceProjectRecord_Id_Field) _Column() string { return "id" }
type StripecoinpaymentsInvoiceProjectRecord_ProjectId_Field struct {
_set bool
_null bool
_value []byte
}
func StripecoinpaymentsInvoiceProjectRecord_ProjectId(v []byte) StripecoinpaymentsInvoiceProjectRecord_ProjectId_Field {
return StripecoinpaymentsInvoiceProjectRecord_ProjectId_Field{_set: true, _value: v}
}
func (f StripecoinpaymentsInvoiceProjectRecord_ProjectId_Field) value() interface{} {
if !f._set || f._null {
return nil
}
return f._value
}
func (StripecoinpaymentsInvoiceProjectRecord_ProjectId_Field) _Column() string { return "project_id" }
type StripecoinpaymentsInvoiceProjectRecord_Storage_Field struct {
_set bool
_null bool
_value float64
}
func StripecoinpaymentsInvoiceProjectRecord_Storage(v float64) StripecoinpaymentsInvoiceProjectRecord_Storage_Field {
return StripecoinpaymentsInvoiceProjectRecord_Storage_Field{_set: true, _value: v}
}
func (f StripecoinpaymentsInvoiceProjectRecord_Storage_Field) value() interface{} {
if !f._set || f._null {
return nil
}
return f._value
}
func (StripecoinpaymentsInvoiceProjectRecord_Storage_Field) _Column() string { return "storage" }
type StripecoinpaymentsInvoiceProjectRecord_Egress_Field struct {
_set bool
_null bool
_value int64
}
func StripecoinpaymentsInvoiceProjectRecord_Egress(v int64) StripecoinpaymentsInvoiceProjectRecord_Egress_Field {
return StripecoinpaymentsInvoiceProjectRecord_Egress_Field{_set: true, _value: v}
}
func (f StripecoinpaymentsInvoiceProjectRecord_Egress_Field) value() interface{} {
if !f._set || f._null {
return nil
}
return f._value
}
func (StripecoinpaymentsInvoiceProjectRecord_Egress_Field) _Column() string { return "egress" }
type StripecoinpaymentsInvoiceProjectRecord_Objects_Field struct {
_set bool
_null bool
_value int64
}
func StripecoinpaymentsInvoiceProjectRecord_Objects(v int64) StripecoinpaymentsInvoiceProjectRecord_Objects_Field {
return StripecoinpaymentsInvoiceProjectRecord_Objects_Field{_set: true, _value: v}
}
func (f StripecoinpaymentsInvoiceProjectRecord_Objects_Field) value() interface{} {
if !f._set || f._null {
return nil
}
return f._value
}
func (StripecoinpaymentsInvoiceProjectRecord_Objects_Field) _Column() string { return "objects" }
type StripecoinpaymentsInvoiceProjectRecord_PeriodStart_Field struct {
_set bool
_null bool
_value time.Time
}
func StripecoinpaymentsInvoiceProjectRecord_PeriodStart(v time.Time) StripecoinpaymentsInvoiceProjectRecord_PeriodStart_Field {
return StripecoinpaymentsInvoiceProjectRecord_PeriodStart_Field{_set: true, _value: v}
}
func (f StripecoinpaymentsInvoiceProjectRecord_PeriodStart_Field) value() interface{} {
if !f._set || f._null {
return nil
}
return f._value
}
func (StripecoinpaymentsInvoiceProjectRecord_PeriodStart_Field) _Column() string {
return "period_start"
}
type StripecoinpaymentsInvoiceProjectRecord_PeriodEnd_Field struct {
_set bool
_null bool
_value time.Time
}
func StripecoinpaymentsInvoiceProjectRecord_PeriodEnd(v time.Time) StripecoinpaymentsInvoiceProjectRecord_PeriodEnd_Field {
return StripecoinpaymentsInvoiceProjectRecord_PeriodEnd_Field{_set: true, _value: v}
}
func (f StripecoinpaymentsInvoiceProjectRecord_PeriodEnd_Field) value() interface{} {
if !f._set || f._null {
return nil
}
return f._value
}
func (StripecoinpaymentsInvoiceProjectRecord_PeriodEnd_Field) _Column() string { return "period_end" }
type StripecoinpaymentsInvoiceProjectRecord_State_Field struct {
_set bool
_null bool
_value int
}
func StripecoinpaymentsInvoiceProjectRecord_State(v int) StripecoinpaymentsInvoiceProjectRecord_State_Field {
return StripecoinpaymentsInvoiceProjectRecord_State_Field{_set: true, _value: v}
}
func (f StripecoinpaymentsInvoiceProjectRecord_State_Field) value() interface{} {
if !f._set || f._null {
return nil
}
return f._value
}
func (StripecoinpaymentsInvoiceProjectRecord_State_Field) _Column() string { return "state" }
type StripecoinpaymentsInvoiceProjectRecord_CreatedAt_Field struct {
_set bool
_null bool
_value time.Time
}
func StripecoinpaymentsInvoiceProjectRecord_CreatedAt(v time.Time) StripecoinpaymentsInvoiceProjectRecord_CreatedAt_Field {
return StripecoinpaymentsInvoiceProjectRecord_CreatedAt_Field{_set: true, _value: v}
}
func (f StripecoinpaymentsInvoiceProjectRecord_CreatedAt_Field) value() interface{} {
if !f._set || f._null {
return nil
}
return f._value
}
func (StripecoinpaymentsInvoiceProjectRecord_CreatedAt_Field) _Column() string { return "created_at" }
type User struct { type User struct {
Id []byte Id []byte
Email string Email string
@ -6451,6 +6657,42 @@ func (obj *postgresImpl) Create_StripecoinpaymentsApplyBalanceIntent(ctx context
} }
func (obj *postgresImpl) Create_StripecoinpaymentsInvoiceProjectRecord(ctx context.Context,
stripecoinpayments_invoice_project_record_id StripecoinpaymentsInvoiceProjectRecord_Id_Field,
stripecoinpayments_invoice_project_record_project_id StripecoinpaymentsInvoiceProjectRecord_ProjectId_Field,
stripecoinpayments_invoice_project_record_storage StripecoinpaymentsInvoiceProjectRecord_Storage_Field,
stripecoinpayments_invoice_project_record_egress StripecoinpaymentsInvoiceProjectRecord_Egress_Field,
stripecoinpayments_invoice_project_record_objects StripecoinpaymentsInvoiceProjectRecord_Objects_Field,
stripecoinpayments_invoice_project_record_period_start StripecoinpaymentsInvoiceProjectRecord_PeriodStart_Field,
stripecoinpayments_invoice_project_record_period_end StripecoinpaymentsInvoiceProjectRecord_PeriodEnd_Field,
stripecoinpayments_invoice_project_record_state StripecoinpaymentsInvoiceProjectRecord_State_Field) (
stripecoinpayments_invoice_project_record *StripecoinpaymentsInvoiceProjectRecord, err error) {
__now := obj.db.Hooks.Now().UTC()
__id_val := stripecoinpayments_invoice_project_record_id.value()
__project_id_val := stripecoinpayments_invoice_project_record_project_id.value()
__storage_val := stripecoinpayments_invoice_project_record_storage.value()
__egress_val := stripecoinpayments_invoice_project_record_egress.value()
__objects_val := stripecoinpayments_invoice_project_record_objects.value()
__period_start_val := stripecoinpayments_invoice_project_record_period_start.value()
__period_end_val := stripecoinpayments_invoice_project_record_period_end.value()
__state_val := stripecoinpayments_invoice_project_record_state.value()
__created_at_val := __now
var __embed_stmt = __sqlbundle_Literal("INSERT INTO stripecoinpayments_invoice_project_records ( id, project_id, storage, egress, objects, period_start, period_end, state, created_at ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? ) RETURNING stripecoinpayments_invoice_project_records.id, stripecoinpayments_invoice_project_records.project_id, stripecoinpayments_invoice_project_records.storage, stripecoinpayments_invoice_project_records.egress, stripecoinpayments_invoice_project_records.objects, stripecoinpayments_invoice_project_records.period_start, stripecoinpayments_invoice_project_records.period_end, stripecoinpayments_invoice_project_records.state, stripecoinpayments_invoice_project_records.created_at")
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
obj.logStmt(__stmt, __id_val, __project_id_val, __storage_val, __egress_val, __objects_val, __period_start_val, __period_end_val, __state_val, __created_at_val)
stripecoinpayments_invoice_project_record = &StripecoinpaymentsInvoiceProjectRecord{}
err = obj.driver.QueryRow(__stmt, __id_val, __project_id_val, __storage_val, __egress_val, __objects_val, __period_start_val, __period_end_val, __state_val, __created_at_val).Scan(&stripecoinpayments_invoice_project_record.Id, &stripecoinpayments_invoice_project_record.ProjectId, &stripecoinpayments_invoice_project_record.Storage, &stripecoinpayments_invoice_project_record.Egress, &stripecoinpayments_invoice_project_record.Objects, &stripecoinpayments_invoice_project_record.PeriodStart, &stripecoinpayments_invoice_project_record.PeriodEnd, &stripecoinpayments_invoice_project_record.State, &stripecoinpayments_invoice_project_record.CreatedAt)
if err != nil {
return nil, obj.makeErr(err)
}
return stripecoinpayments_invoice_project_record, nil
}
func (obj *postgresImpl) Get_ValueAttribution_By_ProjectId_And_BucketName(ctx context.Context, func (obj *postgresImpl) Get_ValueAttribution_By_ProjectId_And_BucketName(ctx context.Context,
value_attribution_project_id ValueAttribution_ProjectId_Field, value_attribution_project_id ValueAttribution_ProjectId_Field,
value_attribution_bucket_name ValueAttribution_BucketName_Field) ( value_attribution_bucket_name ValueAttribution_BucketName_Field) (
@ -6969,6 +7211,42 @@ func (obj *postgresImpl) All_Project_By_ProjectMember_MemberId_OrderBy_Asc_Proje
} }
func (obj *postgresImpl) Limited_Project_By_CreatedAt_Less_OrderBy_Asc_CreatedAt(ctx context.Context,
project_created_at_less Project_CreatedAt_Field,
limit int, offset int64) (
rows []*Project, err error) {
var __embed_stmt = __sqlbundle_Literal("SELECT projects.id, projects.name, projects.description, projects.usage_limit, projects.partner_id, projects.owner_id, projects.created_at FROM projects WHERE projects.created_at < ? ORDER BY projects.created_at LIMIT ? OFFSET ?")
var __values []interface{}
__values = append(__values, project_created_at_less.value())
__values = append(__values, limit, offset)
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
obj.logStmt(__stmt, __values...)
__rows, err := obj.driver.Query(__stmt, __values...)
if err != nil {
return nil, obj.makeErr(err)
}
defer __rows.Close()
for __rows.Next() {
project := &Project{}
err = __rows.Scan(&project.Id, &project.Name, &project.Description, &project.UsageLimit, &project.PartnerId, &project.OwnerId, &project.CreatedAt)
if err != nil {
return nil, obj.makeErr(err)
}
rows = append(rows, project)
}
if err := __rows.Err(); err != nil {
return nil, obj.makeErr(err)
}
return rows, nil
}
func (obj *postgresImpl) Get_ProjectInvoiceStamp_By_ProjectId_And_StartDate(ctx context.Context, func (obj *postgresImpl) Get_ProjectInvoiceStamp_By_ProjectId_And_StartDate(ctx context.Context,
project_invoice_stamp_project_id ProjectInvoiceStamp_ProjectId_Field, project_invoice_stamp_project_id ProjectInvoiceStamp_ProjectId_Field,
project_invoice_stamp_start_date ProjectInvoiceStamp_StartDate_Field) ( project_invoice_stamp_start_date ProjectInvoiceStamp_StartDate_Field) (
@ -7939,6 +8217,42 @@ func (obj *postgresImpl) Get_StripeCustomer_CustomerId_By_UserId(ctx context.Con
} }
func (obj *postgresImpl) Limited_StripeCustomer_By_CreatedAt_LessOrEqual_OrderBy_Desc_CreatedAt(ctx context.Context,
stripe_customer_created_at_less_or_equal StripeCustomer_CreatedAt_Field,
limit int, offset int64) (
rows []*StripeCustomer, err error) {
var __embed_stmt = __sqlbundle_Literal("SELECT stripe_customers.user_id, stripe_customers.customer_id, stripe_customers.created_at FROM stripe_customers WHERE stripe_customers.created_at <= ? ORDER BY stripe_customers.created_at DESC LIMIT ? OFFSET ?")
var __values []interface{}
__values = append(__values, stripe_customer_created_at_less_or_equal.value())
__values = append(__values, limit, offset)
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
obj.logStmt(__stmt, __values...)
__rows, err := obj.driver.Query(__stmt, __values...)
if err != nil {
return nil, obj.makeErr(err)
}
defer __rows.Close()
for __rows.Next() {
stripe_customer := &StripeCustomer{}
err = __rows.Scan(&stripe_customer.UserId, &stripe_customer.CustomerId, &stripe_customer.CreatedAt)
if err != nil {
return nil, obj.makeErr(err)
}
rows = append(rows, stripe_customer)
}
if err := __rows.Err(); err != nil {
return nil, obj.makeErr(err)
}
return rows, nil
}
func (obj *postgresImpl) Limited_CoinpaymentsTransaction_By_CreatedAt_LessOrEqual_And_Status_OrderBy_Desc_CreatedAt(ctx context.Context, func (obj *postgresImpl) Limited_CoinpaymentsTransaction_By_CreatedAt_LessOrEqual_And_Status_OrderBy_Desc_CreatedAt(ctx context.Context,
coinpayments_transaction_created_at_less_or_equal CoinpaymentsTransaction_CreatedAt_Field, coinpayments_transaction_created_at_less_or_equal CoinpaymentsTransaction_CreatedAt_Field,
coinpayments_transaction_status CoinpaymentsTransaction_Status_Field, coinpayments_transaction_status CoinpaymentsTransaction_Status_Field,
@ -7976,6 +8290,66 @@ func (obj *postgresImpl) Limited_CoinpaymentsTransaction_By_CreatedAt_LessOrEqua
} }
func (obj *postgresImpl) Get_StripecoinpaymentsInvoiceProjectRecord_By_ProjectId_And_PeriodStart_And_PeriodEnd(ctx context.Context,
stripecoinpayments_invoice_project_record_project_id StripecoinpaymentsInvoiceProjectRecord_ProjectId_Field,
stripecoinpayments_invoice_project_record_period_start StripecoinpaymentsInvoiceProjectRecord_PeriodStart_Field,
stripecoinpayments_invoice_project_record_period_end StripecoinpaymentsInvoiceProjectRecord_PeriodEnd_Field) (
stripecoinpayments_invoice_project_record *StripecoinpaymentsInvoiceProjectRecord, err error) {
var __embed_stmt = __sqlbundle_Literal("SELECT stripecoinpayments_invoice_project_records.id, stripecoinpayments_invoice_project_records.project_id, stripecoinpayments_invoice_project_records.storage, stripecoinpayments_invoice_project_records.egress, stripecoinpayments_invoice_project_records.objects, stripecoinpayments_invoice_project_records.period_start, stripecoinpayments_invoice_project_records.period_end, stripecoinpayments_invoice_project_records.state, stripecoinpayments_invoice_project_records.created_at FROM stripecoinpayments_invoice_project_records WHERE stripecoinpayments_invoice_project_records.project_id = ? AND stripecoinpayments_invoice_project_records.period_start = ? AND stripecoinpayments_invoice_project_records.period_end = ?")
var __values []interface{}
__values = append(__values, stripecoinpayments_invoice_project_record_project_id.value(), stripecoinpayments_invoice_project_record_period_start.value(), stripecoinpayments_invoice_project_record_period_end.value())
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
obj.logStmt(__stmt, __values...)
stripecoinpayments_invoice_project_record = &StripecoinpaymentsInvoiceProjectRecord{}
err = obj.driver.QueryRow(__stmt, __values...).Scan(&stripecoinpayments_invoice_project_record.Id, &stripecoinpayments_invoice_project_record.ProjectId, &stripecoinpayments_invoice_project_record.Storage, &stripecoinpayments_invoice_project_record.Egress, &stripecoinpayments_invoice_project_record.Objects, &stripecoinpayments_invoice_project_record.PeriodStart, &stripecoinpayments_invoice_project_record.PeriodEnd, &stripecoinpayments_invoice_project_record.State, &stripecoinpayments_invoice_project_record.CreatedAt)
if err != nil {
return nil, obj.makeErr(err)
}
return stripecoinpayments_invoice_project_record, nil
}
func (obj *postgresImpl) Limited_StripecoinpaymentsInvoiceProjectRecord_By_CreatedAt_LessOrEqual_And_State_OrderBy_Desc_CreatedAt(ctx context.Context,
stripecoinpayments_invoice_project_record_created_at_less_or_equal StripecoinpaymentsInvoiceProjectRecord_CreatedAt_Field,
stripecoinpayments_invoice_project_record_state StripecoinpaymentsInvoiceProjectRecord_State_Field,
limit int, offset int64) (
rows []*StripecoinpaymentsInvoiceProjectRecord, err error) {
var __embed_stmt = __sqlbundle_Literal("SELECT stripecoinpayments_invoice_project_records.id, stripecoinpayments_invoice_project_records.project_id, stripecoinpayments_invoice_project_records.storage, stripecoinpayments_invoice_project_records.egress, stripecoinpayments_invoice_project_records.objects, stripecoinpayments_invoice_project_records.period_start, stripecoinpayments_invoice_project_records.period_end, stripecoinpayments_invoice_project_records.state, stripecoinpayments_invoice_project_records.created_at FROM stripecoinpayments_invoice_project_records WHERE stripecoinpayments_invoice_project_records.created_at <= ? AND stripecoinpayments_invoice_project_records.state = ? ORDER BY stripecoinpayments_invoice_project_records.created_at DESC LIMIT ? OFFSET ?")
var __values []interface{}
__values = append(__values, stripecoinpayments_invoice_project_record_created_at_less_or_equal.value(), stripecoinpayments_invoice_project_record_state.value())
__values = append(__values, limit, offset)
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
obj.logStmt(__stmt, __values...)
__rows, err := obj.driver.Query(__stmt, __values...)
if err != nil {
return nil, obj.makeErr(err)
}
defer __rows.Close()
for __rows.Next() {
stripecoinpayments_invoice_project_record := &StripecoinpaymentsInvoiceProjectRecord{}
err = __rows.Scan(&stripecoinpayments_invoice_project_record.Id, &stripecoinpayments_invoice_project_record.ProjectId, &stripecoinpayments_invoice_project_record.Storage, &stripecoinpayments_invoice_project_record.Egress, &stripecoinpayments_invoice_project_record.Objects, &stripecoinpayments_invoice_project_record.PeriodStart, &stripecoinpayments_invoice_project_record.PeriodEnd, &stripecoinpayments_invoice_project_record.State, &stripecoinpayments_invoice_project_record.CreatedAt)
if err != nil {
return nil, obj.makeErr(err)
}
rows = append(rows, stripecoinpayments_invoice_project_record)
}
if err := __rows.Err(); err != nil {
return nil, obj.makeErr(err)
}
return rows, nil
}
func (obj *postgresImpl) Update_PendingAudits_By_NodeId(ctx context.Context, func (obj *postgresImpl) Update_PendingAudits_By_NodeId(ctx context.Context,
pending_audits_node_id PendingAudits_NodeId_Field, pending_audits_node_id PendingAudits_NodeId_Field,
update PendingAudits_Update_Fields) ( update PendingAudits_Update_Fields) (
@ -9081,6 +9455,46 @@ func (obj *postgresImpl) Update_StripecoinpaymentsApplyBalanceIntent_By_TxId(ctx
return stripecoinpayments_apply_balance_intent, nil return stripecoinpayments_apply_balance_intent, nil
} }
func (obj *postgresImpl) Update_StripecoinpaymentsInvoiceProjectRecord_By_Id(ctx context.Context,
stripecoinpayments_invoice_project_record_id StripecoinpaymentsInvoiceProjectRecord_Id_Field,
update StripecoinpaymentsInvoiceProjectRecord_Update_Fields) (
stripecoinpayments_invoice_project_record *StripecoinpaymentsInvoiceProjectRecord, err error) {
var __sets = &__sqlbundle_Hole{}
var __embed_stmt = __sqlbundle_Literals{Join: "", SQLs: []__sqlbundle_SQL{__sqlbundle_Literal("UPDATE stripecoinpayments_invoice_project_records SET "), __sets, __sqlbundle_Literal(" WHERE stripecoinpayments_invoice_project_records.id = ? RETURNING stripecoinpayments_invoice_project_records.id, stripecoinpayments_invoice_project_records.project_id, stripecoinpayments_invoice_project_records.storage, stripecoinpayments_invoice_project_records.egress, stripecoinpayments_invoice_project_records.objects, stripecoinpayments_invoice_project_records.period_start, stripecoinpayments_invoice_project_records.period_end, stripecoinpayments_invoice_project_records.state, stripecoinpayments_invoice_project_records.created_at")}}
__sets_sql := __sqlbundle_Literals{Join: ", "}
var __values []interface{}
var __args []interface{}
if update.State._set {
__values = append(__values, update.State.value())
__sets_sql.SQLs = append(__sets_sql.SQLs, __sqlbundle_Literal("state = ?"))
}
if len(__sets_sql.SQLs) == 0 {
return nil, emptyUpdate()
}
__args = append(__args, stripecoinpayments_invoice_project_record_id.value())
__values = append(__values, __args...)
__sets.SQL = __sets_sql
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
obj.logStmt(__stmt, __values...)
stripecoinpayments_invoice_project_record = &StripecoinpaymentsInvoiceProjectRecord{}
err = obj.driver.QueryRow(__stmt, __values...).Scan(&stripecoinpayments_invoice_project_record.Id, &stripecoinpayments_invoice_project_record.ProjectId, &stripecoinpayments_invoice_project_record.Storage, &stripecoinpayments_invoice_project_record.Egress, &stripecoinpayments_invoice_project_record.Objects, &stripecoinpayments_invoice_project_record.PeriodStart, &stripecoinpayments_invoice_project_record.PeriodEnd, &stripecoinpayments_invoice_project_record.State, &stripecoinpayments_invoice_project_record.CreatedAt)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, obj.makeErr(err)
}
return stripecoinpayments_invoice_project_record, nil
}
func (obj *postgresImpl) Delete_ValueAttribution_By_ProjectId_And_BucketName(ctx context.Context, func (obj *postgresImpl) Delete_ValueAttribution_By_ProjectId_And_BucketName(ctx context.Context,
value_attribution_project_id ValueAttribution_ProjectId_Field, value_attribution_project_id ValueAttribution_ProjectId_Field,
value_attribution_bucket_name ValueAttribution_BucketName_Field) ( value_attribution_bucket_name ValueAttribution_BucketName_Field) (
@ -9554,6 +9968,32 @@ func (obj *postgresImpl) Delete_StripecoinpaymentsApplyBalanceIntent_By_TxId(ctx
} }
func (obj *postgresImpl) Delete_StripecoinpaymentsInvoiceProjectRecord_By_Id(ctx context.Context,
stripecoinpayments_invoice_project_record_id StripecoinpaymentsInvoiceProjectRecord_Id_Field) (
deleted bool, err error) {
var __embed_stmt = __sqlbundle_Literal("DELETE FROM stripecoinpayments_invoice_project_records WHERE stripecoinpayments_invoice_project_records.id = ?")
var __values []interface{}
__values = append(__values, stripecoinpayments_invoice_project_record_id.value())
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
obj.logStmt(__stmt, __values...)
__res, err := obj.driver.Exec(__stmt, __values...)
if err != nil {
return false, obj.makeErr(err)
}
__count, err := __res.RowsAffected()
if err != nil {
return false, obj.makeErr(err)
}
return __count > 0, nil
}
func (impl postgresImpl) isConstraintError(err error) ( func (impl postgresImpl) isConstraintError(err error) (
constraint string, ok bool) { constraint string, ok bool) {
if e, ok := err.(*pq.Error); ok { if e, ok := err.(*pq.Error); ok {
@ -9652,6 +10092,16 @@ func (obj *postgresImpl) deleteAll(ctx context.Context) (count int64, err error)
return 0, obj.makeErr(err) return 0, obj.makeErr(err)
} }
__count, err = __res.RowsAffected()
if err != nil {
return 0, obj.makeErr(err)
}
count += __count
__res, err = obj.driver.Exec("DELETE FROM stripecoinpayments_invoice_project_records;")
if err != nil {
return 0, obj.makeErr(err)
}
__count, err = __res.RowsAffected() __count, err = __res.RowsAffected()
if err != nil { if err != nil {
return 0, obj.makeErr(err) return 0, obj.makeErr(err)
@ -10437,6 +10887,24 @@ func (rx *Rx) Create_StripecoinpaymentsApplyBalanceIntent(ctx context.Context,
} }
func (rx *Rx) Create_StripecoinpaymentsInvoiceProjectRecord(ctx context.Context,
stripecoinpayments_invoice_project_record_id StripecoinpaymentsInvoiceProjectRecord_Id_Field,
stripecoinpayments_invoice_project_record_project_id StripecoinpaymentsInvoiceProjectRecord_ProjectId_Field,
stripecoinpayments_invoice_project_record_storage StripecoinpaymentsInvoiceProjectRecord_Storage_Field,
stripecoinpayments_invoice_project_record_egress StripecoinpaymentsInvoiceProjectRecord_Egress_Field,
stripecoinpayments_invoice_project_record_objects StripecoinpaymentsInvoiceProjectRecord_Objects_Field,
stripecoinpayments_invoice_project_record_period_start StripecoinpaymentsInvoiceProjectRecord_PeriodStart_Field,
stripecoinpayments_invoice_project_record_period_end StripecoinpaymentsInvoiceProjectRecord_PeriodEnd_Field,
stripecoinpayments_invoice_project_record_state StripecoinpaymentsInvoiceProjectRecord_State_Field) (
stripecoinpayments_invoice_project_record *StripecoinpaymentsInvoiceProjectRecord, err error) {
var tx *Tx
if tx, err = rx.getTx(ctx); err != nil {
return
}
return tx.Create_StripecoinpaymentsInvoiceProjectRecord(ctx, stripecoinpayments_invoice_project_record_id, stripecoinpayments_invoice_project_record_project_id, stripecoinpayments_invoice_project_record_storage, stripecoinpayments_invoice_project_record_egress, stripecoinpayments_invoice_project_record_objects, stripecoinpayments_invoice_project_record_period_start, stripecoinpayments_invoice_project_record_period_end, stripecoinpayments_invoice_project_record_state)
}
func (rx *Rx) Create_User(ctx context.Context, func (rx *Rx) Create_User(ctx context.Context,
user_id User_Id_Field, user_id User_Id_Field,
user_email User_Email_Field, user_email User_Email_Field,
@ -10649,6 +11117,16 @@ func (rx *Rx) Delete_StripecoinpaymentsApplyBalanceIntent_By_TxId(ctx context.Co
return tx.Delete_StripecoinpaymentsApplyBalanceIntent_By_TxId(ctx, stripecoinpayments_apply_balance_intent_tx_id) return tx.Delete_StripecoinpaymentsApplyBalanceIntent_By_TxId(ctx, stripecoinpayments_apply_balance_intent_tx_id)
} }
func (rx *Rx) Delete_StripecoinpaymentsInvoiceProjectRecord_By_Id(ctx context.Context,
stripecoinpayments_invoice_project_record_id StripecoinpaymentsInvoiceProjectRecord_Id_Field) (
deleted bool, err error) {
var tx *Tx
if tx, err = rx.getTx(ctx); err != nil {
return
}
return tx.Delete_StripecoinpaymentsInvoiceProjectRecord_By_Id(ctx, stripecoinpayments_invoice_project_record_id)
}
func (rx *Rx) Delete_User_By_Id(ctx context.Context, func (rx *Rx) Delete_User_By_Id(ctx context.Context,
user_id User_Id_Field) ( user_id User_Id_Field) (
deleted bool, err error) { deleted bool, err error) {
@ -10940,6 +11418,18 @@ func (rx *Rx) Get_StripeCustomer_CustomerId_By_UserId(ctx context.Context,
return tx.Get_StripeCustomer_CustomerId_By_UserId(ctx, stripe_customer_user_id) return tx.Get_StripeCustomer_CustomerId_By_UserId(ctx, stripe_customer_user_id)
} }
func (rx *Rx) Get_StripecoinpaymentsInvoiceProjectRecord_By_ProjectId_And_PeriodStart_And_PeriodEnd(ctx context.Context,
stripecoinpayments_invoice_project_record_project_id StripecoinpaymentsInvoiceProjectRecord_ProjectId_Field,
stripecoinpayments_invoice_project_record_period_start StripecoinpaymentsInvoiceProjectRecord_PeriodStart_Field,
stripecoinpayments_invoice_project_record_period_end StripecoinpaymentsInvoiceProjectRecord_PeriodEnd_Field) (
stripecoinpayments_invoice_project_record *StripecoinpaymentsInvoiceProjectRecord, err error) {
var tx *Tx
if tx, err = rx.getTx(ctx); err != nil {
return
}
return tx.Get_StripecoinpaymentsInvoiceProjectRecord_By_ProjectId_And_PeriodStart_And_PeriodEnd(ctx, stripecoinpayments_invoice_project_record_project_id, stripecoinpayments_invoice_project_record_period_start, stripecoinpayments_invoice_project_record_period_end)
}
func (rx *Rx) Get_User_By_Id(ctx context.Context, func (rx *Rx) Get_User_By_Id(ctx context.Context,
user_id User_Id_Field) ( user_id User_Id_Field) (
user *User, err error) { user *User, err error) {
@ -11051,6 +11541,40 @@ func (rx *Rx) Limited_ProjectMember_By_ProjectId(ctx context.Context,
return tx.Limited_ProjectMember_By_ProjectId(ctx, project_member_project_id, limit, offset) return tx.Limited_ProjectMember_By_ProjectId(ctx, project_member_project_id, limit, offset)
} }
func (rx *Rx) Limited_Project_By_CreatedAt_Less_OrderBy_Asc_CreatedAt(ctx context.Context,
project_created_at_less Project_CreatedAt_Field,
limit int, offset int64) (
rows []*Project, err error) {
var tx *Tx
if tx, err = rx.getTx(ctx); err != nil {
return
}
return tx.Limited_Project_By_CreatedAt_Less_OrderBy_Asc_CreatedAt(ctx, project_created_at_less, limit, offset)
}
func (rx *Rx) Limited_StripeCustomer_By_CreatedAt_LessOrEqual_OrderBy_Desc_CreatedAt(ctx context.Context,
stripe_customer_created_at_less_or_equal StripeCustomer_CreatedAt_Field,
limit int, offset int64) (
rows []*StripeCustomer, err error) {
var tx *Tx
if tx, err = rx.getTx(ctx); err != nil {
return
}
return tx.Limited_StripeCustomer_By_CreatedAt_LessOrEqual_OrderBy_Desc_CreatedAt(ctx, stripe_customer_created_at_less_or_equal, limit, offset)
}
func (rx *Rx) Limited_StripecoinpaymentsInvoiceProjectRecord_By_CreatedAt_LessOrEqual_And_State_OrderBy_Desc_CreatedAt(ctx context.Context,
stripecoinpayments_invoice_project_record_created_at_less_or_equal StripecoinpaymentsInvoiceProjectRecord_CreatedAt_Field,
stripecoinpayments_invoice_project_record_state StripecoinpaymentsInvoiceProjectRecord_State_Field,
limit int, offset int64) (
rows []*StripecoinpaymentsInvoiceProjectRecord, err error) {
var tx *Tx
if tx, err = rx.getTx(ctx); err != nil {
return
}
return tx.Limited_StripecoinpaymentsInvoiceProjectRecord_By_CreatedAt_LessOrEqual_And_State_OrderBy_Desc_CreatedAt(ctx, stripecoinpayments_invoice_project_record_created_at_less_or_equal, stripecoinpayments_invoice_project_record_state, limit, offset)
}
func (rx *Rx) UpdateNoReturn_AccountingTimestamps_By_Name(ctx context.Context, func (rx *Rx) UpdateNoReturn_AccountingTimestamps_By_Name(ctx context.Context,
accounting_timestamps_name AccountingTimestamps_Name_Field, accounting_timestamps_name AccountingTimestamps_Name_Field,
update AccountingTimestamps_Update_Fields) ( update AccountingTimestamps_Update_Fields) (
@ -11219,6 +11743,17 @@ func (rx *Rx) Update_StripecoinpaymentsApplyBalanceIntent_By_TxId(ctx context.Co
return tx.Update_StripecoinpaymentsApplyBalanceIntent_By_TxId(ctx, stripecoinpayments_apply_balance_intent_tx_id, update) return tx.Update_StripecoinpaymentsApplyBalanceIntent_By_TxId(ctx, stripecoinpayments_apply_balance_intent_tx_id, update)
} }
func (rx *Rx) Update_StripecoinpaymentsInvoiceProjectRecord_By_Id(ctx context.Context,
stripecoinpayments_invoice_project_record_id StripecoinpaymentsInvoiceProjectRecord_Id_Field,
update StripecoinpaymentsInvoiceProjectRecord_Update_Fields) (
stripecoinpayments_invoice_project_record *StripecoinpaymentsInvoiceProjectRecord, err error) {
var tx *Tx
if tx, err = rx.getTx(ctx); err != nil {
return
}
return tx.Update_StripecoinpaymentsInvoiceProjectRecord_By_Id(ctx, stripecoinpayments_invoice_project_record_id, update)
}
func (rx *Rx) Update_User_By_Id(ctx context.Context, func (rx *Rx) Update_User_By_Id(ctx context.Context,
user_id User_Id_Field, user_id User_Id_Field,
update User_Update_Fields) ( update User_Update_Fields) (
@ -11501,6 +12036,17 @@ type Methods interface {
stripecoinpayments_apply_balance_intent_state StripecoinpaymentsApplyBalanceIntent_State_Field) ( stripecoinpayments_apply_balance_intent_state StripecoinpaymentsApplyBalanceIntent_State_Field) (
stripecoinpayments_apply_balance_intent *StripecoinpaymentsApplyBalanceIntent, err error) stripecoinpayments_apply_balance_intent *StripecoinpaymentsApplyBalanceIntent, err error)
Create_StripecoinpaymentsInvoiceProjectRecord(ctx context.Context,
stripecoinpayments_invoice_project_record_id StripecoinpaymentsInvoiceProjectRecord_Id_Field,
stripecoinpayments_invoice_project_record_project_id StripecoinpaymentsInvoiceProjectRecord_ProjectId_Field,
stripecoinpayments_invoice_project_record_storage StripecoinpaymentsInvoiceProjectRecord_Storage_Field,
stripecoinpayments_invoice_project_record_egress StripecoinpaymentsInvoiceProjectRecord_Egress_Field,
stripecoinpayments_invoice_project_record_objects StripecoinpaymentsInvoiceProjectRecord_Objects_Field,
stripecoinpayments_invoice_project_record_period_start StripecoinpaymentsInvoiceProjectRecord_PeriodStart_Field,
stripecoinpayments_invoice_project_record_period_end StripecoinpaymentsInvoiceProjectRecord_PeriodEnd_Field,
stripecoinpayments_invoice_project_record_state StripecoinpaymentsInvoiceProjectRecord_State_Field) (
stripecoinpayments_invoice_project_record *StripecoinpaymentsInvoiceProjectRecord, err error)
Create_User(ctx context.Context, Create_User(ctx context.Context,
user_id User_Id_Field, user_id User_Id_Field,
user_email User_Email_Field, user_email User_Email_Field,
@ -11593,6 +12139,10 @@ type Methods interface {
stripecoinpayments_apply_balance_intent_tx_id StripecoinpaymentsApplyBalanceIntent_TxId_Field) ( stripecoinpayments_apply_balance_intent_tx_id StripecoinpaymentsApplyBalanceIntent_TxId_Field) (
deleted bool, err error) deleted bool, err error)
Delete_StripecoinpaymentsInvoiceProjectRecord_By_Id(ctx context.Context,
stripecoinpayments_invoice_project_record_id StripecoinpaymentsInvoiceProjectRecord_Id_Field) (
deleted bool, err error)
Delete_User_By_Id(ctx context.Context, Delete_User_By_Id(ctx context.Context,
user_id User_Id_Field) ( user_id User_Id_Field) (
deleted bool, err error) deleted bool, err error)
@ -11716,6 +12266,12 @@ type Methods interface {
stripe_customer_user_id StripeCustomer_UserId_Field) ( stripe_customer_user_id StripeCustomer_UserId_Field) (
row *CustomerId_Row, err error) row *CustomerId_Row, err error)
Get_StripecoinpaymentsInvoiceProjectRecord_By_ProjectId_And_PeriodStart_And_PeriodEnd(ctx context.Context,
stripecoinpayments_invoice_project_record_project_id StripecoinpaymentsInvoiceProjectRecord_ProjectId_Field,
stripecoinpayments_invoice_project_record_period_start StripecoinpaymentsInvoiceProjectRecord_PeriodStart_Field,
stripecoinpayments_invoice_project_record_period_end StripecoinpaymentsInvoiceProjectRecord_PeriodEnd_Field) (
stripecoinpayments_invoice_project_record *StripecoinpaymentsInvoiceProjectRecord, err error)
Get_User_By_Id(ctx context.Context, Get_User_By_Id(ctx context.Context,
user_id User_Id_Field) ( user_id User_Id_Field) (
user *User, err error) user *User, err error)
@ -11767,6 +12323,22 @@ type Methods interface {
limit int, offset int64) ( limit int, offset int64) (
rows []*ProjectMember, err error) rows []*ProjectMember, err error)
Limited_Project_By_CreatedAt_Less_OrderBy_Asc_CreatedAt(ctx context.Context,
project_created_at_less Project_CreatedAt_Field,
limit int, offset int64) (
rows []*Project, err error)
Limited_StripeCustomer_By_CreatedAt_LessOrEqual_OrderBy_Desc_CreatedAt(ctx context.Context,
stripe_customer_created_at_less_or_equal StripeCustomer_CreatedAt_Field,
limit int, offset int64) (
rows []*StripeCustomer, err error)
Limited_StripecoinpaymentsInvoiceProjectRecord_By_CreatedAt_LessOrEqual_And_State_OrderBy_Desc_CreatedAt(ctx context.Context,
stripecoinpayments_invoice_project_record_created_at_less_or_equal StripecoinpaymentsInvoiceProjectRecord_CreatedAt_Field,
stripecoinpayments_invoice_project_record_state StripecoinpaymentsInvoiceProjectRecord_State_Field,
limit int, offset int64) (
rows []*StripecoinpaymentsInvoiceProjectRecord, err error)
UpdateNoReturn_AccountingTimestamps_By_Name(ctx context.Context, UpdateNoReturn_AccountingTimestamps_By_Name(ctx context.Context,
accounting_timestamps_name AccountingTimestamps_Name_Field, accounting_timestamps_name AccountingTimestamps_Name_Field,
update AccountingTimestamps_Update_Fields) ( update AccountingTimestamps_Update_Fields) (
@ -11845,6 +12417,11 @@ type Methods interface {
update StripecoinpaymentsApplyBalanceIntent_Update_Fields) ( update StripecoinpaymentsApplyBalanceIntent_Update_Fields) (
stripecoinpayments_apply_balance_intent *StripecoinpaymentsApplyBalanceIntent, err error) stripecoinpayments_apply_balance_intent *StripecoinpaymentsApplyBalanceIntent, err error)
Update_StripecoinpaymentsInvoiceProjectRecord_By_Id(ctx context.Context,
stripecoinpayments_invoice_project_record_id StripecoinpaymentsInvoiceProjectRecord_Id_Field,
update StripecoinpaymentsInvoiceProjectRecord_Update_Fields) (
stripecoinpayments_invoice_project_record *StripecoinpaymentsInvoiceProjectRecord, err error)
Update_User_By_Id(ctx context.Context, Update_User_By_Id(ctx context.Context,
user_id User_Id_Field, user_id User_Id_Field,
update User_Update_Fields) ( update User_Update_Fields) (

View File

@ -211,6 +211,19 @@ CREATE TABLE stripe_customers (
PRIMARY KEY ( user_id ), PRIMARY KEY ( user_id ),
UNIQUE ( customer_id ) UNIQUE ( customer_id )
); );
CREATE TABLE stripecoinpayments_invoice_project_records (
id bytea NOT NULL,
project_id bytea NOT NULL,
storage double precision NOT NULL,
egress bigint NOT NULL,
objects bigint NOT NULL,
period_start timestamp with time zone NOT NULL,
period_end timestamp with time zone NOT NULL,
state integer NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( id ),
UNIQUE ( project_id, period_start, period_end )
);
CREATE TABLE users ( CREATE TABLE users (
id bytea NOT NULL, id bytea NOT NULL,
email text NOT NULL, email text NOT NULL,

View File

@ -0,0 +1,163 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package satellitedb
import (
"context"
"database/sql"
"time"
"github.com/skyrings/skyring-common/tools/uuid"
"github.com/zeebo/errs"
"storj.io/storj/satellite/payments/stripecoinpayments"
dbx "storj.io/storj/satellite/satellitedb/dbx"
)
// ensure that invoiceProjectRecords implements stripecoinpayments.ProjectRecordsDB.
var _ stripecoinpayments.ProjectRecordsDB = (*invoiceProjectRecords)(nil)
// invoiceProjectRecordState defines states of the invoice project record.
type invoiceProjectRecordState int
const (
// invoice project record is not yet applied to customer invoice.
invoiceProjectRecordStateUnapplied invoiceProjectRecordState = 0
// invoice project record has been used during creating customer invoice.
invoiceProjectRecordStateConsumed invoiceProjectRecordState = 1
)
// Int returns intent state as int.
func (intent invoiceProjectRecordState) Int() int {
return int(intent)
}
// invoiceProjectRecords is stripecoinpayments project records DB.
//
// architecture: Database
type invoiceProjectRecords struct {
db *dbx.DB
}
// Create creates new invoice project record in the DB.
func (db *invoiceProjectRecords) Create(ctx context.Context, records []stripecoinpayments.CreateProjectRecord, start, end time.Time) (err error) {
defer mon.Task()(&ctx)(&err)
return db.db.WithTx(ctx, func(ctx context.Context, tx *dbx.Tx) error {
for _, record := range records {
id, err := uuid.New()
if err != nil {
return Error.Wrap(err)
}
_, err = db.db.Create_StripecoinpaymentsInvoiceProjectRecord(ctx,
dbx.StripecoinpaymentsInvoiceProjectRecord_Id(id[:]),
dbx.StripecoinpaymentsInvoiceProjectRecord_ProjectId(record.ProjectID[:]),
dbx.StripecoinpaymentsInvoiceProjectRecord_Storage(record.Storage),
dbx.StripecoinpaymentsInvoiceProjectRecord_Egress(record.Egress),
dbx.StripecoinpaymentsInvoiceProjectRecord_Objects(record.Objects),
dbx.StripecoinpaymentsInvoiceProjectRecord_PeriodStart(start),
dbx.StripecoinpaymentsInvoiceProjectRecord_PeriodEnd(end),
dbx.StripecoinpaymentsInvoiceProjectRecord_State(invoiceProjectRecordStateUnapplied.Int()),
)
if err != nil {
return err
}
}
return nil
})
}
// Check checks if invoice project record for specified project and billing period exists.
func (db *invoiceProjectRecords) Check(ctx context.Context, projectID uuid.UUID, start, end time.Time) (err error) {
defer mon.Task()(&ctx)(&err)
_, err = db.db.Get_StripecoinpaymentsInvoiceProjectRecord_By_ProjectId_And_PeriodStart_And_PeriodEnd(ctx,
dbx.StripecoinpaymentsInvoiceProjectRecord_ProjectId(projectID[:]),
dbx.StripecoinpaymentsInvoiceProjectRecord_PeriodStart(start),
dbx.StripecoinpaymentsInvoiceProjectRecord_PeriodEnd(end),
)
if err != nil {
if err == sql.ErrNoRows {
return nil
}
return err
}
return stripecoinpayments.ErrProjectRecordExists
}
// Consume consumes invoice project record.
func (db *invoiceProjectRecords) Consume(ctx context.Context, id uuid.UUID) (err error) {
defer mon.Task()(&ctx)(&err)
_, err = db.db.Update_StripecoinpaymentsInvoiceProjectRecord_By_Id(ctx,
dbx.StripecoinpaymentsInvoiceProjectRecord_Id(id[:]),
dbx.StripecoinpaymentsInvoiceProjectRecord_Update_Fields{
State: dbx.StripecoinpaymentsInvoiceProjectRecord_State(invoiceProjectRecordStateConsumed.Int()),
},
)
return err
}
// ListUnapplied returns project records page with unapplied project records.
func (db *invoiceProjectRecords) ListUnapplied(ctx context.Context, offset int64, limit int, before time.Time) (_ stripecoinpayments.ProjectRecordsPage, err error) {
defer mon.Task()(&ctx)(&err)
var page stripecoinpayments.ProjectRecordsPage
dbxRecords, err := db.db.Limited_StripecoinpaymentsInvoiceProjectRecord_By_CreatedAt_LessOrEqual_And_State_OrderBy_Desc_CreatedAt(ctx,
dbx.StripecoinpaymentsInvoiceProjectRecord_CreatedAt(before),
dbx.StripecoinpaymentsInvoiceProjectRecord_State(invoiceProjectRecordStateUnapplied.Int()),
limit+1,
offset,
)
if err != nil {
return stripecoinpayments.ProjectRecordsPage{}, err
}
if len(dbxRecords) == limit+1 {
page.Next = true
page.NextOffset = offset + int64(limit) + 1
dbxRecords = dbxRecords[:len(dbxRecords)-1]
}
for _, dbxRecord := range dbxRecords {
record, err := fromDBXInvoiceProjectRecord(dbxRecord)
if err != nil {
return stripecoinpayments.ProjectRecordsPage{}, err
}
page.Records = append(page.Records, *record)
}
return page, nil
}
// fromDBXInvoiceProjectRecord converts *dbx.StripecoinpaymentsInvoiceProjectRecord to *stripecoinpayments.ProjectRecord
func fromDBXInvoiceProjectRecord(dbxRecord *dbx.StripecoinpaymentsInvoiceProjectRecord) (*stripecoinpayments.ProjectRecord, error) {
id, err := bytesToUUID(dbxRecord.Id)
if err != nil {
return nil, errs.Wrap(err)
}
projectID, err := bytesToUUID(dbxRecord.ProjectId)
if err != nil {
return nil, errs.Wrap(err)
}
return &stripecoinpayments.ProjectRecord{
ID: id,
ProjectID: projectID,
Storage: dbxRecord.Storage,
Egress: dbxRecord.Egress,
Objects: dbxRecord.Objects,
PeriodStart: dbxRecord.PeriodStart,
PeriodEnd: dbxRecord.PeriodEnd,
}, nil
}

View File

@ -1360,6 +1360,26 @@ func (db *DB) PostgresMigration() *migrate.Migration {
`DROP TABLE bucket_usages CASCADE;`, `DROP TABLE bucket_usages CASCADE;`,
}, },
}, },
{
DB: db.db,
Description: "Add stripecoinpayments_invoice_project_records",
Version: 65,
Action: migrate.SQL{
`CREATE TABLE stripecoinpayments_invoice_project_records (
id bytea NOT NULL,
project_id bytea NOT NULL,
storage double precision NOT NULL,
egress bigint NOT NULL,
objects bigint NOT NULL,
period_start timestamp with time zone NOT NULL,
period_end timestamp with time zone NOT NULL,
state integer NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( id ),
UNIQUE ( project_id, period_start, period_end )
);`,
},
},
}, },
} }
} }

View File

@ -124,6 +124,37 @@ func (projects *projects) Update(ctx context.Context, project *console.Project)
return err return err
} }
// List returns paginated projects, created before provided timestamp.
func (projects *projects) List(ctx context.Context, offset int64, limit int, before time.Time) (_ console.ProjectsPage, err error) {
defer mon.Task()(&ctx)(&err)
var page console.ProjectsPage
dbxProjects, err := projects.db.Limited_Project_By_CreatedAt_Less_OrderBy_Asc_CreatedAt(ctx,
dbx.Project_CreatedAt(before.UTC()),
limit+1,
offset,
)
if err != nil {
return console.ProjectsPage{}, err
}
if len(dbxProjects) == limit+1 {
page.Next = true
page.NextOffset = offset + int64(limit) + 1
dbxProjects = dbxProjects[:len(dbxProjects)-1]
}
projs, err := projectsFromDbxSlice(ctx, dbxProjects)
if err != nil {
return console.ProjectsPage{}, err
}
page.Projects = projs
return page, nil
}
// projectFromDBX is used for creating Project entity from autogenerated dbx.Project struct // projectFromDBX is used for creating Project entity from autogenerated dbx.Project struct
func projectFromDBX(ctx context.Context, project *dbx.Project) (_ *console.Project, err error) { func projectFromDBX(ctx context.Context, project *dbx.Project) (_ *console.Project, err error) {
defer mon.Task()(&ctx)(&err) defer mon.Task()(&ctx)(&err)

View File

@ -0,0 +1,34 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package satellitedb
import (
"storj.io/storj/satellite/payments/stripecoinpayments"
dbx "storj.io/storj/satellite/satellitedb/dbx"
)
// ensures that *stripeCoinPaymentsDB implements stripecoinpayments.DB.
var _ stripecoinpayments.DB = (*stripeCoinPaymentsDB)(nil)
// stripeCoinPaymentsDB is stripecoinpayments DB.
//
// architecture: Database
type stripeCoinPaymentsDB struct {
db *dbx.DB
}
// Customers is getter for customers db.
func (db *stripeCoinPaymentsDB) Customers() stripecoinpayments.CustomersDB {
return &customers{db: db.db}
}
// Transactions is getter for transactions db.
func (db *stripeCoinPaymentsDB) Transactions() stripecoinpayments.TransactionsDB {
return &coinPaymentsTransactions{db: db.db}
}
// ProjectRecords is getter for invoice project records db.
func (db *stripeCoinPaymentsDB) ProjectRecords() stripecoinpayments.ProjectRecordsDB {
return &invoiceProjectRecords{db: db.db}
}

View File

@ -0,0 +1,420 @@
-- AUTOGENERATED BY gopkg.in/spacemonkeygo/dbx.v1
-- DO NOT EDIT
CREATE TABLE accounting_rollups
(
id bigserial NOT NULL,
node_id bytea NOT NULL,
start_time timestamp with time zone NOT NULL,
put_total bigint NOT NULL,
get_total bigint NOT NULL,
get_audit_total bigint NOT NULL,
get_repair_total bigint NOT NULL,
put_repair_total bigint NOT NULL,
at_rest_total double precision NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE accounting_timestamps
(
name text NOT NULL,
value timestamp with time zone NOT NULL,
PRIMARY KEY (name)
);
CREATE TABLE bucket_bandwidth_rollups
(
bucket_name bytea NOT NULL,
project_id bytea NOT NULL,
interval_start timestamp NOT NULL,
interval_seconds integer NOT NULL,
action integer NOT NULL,
inline bigint NOT NULL,
allocated bigint NOT NULL,
settled bigint NOT NULL,
PRIMARY KEY (bucket_name, project_id, interval_start, action)
);
CREATE TABLE bucket_storage_tallies
(
bucket_name bytea NOT NULL,
project_id bytea NOT NULL,
interval_start timestamp NOT NULL,
inline bigint NOT NULL,
remote bigint NOT NULL,
remote_segments_count integer NOT NULL,
inline_segments_count integer NOT NULL,
object_count integer NOT NULL,
metadata_size bigint NOT NULL,
PRIMARY KEY (bucket_name, project_id, interval_start)
);
CREATE TABLE injuredsegments
(
path bytea NOT NULL,
data bytea NOT NULL,
attempted timestamp,
PRIMARY KEY (path)
);
CREATE TABLE irreparabledbs
(
segmentpath bytea NOT NULL,
segmentdetail bytea NOT NULL,
pieces_lost_count bigint NOT NULL,
seg_damaged_unix_sec bigint NOT NULL,
repair_attempt_count bigint NOT NULL,
PRIMARY KEY (segmentpath)
);
CREATE TABLE nodes
(
id bytea NOT NULL,
address text NOT NULL,
last_net text NOT NULL,
protocol integer NOT NULL,
type integer NOT NULL,
email text NOT NULL,
wallet text NOT NULL,
free_bandwidth bigint NOT NULL,
free_disk bigint NOT NULL,
piece_count bigint NOT NULL,
major bigint NOT NULL,
minor bigint NOT NULL,
patch bigint NOT NULL,
hash text NOT NULL,
timestamp timestamp with time zone NOT NULL,
release boolean NOT NULL,
latency_90 bigint NOT NULL,
audit_success_count bigint NOT NULL,
total_audit_count bigint NOT NULL,
uptime_success_count bigint NOT NULL,
total_uptime_count bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
last_contact_success timestamp with time zone NOT NULL,
last_contact_failure timestamp with time zone NOT NULL,
contained boolean NOT NULL,
disqualified timestamp with time zone,
audit_reputation_alpha double precision NOT NULL,
audit_reputation_beta double precision NOT NULL,
uptime_reputation_alpha double precision NOT NULL,
uptime_reputation_beta double precision NOT NULL,
exit_initiated_at timestamp,
exit_loop_completed_at timestamp,
exit_finished_at timestamp,
exit_success boolean NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE offers
(
id serial NOT NULL,
name text NOT NULL,
description text NOT NULL,
award_credit_in_cents integer NOT NULL,
invitee_credit_in_cents integer NOT NULL,
award_credit_duration_days integer,
invitee_credit_duration_days integer,
redeemable_cap integer,
expires_at timestamp with time zone NOT NULL,
created_at timestamp with time zone NOT NULL,
status integer NOT NULL,
type integer NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE peer_identities
(
node_id bytea NOT NULL,
leaf_serial_number bytea NOT NULL,
chain bytea NOT NULL,
updated_at timestamp with time zone NOT NULL,
PRIMARY KEY (node_id)
);
CREATE TABLE pending_audits
(
node_id bytea NOT NULL,
piece_id bytea NOT NULL,
stripe_index bigint NOT NULL,
share_size bigint NOT NULL,
expected_share_hash bytea NOT NULL,
reverify_count bigint NOT NULL,
path bytea NOT NULL,
PRIMARY KEY (node_id)
);
CREATE TABLE projects
(
id bytea NOT NULL,
name text NOT NULL,
description text NOT NULL,
usage_limit bigint NOT NULL,
partner_id bytea,
owner_id bytea NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE registration_tokens
(
secret bytea NOT NULL,
owner_id bytea,
project_limit integer NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY (secret),
UNIQUE (owner_id)
);
CREATE TABLE reset_password_tokens
(
secret bytea NOT NULL,
owner_id bytea NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY (secret),
UNIQUE (owner_id)
);
CREATE TABLE serial_numbers
(
id serial NOT NULL,
serial_number bytea NOT NULL,
bucket_id bytea NOT NULL,
expires_at timestamp NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE storagenode_bandwidth_rollups
(
storagenode_id bytea NOT NULL,
interval_start timestamp NOT NULL,
interval_seconds integer NOT NULL,
action integer NOT NULL,
allocated bigint NOT NULL,
settled bigint NOT NULL,
PRIMARY KEY (storagenode_id, interval_start, action)
);
CREATE TABLE storagenode_storage_tallies
(
id bigserial NOT NULL,
node_id bytea NOT NULL,
interval_end_time timestamp with time zone NOT NULL,
data_total double precision NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE users (
id bytea NOT NULL,
email text NOT NULL,
normalized_email text NOT NULL,
full_name text NOT NULL,
short_name text,
password_hash bytea NOT NULL,
status integer NOT NULL,
partner_id bytea,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( id )
);
CREATE TABLE value_attributions
(
project_id bytea NOT NULL,
bucket_name bytea NOT NULL,
partner_id bytea NOT NULL,
last_updated timestamp NOT NULL,
PRIMARY KEY (project_id, bucket_name)
);
CREATE TABLE api_keys
(
id bytea NOT NULL,
project_id bytea NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
head bytea NOT NULL,
name text NOT NULL,
secret bytea NOT NULL,
partner_id bytea,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY (id),
UNIQUE (head),
UNIQUE (name, project_id)
);
CREATE TABLE bucket_metainfos
(
id bytea NOT NULL,
project_id bytea NOT NULL REFERENCES projects (id),
name bytea NOT NULL,
partner_id bytea,
path_cipher integer NOT NULL,
created_at timestamp with time zone NOT NULL,
default_segment_size integer NOT NULL,
default_encryption_cipher_suite integer NOT NULL,
default_encryption_block_size integer NOT NULL,
default_redundancy_algorithm integer NOT NULL,
default_redundancy_share_size integer NOT NULL,
default_redundancy_required_shares integer NOT NULL,
default_redundancy_repair_shares integer NOT NULL,
default_redundancy_optimal_shares integer NOT NULL,
default_redundancy_total_shares integer NOT NULL,
PRIMARY KEY (id),
UNIQUE (name, project_id)
);
CREATE TABLE project_invoice_stamps
(
project_id bytea NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
invoice_id bytea NOT NULL,
start_date timestamp with time zone NOT NULL,
end_date timestamp with time zone NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY (project_id, start_date, end_date),
UNIQUE (invoice_id)
);
CREATE TABLE project_members
(
member_id bytea NOT NULL REFERENCES users (id) ON DELETE CASCADE,
project_id bytea NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY (member_id, project_id)
);
CREATE TABLE used_serials
(
serial_number_id integer NOT NULL REFERENCES serial_numbers (id) ON DELETE CASCADE,
storage_node_id bytea NOT NULL,
PRIMARY KEY (serial_number_id, storage_node_id)
);
CREATE TABLE user_credits
(
id serial NOT NULL,
user_id bytea NOT NULL REFERENCES users (id) ON DELETE CASCADE,
offer_id integer NOT NULL REFERENCES offers (id),
referred_by bytea REFERENCES users (id) ON DELETE SET NULL,
type text NOT NULL,
credits_earned_in_cents integer NOT NULL,
credits_used_in_cents integer NOT NULL,
expires_at timestamp with time zone NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE graceful_exit_progress (
node_id bytea NOT NULL,
bytes_transferred bigint NOT NULL,
pieces_transferred bigint NOT NULL,
pieces_failed bigint NOT NULL,
updated_at timestamp NOT NULL,
PRIMARY KEY ( node_id )
);
CREATE TABLE graceful_exit_transfer_queue (
node_id bytea NOT NULL,
path bytea NOT NULL,
piece_num integer NOT NULL,
durability_ratio double precision NOT NULL,
queued_at timestamp NOT NULL,
requested_at timestamp,
last_failed_at timestamp,
last_failed_code integer,
failed_count integer,
finished_at timestamp,
PRIMARY KEY ( node_id, path, piece_num )
);
CREATE TABLE stripe_customers (
user_id bytea NOT NULL,
customer_id text NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( user_id ),
UNIQUE ( customer_id )
);
CREATE TABLE coinpayments_transactions (
id text NOT NULL,
user_id bytea NOT NULL,
address text NOT NULL,
amount bytea NOT NULL,
received bytea NOT NULL,
status integer NOT NULL,
key text NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( id )
);
CREATE TABLE stripecoinpayments_apply_balance_intents (
tx_id text NOT NULL REFERENCES coinpayments_transactions( id ) ON DELETE CASCADE,
state integer NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( tx_id )
);
CREATE TABLE stripecoinpayments_invoice_project_records (
id bytea NOT NULL,
project_id bytea NOT NULL,
storage double precision NOT NULL,
egress bigint NOT NULL,
objects bigint NOT NULL,
period_start timestamp with time zone NOT NULL,
period_end timestamp with time zone NOT NULL,
state integer NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( id ),
UNIQUE ( project_id, period_start, period_end )
);
CREATE INDEX bucket_name_project_id_interval_start_interval_seconds ON bucket_bandwidth_rollups ( bucket_name, project_id, interval_start, interval_seconds );
CREATE INDEX node_last_ip ON nodes ( last_net );
CREATE UNIQUE INDEX serial_number ON serial_numbers ( serial_number );
CREATE INDEX serial_numbers_expires_at_index ON serial_numbers ( expires_at );
CREATE INDEX storagenode_id_interval_start_interval_seconds ON storagenode_bandwidth_rollups ( storagenode_id, interval_start, interval_seconds );
CREATE UNIQUE INDEX credits_earned_user_id_offer_id ON user_credits (id, offer_id) WHERE credits_earned_in_cents=0;
INSERT INTO "accounting_rollups"("id", "node_id", "start_time", "put_total", "get_total", "get_audit_total", "get_repair_total", "put_repair_total", "at_rest_total") VALUES (1, E'\\367M\\177\\251]t/\\022\\256\\214\\265\\025\\224\\204:\\217\\212\\0102<\\321\\374\\020&\\271Qc\\325\\261\\354\\246\\233'::bytea, '2019-02-09 00:00:00+00', 1000, 2000, 3000, 4000, 0, 5000);
INSERT INTO "accounting_timestamps" VALUES ('LastAtRestTally', '0001-01-01 00:00:00+00');
INSERT INTO "accounting_timestamps" VALUES ('LastRollup', '0001-01-01 00:00:00+00');
INSERT INTO "accounting_timestamps" VALUES ('LastBandwidthTally', '0001-01-01 00:00:00+00');
INSERT INTO "nodes"("id", "address", "last_net", "protocol", "type", "email", "wallet", "free_bandwidth", "free_disk", "piece_count", "major", "minor", "patch", "hash", "timestamp", "release","latency_90", "audit_success_count", "total_audit_count", "uptime_success_count", "total_uptime_count", "created_at", "updated_at", "last_contact_success", "last_contact_failure", "contained", "disqualified", "audit_reputation_alpha", "audit_reputation_beta", "uptime_reputation_alpha", "uptime_reputation_beta", "exit_success") VALUES (E'\\153\\313\\233\\074\\327\\177\\136\\070\\346\\001', '127.0.0.1:55516', '', 0, 4, '', '', -1, -1, 0, 0, 1, 0, '', 'epoch', false, 0, 0, 5, 0, 5, '2019-02-14 08:07:31.028103+00', '2019-02-14 08:07:31.108963+00', 'epoch', 'epoch', false, NULL, 50, 5, 100, 5, false);
INSERT INTO "nodes"("id", "address", "last_net", "protocol", "type", "email", "wallet", "free_bandwidth", "free_disk", "piece_count", "major", "minor", "patch", "hash", "timestamp", "release","latency_90", "audit_success_count", "total_audit_count", "uptime_success_count", "total_uptime_count", "created_at", "updated_at", "last_contact_success", "last_contact_failure", "contained", "disqualified", "audit_reputation_alpha", "audit_reputation_beta", "uptime_reputation_alpha", "uptime_reputation_beta", "exit_success") VALUES (E'\\006\\223\\250R\\221\\005\\365\\377v>0\\266\\365\\216\\255?\\347\\244\\371?2\\264\\262\\230\\007<\\001\\262\\263\\237\\247n', '127.0.0.1:55518', '', 0, 4, '', '', -1, -1, 0, 0, 1, 0, '', 'epoch', false, 0, 0, 0, 3, 3, '2019-02-14 08:07:31.028103+00', '2019-02-14 08:07:31.108963+00', 'epoch', 'epoch', false, NULL, 50, 0, 100, 0, false);
INSERT INTO "nodes"("id", "address", "last_net", "protocol", "type", "email", "wallet", "free_bandwidth", "free_disk", "piece_count", "major", "minor", "patch", "hash", "timestamp", "release","latency_90", "audit_success_count", "total_audit_count", "uptime_success_count", "total_uptime_count", "created_at", "updated_at", "last_contact_success", "last_contact_failure", "contained", "disqualified", "audit_reputation_alpha", "audit_reputation_beta", "uptime_reputation_alpha", "uptime_reputation_beta", "exit_success") VALUES (E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014', '127.0.0.1:55517', '', 0, 4, '', '', -1, -1, 0, 0, 1, 0, '', 'epoch', false, 0, 0, 0, 0, 0, '2019-02-14 08:07:31.028103+00', '2019-02-14 08:07:31.108963+00', 'epoch', 'epoch', false, NULL, 50, 0, 100, 0, false);
INSERT INTO "nodes"("id", "address", "last_net", "protocol", "type", "email", "wallet", "free_bandwidth", "free_disk", "piece_count", "major", "minor", "patch", "hash", "timestamp", "release","latency_90", "audit_success_count", "total_audit_count", "uptime_success_count", "total_uptime_count", "created_at", "updated_at", "last_contact_success", "last_contact_failure", "contained", "disqualified", "audit_reputation_alpha", "audit_reputation_beta", "uptime_reputation_alpha", "uptime_reputation_beta", "exit_success") VALUES (E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\015', '127.0.0.1:55519', '', 0, 4, '', '', -1, -1, 0, 0, 1, 0, '', 'epoch', false, 0, 1, 2, 1, 2, '2019-02-14 08:07:31.028103+00', '2019-02-14 08:07:31.108963+00', 'epoch', 'epoch', false, NULL, 50, 1, 100, 1, false);
INSERT INTO "nodes"("id", "address", "last_net", "protocol", "type", "email", "wallet", "free_bandwidth", "free_disk", "piece_count", "major", "minor", "patch", "hash", "timestamp", "release","latency_90", "audit_success_count", "total_audit_count", "uptime_success_count", "total_uptime_count", "created_at", "updated_at", "last_contact_success", "last_contact_failure", "contained", "disqualified", "audit_reputation_alpha", "audit_reputation_beta", "uptime_reputation_alpha", "uptime_reputation_beta", "exit_success") VALUES (E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\016', '127.0.0.1:55520', '', 0, 4, '', '', -1, -1, 0, 0, 1, 0, '', 'epoch', false, 0, 300, 400, 300, 400, '2019-02-14 08:07:31.028103+00', '2019-02-14 08:07:31.108963+00', 'epoch', 'epoch', false, NULL, 300, 100, 300, 100, false);
INSERT INTO "users"("id", "full_name", "short_name", "email", "normalized_email", "password_hash", "status", "partner_id", "created_at") VALUES (E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, 'Noahson', 'William', '1email1@mail.test', '1EMAIL1@MAIL.TEST', E'some_readable_hash'::bytea, 1, NULL, '2019-02-14 08:28:24.614594+00');
INSERT INTO "projects"("id", "name", "description", "usage_limit", "partner_id", "owner_id", "created_at") VALUES (E'\\022\\217/\\014\\376!K\\023\\276\\031\\311}m\\236\\205\\300'::bytea, 'ProjectName', 'projects description', 0, NULL, E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, '2019-02-14 08:28:24.254934+00');
INSERT INTO "projects"("id", "name", "description", "usage_limit", "partner_id", "owner_id", "created_at") VALUES (E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014'::bytea, 'projName1', 'Test project 1', 0, NULL, E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, '2019-02-14 08:28:24.636949+00');
INSERT INTO "project_members"("member_id", "project_id", "created_at") VALUES (E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014'::bytea, '2019-02-14 08:28:24.677953+00');
INSERT INTO "project_members"("member_id", "project_id", "created_at") VALUES (E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, E'\\022\\217/\\014\\376!K\\023\\276\\031\\311}m\\236\\205\\300'::bytea, '2019-02-13 08:28:24.677953+00');
INSERT INTO "irreparabledbs" ("segmentpath", "segmentdetail", "pieces_lost_count", "seg_damaged_unix_sec", "repair_attempt_count") VALUES ('\x49616d5365676d656e746b6579696e666f30', '\x49616d5365676d656e7464657461696c696e666f30', 10, 1550159554, 10);
INSERT INTO "injuredsegments" ("path", "data") VALUES ('0', '\x0a0130120100');
INSERT INTO "injuredsegments" ("path", "data") VALUES ('here''s/a/great/path', '\x0a136865726527732f612f67726561742f70617468120a0102030405060708090a');
INSERT INTO "injuredsegments" ("path", "data") VALUES ('yet/another/cool/path', '\x0a157965742f616e6f746865722f636f6f6c2f70617468120a0102030405060708090a');
INSERT INTO "injuredsegments" ("path", "data") VALUES ('so/many/iconic/paths/to/choose/from', '\x0a23736f2f6d616e792f69636f6e69632f70617468732f746f2f63686f6f73652f66726f6d120a0102030405060708090a');
INSERT INTO "registration_tokens" ("secret", "owner_id", "project_limit", "created_at") VALUES (E'\\070\\127\\144\\013\\332\\344\\102\\376\\306\\056\\303\\130\\106\\132\\321\\276\\321\\274\\170\\264\\054\\333\\221\\116\\154\\221\\335\\070\\220\\146\\344\\216'::bytea, null, 1, '2019-02-14 08:28:24.677953+00');
INSERT INTO "serial_numbers" ("id", "serial_number", "bucket_id", "expires_at") VALUES (1, E'0123456701234567'::bytea, E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014/testbucket'::bytea, '2019-03-06 08:28:24.677953+00');
INSERT INTO "used_serials" ("serial_number_id", "storage_node_id") VALUES (1, E'\\006\\223\\250R\\221\\005\\365\\377v>0\\266\\365\\216\\255?\\347\\244\\371?2\\264\\262\\230\\007<\\001\\262\\263\\237\\247n');
INSERT INTO "storagenode_bandwidth_rollups" ("storagenode_id", "interval_start", "interval_seconds", "action", "allocated", "settled") VALUES (E'\\006\\223\\250R\\221\\005\\365\\377v>0\\266\\365\\216\\255?\\347\\244\\371?2\\264\\262\\230\\007<\\001\\262\\263\\237\\247n', '2019-03-06 08:00:00.000000+00', 3600, 1, 1024, 2024);
INSERT INTO "storagenode_storage_tallies" VALUES (1, E'\\3510\\323\\225"~\\036<\\342\\330m\\0253Jhr\\246\\233K\\246#\\2303\\351\\256\\275j\\212UM\\362\\207', '2019-02-14 08:16:57.812849+00', 1000);
INSERT INTO "bucket_bandwidth_rollups" ("bucket_name", "project_id", "interval_start", "interval_seconds", "action", "inline", "allocated", "settled") VALUES (E'testbucket'::bytea, E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014'::bytea,'2019-03-06 08:00:00.000000+00', 3600, 1, 1024, 2024, 3024);
INSERT INTO "bucket_storage_tallies" ("bucket_name", "project_id", "interval_start", "inline", "remote", "remote_segments_count", "inline_segments_count", "object_count", "metadata_size") VALUES (E'testbucket'::bytea, E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014'::bytea,'2019-03-06 08:00:00.000000+00', 4024, 5024, 0, 0, 0, 0);
INSERT INTO "bucket_bandwidth_rollups" ("bucket_name", "project_id", "interval_start", "interval_seconds", "action", "inline", "allocated", "settled") VALUES (E'testbucket'::bytea, E'\\170\\160\\157\\370\\274\\366\\113\\364\\272\\235\\301\\243\\321\\102\\321\\136'::bytea,'2019-03-06 08:00:00.000000+00', 3600, 1, 1024, 2024, 3024);
INSERT INTO "bucket_storage_tallies" ("bucket_name", "project_id", "interval_start", "inline", "remote", "remote_segments_count", "inline_segments_count", "object_count", "metadata_size") VALUES (E'testbucket'::bytea, E'\\170\\160\\157\\370\\274\\366\\113\\364\\272\\235\\301\\243\\321\\102\\321\\136'::bytea,'2019-03-06 08:00:00.000000+00', 4024, 5024, 0, 0, 0, 0);
INSERT INTO "reset_password_tokens" ("secret", "owner_id", "created_at") VALUES (E'\\070\\127\\144\\013\\332\\344\\102\\376\\306\\056\\303\\130\\106\\132\\321\\276\\321\\274\\170\\264\\054\\333\\221\\116\\154\\221\\335\\070\\220\\146\\344\\216'::bytea, E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, '2019-05-08 08:28:24.677953+00');
INSERT INTO "offers" ("name", "description", "award_credit_in_cents", "invitee_credit_in_cents", "award_credit_duration_days", "invitee_credit_duration_days", "redeemable_cap", "expires_at", "created_at", "status", "type") VALUES ('testOffer', 'Test offer 1', 0, 0, 14, 14, 50, '2019-03-14 08:28:24.636949+00', '2019-02-14 08:28:24.636949+00', 0, 0);
INSERT INTO "offers" ("name","description","award_credit_in_cents","award_credit_duration_days", "invitee_credit_in_cents","invitee_credit_duration_days", "expires_at","created_at","status","type") VALUES ('Default free credit offer','Is active when no active free credit offer',0, NULL,300, 14, '2119-03-14 08:28:24.636949+00','2019-07-14 08:28:24.636949+00',1,1);
INSERT INTO "api_keys" ("id", "project_id", "head", "name", "secret", "partner_id", "created_at") VALUES (E'\\334/\\302;\\225\\355O\\323\\276f\\247\\354/6\\241\\033'::bytea, E'\\022\\217/\\014\\376!K\\023\\276\\031\\311}m\\236\\205\\300'::bytea, E'\\111\\142\\147\\304\\132\\375\\070\\163\\270\\160\\251\\370\\126\\063\\351\\037\\257\\071\\143\\375\\351\\320\\253\\232\\220\\260\\075\\173\\306\\307\\115\\136'::bytea, 'key 2', E'\\254\\011\\315\\333\\273\\365\\001\\071\\024\\154\\253\\332\\301\\216\\361\\074\\221\\367\\251\\231\\274\\333\\300\\367\\001\\272\\327\\111\\315\\123\\042\\016'::bytea, NULL, '2019-02-14 08:28:24.267934+00');
INSERT INTO "project_invoice_stamps" ("project_id", "invoice_id", "start_date", "end_date", "created_at") VALUES (E'\\022\\217/\\014\\376!K\\023\\276\\031\\311}m\\236\\205\\300'::bytea, E'\\363\\311\\033w\\222\\303,'::bytea, '2019-06-01 08:28:24.267934+00', '2019-06-29 08:28:24.267934+00', '2019-06-01 08:28:24.267934+00');
INSERT INTO "value_attributions" ("project_id", "bucket_name", "partner_id", "last_updated") VALUES (E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, E''::bytea, E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014'::bytea,'2019-02-14 08:07:31.028103+00');
INSERT INTO "user_credits" ("id", "user_id", "offer_id", "referred_by", "credits_earned_in_cents", "credits_used_in_cents", "type", "expires_at", "created_at") VALUES (1, E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, 1, E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, 200, 0, 'invalid', '2019-10-01 08:28:24.267934+00', '2019-06-01 08:28:24.267934+00');
INSERT INTO "bucket_metainfos" ("id", "project_id", "name", "partner_id", "created_at", "path_cipher", "default_segment_size", "default_encryption_cipher_suite", "default_encryption_block_size", "default_redundancy_algorithm", "default_redundancy_share_size", "default_redundancy_required_shares", "default_redundancy_repair_shares", "default_redundancy_optimal_shares", "default_redundancy_total_shares") VALUES (E'\\334/\\302;\\225\\355O\\323\\276f\\247\\354/6\\241\\033'::bytea, E'\\022\\217/\\014\\376!K\\023\\276\\031\\311}m\\236\\205\\300'::bytea, E'testbucketuniquename'::bytea, NULL, '2019-06-14 08:28:24.677953+00', 1, 65536, 1, 8192, 1, 4096, 4, 6, 8, 10);
INSERT INTO "pending_audits" ("node_id", "piece_id", "stripe_index", "share_size", "expected_share_hash", "reverify_count", "path") VALUES (E'\\153\\313\\233\\074\\327\\177\\136\\070\\346\\001'::bytea, E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, 5, 1024, E'\\070\\127\\144\\013\\332\\344\\102\\376\\306\\056\\303\\130\\106\\132\\321\\276\\321\\274\\170\\264\\054\\333\\221\\116\\154\\221\\335\\070\\220\\146\\344\\216'::bytea, 1, 'not null');
INSERT INTO "peer_identities" VALUES (E'\\334/\\302;\\225\\355O\\323\\276f\\247\\354/6\\241\\033'::bytea, E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014'::bytea, E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, '2019-02-14 08:07:31.335028+00');
INSERT INTO "graceful_exit_progress" ("node_id", "bytes_transferred", "pieces_transferred", "pieces_failed", "updated_at") VALUES (E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\016', 1000000000000000, 0, 0, '2019-09-12 10:07:31.028103');
INSERT INTO "graceful_exit_transfer_queue" ("node_id", "path", "piece_num", "durability_ratio", "queued_at", "requested_at", "last_failed_at", "last_failed_code", "failed_count", "finished_at") VALUES (E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\016', E'f8419768-5baa-4901-b3ba-62808013ec45/s0/test3/\\240\\243\\223n \\334~b}\\2624)\\250m\\201\\202\\235\\276\\361\\3304\\323\\352\\311\\361\\353;\\326\\311', 8, 1.0, '2019-09-12 10:07:31.028103', '2019-09-12 10:07:32.028103', null, null, 0, '2019-09-12 10:07:33.028103');
INSERT INTO "graceful_exit_transfer_queue" ("node_id", "path", "piece_num", "durability_ratio", "queued_at", "requested_at", "last_failed_at", "last_failed_code", "failed_count", "finished_at") VALUES (E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\016', E'f8419768-5baa-4901-b3ba-62808013ec45/s0/test3/\\240\\243\\223n \\334~b}\\2624)\\250m\\201\\202\\235\\276\\361\\3304\\323\\352\\311\\361\\353;\\326\\312', 8, 1.0, '2019-09-12 10:07:31.028103', '2019-09-12 10:07:32.028103', null, null, 0, '2019-09-12 10:07:33.028103');
INSERT INTO "stripe_customers" ("user_id", "customer_id", "created_at") VALUES (E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, 'stripe_id', '2019-06-01 08:28:24.267934+00');
INSERT INTO "coinpayments_transactions" ("id", "user_id", "address", "amount", "received", "status", "key", "created_at") VALUES ('tx_id', E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, 'address', E'\\363\\311\\033w'::bytea, E'\\363\\311\\033w'::bytea, 1, 'key', '2019-06-01 08:28:24.267934+00');
INSERT INTO "graceful_exit_transfer_queue" ("node_id", "path", "piece_num", "durability_ratio", "queued_at", "requested_at", "last_failed_at", "last_failed_code", "failed_count", "finished_at") VALUES (E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\016', E'f8419768-5baa-4901-b3ba-62808013ec45/s0/test3/\\240\\243\\223n \\334~b}\\2624)\\250m\\201\\202\\235\\276\\361\\3304\\323\\352\\311\\361\\353;\\326\\311', 9, 1.0, '2019-09-12 10:07:31.028103', '2019-09-12 10:07:32.028103', null, null, 0, '2019-09-12 10:07:33.028103');
INSERT INTO "graceful_exit_transfer_queue" ("node_id", "path", "piece_num", "durability_ratio", "queued_at", "requested_at", "last_failed_at", "last_failed_code", "failed_count", "finished_at") VALUES (E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\016', E'f8419768-5baa-4901-b3ba-62808013ec45/s0/test3/\\240\\243\\223n \\334~b}\\2624)\\250m\\201\\202\\235\\276\\361\\3304\\323\\352\\311\\361\\353;\\326\\312', 9, 1.0, '2019-09-12 10:07:31.028103', '2019-09-12 10:07:32.028103', null, null, 0, '2019-09-12 10:07:33.028103');
INSERT INTO "stripecoinpayments_apply_balance_intents" ("tx_id", "state", "created_at") VALUES ('tx_id', 0, '2019-06-01 08:28:24.267934+00');
-- NEW DATA --
INSERT INTO "stripecoinpayments_invoice_project_records"("id", "project_id", "storage", "egress", "objects", "period_start", "period_end", "state", "created_at") VALUES (E'\\022\\217/\\014\\376!K\\023\\276\\031\\311}m\\236\\205\\300'::bytea, E'\\021\\217/\\014\\376!K\\023\\276\\031\\311}m\\236\\205\\300'::bytea, 0, 0, 0, '2019-06-01 08:28:24.267934+00', '2019-06-01 08:28:24.267934+00', 0, '2019-06-01 08:28:24.267934+00')