187 lines
5.9 KiB
Go
187 lines
5.9 KiB
Go
|
|
package processor
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"fmt"
|
||
|
|
|
||
|
|
"golang.org/x/crypto/bcrypt"
|
||
|
|
|
||
|
|
"apskel-pos-be/internal/entities"
|
||
|
|
"apskel-pos-be/internal/mappers"
|
||
|
|
"apskel-pos-be/internal/models"
|
||
|
|
|
||
|
|
"github.com/google/uuid"
|
||
|
|
)
|
||
|
|
|
||
|
|
type OrganizationProcessor interface {
|
||
|
|
CreateOrganization(ctx context.Context, req *models.CreateOrganizationRequest) (*models.CreateOrganizationResponse, error)
|
||
|
|
UpdateOrganization(ctx context.Context, id uuid.UUID, req *models.UpdateOrganizationRequest) (*models.OrganizationResponse, error)
|
||
|
|
DeleteOrganization(ctx context.Context, id uuid.UUID) error
|
||
|
|
GetOrganizationByID(ctx context.Context, id uuid.UUID) (*models.OrganizationResponse, error)
|
||
|
|
ListOrganizations(ctx context.Context, filters map[string]interface{}, page, limit int) ([]models.OrganizationResponse, int, error)
|
||
|
|
}
|
||
|
|
|
||
|
|
type OrganizationProcessorImpl struct {
|
||
|
|
organizationRepo OrganizationRepository
|
||
|
|
outletRepo OutletRepository
|
||
|
|
userRepo UserRepository
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewOrganizationProcessorImpl(
|
||
|
|
organizationRepo OrganizationRepository,
|
||
|
|
outletRepo OutletRepository,
|
||
|
|
userRepo UserRepository,
|
||
|
|
) *OrganizationProcessorImpl {
|
||
|
|
return &OrganizationProcessorImpl{
|
||
|
|
organizationRepo: organizationRepo,
|
||
|
|
outletRepo: outletRepo,
|
||
|
|
userRepo: userRepo,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p *OrganizationProcessorImpl) CreateOrganization(ctx context.Context, req *models.CreateOrganizationRequest) (*models.CreateOrganizationResponse, error) {
|
||
|
|
if req.OrganizationEmail != nil && *req.OrganizationEmail != "" {
|
||
|
|
existingOrg, err := p.organizationRepo.GetByEmail(ctx, *req.OrganizationEmail)
|
||
|
|
if err == nil && existingOrg != nil {
|
||
|
|
return nil, fmt.Errorf("organization with email %s already exists", *req.OrganizationEmail)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
existingUser, err := p.userRepo.GetByEmail(ctx, req.AdminEmail)
|
||
|
|
if err == nil && existingUser != nil {
|
||
|
|
return nil, fmt.Errorf("user with email %s already exists", req.AdminEmail)
|
||
|
|
}
|
||
|
|
|
||
|
|
organizationEntity := &entities.Organization{
|
||
|
|
Name: req.OrganizationName,
|
||
|
|
Email: req.OrganizationEmail,
|
||
|
|
PhoneNumber: req.OrganizationPhoneNumber,
|
||
|
|
PlanType: string(req.PlanType),
|
||
|
|
}
|
||
|
|
|
||
|
|
err = p.organizationRepo.Create(ctx, organizationEntity)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to create organization: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.AdminPassword), bcrypt.DefaultCost)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to hash password: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
adminUserEntity := &entities.User{
|
||
|
|
OrganizationID: organizationEntity.ID,
|
||
|
|
Name: req.AdminName,
|
||
|
|
Email: req.AdminEmail,
|
||
|
|
PasswordHash: string(passwordHash),
|
||
|
|
Role: entities.RoleAdmin,
|
||
|
|
IsActive: true,
|
||
|
|
}
|
||
|
|
|
||
|
|
err = p.userRepo.Create(ctx, adminUserEntity)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to create admin user: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
defaultOutletEntity := &entities.Outlet{
|
||
|
|
OrganizationID: organizationEntity.ID,
|
||
|
|
Name: req.OutletName,
|
||
|
|
Address: req.OutletAddress,
|
||
|
|
Timezone: req.OutletTimezone,
|
||
|
|
Currency: req.OutletCurrency,
|
||
|
|
TaxRate: 0.0,
|
||
|
|
IsActive: true,
|
||
|
|
}
|
||
|
|
|
||
|
|
err = p.outletRepo.Create(ctx, defaultOutletEntity)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to create default outlet: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
organizationResponse := mappers.OrganizationEntityToResponse(organizationEntity)
|
||
|
|
adminUserResponse := mappers.UserEntityToResponse(adminUserEntity)
|
||
|
|
outletResponse := mappers.OutletEntityToResponse(defaultOutletEntity)
|
||
|
|
|
||
|
|
return &models.CreateOrganizationResponse{
|
||
|
|
Organization: organizationResponse,
|
||
|
|
AdminUser: adminUserResponse,
|
||
|
|
DefaultOutlet: outletResponse,
|
||
|
|
}, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p *OrganizationProcessorImpl) UpdateOrganization(ctx context.Context, id uuid.UUID, req *models.UpdateOrganizationRequest) (*models.OrganizationResponse, error) {
|
||
|
|
existingOrg, err := p.organizationRepo.GetByID(ctx, id)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("organization not found: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if req.Email != nil && (existingOrg.Email == nil || *req.Email != *existingOrg.Email) {
|
||
|
|
existingOrgByEmail, err := p.organizationRepo.GetByEmail(ctx, *req.Email)
|
||
|
|
if err == nil && existingOrgByEmail != nil && existingOrgByEmail.ID != id {
|
||
|
|
return nil, fmt.Errorf("organization with email %s already exists", *req.Email)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if req.Name != nil {
|
||
|
|
existingOrg.Name = *req.Name
|
||
|
|
}
|
||
|
|
if req.Email != nil {
|
||
|
|
existingOrg.Email = req.Email
|
||
|
|
}
|
||
|
|
if req.PhoneNumber != nil {
|
||
|
|
existingOrg.PhoneNumber = req.PhoneNumber
|
||
|
|
}
|
||
|
|
if req.PlanType != nil {
|
||
|
|
existingOrg.PlanType = string(*req.PlanType)
|
||
|
|
}
|
||
|
|
|
||
|
|
err = p.organizationRepo.Update(ctx, existingOrg)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to update organization: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return mappers.OrganizationEntityToResponse(existingOrg), nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p *OrganizationProcessorImpl) DeleteOrganization(ctx context.Context, id uuid.UUID) error {
|
||
|
|
_, err := p.organizationRepo.GetByID(ctx, id)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("organization not found: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
err = p.organizationRepo.Delete(ctx, id)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("failed to delete organization: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p *OrganizationProcessorImpl) GetOrganizationByID(ctx context.Context, id uuid.UUID) (*models.OrganizationResponse, error) {
|
||
|
|
organization, err := p.organizationRepo.GetByID(ctx, id)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("organization not found: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return mappers.OrganizationEntityToResponse(organization), nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p *OrganizationProcessorImpl) ListOrganizations(ctx context.Context, filters map[string]interface{}, page, limit int) ([]models.OrganizationResponse, int, error) {
|
||
|
|
offset := (page - 1) * limit
|
||
|
|
|
||
|
|
organizations, totalCount, err := p.organizationRepo.List(ctx, filters, limit, offset)
|
||
|
|
if err != nil {
|
||
|
|
return nil, 0, fmt.Errorf("failed to get organizations: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
responses := make([]models.OrganizationResponse, len(organizations))
|
||
|
|
for i, org := range organizations {
|
||
|
|
response := mappers.OrganizationEntityToResponse(org)
|
||
|
|
if response != nil {
|
||
|
|
responses[i] = *response
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return responses, int(totalCount), nil
|
||
|
|
}
|