wms-be/modules/menu/service/menu_service.go

248 lines
6.2 KiB
Go

package service
import (
"context"
"errors"
"github.com/Caknoooo/go-gin-clean-starter/database/entities"
"github.com/Caknoooo/go-gin-clean-starter/modules/auth/service"
"github.com/Caknoooo/go-gin-clean-starter/modules/menu/dto"
"github.com/Caknoooo/go-gin-clean-starter/modules/menu/repository"
staticDto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto"
"github.com/google/uuid"
"gorm.io/gorm"
)
type MenuService interface {
Create(ctx context.Context, menu dto.MenuResponse) (dto.MenuResponse, error)
GetById(ctx context.Context, menuId string) (dto.MenuResponse, error)
GetByName(ctx context.Context, name string) (dto.MenuResponse, error)
Update(ctx context.Context, menuId string, menu dto.MenuUpdateRequest) (dto.MenuResponse, error)
Delete(ctx context.Context, menuId string) error
}
type menuService struct {
menuRepository repository.MenuRepository
jwtService service.JWTService
db *gorm.DB
}
// Create implements MenuService.
func (m *menuService) Create(ctx context.Context, menu dto.MenuResponse) (dto.MenuResponse, error) {
var entity entities.M_Menu
// ID: use provided or generate new
if menu.ID != "" {
id, err := uuid.Parse(menu.ID)
if err != nil {
return dto.MenuResponse{}, err
}
entity.ID = id
} else {
entity.ID = uuid.New()
}
// map simple fields
entity.Name = menu.Name
entity.IconUrl = menu.IconUrl
entity.Url = menu.Url
entity.Sequence = menu.Sequence
entity.Mode = menu.Mode
entity.Status = menu.Status
// ParentID if provided
if menu.Parent != nil && menu.Parent.ID != "" {
pid, err := uuid.Parse(menu.Parent.ID)
if err != nil {
return dto.MenuResponse{}, err
}
entity.ParentID = &pid
} else {
entity.ParentID = nil
}
created, err := m.menuRepository.Create(ctx, m.db, entity)
if err != nil {
return dto.MenuResponse{}, err
}
// map back to DTO
res := dto.MenuResponse{
ID: created.ID.String(),
Name: created.Name,
IconUrl: created.IconUrl,
Url: created.Url,
Sequence: created.Sequence,
Mode: created.Mode,
Status: created.Status,
}
if created.Parent != nil {
res.Parent = &dto.MenuParentResponse{
ID: created.Parent.ID.String(),
Name: created.Parent.Name,
}
} else if created.ParentID != nil {
res.Parent = &dto.MenuParentResponse{ID: created.ParentID.String()}
}
return res, nil
}
// Delete implements MenuService.
func (m *menuService) Delete(ctx context.Context, menuId string) error {
return m.menuRepository.Delete(ctx, m.db, menuId)
}
// GetById implements MenuService.
func (m *menuService) GetById(ctx context.Context, menuId string) (dto.MenuResponse, error) {
entity, err := m.menuRepository.GetById(ctx, m.db, menuId)
if err != nil {
return dto.MenuResponse{}, err
}
res := dto.MenuResponse{
ID: entity.ID.String(),
Name: entity.Name,
IconUrl: entity.IconUrl,
Url: entity.Url,
Sequence: entity.Sequence,
Mode: entity.Mode,
Status: entity.Status,
}
if entity.Parent != nil {
res.Parent = &dto.MenuParentResponse{
ID: entity.Parent.ID.String(),
Name: entity.Parent.Name,
}
} else if entity.ParentID != nil {
res.Parent = &dto.MenuParentResponse{ID: entity.ParentID.String()}
}
if len(entity.Permissions) > 0 {
res.Permissions = make([]staticDto.PermissionResponse, 0, len(entity.Permissions))
for _, perm := range entity.Permissions {
res.Permissions = append(res.Permissions, staticDto.PermissionResponse{
ID: perm.ID.String(),
Name: perm.Name,
// Description: perm.Description,
// Code: perm.Code,
})
}
}
return res, nil
}
// GetByName implements MenuService.
func (m *menuService) GetByName(ctx context.Context, name string) (dto.MenuResponse, error) {
entity, err := m.menuRepository.GetByName(ctx, m.db, name)
if err != nil {
return dto.MenuResponse{}, err
}
res := dto.MenuResponse{
ID: entity.ID.String(),
Name: entity.Name,
IconUrl: entity.IconUrl,
Url: entity.Url,
Sequence: entity.Sequence,
Mode: entity.Mode,
Status: entity.Status,
}
if entity.Parent != nil {
res.Parent = &dto.MenuParentResponse{
ID: entity.Parent.ID.String(),
Name: entity.Parent.Name,
}
} else if entity.ParentID != nil {
res.Parent = &dto.MenuParentResponse{ID: entity.ParentID.String()}
}
return res, nil
}
// Update implements MenuService.
func (m *menuService) Update(ctx context.Context, menuId string, menu dto.MenuUpdateRequest) (dto.MenuResponse, error) {
// ensure exists
existing, err := m.menuRepository.GetById(ctx, m.db, menuId)
if err != nil {
return dto.MenuResponse{}, dto.ErrMenuNotFound
}
// Only update fields if provided (not empty)
if menu.Name != "" {
// Check for duplicate name
menuByName, err := m.menuRepository.GetByName(ctx, m.db, menu.Name)
if err == nil && menuByName.ID != existing.ID {
return dto.MenuResponse{}, errors.New("menu name already exists")
}
existing.Name = menu.Name
}
if menu.IconUrl != "" {
existing.IconUrl = menu.IconUrl
}
if menu.Url != "" {
existing.Url = menu.Url
}
if menu.Mode != "" {
existing.Mode = menu.Mode
}
if menu.Status != "" {
existing.Status = menu.Status
}
if menu.Sequence != 0 {
existing.Sequence = menu.Sequence
}
if menu.ParentID != nil && menu.ParentID.String() != "" {
pid, err := uuid.Parse(menu.ParentID.String())
if err != nil {
return dto.MenuResponse{}, err
}
existing.ParentID = &pid
} else if menu.ParentID != nil && menu.ParentID.String() == "" {
existing.ParentID = nil
}
updated, err := m.menuRepository.Update(ctx, m.db, existing)
if err != nil {
return dto.MenuResponse{}, err
}
res := dto.MenuResponse{
ID: updated.ID.String(),
Name: updated.Name,
IconUrl: updated.IconUrl,
Url: updated.Url,
Sequence: updated.Sequence,
Mode: updated.Mode,
Status: updated.Status,
}
if updated.Parent != nil {
res.Parent = &dto.MenuParentResponse{
ID: updated.Parent.ID.String(),
Name: updated.Parent.Name,
}
} else if updated.ParentID != nil {
res.Parent = &dto.MenuParentResponse{ID: updated.ParentID.String()}
}
return res, nil
}
func NewMenuService(
menuRepo repository.MenuRepository,
jwtService service.JWTService,
db *gorm.DB,
) MenuService {
return &menuService{
menuRepository: menuRepo,
jwtService: jwtService,
db: db,
}
}