This commit is contained in:
Aditya Siregar
2025-07-30 23:18:20 +07:00
parent 4a921df55d
commit a759e0f57c
57 changed files with 3633 additions and 190 deletions
@@ -0,0 +1,214 @@
package processor
import (
"context"
"fmt"
"apskel-pos-be/internal/entities"
"apskel-pos-be/internal/mappers"
"apskel-pos-be/internal/models"
"apskel-pos-be/internal/repository"
"github.com/google/uuid"
)
type InventoryMovementProcessor interface {
CreateMovement(ctx context.Context, req *models.CreateInventoryMovementRequest) (*models.InventoryMovementResponse, error)
GetMovementByID(ctx context.Context, id uuid.UUID) (*models.InventoryMovementResponse, error)
ListMovements(ctx context.Context, req *models.ListInventoryMovementsRequest) (*models.ListInventoryMovementsResponse, error)
GetMovementsByProductAndOutlet(ctx context.Context, productID, outletID uuid.UUID, limit, offset int) (*models.ListInventoryMovementsResponse, error)
GetMovementsByOrderID(ctx context.Context, orderID uuid.UUID) ([]models.InventoryMovementResponse, error)
GetMovementsByPaymentID(ctx context.Context, paymentID uuid.UUID) ([]models.InventoryMovementResponse, error)
}
type InventoryMovementRepository interface {
Create(ctx context.Context, movement *entities.InventoryMovement) error
GetByID(ctx context.Context, id uuid.UUID) (*entities.InventoryMovement, error)
GetWithRelations(ctx context.Context, id uuid.UUID) (*entities.InventoryMovement, error)
List(ctx context.Context, filters map[string]interface{}, limit, offset int) ([]*entities.InventoryMovement, int64, error)
GetByProductAndOutlet(ctx context.Context, productID, outletID uuid.UUID, limit, offset int) ([]*entities.InventoryMovement, int64, error)
GetByOrderID(ctx context.Context, orderID uuid.UUID) ([]*entities.InventoryMovement, error)
GetByPaymentID(ctx context.Context, paymentID uuid.UUID) ([]*entities.InventoryMovement, error)
Count(ctx context.Context, filters map[string]interface{}) (int64, error)
}
type InventoryMovementProcessorImpl struct {
movementRepo InventoryMovementRepository
inventoryRepo repository.InventoryRepository
}
func NewInventoryMovementProcessorImpl(
movementRepo InventoryMovementRepository,
inventoryRepo repository.InventoryRepository,
) *InventoryMovementProcessorImpl {
return &InventoryMovementProcessorImpl{
movementRepo: movementRepo,
inventoryRepo: inventoryRepo,
}
}
func (p *InventoryMovementProcessorImpl) CreateMovement(ctx context.Context, req *models.CreateInventoryMovementRequest) (*models.InventoryMovementResponse, error) {
currentInventory, err := p.inventoryRepo.GetByProductAndOutlet(ctx, req.ProductID, req.OutletID)
if err != nil {
return nil, fmt.Errorf("failed to get current inventory: %w", err)
}
previousQuantity := currentInventory.Quantity
newQuantity := previousQuantity + req.Quantity
movement := &entities.InventoryMovement{
OrganizationID: req.OrganizationID,
OutletID: req.OutletID,
ProductID: req.ProductID,
MovementType: entities.InventoryMovementType(req.MovementType),
Quantity: req.Quantity,
PreviousQuantity: previousQuantity,
NewQuantity: newQuantity,
UnitCost: req.UnitCost,
TotalCost: float64(req.Quantity) * req.UnitCost,
ReferenceType: (*entities.InventoryMovementReferenceType)(req.ReferenceType),
ReferenceID: req.ReferenceID,
OrderID: req.OrderID,
PaymentID: req.PaymentID,
UserID: req.UserID,
Reason: req.Reason,
Notes: req.Notes,
Metadata: entities.Metadata(req.Metadata),
}
if err := p.movementRepo.Create(ctx, movement); err != nil {
return nil, fmt.Errorf("failed to create inventory movement: %w", err)
}
movementWithRelations, err := p.movementRepo.GetWithRelations(ctx, movement.ID)
if err != nil {
return nil, fmt.Errorf("failed to retrieve created movement: %w", err)
}
response := mappers.InventoryMovementEntityToResponse(movementWithRelations)
return response, nil
}
func (p *InventoryMovementProcessorImpl) GetMovementByID(ctx context.Context, id uuid.UUID) (*models.InventoryMovementResponse, error) {
movement, err := p.movementRepo.GetWithRelations(ctx, id)
if err != nil {
return nil, fmt.Errorf("movement not found: %w", err)
}
response := mappers.InventoryMovementEntityToResponse(movement)
return response, nil
}
func (p *InventoryMovementProcessorImpl) ListMovements(ctx context.Context, req *models.ListInventoryMovementsRequest) (*models.ListInventoryMovementsResponse, error) {
filters := make(map[string]interface{})
if req.OrganizationID != nil {
filters["organization_id"] = *req.OrganizationID
}
if req.OutletID != nil {
filters["outlet_id"] = *req.OutletID
}
if req.ProductID != nil {
filters["product_id"] = *req.ProductID
}
if req.MovementType != nil {
filters["movement_type"] = string(*req.MovementType)
}
if req.ReferenceType != nil {
filters["reference_type"] = string(*req.ReferenceType)
}
if req.ReferenceID != nil {
filters["reference_id"] = *req.ReferenceID
}
if req.OrderID != nil {
filters["order_id"] = *req.OrderID
}
if req.PaymentID != nil {
filters["payment_id"] = *req.PaymentID
}
if req.UserID != nil {
filters["user_id"] = *req.UserID
}
if req.DateFrom != nil {
filters["date_from"] = *req.DateFrom
}
if req.DateTo != nil {
filters["date_to"] = *req.DateTo
}
offset := (req.Page - 1) * req.Limit
movements, total, err := p.movementRepo.List(ctx, filters, req.Limit, offset)
if err != nil {
return nil, fmt.Errorf("failed to list movements: %w", err)
}
// Convert to responses
movementResponses := make([]models.InventoryMovementResponse, len(movements))
for i, movement := range movements {
response := mappers.InventoryMovementEntityToResponse(movement)
if response != nil {
movementResponses[i] = *response
}
}
// Calculate total pages
totalPages := int(total) / req.Limit
if int(total)%req.Limit > 0 {
totalPages++
}
return &models.ListInventoryMovementsResponse{
Movements: movementResponses,
TotalCount: int(total),
Page: req.Page,
Limit: req.Limit,
TotalPages: totalPages,
}, nil
}
func (p *InventoryMovementProcessorImpl) GetMovementsByProductAndOutlet(ctx context.Context, productID, outletID uuid.UUID, limit, offset int) (*models.ListInventoryMovementsResponse, error) {
movements, total, err := p.movementRepo.GetByProductAndOutlet(ctx, productID, outletID, limit, offset)
if err != nil {
return nil, fmt.Errorf("failed to get movements by product and outlet: %w", err)
}
movementResponses := make([]models.InventoryMovementResponse, len(movements))
for i, movement := range movements {
response := mappers.InventoryMovementEntityToResponse(movement)
if response != nil {
movementResponses[i] = *response
}
}
totalPages := int(total) / limit
if int(total)%limit > 0 {
totalPages++
}
return &models.ListInventoryMovementsResponse{
Movements: movementResponses,
TotalCount: int(total),
Page: 1,
Limit: limit,
TotalPages: totalPages,
}, nil
}
func (p *InventoryMovementProcessorImpl) GetMovementsByOrderID(ctx context.Context, orderID uuid.UUID) ([]models.InventoryMovementResponse, error) {
movements, err := p.movementRepo.GetByOrderID(ctx, orderID)
if err != nil {
return nil, fmt.Errorf("failed to get movements by order ID: %w", err)
}
responses := mappers.InventoryMovementEntitiesToResponses(movements)
return responses, nil
}
func (p *InventoryMovementProcessorImpl) GetMovementsByPaymentID(ctx context.Context, paymentID uuid.UUID) ([]models.InventoryMovementResponse, error) {
movements, err := p.movementRepo.GetByPaymentID(ctx, paymentID)
if err != nil {
return nil, fmt.Errorf("failed to get movements by payment ID: %w", err)
}
responses := mappers.InventoryMovementEntitiesToResponses(movements)
return responses, nil
}
+3 -24
View File
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
"apskel-pos-be/internal/entities"
"apskel-pos-be/internal/mappers"
"apskel-pos-be/internal/models"
"apskel-pos-be/internal/repository"
"github.com/google/uuid"
)
@@ -22,35 +22,14 @@ type InventoryProcessor interface {
GetZeroStockItems(ctx context.Context, outletID uuid.UUID) ([]models.InventoryResponse, error)
}
type InventoryRepository interface {
Create(ctx context.Context, inventory *entities.Inventory) error
GetByID(ctx context.Context, id uuid.UUID) (*entities.Inventory, error)
GetWithRelations(ctx context.Context, id uuid.UUID) (*entities.Inventory, error)
GetByProductAndOutlet(ctx context.Context, productID, outletID uuid.UUID) (*entities.Inventory, error)
GetByOutlet(ctx context.Context, outletID uuid.UUID) ([]*entities.Inventory, error)
GetByProduct(ctx context.Context, productID uuid.UUID) ([]*entities.Inventory, error)
GetLowStock(ctx context.Context, outletID uuid.UUID) ([]*entities.Inventory, error)
GetZeroStock(ctx context.Context, outletID uuid.UUID) ([]*entities.Inventory, error)
Update(ctx context.Context, inventory *entities.Inventory) error
Delete(ctx context.Context, id uuid.UUID) error
List(ctx context.Context, filters map[string]interface{}, limit, offset int) ([]*entities.Inventory, int64, error)
Count(ctx context.Context, filters map[string]interface{}) (int64, error)
AdjustQuantity(ctx context.Context, productID, outletID uuid.UUID, delta int) (*entities.Inventory, error)
SetQuantity(ctx context.Context, productID, outletID uuid.UUID, quantity int) (*entities.Inventory, error)
UpdateReorderLevel(ctx context.Context, id uuid.UUID, reorderLevel int) error
BulkCreate(ctx context.Context, inventoryItems []*entities.Inventory) error
BulkAdjustQuantity(ctx context.Context, adjustments map[uuid.UUID]int, outletID uuid.UUID) error
GetTotalValueByOutlet(ctx context.Context, outletID uuid.UUID) (float64, error)
}
type InventoryProcessorImpl struct {
inventoryRepo InventoryRepository
inventoryRepo repository.InventoryRepository
productRepo ProductRepository
outletRepo OutletRepository
}
func NewInventoryProcessorImpl(
inventoryRepo InventoryRepository,
inventoryRepo repository.InventoryRepository,
productRepo ProductRepository,
outletRepo OutletRepository,
) *InventoryProcessorImpl {
+33 -100
View File
@@ -8,6 +8,7 @@ import (
"apskel-pos-be/internal/entities"
"apskel-pos-be/internal/mappers"
"apskel-pos-be/internal/models"
"apskel-pos-be/internal/repository"
"github.com/google/uuid"
)
@@ -62,6 +63,8 @@ type PaymentRepository interface {
RefundPayment(ctx context.Context, id uuid.UUID, refundAmount float64, reason string, refundedBy uuid.UUID) error
UpdateStatus(ctx context.Context, id uuid.UUID, status entities.PaymentTransactionStatus) error
GetTotalPaidByOrderID(ctx context.Context, orderID uuid.UUID) (float64, error)
CreatePaymentWithInventoryMovement(ctx context.Context, req *models.CreatePaymentRequest, order *entities.Order, totalPaid float64) (*entities.Payment, error)
RefundPaymentWithInventoryMovement(ctx context.Context, paymentID uuid.UUID, refundAmount float64, reason string, refundedBy uuid.UUID, order *entities.Payment) error
}
type PaymentMethodRepository interface {
@@ -89,15 +92,16 @@ func (r *SimplePaymentMethodRepository) GetByID(ctx context.Context, id uuid.UUI
}
type OrderProcessorImpl struct {
orderRepo OrderRepository
orderItemRepo OrderItemRepository
paymentRepo PaymentRepository
productRepo ProductRepository
paymentMethodRepo PaymentMethodRepository
inventoryRepo InventoryRepository
productVariantRepo ProductVariantRepository
outletRepo OutletRepository
customerRepo CustomerRepository
orderRepo OrderRepository
orderItemRepo OrderItemRepository
paymentRepo PaymentRepository
productRepo ProductRepository
paymentMethodRepo PaymentMethodRepository
inventoryRepo repository.InventoryRepository
inventoryMovementRepo repository.InventoryMovementRepository
productVariantRepo ProductVariantRepository
outletRepo OutletRepository
customerRepo CustomerRepository
}
func NewOrderProcessorImpl(
@@ -106,21 +110,23 @@ func NewOrderProcessorImpl(
paymentRepo PaymentRepository,
productRepo ProductRepository,
paymentMethodRepo PaymentMethodRepository,
inventoryRepo InventoryRepository,
inventoryRepo repository.InventoryRepository,
inventoryMovementRepo repository.InventoryMovementRepository,
productVariantRepo ProductVariantRepository,
outletRepo OutletRepository,
customerRepo CustomerRepository,
) *OrderProcessorImpl {
return &OrderProcessorImpl{
orderRepo: orderRepo,
orderItemRepo: orderItemRepo,
paymentRepo: paymentRepo,
productRepo: productRepo,
paymentMethodRepo: paymentMethodRepo,
inventoryRepo: inventoryRepo,
productVariantRepo: productVariantRepo,
outletRepo: outletRepo,
customerRepo: customerRepo,
orderRepo: orderRepo,
orderItemRepo: orderItemRepo,
paymentRepo: paymentRepo,
productRepo: productRepo,
paymentMethodRepo: paymentMethodRepo,
inventoryRepo: inventoryRepo,
inventoryMovementRepo: inventoryMovementRepo,
productVariantRepo: productVariantRepo,
outletRepo: outletRepo,
customerRepo: customerRepo,
}
}
@@ -619,7 +625,6 @@ func (p *OrderProcessorImpl) RefundOrder(ctx context.Context, id uuid.UUID, req
return fmt.Errorf("order not found: %w", err)
}
// Check if order can be refunded
if order.IsRefund {
return fmt.Errorf("order is already refunded")
}
@@ -738,69 +743,11 @@ func (p *OrderProcessorImpl) CreatePayment(ctx context.Context, req *models.Crea
return nil, fmt.Errorf("payment amount exceeds remaining balance")
}
payment := &entities.Payment{
OrderID: req.OrderID,
PaymentMethodID: req.PaymentMethodID,
Amount: req.Amount,
Status: entities.PaymentTransactionStatusCompleted,
TransactionID: req.TransactionID,
SplitNumber: req.SplitNumber,
SplitTotal: req.SplitTotal,
SplitDescription: req.SplitDescription,
Metadata: entities.Metadata(req.Metadata),
payment, err := p.paymentRepo.CreatePaymentWithInventoryMovement(ctx, req, order, totalPaid)
if err != nil {
return nil, err
}
if err := p.paymentRepo.Create(ctx, payment); err != nil {
return nil, fmt.Errorf("failed to create payment: %w", err)
}
if len(req.PaymentOrderItems) > 0 {
for _, itemPayment := range req.PaymentOrderItems {
paymentOrderItem := &entities.PaymentOrderItem{
PaymentID: payment.ID,
OrderItemID: itemPayment.OrderItemID,
Amount: itemPayment.Amount,
}
fmt.Println(paymentOrderItem)
// TODO: Create payment order item in database
// This would require a PaymentOrderItemRepository
}
}
// Update order payment status if fully paid
newTotalPaid := totalPaid + req.Amount
orderJustCompleted := false
if newTotalPaid >= order.TotalAmount {
if order.PaymentStatus != entities.PaymentStatusCompleted {
orderJustCompleted = true
}
if err := p.orderRepo.UpdatePaymentStatus(ctx, req.OrderID, entities.PaymentStatusCompleted); err != nil {
return nil, fmt.Errorf("failed to update order payment status: %w", err)
}
// Set order status to completed when fully paid
if err := p.orderRepo.UpdateStatus(ctx, req.OrderID, entities.OrderStatusCompleted); err != nil {
return nil, fmt.Errorf("failed to update order status: %w", err)
}
} else {
if err := p.orderRepo.UpdatePaymentStatus(ctx, req.OrderID, entities.PaymentStatusPartiallyRefunded); err != nil {
return nil, fmt.Errorf("failed to update order payment status: %w", err)
}
}
if orderJustCompleted {
orderItems, err := p.orderItemRepo.GetByOrderID(ctx, req.OrderID)
if err != nil {
return nil, fmt.Errorf("failed to get order items for inventory adjustment: %w", err)
}
for _, item := range orderItems {
if _, err := p.inventoryRepo.AdjustQuantity(ctx, item.ProductID, order.OutletID, -item.Quantity); err != nil {
return nil, fmt.Errorf("failed to adjust inventory for product %s: %w", item.ProductID, err)
}
}
}
// Get payment with relations for response
paymentWithRelations, err := p.paymentRepo.GetByID(ctx, payment.ID)
if err != nil {
return nil, fmt.Errorf("failed to retrieve created payment: %w", err)
@@ -810,14 +757,16 @@ func (p *OrderProcessorImpl) CreatePayment(ctx context.Context, req *models.Crea
return response, nil
}
func stringPtr(s string) *string {
return &s
}
func (p *OrderProcessorImpl) RefundPayment(ctx context.Context, paymentID uuid.UUID, refundAmount float64, reason string, refundedBy uuid.UUID) error {
// Get payment
payment, err := p.paymentRepo.GetByID(ctx, paymentID)
if err != nil {
return fmt.Errorf("payment not found: %w", err)
}
// Check if payment can be refunded
if payment.Status != entities.PaymentTransactionStatusCompleted {
return fmt.Errorf("payment is not completed, cannot refund")
}
@@ -826,23 +775,7 @@ func (p *OrderProcessorImpl) RefundPayment(ctx context.Context, paymentID uuid.U
return fmt.Errorf("refund amount cannot exceed payment amount")
}
// Process refund
if err := p.paymentRepo.RefundPayment(ctx, paymentID, refundAmount, reason, refundedBy); err != nil {
return fmt.Errorf("failed to refund payment: %w", err)
}
// Update order refund amount
order, err := p.orderRepo.GetByID(ctx, payment.OrderID)
if err != nil {
return fmt.Errorf("failed to get order: %w", err)
}
order.RefundAmount += refundAmount
if err := p.orderRepo.Update(ctx, order); err != nil {
return fmt.Errorf("failed to update order refund amount: %w", err)
}
return nil
return p.paymentRepo.RefundPaymentWithInventoryMovement(ctx, paymentID, refundAmount, reason, refundedBy, payment)
}
func (p *OrderProcessorImpl) SetOrderCustomer(ctx context.Context, orderID uuid.UUID, req *models.SetOrderCustomerRequest, organizationID uuid.UUID) (*models.SetOrderCustomerResponse, error) {
+2 -2
View File
@@ -45,11 +45,11 @@ type ProductProcessorImpl struct {
productRepo ProductRepository
categoryRepo CategoryRepository
productVariantRepo repository.ProductVariantRepository
inventoryRepo InventoryRepository
inventoryRepo repository.InventoryRepository
outletRepo OutletRepository
}
func NewProductProcessorImpl(productRepo ProductRepository, categoryRepo CategoryRepository, productVariantRepo repository.ProductVariantRepository, inventoryRepo InventoryRepository, outletRepo OutletRepository) *ProductProcessorImpl {
func NewProductProcessorImpl(productRepo ProductRepository, categoryRepo CategoryRepository, productVariantRepo repository.ProductVariantRepository, inventoryRepo repository.InventoryRepository, outletRepo OutletRepository) *ProductProcessorImpl {
return &ProductProcessorImpl{
productRepo: productRepo,
categoryRepo: categoryRepo,
+262
View File
@@ -0,0 +1,262 @@
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
}
+29
View File
@@ -224,3 +224,32 @@ func (p *UserProcessorImpl) DeactivateUser(ctx context.Context, userID uuid.UUID
return nil
}
func (p *UserProcessorImpl) UpdateUserOutlet(ctx context.Context, userID uuid.UUID, req *models.UpdateUserOutletRequest) (*models.UserResponse, error) {
// Get user first to validate existence and get organization_id
existingUser, err := p.userRepo.GetByID(ctx, userID)
if err != nil {
return nil, fmt.Errorf("user not found: %w", err)
}
// Validate outlet exists
outlet, err := p.outletRepo.GetByID(ctx, req.OutletID)
if err != nil {
return nil, fmt.Errorf("outlet not found: %w", err)
}
// Validate outlet belongs to user's organization
if outlet.OrganizationID != existingUser.OrganizationID {
return nil, fmt.Errorf("outlet does not belong to user's organization")
}
// Update user's outlet_id
existingUser.OutletID = &req.OutletID
err = p.userRepo.Update(ctx, existingUser)
if err != nil {
return nil, fmt.Errorf("failed to update user outlet: %w", err)
}
return mappers.UserEntityToResponse(existingUser), nil
}