package service import ( "context" "testing" "time" "apskel-pos-be/internal/entities" "apskel-pos-be/internal/models" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) // Mock implementations for testing type MockOrderProcessor struct { mock.Mock } func (m *MockOrderProcessor) CreateOrder(ctx context.Context, req *models.CreateOrderRequest, organizationID uuid.UUID) (*models.OrderResponse, error) { args := m.Called(ctx, req, organizationID) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*models.OrderResponse), args.Error(1) } func (m *MockOrderProcessor) AddToOrder(ctx context.Context, orderID uuid.UUID, req *models.AddToOrderRequest) (*models.AddToOrderResponse, error) { args := m.Called(ctx, orderID, req) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*models.AddToOrderResponse), args.Error(1) } func (m *MockOrderProcessor) UpdateOrder(ctx context.Context, id uuid.UUID, req *models.UpdateOrderRequest) (*models.OrderResponse, error) { args := m.Called(ctx, id, req) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*models.OrderResponse), args.Error(1) } func (m *MockOrderProcessor) GetOrderByID(ctx context.Context, id uuid.UUID) (*models.OrderResponse, error) { args := m.Called(ctx, id) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*models.OrderResponse), args.Error(1) } func (m *MockOrderProcessor) ListOrders(ctx context.Context, req *models.ListOrdersRequest) (*models.ListOrdersResponse, error) { args := m.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*models.ListOrdersResponse), args.Error(1) } func (m *MockOrderProcessor) VoidOrder(ctx context.Context, req *models.VoidOrderRequest, voidedBy uuid.UUID) error { args := m.Called(ctx, req, voidedBy) return args.Error(0) } func (m *MockOrderProcessor) RefundOrder(ctx context.Context, id uuid.UUID, req *models.RefundOrderRequest, refundedBy uuid.UUID) error { args := m.Called(ctx, id, req, refundedBy) return args.Error(0) } func (m *MockOrderProcessor) CreatePayment(ctx context.Context, req *models.CreatePaymentRequest) (*models.PaymentResponse, error) { args := m.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*models.PaymentResponse), args.Error(1) } func (m *MockOrderProcessor) RefundPayment(ctx context.Context, paymentID uuid.UUID, refundAmount float64, reason string, refundedBy uuid.UUID) error { args := m.Called(ctx, paymentID, refundAmount, reason, refundedBy) return args.Error(0) } func (m *MockOrderProcessor) SetOrderCustomer(ctx context.Context, orderID uuid.UUID, req *models.SetOrderCustomerRequest, organizationID uuid.UUID) (*models.SetOrderCustomerResponse, error) { args := m.Called(ctx, orderID, req, organizationID) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*models.SetOrderCustomerResponse), args.Error(1) } func (m *MockOrderProcessor) SplitBill(ctx context.Context, req *models.SplitBillRequest) (*models.SplitBillResponse, error) { args := m.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*models.SplitBillResponse), args.Error(1) } type MockTableRepository struct { mock.Mock } func (m *MockTableRepository) Create(ctx context.Context, table *entities.Table) error { args := m.Called(ctx, table) return args.Error(0) } func (m *MockTableRepository) GetByID(ctx context.Context, id uuid.UUID) (*entities.Table, error) { args := m.Called(ctx, id) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*entities.Table), args.Error(1) } func (m *MockTableRepository) GetByOutletID(ctx context.Context, outletID uuid.UUID) ([]entities.Table, error) { args := m.Called(ctx, outletID) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).([]entities.Table), args.Error(1) } func (m *MockTableRepository) GetByOrganizationID(ctx context.Context, organizationID uuid.UUID) ([]entities.Table, error) { args := m.Called(ctx, organizationID) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).([]entities.Table), args.Error(1) } func (m *MockTableRepository) Update(ctx context.Context, table *entities.Table) error { args := m.Called(ctx, table) return args.Error(0) } func (m *MockTableRepository) Delete(ctx context.Context, id uuid.UUID) error { args := m.Called(ctx, id) return args.Error(0) } func (m *MockTableRepository) List(ctx context.Context, organizationID, outletID *uuid.UUID, status *string, isActive *bool, search string, page, limit int) ([]entities.Table, int64, error) { args := m.Called(ctx, organizationID, outletID, status, isActive, search, page, limit) if args.Get(0) == nil { return nil, 0, args.Error(2) } return args.Get(0).([]entities.Table), args.Get(1).(int64), args.Error(2) } func (m *MockTableRepository) GetAvailableTables(ctx context.Context, outletID uuid.UUID) ([]entities.Table, error) { args := m.Called(ctx, outletID) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).([]entities.Table), args.Error(1) } func (m *MockTableRepository) GetOccupiedTables(ctx context.Context, outletID uuid.UUID) ([]entities.Table, error) { args := m.Called(ctx, outletID) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).([]entities.Table), args.Error(1) } func (m *MockTableRepository) OccupyTable(ctx context.Context, tableID, orderID uuid.UUID, startTime *time.Time) error { args := m.Called(ctx, tableID, orderID, startTime) return args.Error(0) } func (m *MockTableRepository) ReleaseTable(ctx context.Context, tableID uuid.UUID, paymentAmount float64) error { args := m.Called(ctx, tableID, paymentAmount) return args.Error(0) } func (m *MockTableRepository) GetByOrderID(ctx context.Context, orderID uuid.UUID) (*entities.Table, error) { args := m.Called(ctx, orderID) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*entities.Table), args.Error(1) } func TestCreateOrderWithTableOccupation(t *testing.T) { // Setup ctx := context.Background() organizationID := uuid.New() outletID := uuid.New() userID := uuid.New() tableID := uuid.New() orderID := uuid.New() // Create mock table mockTable := &entities.Table{ ID: tableID, OrganizationID: organizationID, OutletID: outletID, TableName: "Table 1", Status: "available", IsActive: true, } // Create mock order response mockOrderResponse := &models.OrderResponse{ ID: orderID, // Add other required fields } // Create mock repositories mockTableRepo := &MockTableRepository{} mockOrderProcessor := &MockOrderProcessor{} // Set up expectations mockTableRepo.On("GetByID", ctx, tableID).Return(mockTable, nil) mockOrderProcessor.On("CreateOrder", ctx, mock.AnythingOfType("*models.CreateOrderRequest"), organizationID).Return(mockOrderResponse, nil) mockTableRepo.On("OccupyTable", ctx, tableID, orderID, mock.AnythingOfType("*time.Time")).Return(nil) // Create service with mock dependencies service := &OrderServiceImpl{ orderProcessor: mockOrderProcessor, tableRepo: mockTableRepo, } // Create test request req := &models.CreateOrderRequest{ OutletID: outletID, UserID: userID, TableID: &tableID, OrderType: "dine_in", OrderItems: []models.CreateOrderItemRequest{ { ProductID: uuid.New(), Quantity: 1, }, }, } // Test order creation with table occupation response, err := service.CreateOrder(ctx, req, organizationID) // Assertions assert.NoError(t, err) assert.NotNil(t, response) assert.Equal(t, orderID, response.ID) // Verify mock calls mockTableRepo.AssertExpectations(t) mockOrderProcessor.AssertExpectations(t) } func TestCreateOrderTableValidationFailure(t *testing.T) { // Setup ctx := context.Background() organizationID := uuid.New() outletID := uuid.New() userID := uuid.New() tableID := uuid.New() // Create mock table that's already occupied mockTable := &entities.Table{ ID: tableID, OrganizationID: organizationID, OutletID: outletID, TableName: "Table 1", Status: "occupied", // Already occupied IsActive: true, } // Create mock repositories mockTableRepo := &MockTableRepository{} mockOrderProcessor := &MockOrderProcessor{} // Set up expectations mockTableRepo.On("GetByID", ctx, tableID).Return(mockTable, nil) // Create service with mock dependencies service := &OrderServiceImpl{ orderProcessor: mockOrderProcessor, tableRepo: mockTableRepo, } // Create test request req := &models.CreateOrderRequest{ OutletID: outletID, UserID: userID, TableID: &tableID, OrderType: "dine_in", OrderItems: []models.CreateOrderItemRequest{ { ProductID: uuid.New(), Quantity: 1, }, }, } // Test order creation with occupied table response, err := service.CreateOrder(ctx, req, organizationID) // Assertions assert.Error(t, err) assert.Nil(t, response) assert.Contains(t, err.Error(), "table is not available for occupation") // Verify mock calls mockTableRepo.AssertExpectations(t) mockOrderProcessor.AssertNotCalled(t, "CreateOrder") }