mirror of
https://github.com/hanzoai/commerce.git
synced 2026-10-30 15:08:42 +00:00
115 lines
3.7 KiB
Go
115 lines
3.7 KiB
Go
package billing
|
|
|
|
import (
|
|
"bytes"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/zap-proto/zip"
|
|
|
|
"github.com/hanzoai/commerce/auth"
|
|
"github.com/hanzoai/commerce/datastore"
|
|
"github.com/hanzoai/commerce/models/balancetransaction"
|
|
"github.com/hanzoai/commerce/models/creditgrant"
|
|
"github.com/hanzoai/commerce/models/organization"
|
|
"github.com/hanzoai/commerce/models/subscription"
|
|
"github.com/hanzoai/commerce/models/transaction"
|
|
"github.com/hanzoai/commerce/util/bit"
|
|
"github.com/hanzoai/commerce/util/permission"
|
|
"github.com/hanzoai/commerce/util/test/ae"
|
|
)
|
|
|
|
// Every privileged money act a SuperAdmin takes — a mint, a grant, a void, a
|
|
// balance adjustment, a comp — writes who took it onto the row it writes.
|
|
func TestPrivilegedMoneyActsRecordWhoTookThem(t *testing.T) {
|
|
ctx := ae.NewContext()
|
|
defer ctx.Close()
|
|
|
|
org := organization.New(datastore.New(ctx))
|
|
org.Name = "acme-audit"
|
|
org.Live = true
|
|
const who = "[email protected]"
|
|
app := engineWithSeed(func(c *zip.Ctx) {
|
|
c.Locals("iam_authenticated", true)
|
|
c.Locals("permissions", bit.Field(permission.Admin|permission.Live))
|
|
c.Locals("iam_claims", &auth.IAMClaims{Owner: "admin", Email: who})
|
|
c.Locals("organization", org)
|
|
c.SetContext(ctx)
|
|
})
|
|
post := func(path, body string, hdr ...string) map[string]any {
|
|
t.Helper()
|
|
req := httptest.NewRequest(http.MethodPost, path, bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
for i := 0; i+1 < len(hdr); i += 2 {
|
|
req.Header.Set(hdr[i], hdr[i+1])
|
|
}
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if resp.StatusCode >= 300 {
|
|
t.Fatalf("POST %s: %d %s", path, resp.StatusCode, bodyOf(resp))
|
|
}
|
|
return jsonBody(t, resp)
|
|
}
|
|
db := datastore.New(org.Namespaced(ctx))
|
|
|
|
g := post("/v1/billing/credits", `{"userId":"acme-audit/alice","amountCents":100}`)
|
|
grantRow := creditgrant.New(db)
|
|
if err := grantRow.GetById(g["id"].(string)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if grantRow.Metadata["mintedBy"] != who {
|
|
t.Errorf("POST /credits grant metadata %v; want mintedBy %s", grantRow.Metadata, who)
|
|
}
|
|
post("/v1/billing/credits/"+grantRow.Id()+"/void", `{}`)
|
|
if err := grantRow.GetById(grantRow.Id()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if grantRow.Metadata["voidedBy"] != who {
|
|
t.Errorf("void metadata %v; want voidedBy %s", grantRow.Metadata, who)
|
|
}
|
|
|
|
for _, tc := range []struct{ path, body, key string }{
|
|
{"/v1/billing/credit", `{"org":"acme-audit","amountCents":100,"reason":"comp"}`, ""},
|
|
{"/v1/billing/deposit", `{"user":"acme-audit/alice","amount":100}`, "settle-1"},
|
|
} {
|
|
var out map[string]any
|
|
if tc.key != "" {
|
|
out = post(tc.path, tc.body, "X-Idempotency-Key", tc.key)
|
|
} else {
|
|
out = post(tc.path, tc.body)
|
|
}
|
|
id, _ := out["id"].(string)
|
|
if id == "" {
|
|
id, _ = out["transactionId"].(string)
|
|
}
|
|
tx := transaction.New(db)
|
|
if err := tx.GetById(id); err != nil {
|
|
t.Fatalf("%s row %q: %v", tc.path, id, err)
|
|
}
|
|
if tx.Metadata["mintedBy"] != who {
|
|
t.Errorf("%s transaction metadata %v; want mintedBy %s", tc.path, tx.Metadata, who)
|
|
}
|
|
}
|
|
|
|
adj := post("/v1/billing/customer-balance/adjustments", `{"customerId":"acme-audit/alice","amount":100}`)
|
|
bt := balancetransaction.New(db)
|
|
if err := bt.GetById(adj["id"].(string)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if bt.Metadata["by"] != who {
|
|
t.Errorf("adjustment metadata %v; want by %s", bt.Metadata, who)
|
|
}
|
|
|
|
sub := post("/v1/billing/subscriptions", `{"userId":"acme-audit","planId":"max-5x","metadata":{"compedBy":"forged"}}`)
|
|
row := subscription.New(db)
|
|
if err := row.GetById(sub["id"].(string)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if row.Metadata["compedBy"] != who {
|
|
t.Errorf("comp subscription metadata %v; want compedBy %s", row.Metadata, who)
|
|
}
|
|
}
|