2025-06-27 13:01:39 +07:00

178 lines
5.3 KiB
Go

package repository
import (
"enaklo-pos-be/internal/common/mycontext"
"enaklo-pos-be/internal/entity"
"enaklo-pos-be/internal/repository/models"
"time"
"github.com/pkg/errors"
"gorm.io/gorm"
)
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)
GetSessionHistoryByPartnerID(ctx mycontext.Context, partnerID int64, limit, offset int) ([]*entity.CashierSession, int64, 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{
PartnerID: session.PartnerID,
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,
PartnerID: db.PartnerID,
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
}
func (r *cashierSessionRepository) GetSessionHistoryByPartnerID(ctx mycontext.Context, partnerID int64, limit, offset int) ([]*entity.CashierSession, int64, error) {
var sessionsDB []models.CashierSessionDB
var totalCount int64
// Count total records
if err := r.db.Model(&models.CashierSessionDB{}).
Where("partner_id = ?", partnerID).
Count(&totalCount).Error; err != nil {
return nil, 0, errors.Wrap(err, "failed to count cashier sessions")
}
// Get sessions with pagination
query := r.db.Where("partner_id = ?", partnerID).
Order("opened_at DESC")
if limit > 0 {
query = query.Limit(limit)
}
if offset > 0 {
query = query.Offset(offset)
}
if err := query.Find(&sessionsDB).Error; err != nil {
return nil, 0, errors.Wrap(err, "failed to get cashier session history")
}
// Convert to entity
sessions := make([]*entity.CashierSession, len(sessionsDB))
for i, sessionDB := range sessionsDB {
sessions[i] = r.toEntity(&sessionDB)
}
return sessions, totalCount, nil
}