package repository import ( "enaklo-pos-be/internal/common/mycontext" "enaklo-pos-be/internal/entity" "enaklo-pos-be/internal/repository/models" "github.com/pkg/errors" "gorm.io/gorm" "time" ) type CashierSessionRepository interface { CreateSession(ctx mycontext.Context, session *entity.CashierSession) (*entity.CashierSession, error) CloseSession(ctx mycontext.Context, sessionID int64, closingAmount, expectedAmount float64) error GetOpenSessionByCashierID(ctx mycontext.Context, cashierID int64) (*entity.CashierSession, error) GetSessionByID(ctx mycontext.Context, sessionID int64) (*entity.CashierSession, error) GetPaymentSummaryBySessionID(ctx mycontext.Context, sessionID int64) ([]entity.PaymentSummary, error) } type cashierSessionRepository struct { db *gorm.DB } func NewCashierSessionRepository(db *gorm.DB) CashierSessionRepository { return &cashierSessionRepository{db: db} } func (r *cashierSessionRepository) CreateSession(ctx mycontext.Context, session *entity.CashierSession) (*entity.CashierSession, error) { dbModel := models.CashierSessionDB{ CashierID: session.CashierID, OpenedAt: time.Now(), OpeningAmount: session.OpeningAmount, Status: "open", CreatedAt: time.Now(), } if err := r.db.Create(&dbModel).Error; err != nil { return nil, errors.Wrap(err, "failed to create cashier session") } session.ID = dbModel.ID session.Status = dbModel.Status session.OpenedAt = dbModel.OpenedAt return session, nil } func (r *cashierSessionRepository) CloseSession(ctx mycontext.Context, sessionID int64, closingAmount, expectedAmount float64) error { result := r.db.Model(&models.CashierSessionDB{}). Where("id = ?", sessionID). Updates(map[string]interface{}{ "closed_at": time.Now(), "closing_amount": closingAmount, "expected_amount": expectedAmount, "status": "closed", }) if result.Error != nil { return errors.Wrap(result.Error, "failed to close session") } if result.RowsAffected == 0 { return errors.New("no session updated") } return nil } func (r *cashierSessionRepository) GetOpenSessionByCashierID(ctx mycontext.Context, cashierID int64) (*entity.CashierSession, error) { var dbModel models.CashierSessionDB if err := r.db.Where("cashier_id = ? AND status = 'open'", cashierID). Order("opened_at DESC").First(&dbModel).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil } return nil, errors.Wrap(err, "failed to get open session") } return r.toEntity(&dbModel), nil } func (r *cashierSessionRepository) GetSessionByID(ctx mycontext.Context, sessionID int64) (*entity.CashierSession, error) { var dbModel models.CashierSessionDB if err := r.db.First(&dbModel, sessionID).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil } return nil, errors.Wrap(err, "failed to get session by ID") } return r.toEntity(&dbModel), nil } func (r *cashierSessionRepository) toEntity(db *models.CashierSessionDB) *entity.CashierSession { return &entity.CashierSession{ ID: db.ID, CashierID: db.CashierID, OpenedAt: db.OpenedAt, ClosedAt: db.ClosedAt, OpeningAmount: db.OpeningAmount, ClosingAmount: db.ClosingAmount, ExpectedAmount: db.ExpectedAmount, Status: db.Status, } } func (r *cashierSessionRepository) GetPaymentSummaryBySessionID(ctx mycontext.Context, sessionID int64) ([]entity.PaymentSummary, error) { type result struct { PaymentType string PaymentProvider string TotalAmount float64 } var rows []result err := r.db.WithContext(ctx). Table("orders"). Select("payment_type, payment_provider, SUM(total) AS total_amount"). Where("cashier_session_id = ?", sessionID). Group("payment_type, payment_provider"). Scan(&rows).Error if err != nil { return nil, errors.Wrap(err, "failed to summarize payments from orders") } summary := make([]entity.PaymentSummary, len(rows)) for i, row := range rows { summary[i] = entity.PaymentSummary{ PaymentType: row.PaymentType, PaymentProvider: row.PaymentProvider, TotalAmount: row.TotalAmount, } } return summary, nil }