package users import ( "context" "enaklo-pos-be/internal/common/logger" "enaklo-pos-be/internal/entity" "go.uber.org/zap" "gorm.io/gorm" ) type UserRepository struct { db *gorm.DB } func NewUserRepository(db *gorm.DB) *UserRepository { return &UserRepository{ db: db, } } func (r *UserRepository) Create(ctx context.Context, user *entity.UserDB) (*entity.UserDB, error) { tx := r.db.Begin() user.ID = 0 if err := tx.Select("name", "email", "password", "status", "created_by", "nik", "user_type", "phone_number").Create(user).Error; err != nil { tx.Rollback() logError(ctx, "creating user", err) return nil, err } if err := tx.First(user, user.ID).Error; err != nil { tx.Rollback() logError(ctx, "retrieving user", err) return nil, err } if user.UserType != "CUSTOMER" { userRole := user.ToUserRoleDB() if err := tx.Create(userRole).Error; err != nil { tx.Rollback() logError(ctx, "creating user role", err) return nil, err } } if err := tx.Commit().Error; err != nil { tx.Rollback() logError(ctx, "committing transaction", err) return nil, err } return user, nil } func (r *UserRepository) CreateWithTx(ctx context.Context, tx *gorm.DB, user *entity.UserDB) (*entity.UserDB, error) { user.ID = 0 if err := tx.Select("name", "email", "password", "status", "created_by", "nik", "user_type", "phone_number").Create(user).Error; err != nil { logError(ctx, "creating user", err) return nil, err } if err := tx.First(user, user.ID).Error; err != nil { tx.Rollback() logError(ctx, "retrieving user", err) return nil, err } userRole := user.ToUserRoleDB() if err := tx.Create(userRole).Error; err != nil { tx.Rollback() logError(ctx, "creating user role", err) return nil, err } return user, nil } func (b *UserRepository) GetAllUsers(ctx context.Context, req entity.UserSearch) (entity.UserList, int, error) { var users []*entity.UserDB var total int64 query := b.db.Table("users"). Select("users.id, users.email, users.name, users.status, users.created_at, users.updated_at, ur.role_id, r.role_name, ur.partner_id, b.name as partner_name"). Joins("LEFT JOIN user_roles ur ON users.id = ur.user_id"). Joins("LEFT JOIN roles r ON ur.role_id = r.role_id"). Joins("LEFT JOIN partners b ON ur.partner_id = b.id"). Where("users.deleted_at is null"). Where("users.user_type != ?", "CUSTOMER") if req.Search != "" { query = query.Where("users.name ILIKE ? or users.email ILIKE ? or r.role_name ILIKE ? or b.name ILIKE ? ", "%"+req.Search+"%", "%"+req.Search+"%", "%"+req.Search+"%", "%"+req.Search+"%") } if req.Name != "" { query = query.Where("users.name ILIKE ?", "%"+req.Name+"%") } if req.RoleID > 0 { query = query.Where("ur.role_id = ? ", req.RoleID) } if req.PartnerID > 0 { query = query.Where("ur.partner_id = ? ", req.PartnerID) } if req.SiteID > 0 { query = query.Where("ur.site_id = ? ", req.SiteID) } // Get the total count without applying the limit and offset. if err := query.Model(&entity.UserDB{}).Count(&total).Error; err != nil { logger.ContextLogger(ctx).Error("error when count users", zap.Error(err)) return nil, 0, err } // Apply pagination. query = query.Offset(req.Offset).Limit(req.Limit) if err := query.Scan(&users).Error; err != nil { logger.ContextLogger(ctx).Error("error when get all users", zap.Error(err)) return nil, 0, err } return users, int(total), nil } func (b *UserRepository) GetAllCustomer(ctx context.Context, req entity.CustomerSearch) (entity.CustomerList, int, error) { var users []*entity.UserDB var total int64 query := b.db.Table("users"). Select("users.id, users.email, users.name, users.phone_number, users.status, users.user_type, users.created_at, users.updated_at, ur.role_id, r.role_name, ur.partner_id, b.name as partner_name"). Joins("LEFT JOIN user_roles ur ON users.id = ur.user_id"). Joins("LEFT JOIN roles r ON ur.role_id = r.role_id"). Joins("LEFT JOIN partners b ON ur.partner_id = b.id"). Where("users.deleted_at is null"). Where("users.user_type = 'CUSTOMER'") if req.Search != "" { query = query.Where("users.name ILIKE ? or users.email ILIKE ? or users.phone_number ILIKE ? or r.role_name ILIKE ? or b.name ILIKE ?", "%"+req.Search+"%", "%"+req.Search+"%", "%"+req.Search+"%", "%"+req.Search+"%", "%"+req.Search+"%") } if req.Name != "" { query = query.Where("users.name ILIKE ?", "%"+req.Name+"%") } if req.RoleID > 0 { query = query.Where("ur.role_id = ? ", req.RoleID) } if req.PartnerID > 0 { query = query.Where("ur.partner_id = ? ", req.PartnerID) } if req.SiteID > 0 { query = query.Where("ur.site_id = ? ", req.SiteID) } // Get the total count without applying the limit and offset. if err := query.Model(&entity.UserDB{}).Count(&total).Error; err != nil { logger.ContextLogger(ctx).Error("error when count users", zap.Error(err)) return nil, 0, err } // Apply pagination. query = query.Offset(req.Offset).Limit(req.Limit) if err := query.Scan(&users).Error; err != nil { logger.ContextLogger(ctx).Error("error when get all users", zap.Error(err)) return nil, 0, err } return users, int(total), nil } func (b *UserRepository) GetUserByID(ctx context.Context, id int64) (*entity.UserDB, error) { var user *entity.UserDB query := b.db.Table("users"). Select("users.id, users.email,users.phone_number,users.nik, users.password , users.name, users.status, users.created_at, users.updated_at, ur.role_id, r.role_name, ur.partner_id, ur.site_id, b.name as partner_name"). Joins("LEFT JOIN user_roles ur ON users.id = ur.user_id"). Joins("LEFT JOIN roles r ON ur.role_id = r.role_id"). Joins("LEFT JOIN partners b ON ur.partner_id = b.id"). Where("users.id = ?", id) if err := query.Scan(&user).Error; err != nil { logger.ContextLogger(ctx).Error("error when get user", zap.Error(err)) return nil, err } return user, nil } func (b *UserRepository) GetPartnerAdmin(ctx context.Context, partnerID int64) (*entity.UserDB, error) { var user *entity.UserDB partnerAdmin := 3 query := b.db.Table("users"). Select("users.id, users.email,users.phone_number,users.nik, users.password , users.name, users.status, users.created_at, users.updated_at, ur.role_id, r.role_name, ur.partner_id, b.name as partner_name"). Joins("LEFT JOIN user_roles ur ON users.id = ur.user_id"). Joins("LEFT JOIN roles r ON ur.role_id = r.role_id"). Joins("LEFT JOIN partners b ON ur.partner_id = b.id"). Where("ur.partner_id = ?", partnerID). Where("ur.role_id = ?", partnerAdmin) if err := query.Scan(&user).Error; err != nil { logger.ContextLogger(ctx).Error("error when get user", zap.Error(err)) return nil, err } return user, nil } func (b *UserRepository) GetUserByEmail(ctx context.Context, email string) (*entity.UserDB, error) { var user *entity.UserDB query := b.db.Table("users"). Select("users.id, users.email, users.name, users.status, users.created_at, users.updated_at, ur.role_id, r.role_name, ur.partner_id, b.name as partner_name"). Joins("LEFT JOIN user_roles ur ON users.id = ur.user_id"). Joins("LEFT JOIN roles r ON ur.role_id = r.role_id"). Joins("LEFT JOIN partners b ON ur.partner_id = b.id"). Where("users.email = ?", email) if err := query.Scan(&user).Error; err != nil { logger.ContextLogger(ctx).Error("error when get user", zap.Error(err)) return nil, err } return user, nil } func (r *UserRepository) UpdateUser(ctx context.Context, user *entity.UserDB) (*entity.UserDB, error) { tx := r.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() if err := tx.Select("name", "email", "password", "status", "deleted_at", "updated_by", "nik", "phone_number").Save(user).Error; err != nil { tx.Rollback() logError(ctx, "update user", err) return nil, err } userRole := user.ToUserRoleDB() if err := tx.Model(userRole).Where("user_id = ?", user.ID).Updates(userRole).Error; err != nil { tx.Rollback() logError(ctx, "update user role", err) return nil, err } if err := tx.Commit().Error; err != nil { tx.Rollback() logError(ctx, "committing transaction", err) return nil, err } return user, nil } func (r *UserRepository) UpdateUserWithTx(ctx context.Context, tx *gorm.DB, user *entity.UserDB) (*entity.UserDB, error) { if err := tx.Select("name", "email", "nik", "phone_number", "password", "status", "deleted_at", "updated_by").Save(user).Error; err != nil { logError(ctx, "update user", err) return nil, err } userRole := user.ToUserRoleDB() if err := tx.Model(userRole).Where("user_id = ?", user.ID).Updates(userRole).Error; err != nil { tx.Rollback() logError(ctx, "update user role", err) return nil, err } return user, nil } func logError(ctx context.Context, action string, err error) { logger.ContextLogger(ctx).Error("error when "+action, zap.Error(err)) } func (r *UserRepository) CountUsersByRoleAndSiteOrPartner(ctx context.Context, roleID int, siteID *int64) (int, error) { var count int64 query := r.db.Table("users"). Joins("LEFT JOIN user_roles ur ON users.id = ur.user_id"). Where("ur.role_id = ?", roleID) if siteID != nil { query = query.Where("ur.site_id = ?", siteID) } if err := query.Count(&count).Error; err != nil { logger.ContextLogger(ctx).Error("error when counting users by role and site/partner", zap.Error(err)) return 0, err } return int(count), nil }