package processor import ( "context" "testing" "time" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "apskel-pos-be/internal/models" "apskel-pos-be/internal/repository" ) type customerOrderRepoFake struct { owner map[uuid.UUID]uuid.UUID // order -> customer orders []repository.CustomerOrderRow items map[uuid.UUID][]repository.CustomerOrderItemRow payments map[uuid.UUID][]repository.CustomerOrderPaymentRow offset int limit int } func (f *customerOrderRepoFake) ListOrders(_ context.Context, customerID uuid.UUID, offset, limit int) ([]repository.CustomerOrderRow, int64, error) { f.offset, f.limit = offset, limit var mine []repository.CustomerOrderRow for _, o := range f.orders { if f.owner[o.ID] == customerID { mine = append(mine, o) } } return mine, int64(len(mine)), nil } func (f *customerOrderRepoFake) GetOrder(_ context.Context, customerID, orderID uuid.UUID) (*repository.CustomerOrderRow, error) { for _, o := range f.orders { if o.ID == orderID && f.owner[o.ID] == customerID { c := o return &c, nil } } return nil, repository.ErrCustomerOrderNotFound } func (f *customerOrderRepoFake) ListItems(_ context.Context, orderID uuid.UUID) ([]repository.CustomerOrderItemRow, error) { return f.items[orderID], nil } func (f *customerOrderRepoFake) ListPayments(_ context.Context, orderID uuid.UUID) ([]repository.CustomerOrderPaymentRow, error) { return f.payments[orderID], nil } type earnedFake map[uuid.UUID]OrderEarned func (f earnedFake) EarnedByOrders(_ context.Context, ids []uuid.UUID) (map[uuid.UUID]OrderEarned, error) { out := map[uuid.UUID]OrderEarned{} for _, id := range ids { if e, ok := f[id]; ok { out[id] = e } } return out, nil } func newCustomerOrderTest() (*customerOrderRepoFake, uuid.UUID, uuid.UUID, uuid.UUID) { customer, other := uuid.New(), uuid.New() mine, theirs := uuid.New(), uuid.New() repo := &customerOrderRepoFake{ owner: map[uuid.UUID]uuid.UUID{mine: customer, theirs: other}, orders: []repository.CustomerOrderRow{ {ID: mine, OrderNumber: "ORD-1", OutletName: "Gokuna 1", Status: "completed", PaymentStatus: "completed", Subtotal: 90000, TotalAmount: 99000, ItemCount: 2, CreatedAt: time.Now()}, {ID: theirs, OrderNumber: "ORD-2"}, }, } return repo, customer, mine, theirs } func TestCustomerOrders_ListShowsOnlyTheCustomersOrdersWithEarning(t *testing.T) { repo, customer, mine, _ := newCustomerOrderTest() p := NewCustomerOrderProcessor(repo, earnedFake{mine: {Points: 900, Coins: 3}}) got, err := p.List(context.Background(), customer, models.ListCustomerOrdersQuery{Page: 2, Limit: 10}) require.NoError(t, err) require.Len(t, got.Data, 1) assert.Equal(t, "ORD-1", got.Data[0].OrderNumber) assert.Equal(t, int64(900), got.Data[0].PointsEarned) assert.Equal(t, int64(3), got.Data[0].CoinsEarned) assert.Equal(t, 10, repo.offset, "page 2 of 10 skips the first 10") assert.Equal(t, 10, repo.limit) assert.Equal(t, 2, got.Pagination.Page) } func TestCustomerOrders_ListDefaultsAndLimits(t *testing.T) { repo, customer, _, _ := newCustomerOrderTest() p := NewCustomerOrderProcessor(repo, earnedFake{}) got, err := p.List(context.Background(), customer, models.ListCustomerOrdersQuery{}) require.NoError(t, err) assert.Equal(t, 1, got.Pagination.Page) assert.Equal(t, 20, got.Pagination.Limit) for _, q := range []models.ListCustomerOrdersQuery{{Page: -1}, {Limit: 101}, {Limit: -5}} { _, err := p.List(context.Background(), customer, q) assert.ErrorIs(t, err, ErrInvalidWalletQuery, "%+v", q) } } func TestCustomerOrders_DetailHasItemsPaymentsAndEarning(t *testing.T) { repo, customer, mine, _ := newCustomerOrderTest() variant, unit := "Large", "ons" weight := 4.2 repo.items = map[uuid.UUID][]repository.CustomerOrderItemRow{ mine: { {ProductName: "Kopi Susu", VariantName: &variant, Quantity: 2, UnitPrice: 25000, TotalPrice: 50000, Status: "completed"}, {ProductName: "Ikan Tude", Quantity: 1, Weight: &weight, UnitName: &unit, UnitPrice: 4500, TotalPrice: 18900, Status: "completed"}, }, } repo.payments = map[uuid.UUID][]repository.CustomerOrderPaymentRow{ mine: { {MethodName: "Card", MethodType: "card", Amount: 12500, Status: "completed"}, {MethodName: "Cash", MethodType: "cash", Amount: 86500, Status: "completed"}, }, } p := NewCustomerOrderProcessor(repo, earnedFake{mine: {Points: 865}}) got, err := p.Detail(context.Background(), customer, mine) require.NoError(t, err) assert.Equal(t, "Gokuna 1", got.OutletName) assert.Equal(t, float64(90000), got.Subtotal) assert.Equal(t, int64(865), got.PointsEarned) require.Len(t, got.Items, 2) assert.Equal(t, "Large", *got.Items[0].VariantName) assert.Equal(t, []map[string]interface{}{}, got.Items[0].Modifiers, "no modifiers is an empty list, not null") assert.Equal(t, 4.2, *got.Items[1].Weight) require.Len(t, got.Payments, 2) assert.Equal(t, "Card", got.Payments[0].MethodName) assert.Equal(t, float64(12500), got.Payments[0].Amount) } func TestCustomerOrders_AnotherCustomersOrderIsNotFound(t *testing.T) { repo, customer, _, theirs := newCustomerOrderTest() _, err := NewCustomerOrderProcessor(repo, earnedFake{}).Detail(context.Background(), customer, theirs) assert.ErrorIs(t, err, repository.ErrCustomerOrderNotFound) }