feat: user service
This commit is contained in:
@@ -0,0 +1,565 @@
|
||||
package entitlementsvc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"galaxy/user/internal/domain/account"
|
||||
"galaxy/user/internal/domain/common"
|
||||
"galaxy/user/internal/domain/entitlement"
|
||||
"galaxy/user/internal/domain/policy"
|
||||
"galaxy/user/internal/ports"
|
||||
"galaxy/user/internal/service/shared"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestReaderGetByUserIDRepairsExpiredFinitePaidSnapshot(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
userID := common.UserID("user-123")
|
||||
startsAt := time.Unix(1_775_240_000, 0).UTC()
|
||||
endsAt := startsAt.Add(24 * time.Hour)
|
||||
now := endsAt.Add(2 * time.Hour)
|
||||
snapshotStore := &fakeSnapshotStore{
|
||||
byUserID: map[common.UserID]entitlement.CurrentSnapshot{
|
||||
userID: paidSnapshot(
|
||||
userID,
|
||||
entitlement.PlanCodePaidMonthly,
|
||||
startsAt,
|
||||
endsAt,
|
||||
common.Source("admin"),
|
||||
common.ReasonCode("manual_grant"),
|
||||
),
|
||||
},
|
||||
}
|
||||
historyStore := &fakeHistoryStore{
|
||||
byUserID: map[common.UserID][]entitlement.PeriodRecord{
|
||||
userID: {
|
||||
paidRecord(
|
||||
entitlement.EntitlementRecordID("entitlement-paid"),
|
||||
userID,
|
||||
entitlement.PlanCodePaidMonthly,
|
||||
startsAt,
|
||||
endsAt,
|
||||
common.Source("admin"),
|
||||
common.ReasonCode("manual_grant"),
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
lifecycleStore := &fakeLifecycleStore{
|
||||
historyStore: historyStore,
|
||||
snapshotStore: snapshotStore,
|
||||
}
|
||||
|
||||
reader, err := NewReader(snapshotStore, lifecycleStore, fixedClock{now: now}, fixedIDGenerator{
|
||||
recordID: entitlement.EntitlementRecordID("entitlement-free"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := reader.GetByUserID(context.Background(), userID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, entitlement.PlanCodeFree, got.PlanCode)
|
||||
require.False(t, got.IsPaid)
|
||||
require.Equal(t, endsAt, got.StartsAt)
|
||||
require.Equal(t, expiryRepairSource, got.Source)
|
||||
require.Equal(t, expiryRepairReasonCode, got.ReasonCode)
|
||||
require.Equal(t, common.ActorRef{Type: expiryRepairActorType, ID: expiryRepairActorID}, got.Actor)
|
||||
require.Len(t, historyStore.byUserID[userID], 2)
|
||||
require.Equal(t, got, snapshotStore.byUserID[userID])
|
||||
require.Equal(t, entitlement.EntitlementRecordID("entitlement-free"), lifecycleStore.repairInput.NewRecord.RecordID)
|
||||
}
|
||||
|
||||
func TestGrantServiceExecuteRejectsInvalidPlanRules(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
now := time.Unix(1_775_240_000, 0).UTC()
|
||||
userID := common.UserID("user-123")
|
||||
freeSnapshot := freeSnapshot(userID, now.Add(-24*time.Hour), common.Source("auth_registration"), common.ReasonCode("initial_free_entitlement"))
|
||||
freeRecord := freeRecord(entitlement.EntitlementRecordID("entitlement-free"), userID, now.Add(-24*time.Hour), common.Source("auth_registration"), common.ReasonCode("initial_free_entitlement"))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input GrantInput
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "free plan not allowed",
|
||||
input: GrantInput{
|
||||
UserID: userID.String(),
|
||||
PlanCode: string(entitlement.PlanCodeFree),
|
||||
Source: "admin",
|
||||
ReasonCode: "manual_grant",
|
||||
Actor: ActorInput{Type: "admin", ID: "admin-1"},
|
||||
StartsAt: now.Format(time.RFC3339Nano),
|
||||
},
|
||||
wantErr: shared.ErrorCodeInvalidRequest,
|
||||
},
|
||||
{
|
||||
name: "future starts at rejected",
|
||||
input: GrantInput{
|
||||
UserID: userID.String(),
|
||||
PlanCode: string(entitlement.PlanCodePaidMonthly),
|
||||
Source: "admin",
|
||||
ReasonCode: "manual_grant",
|
||||
Actor: ActorInput{Type: "admin", ID: "admin-1"},
|
||||
StartsAt: now.Add(time.Hour).Format(time.RFC3339Nano),
|
||||
EndsAt: now.Add(31 * 24 * time.Hour).Format(time.RFC3339Nano),
|
||||
},
|
||||
wantErr: shared.ErrorCodeInvalidRequest,
|
||||
},
|
||||
{
|
||||
name: "finite plan requires ends at",
|
||||
input: GrantInput{
|
||||
UserID: userID.String(),
|
||||
PlanCode: string(entitlement.PlanCodePaidMonthly),
|
||||
Source: "admin",
|
||||
ReasonCode: "manual_grant",
|
||||
Actor: ActorInput{Type: "admin", ID: "admin-1"},
|
||||
StartsAt: now.Format(time.RFC3339Nano),
|
||||
},
|
||||
wantErr: shared.ErrorCodeInvalidRequest,
|
||||
},
|
||||
{
|
||||
name: "lifetime plan forbids ends at",
|
||||
input: GrantInput{
|
||||
UserID: userID.String(),
|
||||
PlanCode: string(entitlement.PlanCodePaidLifetime),
|
||||
Source: "admin",
|
||||
ReasonCode: "manual_grant",
|
||||
Actor: ActorInput{Type: "admin", ID: "admin-1"},
|
||||
StartsAt: now.Format(time.RFC3339Nano),
|
||||
EndsAt: now.Add(24 * time.Hour).Format(time.RFC3339Nano),
|
||||
},
|
||||
wantErr: shared.ErrorCodeInvalidRequest,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
service, err := NewGrantService(
|
||||
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
|
||||
&fakeHistoryStore{byUserID: map[common.UserID][]entitlement.PeriodRecord{userID: {freeRecord}}},
|
||||
fakeEffectiveReader{byUserID: map[common.UserID]entitlement.CurrentSnapshot{userID: freeSnapshot}},
|
||||
&fakeLifecycleStore{},
|
||||
fixedClock{now: now},
|
||||
fixedIDGenerator{recordID: entitlement.EntitlementRecordID("entitlement-paid")},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = service.Execute(context.Background(), tt.input)
|
||||
require.Error(t, err)
|
||||
require.Equal(t, tt.wantErr, shared.CodeOf(err))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantServiceExecuteBuildsTransition(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
now := time.Unix(1_775_240_000, 0).UTC()
|
||||
userID := common.UserID("user-123")
|
||||
currentFreeStartsAt := now.Add(-24 * time.Hour)
|
||||
currentSnapshot := freeSnapshot(userID, currentFreeStartsAt, common.Source("auth_registration"), common.ReasonCode("initial_free_entitlement"))
|
||||
currentRecord := freeRecord(entitlement.EntitlementRecordID("entitlement-free"), userID, currentFreeStartsAt, common.Source("auth_registration"), common.ReasonCode("initial_free_entitlement"))
|
||||
lifecycleStore := &fakeLifecycleStore{}
|
||||
|
||||
service, err := NewGrantService(
|
||||
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
|
||||
&fakeHistoryStore{byUserID: map[common.UserID][]entitlement.PeriodRecord{userID: {currentRecord}}},
|
||||
fakeEffectiveReader{byUserID: map[common.UserID]entitlement.CurrentSnapshot{userID: currentSnapshot}},
|
||||
lifecycleStore,
|
||||
fixedClock{now: now},
|
||||
fixedIDGenerator{recordID: entitlement.EntitlementRecordID("entitlement-paid")},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := service.Execute(context.Background(), GrantInput{
|
||||
UserID: userID.String(),
|
||||
PlanCode: string(entitlement.PlanCodePaidMonthly),
|
||||
Source: "admin",
|
||||
ReasonCode: "manual_grant",
|
||||
Actor: ActorInput{Type: "admin", ID: "admin-1"},
|
||||
StartsAt: now.Format(time.RFC3339Nano),
|
||||
EndsAt: now.Add(30 * 24 * time.Hour).Format(time.RFC3339Nano),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, userID.String(), result.UserID)
|
||||
require.Equal(t, entitlement.PlanCodePaidMonthly, result.Entitlement.PlanCode)
|
||||
require.Equal(t, entitlement.EntitlementRecordID("entitlement-paid"), lifecycleStore.grantInput.NewRecord.RecordID)
|
||||
require.Equal(t, currentSnapshot, lifecycleStore.grantInput.ExpectedCurrentSnapshot)
|
||||
require.Equal(t, currentRecord.RecordID, lifecycleStore.grantInput.UpdatedCurrentRecord.RecordID)
|
||||
require.NotNil(t, lifecycleStore.grantInput.UpdatedCurrentRecord.ClosedAt)
|
||||
require.True(t, lifecycleStore.grantInput.UpdatedCurrentRecord.ClosedAt.Equal(now))
|
||||
}
|
||||
|
||||
func TestExtendServiceExecuteBuildsExtensionSegment(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
now := time.Unix(1_775_240_000, 0).UTC()
|
||||
userID := common.UserID("user-123")
|
||||
startsAt := now.Add(-24 * time.Hour)
|
||||
currentEndsAt := now.Add(24 * time.Hour)
|
||||
currentSnapshot := paidSnapshot(
|
||||
userID,
|
||||
entitlement.PlanCodePaidMonthly,
|
||||
startsAt,
|
||||
currentEndsAt,
|
||||
common.Source("admin"),
|
||||
common.ReasonCode("manual_grant"),
|
||||
)
|
||||
currentRecord := paidRecord(
|
||||
entitlement.EntitlementRecordID("entitlement-paid-1"),
|
||||
userID,
|
||||
entitlement.PlanCodePaidMonthly,
|
||||
startsAt,
|
||||
currentEndsAt,
|
||||
common.Source("admin"),
|
||||
common.ReasonCode("manual_grant"),
|
||||
)
|
||||
lifecycleStore := &fakeLifecycleStore{}
|
||||
|
||||
service, err := NewExtendService(
|
||||
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
|
||||
&fakeHistoryStore{byUserID: map[common.UserID][]entitlement.PeriodRecord{userID: {currentRecord}}},
|
||||
fakeEffectiveReader{byUserID: map[common.UserID]entitlement.CurrentSnapshot{userID: currentSnapshot}},
|
||||
lifecycleStore,
|
||||
fixedClock{now: now},
|
||||
fixedIDGenerator{recordID: entitlement.EntitlementRecordID("entitlement-paid-2")},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := service.Execute(context.Background(), ExtendInput{
|
||||
UserID: userID.String(),
|
||||
Source: "admin",
|
||||
ReasonCode: "manual_extend",
|
||||
Actor: ActorInput{Type: "admin", ID: "admin-1"},
|
||||
EndsAt: currentEndsAt.Add(30 * 24 * time.Hour).Format(time.RFC3339Nano),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, currentEndsAt, lifecycleStore.extendInput.NewRecord.StartsAt)
|
||||
require.Equal(t, startsAt, lifecycleStore.extendInput.NewSnapshot.StartsAt)
|
||||
require.Equal(t, entitlement.PlanCodePaidMonthly, result.Entitlement.PlanCode)
|
||||
}
|
||||
|
||||
func TestRevokeServiceExecuteBuildsFreeTransition(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
now := time.Unix(1_775_240_000, 0).UTC()
|
||||
userID := common.UserID("user-123")
|
||||
startsAt := now.Add(-24 * time.Hour)
|
||||
currentEndsAt := now.Add(24 * time.Hour)
|
||||
currentSnapshot := paidSnapshot(
|
||||
userID,
|
||||
entitlement.PlanCodePaidMonthly,
|
||||
startsAt,
|
||||
currentEndsAt,
|
||||
common.Source("admin"),
|
||||
common.ReasonCode("manual_grant"),
|
||||
)
|
||||
currentRecord := paidRecord(
|
||||
entitlement.EntitlementRecordID("entitlement-paid-1"),
|
||||
userID,
|
||||
entitlement.PlanCodePaidMonthly,
|
||||
startsAt,
|
||||
currentEndsAt,
|
||||
common.Source("admin"),
|
||||
common.ReasonCode("manual_grant"),
|
||||
)
|
||||
lifecycleStore := &fakeLifecycleStore{}
|
||||
|
||||
service, err := NewRevokeService(
|
||||
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
|
||||
&fakeHistoryStore{byUserID: map[common.UserID][]entitlement.PeriodRecord{userID: {currentRecord}}},
|
||||
fakeEffectiveReader{byUserID: map[common.UserID]entitlement.CurrentSnapshot{userID: currentSnapshot}},
|
||||
lifecycleStore,
|
||||
fixedClock{now: now},
|
||||
fixedIDGenerator{recordID: entitlement.EntitlementRecordID("entitlement-free-2")},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := service.Execute(context.Background(), RevokeInput{
|
||||
UserID: userID.String(),
|
||||
Source: "admin",
|
||||
ReasonCode: "manual_revoke",
|
||||
Actor: ActorInput{Type: "admin", ID: "admin-1"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, entitlement.PlanCodeFree, result.Entitlement.PlanCode)
|
||||
require.NotNil(t, lifecycleStore.revokeInput.UpdatedCurrentRecord.ClosedAt)
|
||||
require.True(t, lifecycleStore.revokeInput.UpdatedCurrentRecord.ClosedAt.Equal(now))
|
||||
require.Equal(t, now, lifecycleStore.revokeInput.NewRecord.StartsAt)
|
||||
}
|
||||
|
||||
type fakeAccountStore struct {
|
||||
existsByUserID map[common.UserID]bool
|
||||
}
|
||||
|
||||
func (store fakeAccountStore) Create(context.Context, ports.CreateAccountInput) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (store fakeAccountStore) GetByUserID(context.Context, common.UserID) (account.UserAccount, error) {
|
||||
return account.UserAccount{}, ports.ErrNotFound
|
||||
}
|
||||
|
||||
func (store fakeAccountStore) GetByEmail(context.Context, common.Email) (account.UserAccount, error) {
|
||||
return account.UserAccount{}, ports.ErrNotFound
|
||||
}
|
||||
|
||||
func (store fakeAccountStore) GetByRaceName(context.Context, common.RaceName) (account.UserAccount, error) {
|
||||
return account.UserAccount{}, ports.ErrNotFound
|
||||
}
|
||||
|
||||
func (store fakeAccountStore) ExistsByUserID(_ context.Context, userID common.UserID) (bool, error) {
|
||||
return store.existsByUserID[userID], nil
|
||||
}
|
||||
|
||||
func (store fakeAccountStore) RenameRaceName(context.Context, ports.RenameRaceNameInput) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (store fakeAccountStore) Update(context.Context, account.UserAccount) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakeSnapshotStore struct {
|
||||
byUserID map[common.UserID]entitlement.CurrentSnapshot
|
||||
}
|
||||
|
||||
func (store *fakeSnapshotStore) GetByUserID(_ context.Context, userID common.UserID) (entitlement.CurrentSnapshot, error) {
|
||||
record, ok := store.byUserID[userID]
|
||||
if !ok {
|
||||
return entitlement.CurrentSnapshot{}, ports.ErrNotFound
|
||||
}
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
func (store *fakeSnapshotStore) Put(_ context.Context, record entitlement.CurrentSnapshot) error {
|
||||
store.byUserID[record.UserID] = record
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakeHistoryStore struct {
|
||||
byUserID map[common.UserID][]entitlement.PeriodRecord
|
||||
}
|
||||
|
||||
func (store *fakeHistoryStore) Create(_ context.Context, record entitlement.PeriodRecord) error {
|
||||
store.byUserID[record.UserID] = append(store.byUserID[record.UserID], record)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (store *fakeHistoryStore) GetByRecordID(_ context.Context, recordID entitlement.EntitlementRecordID) (entitlement.PeriodRecord, error) {
|
||||
for _, records := range store.byUserID {
|
||||
for _, record := range records {
|
||||
if record.RecordID == recordID {
|
||||
return record, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entitlement.PeriodRecord{}, ports.ErrNotFound
|
||||
}
|
||||
|
||||
func (store *fakeHistoryStore) ListByUserID(_ context.Context, userID common.UserID) ([]entitlement.PeriodRecord, error) {
|
||||
records := store.byUserID[userID]
|
||||
cloned := make([]entitlement.PeriodRecord, len(records))
|
||||
copy(cloned, records)
|
||||
return cloned, nil
|
||||
}
|
||||
|
||||
func (store *fakeHistoryStore) Update(_ context.Context, record entitlement.PeriodRecord) error {
|
||||
records := store.byUserID[record.UserID]
|
||||
for idx := range records {
|
||||
if records[idx].RecordID == record.RecordID {
|
||||
records[idx] = record
|
||||
store.byUserID[record.UserID] = records
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return ports.ErrNotFound
|
||||
}
|
||||
|
||||
type fakeEffectiveReader struct {
|
||||
byUserID map[common.UserID]entitlement.CurrentSnapshot
|
||||
}
|
||||
|
||||
func (reader fakeEffectiveReader) GetByUserID(_ context.Context, userID common.UserID) (entitlement.CurrentSnapshot, error) {
|
||||
record, ok := reader.byUserID[userID]
|
||||
if !ok {
|
||||
return entitlement.CurrentSnapshot{}, ports.ErrNotFound
|
||||
}
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
type fakeLifecycleStore struct {
|
||||
historyStore *fakeHistoryStore
|
||||
snapshotStore *fakeSnapshotStore
|
||||
|
||||
grantInput ports.GrantEntitlementInput
|
||||
extendInput ports.ExtendEntitlementInput
|
||||
revokeInput ports.RevokeEntitlementInput
|
||||
repairInput ports.RepairExpiredEntitlementInput
|
||||
}
|
||||
|
||||
func (store *fakeLifecycleStore) Grant(_ context.Context, input ports.GrantEntitlementInput) error {
|
||||
store.grantInput = input
|
||||
return nil
|
||||
}
|
||||
|
||||
func (store *fakeLifecycleStore) Extend(_ context.Context, input ports.ExtendEntitlementInput) error {
|
||||
store.extendInput = input
|
||||
return nil
|
||||
}
|
||||
|
||||
func (store *fakeLifecycleStore) Revoke(_ context.Context, input ports.RevokeEntitlementInput) error {
|
||||
store.revokeInput = input
|
||||
return nil
|
||||
}
|
||||
|
||||
func (store *fakeLifecycleStore) RepairExpired(_ context.Context, input ports.RepairExpiredEntitlementInput) error {
|
||||
store.repairInput = input
|
||||
if store.historyStore != nil {
|
||||
store.historyStore.byUserID[input.NewRecord.UserID] = append(store.historyStore.byUserID[input.NewRecord.UserID], input.NewRecord)
|
||||
}
|
||||
if store.snapshotStore != nil {
|
||||
store.snapshotStore.byUserID[input.NewSnapshot.UserID] = input.NewSnapshot
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type fixedClock struct {
|
||||
now time.Time
|
||||
}
|
||||
|
||||
func (clock fixedClock) Now() time.Time {
|
||||
return clock.now
|
||||
}
|
||||
|
||||
type fixedIDGenerator struct {
|
||||
recordID entitlement.EntitlementRecordID
|
||||
sanctionRecordID policy.SanctionRecordID
|
||||
limitRecordID policy.LimitRecordID
|
||||
}
|
||||
|
||||
func (generator fixedIDGenerator) NewUserID() (common.UserID, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (generator fixedIDGenerator) NewInitialRaceName() (common.RaceName, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (generator fixedIDGenerator) NewEntitlementRecordID() (entitlement.EntitlementRecordID, error) {
|
||||
return generator.recordID, nil
|
||||
}
|
||||
|
||||
func (generator fixedIDGenerator) NewSanctionRecordID() (policy.SanctionRecordID, error) {
|
||||
return generator.sanctionRecordID, nil
|
||||
}
|
||||
|
||||
func (generator fixedIDGenerator) NewLimitRecordID() (policy.LimitRecordID, error) {
|
||||
return generator.limitRecordID, nil
|
||||
}
|
||||
|
||||
func freeSnapshot(
|
||||
userID common.UserID,
|
||||
startsAt time.Time,
|
||||
source common.Source,
|
||||
reasonCode common.ReasonCode,
|
||||
) entitlement.CurrentSnapshot {
|
||||
return entitlement.CurrentSnapshot{
|
||||
UserID: userID,
|
||||
PlanCode: entitlement.PlanCodeFree,
|
||||
IsPaid: false,
|
||||
StartsAt: startsAt,
|
||||
Source: source,
|
||||
Actor: common.ActorRef{Type: common.ActorType("service"), ID: common.ActorID("user-service")},
|
||||
ReasonCode: reasonCode,
|
||||
UpdatedAt: startsAt,
|
||||
}
|
||||
}
|
||||
|
||||
func freeRecord(
|
||||
recordID entitlement.EntitlementRecordID,
|
||||
userID common.UserID,
|
||||
startsAt time.Time,
|
||||
source common.Source,
|
||||
reasonCode common.ReasonCode,
|
||||
) entitlement.PeriodRecord {
|
||||
return entitlement.PeriodRecord{
|
||||
RecordID: recordID,
|
||||
UserID: userID,
|
||||
PlanCode: entitlement.PlanCodeFree,
|
||||
Source: source,
|
||||
Actor: common.ActorRef{Type: common.ActorType("service"), ID: common.ActorID("user-service")},
|
||||
ReasonCode: reasonCode,
|
||||
StartsAt: startsAt,
|
||||
CreatedAt: startsAt,
|
||||
}
|
||||
}
|
||||
|
||||
func paidSnapshot(
|
||||
userID common.UserID,
|
||||
planCode entitlement.PlanCode,
|
||||
startsAt time.Time,
|
||||
endsAt time.Time,
|
||||
source common.Source,
|
||||
reasonCode common.ReasonCode,
|
||||
) entitlement.CurrentSnapshot {
|
||||
return entitlement.CurrentSnapshot{
|
||||
UserID: userID,
|
||||
PlanCode: planCode,
|
||||
IsPaid: true,
|
||||
StartsAt: startsAt,
|
||||
EndsAt: timePointer(endsAt),
|
||||
Source: source,
|
||||
Actor: common.ActorRef{Type: common.ActorType("admin"), ID: common.ActorID("admin-1")},
|
||||
ReasonCode: reasonCode,
|
||||
UpdatedAt: startsAt,
|
||||
}
|
||||
}
|
||||
|
||||
func paidRecord(
|
||||
recordID entitlement.EntitlementRecordID,
|
||||
userID common.UserID,
|
||||
planCode entitlement.PlanCode,
|
||||
startsAt time.Time,
|
||||
endsAt time.Time,
|
||||
source common.Source,
|
||||
reasonCode common.ReasonCode,
|
||||
) entitlement.PeriodRecord {
|
||||
return entitlement.PeriodRecord{
|
||||
RecordID: recordID,
|
||||
UserID: userID,
|
||||
PlanCode: planCode,
|
||||
Source: source,
|
||||
Actor: common.ActorRef{Type: common.ActorType("admin"), ID: common.ActorID("admin-1")},
|
||||
ReasonCode: reasonCode,
|
||||
StartsAt: startsAt,
|
||||
EndsAt: timePointer(endsAt),
|
||||
CreatedAt: startsAt,
|
||||
}
|
||||
}
|
||||
|
||||
func timePointer(value time.Time) *time.Time {
|
||||
utcValue := value.UTC()
|
||||
return &utcValue
|
||||
}
|
||||
|
||||
var (
|
||||
_ ports.UserAccountStore = fakeAccountStore{}
|
||||
_ ports.EntitlementSnapshotStore = (*fakeSnapshotStore)(nil)
|
||||
_ ports.EntitlementHistoryStore = (*fakeHistoryStore)(nil)
|
||||
_ ports.EntitlementLifecycleStore = (*fakeLifecycleStore)(nil)
|
||||
_ ports.Clock = fixedClock{}
|
||||
_ ports.IDGenerator = fixedIDGenerator{}
|
||||
)
|
||||
Reference in New Issue
Block a user