Aditya Siregar a759e0f57c init
2025-07-30 23:18:20 +07:00

263 lines
7.0 KiB
Go

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
}