package processor import ( "apskel-pos-be/internal/constants" "apskel-pos-be/internal/entities" "apskel-pos-be/internal/models" "apskel-pos-be/internal/repository" "context" "errors" "math" "github.com/google/uuid" ) type TableProcessor struct { tableRepo *repository.TableRepository orderRepo *repository.OrderRepository } func NewTableProcessor(tableRepo *repository.TableRepository, orderRepo *repository.OrderRepository) *TableProcessor { return &TableProcessor{ tableRepo: tableRepo, orderRepo: orderRepo, } } func (p *TableProcessor) Create(ctx context.Context, req models.CreateTableRequest, organizationID uuid.UUID) (*models.TableResponse, error) { table := &entities.Table{ OrganizationID: organizationID, OutletID: req.OutletID, TableName: req.TableName, PositionX: req.PositionX, PositionY: req.PositionY, Capacity: req.Capacity, Status: string(constants.TableStatusAvailable), IsActive: true, Metadata: req.Metadata, } err := p.tableRepo.Create(ctx, table) if err != nil { return nil, err } return p.mapTableToResponse(table), nil } func (p *TableProcessor) GetByID(ctx context.Context, id uuid.UUID) (*models.TableResponse, error) { table, err := p.tableRepo.GetByID(ctx, id) if err != nil { return nil, err } return p.mapTableToResponse(table), nil } func (p *TableProcessor) Update(ctx context.Context, id uuid.UUID, req models.UpdateTableRequest) (*models.TableResponse, error) { table, err := p.tableRepo.GetByID(ctx, id) if err != nil { return nil, err } if req.TableName != nil { table.TableName = *req.TableName } if req.Status != nil { table.Status = string(*req.Status) } if req.PositionX != nil { table.PositionX = *req.PositionX } if req.PositionY != nil { table.PositionY = *req.PositionY } if req.Capacity != nil { table.Capacity = *req.Capacity } if req.IsActive != nil { table.IsActive = *req.IsActive } if req.Metadata != nil { table.Metadata = req.Metadata } err = p.tableRepo.Update(ctx, table) if err != nil { return nil, err } return p.mapTableToResponse(table), nil } func (p *TableProcessor) Delete(ctx context.Context, id uuid.UUID) error { table, err := p.tableRepo.GetByID(ctx, id) if err != nil { return err } if table.IsOccupied() { return errors.New("cannot delete occupied table") } return p.tableRepo.Delete(ctx, id) } func (p *TableProcessor) List(ctx context.Context, req models.ListTablesRequest) (*models.ListTablesResponse, error) { tables, total, err := p.tableRepo.List(ctx, req.OrganizationID, req.OutletID, (*string)(req.Status), req.IsActive, req.Search, req.Page, req.Limit) if err != nil { return nil, err } responses := make([]models.TableResponse, len(tables)) for i, table := range tables { responses[i] = *p.mapTableToResponse(&table) } totalPages := int(math.Ceil(float64(total) / float64(req.Limit))) return &models.ListTablesResponse{ Tables: responses, TotalCount: int(total), Page: req.Page, Limit: req.Limit, TotalPages: totalPages, }, nil } func (p *TableProcessor) OccupyTable(ctx context.Context, tableID uuid.UUID, req models.OccupyTableRequest) (*models.TableResponse, error) { table, err := p.tableRepo.GetByID(ctx, tableID) if err != nil { return nil, err } if !table.CanBeOccupied() { return nil, errors.New("table is not available for occupation") } // Verify order exists order, err := p.orderRepo.GetByID(ctx, req.OrderID) if err != nil { return nil, errors.New("order not found") } err = p.tableRepo.OccupyTable(ctx, tableID, req.OrderID, &req.StartTime) if err != nil { return nil, err } // Get updated table updatedTable, err := p.tableRepo.GetByID(ctx, tableID) if err != nil { return nil, err } return p.mapTableToResponse(updatedTable), nil } func (p *TableProcessor) ReleaseTable(ctx context.Context, tableID uuid.UUID, req models.ReleaseTableRequest) (*models.TableResponse, error) { table, err := p.tableRepo.GetByID(ctx, tableID) if err != nil { return nil, err } if !table.IsOccupied() { return nil, errors.New("table is not occupied") } err = p.tableRepo.ReleaseTable(ctx, tableID, req.PaymentAmount) if err != nil { return nil, err } // Get updated table updatedTable, err := p.tableRepo.GetByID(ctx, tableID) if err != nil { return nil, err } return p.mapTableToResponse(updatedTable), nil } func (p *TableProcessor) GetAvailableTables(ctx context.Context, outletID uuid.UUID) ([]models.TableResponse, error) { tables, err := p.tableRepo.GetAvailableTables(ctx, outletID) if err != nil { return nil, err } responses := make([]models.TableResponse, len(tables)) for i, table := range tables { responses[i] = *p.mapTableToResponse(&table) } return responses, nil } func (p *TableProcessor) GetOccupiedTables(ctx context.Context, outletID uuid.UUID) ([]models.TableResponse, error) { tables, err := p.tableRepo.GetOccupiedTables(ctx, outletID) if err != nil { return nil, err } responses := make([]models.TableResponse, len(tables)) for i, table := range tables { responses[i] = *p.mapTableToResponse(&table) } return responses, nil } func (p *TableProcessor) mapTableToResponse(table *entities.Table) *models.TableResponse { response := &models.TableResponse{ ID: table.ID, OrganizationID: table.OrganizationID, OutletID: table.OutletID, TableName: table.TableName, StartTime: table.StartTime, Status: constants.TableStatus(table.Status), OrderID: table.OrderID, PaymentAmount: table.PaymentAmount, PositionX: table.PositionX, PositionY: table.PositionY, Capacity: table.Capacity, IsActive: table.IsActive, Metadata: table.Metadata, CreatedAt: table.CreatedAt, UpdatedAt: table.UpdatedAt, } if table.Order != nil { response.Order = &models.OrderResponse{ ID: table.Order.ID, OrganizationID: table.Order.OrganizationID, OutletID: table.Order.OutletID, UserID: table.Order.UserID, CustomerID: table.Order.CustomerID, OrderNumber: table.Order.OrderNumber, TableNumber: table.Order.TableNumber, OrderType: constants.OrderType(table.Order.OrderType), Status: constants.OrderStatus(table.Order.Status), Subtotal: table.Order.Subtotal, TaxAmount: table.Order.TaxAmount, DiscountAmount: table.Order.DiscountAmount, TotalAmount: table.Order.TotalAmount, TotalCost: table.Order.TotalCost, PaymentStatus: constants.PaymentStatus(table.Order.PaymentStatus), RefundAmount: table.Order.RefundAmount, IsVoid: table.Order.IsVoid, IsRefund: table.Order.IsRefund, VoidReason: table.Order.VoidReason, VoidedAt: table.Order.VoidedAt, VoidedBy: table.Order.VoidedBy, RefundReason: table.Order.RefundReason, RefundedAt: table.Order.RefundedAt, RefundedBy: table.Order.RefundedBy, Metadata: table.Order.Metadata, CreatedAt: table.Order.CreatedAt, UpdatedAt: table.Order.UpdatedAt, } } return response }