satellite/payments/stripecoinpayments: update invoicing to use credit note
Rather than using Invoice Items to account for storjscan token payments, credit notes will be used and applied to the users finalized invoice. This credit note will reduce the amount due of the users invoice based on the amount of storj token balance the user has on the satellite. Applying credit notes to a finalized invoice also requires that the invoice not be automatically paid when finalized. Therefore, a new command (pay-invoices) was added to initiate payment for users invoices. Change-Id: Ie539375a10e842e3cb64bf0140834bbab0774f54
This commit is contained in:
parent
a3d9630336
commit
a3a3ffd123
@ -213,12 +213,6 @@ var (
|
|||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: cmdCreateCustomerProjectInvoiceItems,
|
RunE: cmdCreateCustomerProjectInvoiceItems,
|
||||||
}
|
}
|
||||||
createCustomerTokenInvoiceItemsCmd = &cobra.Command{
|
|
||||||
Use: "create-token-invoice-items [period]",
|
|
||||||
Short: "Creates stripe invoice line items for token payments",
|
|
||||||
Long: "Creates stripe invoice line items for unapplied token balances.",
|
|
||||||
RunE: cmdCreateCustomerTokenInvoiceItems,
|
|
||||||
}
|
|
||||||
createCustomerInvoicesCmd = &cobra.Command{
|
createCustomerInvoicesCmd = &cobra.Command{
|
||||||
Use: "create-invoices [period]",
|
Use: "create-invoices [period]",
|
||||||
Short: "Creates stripe invoices from pending invoice items",
|
Short: "Creates stripe invoices from pending invoice items",
|
||||||
@ -232,6 +226,12 @@ var (
|
|||||||
Long: "Finalizes all draft stripe invoices known to satellite's stripe account.",
|
Long: "Finalizes all draft stripe invoices known to satellite's stripe account.",
|
||||||
RunE: cmdFinalizeCustomerInvoices,
|
RunE: cmdFinalizeCustomerInvoices,
|
||||||
}
|
}
|
||||||
|
payCustomerInvoicesCmd = &cobra.Command{
|
||||||
|
Use: "pay-invoices",
|
||||||
|
Short: "pay finalized invoices",
|
||||||
|
Long: "attempts payment on all open finalized invoices according to subscriptions settings.",
|
||||||
|
RunE: cmdPayCustomerInvoices,
|
||||||
|
}
|
||||||
stripeCustomerCmd = &cobra.Command{
|
stripeCustomerCmd = &cobra.Command{
|
||||||
Use: "ensure-stripe-customer",
|
Use: "ensure-stripe-customer",
|
||||||
Short: "Ensures that we have a stripe customer for every user",
|
Short: "Ensures that we have a stripe customer for every user",
|
||||||
@ -345,9 +345,9 @@ func init() {
|
|||||||
billingCmd.AddCommand(applyFreeTierCouponsCmd)
|
billingCmd.AddCommand(applyFreeTierCouponsCmd)
|
||||||
billingCmd.AddCommand(prepareCustomerInvoiceRecordsCmd)
|
billingCmd.AddCommand(prepareCustomerInvoiceRecordsCmd)
|
||||||
billingCmd.AddCommand(createCustomerProjectInvoiceItemsCmd)
|
billingCmd.AddCommand(createCustomerProjectInvoiceItemsCmd)
|
||||||
billingCmd.AddCommand(createCustomerTokenInvoiceItemsCmd)
|
|
||||||
billingCmd.AddCommand(createCustomerInvoicesCmd)
|
billingCmd.AddCommand(createCustomerInvoicesCmd)
|
||||||
billingCmd.AddCommand(finalizeCustomerInvoicesCmd)
|
billingCmd.AddCommand(finalizeCustomerInvoicesCmd)
|
||||||
|
billingCmd.AddCommand(payCustomerInvoicesCmd)
|
||||||
billingCmd.AddCommand(stripeCustomerCmd)
|
billingCmd.AddCommand(stripeCustomerCmd)
|
||||||
consistencyCmd.AddCommand(consistencyGECleanupCmd)
|
consistencyCmd.AddCommand(consistencyGECleanupCmd)
|
||||||
process.Bind(runCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
process.Bind(runCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||||
@ -372,9 +372,9 @@ func init() {
|
|||||||
process.Bind(applyFreeTierCouponsCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
process.Bind(applyFreeTierCouponsCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||||
process.Bind(prepareCustomerInvoiceRecordsCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
process.Bind(prepareCustomerInvoiceRecordsCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||||
process.Bind(createCustomerProjectInvoiceItemsCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
process.Bind(createCustomerProjectInvoiceItemsCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||||
process.Bind(createCustomerTokenInvoiceItemsCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
|
||||||
process.Bind(createCustomerInvoicesCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
process.Bind(createCustomerInvoicesCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||||
process.Bind(finalizeCustomerInvoicesCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
process.Bind(finalizeCustomerInvoicesCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||||
|
process.Bind(payCustomerInvoicesCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||||
process.Bind(stripeCustomerCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
process.Bind(stripeCustomerCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||||
process.Bind(consistencyGECleanupCmd, &consistencyGECleanupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
process.Bind(consistencyGECleanupCmd, &consistencyGECleanupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||||
|
|
||||||
@ -747,14 +747,6 @@ func cmdCreateCustomerProjectInvoiceItems(cmd *cobra.Command, args []string) (er
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdCreateCustomerTokenInvoiceItems(cmd *cobra.Command, args []string) (err error) {
|
|
||||||
ctx, _ := process.Ctx(cmd)
|
|
||||||
|
|
||||||
return runBillingCmd(ctx, func(ctx context.Context, payments *stripecoinpayments.Service, _ satellite.DB) error {
|
|
||||||
return payments.InvoiceApplyTokenBalance(ctx)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdCreateCustomerInvoices(cmd *cobra.Command, args []string) (err error) {
|
func cmdCreateCustomerInvoices(cmd *cobra.Command, args []string) (err error) {
|
||||||
ctx, _ := process.Ctx(cmd)
|
ctx, _ := process.Ctx(cmd)
|
||||||
|
|
||||||
@ -776,6 +768,18 @@ func cmdFinalizeCustomerInvoices(cmd *cobra.Command, args []string) (err error)
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cmdPayCustomerInvoices(cmd *cobra.Command, args []string) (err error) {
|
||||||
|
ctx, _ := process.Ctx(cmd)
|
||||||
|
|
||||||
|
return runBillingCmd(ctx, func(ctx context.Context, payments *stripecoinpayments.Service, _ satellite.DB) error {
|
||||||
|
err := payments.InvoiceApplyTokenBalance(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return errs.New("error applying native token payments: %v", err)
|
||||||
|
}
|
||||||
|
return payments.PayInvoices(ctx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func cmdStripeCustomer(cmd *cobra.Command, args []string) (err error) {
|
func cmdStripeCustomer(cmd *cobra.Command, args []string) (err error) {
|
||||||
ctx, _ := process.Ctx(cmd)
|
ctx, _ := process.Ctx(cmd)
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ type StripeClient interface {
|
|||||||
CustomerBalanceTransactions() StripeCustomerBalanceTransactions
|
CustomerBalanceTransactions() StripeCustomerBalanceTransactions
|
||||||
Charges() StripeCharges
|
Charges() StripeCharges
|
||||||
PromoCodes() StripePromoCodes
|
PromoCodes() StripePromoCodes
|
||||||
|
CreditNotes() StripeCreditNotes
|
||||||
}
|
}
|
||||||
|
|
||||||
// StripeCustomers Stripe Customers interface.
|
// StripeCustomers Stripe Customers interface.
|
||||||
@ -46,6 +47,7 @@ type StripeInvoices interface {
|
|||||||
New(params *stripe.InvoiceParams) (*stripe.Invoice, error)
|
New(params *stripe.InvoiceParams) (*stripe.Invoice, error)
|
||||||
List(listParams *stripe.InvoiceListParams) *invoice.Iter
|
List(listParams *stripe.InvoiceListParams) *invoice.Iter
|
||||||
FinalizeInvoice(id string, params *stripe.InvoiceFinalizeParams) (*stripe.Invoice, error)
|
FinalizeInvoice(id string, params *stripe.InvoiceFinalizeParams) (*stripe.Invoice, error)
|
||||||
|
Pay(id string, params *stripe.InvoicePayParams) (*stripe.Invoice, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StripeInvoiceItems Stripe InvoiceItems interface.
|
// StripeInvoiceItems Stripe InvoiceItems interface.
|
||||||
@ -72,6 +74,11 @@ type StripeCustomerBalanceTransactions interface {
|
|||||||
List(listParams *stripe.CustomerBalanceTransactionListParams) *customerbalancetransaction.Iter
|
List(listParams *stripe.CustomerBalanceTransactionListParams) *customerbalancetransaction.Iter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StripeCreditNotes Stripe CreditNotes interface.
|
||||||
|
type StripeCreditNotes interface {
|
||||||
|
New(params *stripe.CreditNoteParams) (*stripe.CreditNote, error)
|
||||||
|
}
|
||||||
|
|
||||||
type stripeClient struct {
|
type stripeClient struct {
|
||||||
client *client.API
|
client *client.API
|
||||||
}
|
}
|
||||||
@ -104,6 +111,10 @@ func (s *stripeClient) PromoCodes() StripePromoCodes {
|
|||||||
return s.client.PromotionCodes
|
return s.client.PromotionCodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *stripeClient) CreditNotes() StripeCreditNotes {
|
||||||
|
return s.client.CreditNotes
|
||||||
|
}
|
||||||
|
|
||||||
// NewStripeClient creates Stripe client from configuration.
|
// NewStripeClient creates Stripe client from configuration.
|
||||||
func NewStripeClient(log *zap.Logger, config Config) StripeClient {
|
func NewStripeClient(log *zap.Logger, config Config) StripeClient {
|
||||||
backendConfig := &stripe.BackendConfig{
|
backendConfig := &stripe.BackendConfig{
|
||||||
|
@ -581,41 +581,47 @@ func (service *Service) InvoiceApplyTokenBalance(ctx context.Context) (err error
|
|||||||
}
|
}
|
||||||
for _, invoice := range invoices {
|
for _, invoice := range invoices {
|
||||||
// if no balance due, do nothing
|
// if no balance due, do nothing
|
||||||
if invoice.AmountDue <= 0 {
|
if invoice.AmountRemaining <= 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var tokenCreditAmount int64
|
var tokenCreditAmount int64
|
||||||
if invoice.AmountDue >= tokenBalance.BaseUnits() {
|
if invoice.AmountRemaining >= tokenBalance.BaseUnits() {
|
||||||
tokenCreditAmount = -tokenBalance.BaseUnits()
|
tokenCreditAmount = tokenBalance.BaseUnits()
|
||||||
} else {
|
} else {
|
||||||
tokenCreditAmount = -invoice.AmountDue
|
tokenCreditAmount = invoice.AmountRemaining
|
||||||
}
|
}
|
||||||
|
|
||||||
txID, err := service.createTokenPaymentBillingTransaction(ctx, wallet.UserID, invoice.ID, wallet.Address.Hex(), tokenCreditAmount)
|
txID, err := service.createTokenPaymentBillingTransaction(ctx, wallet.UserID, invoice.ID, wallet.Address.Hex(), -tokenCreditAmount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errGrp.Add(Error.New("unable to create token payment billing transaction for user %s", wallet.UserID.String()))
|
errGrp.Add(Error.New("unable to create token payment billing transaction for user %s", wallet.UserID.String()))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
invoiceItem, err := service.createTokenPaymentInvoiceItem(ctx, cusID, tokenCreditAmount, txID, wallet.Address.Hex())
|
creditNoteID, err := service.addCreditNoteToInvoice(ctx, invoice.ID, cusID, wallet.Address.Hex(), tokenCreditAmount, txID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errGrp.Add(Error.New("unable to create token payment invoice item for user %s", wallet.UserID.String()))
|
errGrp.Add(Error.New("unable to create token payment credit note for user %s", wallet.UserID.String()))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata, err := json.Marshal(map[string]interface{}{
|
metadata, err := json.Marshal(map[string]interface{}{
|
||||||
"ItemID": invoiceItem.ID,
|
"Credit Note ID": creditNoteID,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errGrp.Add(Error.New("unable to marshall invoice item ID %s", invoiceItem.ID))
|
errGrp.Add(Error.New("unable to marshall credit note ID %s", creditNoteID))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = service.billingDB.UpdateMetadata(ctx, txID, metadata)
|
err = service.billingDB.UpdateMetadata(ctx, txID, metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errGrp.Add(Error.New("unable to add invoice item ID to billing transaction for user %s", wallet.UserID.String()))
|
errGrp.Add(Error.New("unable to add credit note ID to billing transaction for user %s", wallet.UserID.String()))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = service.billingDB.UpdateStatus(ctx, txID, billing.TransactionStatusCompleted)
|
||||||
|
if err != nil {
|
||||||
|
errGrp.Add(Error.New("unable to update status for billing transaction for user %s", wallet.UserID.String()))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -623,13 +629,13 @@ func (service *Service) InvoiceApplyTokenBalance(ctx context.Context) (err error
|
|||||||
return errGrp.Err()
|
return errGrp.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
// getInvoiceBalance returns the stripe customer's current invoices.
|
// getInvoices returns the stripe customer's open finalized invoices.
|
||||||
func (service *Service) getInvoices(ctx context.Context, cusID string) (_ []stripe.Invoice, err error) {
|
func (service *Service) getInvoices(ctx context.Context, cusID string) (_ []stripe.Invoice, err error) {
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
params := &stripe.InvoiceListParams{
|
params := &stripe.InvoiceListParams{
|
||||||
Customer: stripe.String(cusID),
|
Customer: stripe.String(cusID),
|
||||||
Status: stripe.String(string(stripe.InvoiceStatusDraft)),
|
Status: stripe.String(string(stripe.InvoiceStatusOpen)),
|
||||||
}
|
}
|
||||||
invoicesIterator := service.stripeClient.Invoices().List(params)
|
invoicesIterator := service.stripeClient.Invoices().List(params)
|
||||||
var stripeInvoices []stripe.Invoice
|
var stripeInvoices []stripe.Invoice
|
||||||
@ -642,29 +648,34 @@ func (service *Service) getInvoices(ctx context.Context, cusID string) (_ []stri
|
|||||||
return stripeInvoices, nil
|
return stripeInvoices, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// createTokenPaymentInvoiceItem creates an invoice line item for the user token payment.
|
// addCreditNoteToInvoice creates a credit note for the user token payment.
|
||||||
func (service *Service) createTokenPaymentInvoiceItem(ctx context.Context, cusID string, amount int64, txID int64, wallet string) (invoiceItem *stripe.InvoiceItem, err error) {
|
func (service *Service) addCreditNoteToInvoice(ctx context.Context, invoiceID, cusID, wallet string, amount, txID int64) (_ string, err error) {
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
// add an invoice item for the total invoice amount
|
var lineParams []*stripe.CreditNoteLineParams
|
||||||
tokenCredit := &stripe.InvoiceItemParams{
|
|
||||||
Currency: stripe.String(string(stripe.CurrencyUSD)),
|
lineParam := stripe.CreditNoteLineParams{
|
||||||
Customer: stripe.String(cusID),
|
Description: stripe.String("Storjscan Token payment"),
|
||||||
Description: stripe.String("payment from tokens"),
|
Type: stripe.String("custom_line_item"),
|
||||||
UnitAmount: stripe.Int64(amount),
|
UnitAmount: stripe.Int64(amount),
|
||||||
Params: stripe.Params{
|
Quantity: stripe.Int64(1),
|
||||||
Metadata: map[string]string{
|
|
||||||
"transaction ID": strconv.FormatInt(txID, 10),
|
|
||||||
"wallet address": wallet,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
invoiceItem, err = service.stripeClient.InvoiceItems().New(tokenCredit)
|
|
||||||
|
lineParams = append(lineParams, &lineParam)
|
||||||
|
|
||||||
|
params := &stripe.CreditNoteParams{
|
||||||
|
Invoice: stripe.String(invoiceID),
|
||||||
|
Lines: lineParams,
|
||||||
|
Memo: stripe.String("Storjscan Token Payment - Wallet: 0x" + wallet),
|
||||||
|
}
|
||||||
|
params.AddMetadata("txID", "0x"+strconv.FormatInt(txID, 10))
|
||||||
|
params.AddMetadata("wallet address", wallet)
|
||||||
|
creditNote, err := service.stripeClient.CreditNotes().New(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
service.log.Warn("unable to add invoice item for stripe customer", zap.String("Customer ID", cusID))
|
service.log.Warn("unable to add credit note for stripe customer", zap.String("Customer ID", cusID))
|
||||||
return nil, Error.Wrap(err)
|
return "", Error.Wrap(err)
|
||||||
}
|
}
|
||||||
return
|
return creditNote.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// createTokenPaymentBillingTransaction creates a billing DB entry for the user token payment.
|
// createTokenPaymentBillingTransaction creates a billing DB entry for the user token payment.
|
||||||
@ -918,7 +929,7 @@ func (service *Service) createInvoice(ctx context.Context, cusID string, period
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FinalizeInvoices sets autoadvance flag on all draft invoices currently available in stripe.
|
// FinalizeInvoices transitions all draft invoices to open finalized invoices in stripe. No payment is to be collected yet.
|
||||||
func (service *Service) FinalizeInvoices(ctx context.Context) (err error) {
|
func (service *Service) FinalizeInvoices(ctx context.Context) (err error) {
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
@ -934,16 +945,6 @@ func (service *Service) FinalizeInvoices(ctx context.Context) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return Error.Wrap(err)
|
return Error.Wrap(err)
|
||||||
}
|
}
|
||||||
if transactionID, ok := stripeInvoice.Metadata["transaction ID"]; ok {
|
|
||||||
txID, err := strconv.ParseInt(transactionID, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return Error.Wrap(err)
|
|
||||||
}
|
|
||||||
err = service.billingDB.UpdateStatus(ctx, txID, billing.TransactionStatusCompleted)
|
|
||||||
if err != nil {
|
|
||||||
return Error.Wrap(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Error.Wrap(invoicesIterator.Err())
|
return Error.Wrap(invoicesIterator.Err())
|
||||||
@ -952,11 +953,35 @@ func (service *Service) FinalizeInvoices(ctx context.Context) (err error) {
|
|||||||
func (service *Service) finalizeInvoice(ctx context.Context, invoiceID string) (err error) {
|
func (service *Service) finalizeInvoice(ctx context.Context, invoiceID string) (err error) {
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
params := &stripe.InvoiceFinalizeParams{AutoAdvance: stripe.Bool(true)}
|
params := &stripe.InvoiceFinalizeParams{AutoAdvance: stripe.Bool(false)}
|
||||||
_, err = service.stripeClient.Invoices().FinalizeInvoice(invoiceID, params)
|
_, err = service.stripeClient.Invoices().FinalizeInvoice(invoiceID, params)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PayInvoices attempts to transition all open finalized invoices to "paid" by charging the customer according to subscriptions settings.
|
||||||
|
func (service *Service) PayInvoices(ctx context.Context) (err error) {
|
||||||
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
|
params := &stripe.InvoiceListParams{
|
||||||
|
Status: stripe.String("open"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var errGrp errs.Group
|
||||||
|
|
||||||
|
invoicesIterator := service.stripeClient.Invoices().List(params)
|
||||||
|
for invoicesIterator.Next() {
|
||||||
|
stripeInvoice := invoicesIterator.Invoice()
|
||||||
|
|
||||||
|
params := &stripe.InvoicePayParams{}
|
||||||
|
_, err = service.stripeClient.Invoices().Pay(stripeInvoice.ID, params)
|
||||||
|
if err != nil {
|
||||||
|
errGrp.Add(Error.New("unable to pay invoice %s", stripeInvoice.ID))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errGrp.Err()
|
||||||
|
}
|
||||||
|
|
||||||
// projectUsagePrice represents pricing for project usage.
|
// projectUsagePrice represents pricing for project usage.
|
||||||
type projectUsagePrice struct {
|
type projectUsagePrice struct {
|
||||||
Storage decimal.Decimal
|
Storage decimal.Decimal
|
||||||
|
@ -80,6 +80,7 @@ type mockStripeState struct {
|
|||||||
customerBalanceTransactions *mockCustomerBalanceTransactions
|
customerBalanceTransactions *mockCustomerBalanceTransactions
|
||||||
charges *mockCharges
|
charges *mockCharges
|
||||||
promoCodes *mockPromoCodes
|
promoCodes *mockPromoCodes
|
||||||
|
creditNotes *mockCreditNotes
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockStripeClient struct {
|
type mockStripeClient struct {
|
||||||
@ -164,6 +165,10 @@ func (m *mockStripeClient) PromoCodes() StripePromoCodes {
|
|||||||
return m.promoCodes
|
return m.promoCodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockStripeClient) CreditNotes() StripeCreditNotes {
|
||||||
|
return m.creditNotes
|
||||||
|
}
|
||||||
|
|
||||||
type mockCustomers struct {
|
type mockCustomers struct {
|
||||||
customersDB CustomersDB
|
customersDB CustomersDB
|
||||||
usersDB console.Users
|
usersDB console.Users
|
||||||
@ -430,6 +435,10 @@ func (m *mockInvoices) FinalizeInvoice(id string, params *stripe.InvoiceFinalize
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockInvoices) Pay(id string, params *stripe.InvoicePayParams) (*stripe.Invoice, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
type mockInvoiceItems struct {
|
type mockInvoiceItems struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,3 +543,10 @@ func (m *mockPromoCodes) List(params *stripe.PromotionCodeListParams) *promotion
|
|||||||
|
|
||||||
return &promotioncode.Iter{Iter: stripe.GetIter(params, query)}
|
return &promotioncode.Iter{Iter: stripe.GetIter(params, query)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockCreditNotes struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockCreditNotes) New(params *stripe.CreditNoteParams) (*stripe.CreditNote, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user