716 lines
24 KiB
Go
716 lines
24 KiB
Go
package service
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"netidhub-saas-be/app/database/entity"
|
|
stepRepo "netidhub-saas-be/app/module/approval_workflow_steps/repository"
|
|
"netidhub-saas-be/app/module/approval_workflows/repository"
|
|
"netidhub-saas-be/app/module/approval_workflows/request"
|
|
clientApprovalSettingsRepo "netidhub-saas-be/app/module/client_approval_settings/repository"
|
|
usersRepo "netidhub-saas-be/app/module/users/repository"
|
|
"netidhub-saas-be/utils/paginator"
|
|
utilSvc "netidhub-saas-be/utils/service"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/rs/zerolog"
|
|
)
|
|
|
|
type approvalWorkflowsService struct {
|
|
ApprovalWorkflowsRepository repository.ApprovalWorkflowsRepository
|
|
ApprovalWorkflowStepsRepository stepRepo.ApprovalWorkflowStepsRepository
|
|
ClientApprovalSettingsRepository clientApprovalSettingsRepo.ClientApprovalSettingsRepository
|
|
UsersRepository usersRepo.UsersRepository
|
|
Log zerolog.Logger
|
|
}
|
|
|
|
// ApprovalWorkflowsService define interface of IApprovalWorkflowsService
|
|
type ApprovalWorkflowsService interface {
|
|
// Basic CRUD
|
|
GetAll(authToken string, req request.ApprovalWorkflowsQueryRequest) (workflows []*entity.ApprovalWorkflows, paging paginator.Pagination, err error)
|
|
FindOne(authToken string, id uint) (workflow *entity.ApprovalWorkflows, err error)
|
|
Create(authToken string, workflow *entity.ApprovalWorkflows, steps []*entity.ApprovalWorkflowSteps) (workflowReturn *entity.ApprovalWorkflows, err error)
|
|
Update(authToken string, id uint, workflow *entity.ApprovalWorkflows) (err error)
|
|
Delete(authToken string, id uint) (err error)
|
|
|
|
// Workflow management
|
|
GetDefault(authToken string) (workflow *entity.ApprovalWorkflows, err error)
|
|
SetDefault(authToken string, id uint) (err error)
|
|
ActivateWorkflow(authToken string, id uint) (err error)
|
|
DeactivateWorkflow(authToken string, id uint) (err error)
|
|
|
|
// Workflow with steps
|
|
GetWorkflowWithSteps(authToken string, id uint) (workflow *entity.ApprovalWorkflows, steps []*entity.ApprovalWorkflowSteps, err error)
|
|
CreateWorkflowWithSteps(authToken string, workflow *entity.ApprovalWorkflows, steps []*entity.ApprovalWorkflowSteps) (workflowReturn *entity.ApprovalWorkflows, err error)
|
|
UpdateWorkflowWithSteps(authToken string, id uint, workflow *entity.ApprovalWorkflows, steps []*entity.ApprovalWorkflowSteps) (err error)
|
|
|
|
// Validation
|
|
ValidateWorkflow(authToken string, workflow *entity.ApprovalWorkflows, steps []*entity.ApprovalWorkflowSteps) (isValid bool, errors []string, err error)
|
|
CanDeleteWorkflow(authToken string, id uint) (canDelete bool, reason string, err error)
|
|
|
|
// Comprehensive workflow creation with client settings
|
|
CreateWorkflowWithClientSettings(authToken string, req request.CreateApprovalWorkflowWithClientSettingsRequest) (workflow *entity.ApprovalWorkflows, clientSettings *entity.ClientApprovalSettings, err error)
|
|
}
|
|
|
|
func NewApprovalWorkflowsService(
|
|
approvalWorkflowsRepository repository.ApprovalWorkflowsRepository,
|
|
approvalWorkflowStepsRepository stepRepo.ApprovalWorkflowStepsRepository,
|
|
clientApprovalSettingsRepository clientApprovalSettingsRepo.ClientApprovalSettingsRepository,
|
|
usersRepository usersRepo.UsersRepository,
|
|
log zerolog.Logger,
|
|
) ApprovalWorkflowsService {
|
|
return &approvalWorkflowsService{
|
|
ApprovalWorkflowsRepository: approvalWorkflowsRepository,
|
|
ApprovalWorkflowStepsRepository: approvalWorkflowStepsRepository,
|
|
ClientApprovalSettingsRepository: clientApprovalSettingsRepository,
|
|
UsersRepository: usersRepository,
|
|
Log: log,
|
|
}
|
|
}
|
|
|
|
// Basic CRUD implementations
|
|
func (_i *approvalWorkflowsService) GetAll(authToken string, req request.ApprovalWorkflowsQueryRequest) (workflows []*entity.ApprovalWorkflows, paging paginator.Pagination, err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return nil, paginator.Pagination{}, errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
return _i.ApprovalWorkflowsRepository.GetAll(clientId, req)
|
|
}
|
|
|
|
func (_i *approvalWorkflowsService) FindOne(authToken string, id uint) (workflow *entity.ApprovalWorkflows, err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return nil, errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
return _i.ApprovalWorkflowsRepository.FindOne(clientId, id)
|
|
}
|
|
|
|
func (_i *approvalWorkflowsService) Create(authToken string, workflow *entity.ApprovalWorkflows, steps []*entity.ApprovalWorkflowSteps) (workflowReturn *entity.ApprovalWorkflows, err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return nil, errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
// Validate workflow and steps
|
|
isValid, validationErrors, err := _i.ValidateWorkflow(authToken, workflow, steps)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !isValid {
|
|
return nil, errors.New(fmt.Sprintf("Validation failed: %v", validationErrors))
|
|
}
|
|
|
|
// Create workflow
|
|
workflowReturn, err = _i.ApprovalWorkflowsRepository.Create(clientId, workflow)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Create steps
|
|
for i, step := range steps {
|
|
step.WorkflowId = workflowReturn.ID
|
|
step.StepOrder = i + 1
|
|
_, err = _i.ApprovalWorkflowStepsRepository.Create(clientId, step)
|
|
if err != nil {
|
|
// Rollback workflow creation if step creation fails
|
|
_i.ApprovalWorkflowsRepository.Delete(clientId, workflowReturn.ID)
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return workflowReturn, nil
|
|
}
|
|
|
|
func (_i *approvalWorkflowsService) Update(authToken string, id uint, workflow *entity.ApprovalWorkflows) (err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
// Check if workflow exists
|
|
existingWorkflow, err := _i.ApprovalWorkflowsRepository.FindOne(clientId, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if existingWorkflow == nil {
|
|
return errors.New("workflow not found")
|
|
}
|
|
|
|
return _i.ApprovalWorkflowsRepository.Update(clientId, id, workflow)
|
|
}
|
|
|
|
func (_i *approvalWorkflowsService) Delete(authToken string, id uint) (err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
// Check if workflow can be deleted
|
|
canDelete, reason, err := _i.CanDeleteWorkflow(authToken, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !canDelete {
|
|
return errors.New(reason)
|
|
}
|
|
|
|
return _i.ApprovalWorkflowsRepository.Delete(clientId, id)
|
|
}
|
|
|
|
// Workflow management
|
|
func (_i *approvalWorkflowsService) GetDefault(authToken string) (workflow *entity.ApprovalWorkflows, err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return nil, errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
return _i.ApprovalWorkflowsRepository.FindDefault(clientId)
|
|
}
|
|
|
|
func (_i *approvalWorkflowsService) SetDefault(authToken string, id uint) (err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
// Check if workflow exists and is active
|
|
workflow, err := _i.ApprovalWorkflowsRepository.FindOne(clientId, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if workflow == nil {
|
|
return errors.New("workflow not found")
|
|
}
|
|
|
|
if workflow.IsActive == nil || !*workflow.IsActive {
|
|
return errors.New("cannot set inactive workflow as default")
|
|
}
|
|
|
|
return _i.ApprovalWorkflowsRepository.SetDefault(clientId, id)
|
|
}
|
|
|
|
func (_i *approvalWorkflowsService) ActivateWorkflow(authToken string, id uint) (err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
// Validate workflow before activation
|
|
workflow, err := _i.ApprovalWorkflowsRepository.FindOne(clientId, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if workflow == nil {
|
|
return errors.New("workflow not found")
|
|
}
|
|
|
|
// Get workflow steps and validate
|
|
steps, err := _i.ApprovalWorkflowStepsRepository.GetByWorkflowId(clientId, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
isValid, validationErrors, err := _i.ValidateWorkflow(authToken, workflow, steps)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !isValid {
|
|
return errors.New(fmt.Sprintf("Cannot activate invalid workflow: %v", validationErrors))
|
|
}
|
|
|
|
// Activate workflow
|
|
isActive := true
|
|
updateData := &entity.ApprovalWorkflows{IsActive: &isActive}
|
|
return _i.ApprovalWorkflowsRepository.Update(clientId, id, updateData)
|
|
}
|
|
|
|
func (_i *approvalWorkflowsService) DeactivateWorkflow(authToken string, id uint) (err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
// Check if this is the default workflow
|
|
defaultWorkflow, err := _i.ApprovalWorkflowsRepository.FindDefault(clientId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if defaultWorkflow != nil && defaultWorkflow.ID == id {
|
|
return errors.New("cannot deactivate default workflow")
|
|
}
|
|
|
|
// Check if workflow is being used in active approval flows
|
|
canDelete, reason, err := _i.CanDeleteWorkflow(authToken, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !canDelete {
|
|
return errors.New(fmt.Sprintf("Cannot deactivate workflow: %s", reason))
|
|
}
|
|
|
|
// Deactivate workflow
|
|
isActive := false
|
|
updateData := &entity.ApprovalWorkflows{IsActive: &isActive}
|
|
return _i.ApprovalWorkflowsRepository.Update(clientId, id, updateData)
|
|
}
|
|
|
|
// Workflow with steps
|
|
func (_i *approvalWorkflowsService) GetWorkflowWithSteps(authToken string, id uint) (workflow *entity.ApprovalWorkflows, steps []*entity.ApprovalWorkflowSteps, err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return nil, nil, errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
workflow, err = _i.ApprovalWorkflowsRepository.FindOne(clientId, id)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
steps, err = _i.ApprovalWorkflowStepsRepository.GetByWorkflowId(clientId, id)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return workflow, steps, nil
|
|
}
|
|
|
|
func (_i *approvalWorkflowsService) CreateWorkflowWithSteps(authToken string, workflow *entity.ApprovalWorkflows, steps []*entity.ApprovalWorkflowSteps) (workflowReturn *entity.ApprovalWorkflows, err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return nil, errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
return _i.Create(authToken, workflow, steps)
|
|
}
|
|
|
|
func (_i *approvalWorkflowsService) UpdateWorkflowWithSteps(authToken string, id uint, workflow *entity.ApprovalWorkflows, steps []*entity.ApprovalWorkflowSteps) (err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
// Update workflow
|
|
err = _i.Update(authToken, id, workflow)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get existing steps
|
|
existingSteps, err := _i.ApprovalWorkflowStepsRepository.GetByWorkflowId(clientId, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Delete existing steps (simplified approach - in production, you might want to update/merge)
|
|
for _, existingStep := range existingSteps {
|
|
err = _i.ApprovalWorkflowStepsRepository.Delete(clientId, existingStep.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Create new steps
|
|
for i, step := range steps {
|
|
step.WorkflowId = id
|
|
step.StepOrder = i + 1
|
|
_, err = _i.ApprovalWorkflowStepsRepository.Create(clientId, step)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Validation
|
|
func (_i *approvalWorkflowsService) ValidateWorkflow(authToken string, workflow *entity.ApprovalWorkflows, steps []*entity.ApprovalWorkflowSteps) (isValid bool, errors []string, err error) {
|
|
errors = make([]string, 0)
|
|
|
|
// Validate workflow
|
|
if workflow.Name == "" {
|
|
errors = append(errors, "Workflow name is required")
|
|
}
|
|
|
|
// Validate steps
|
|
if len(steps) == 0 {
|
|
errors = append(errors, "Workflow must have at least one step")
|
|
} else {
|
|
// For multi-branch workflow, we need different validation logic
|
|
_i.validateMultiBranchSteps(steps, &errors)
|
|
}
|
|
|
|
isValid = len(errors) == 0
|
|
return isValid, errors, nil
|
|
}
|
|
|
|
// validateMultiBranchSteps validates steps for multi-branch workflow
|
|
func (_i *approvalWorkflowsService) validateMultiBranchSteps(steps []*entity.ApprovalWorkflowSteps, errors *[]string) {
|
|
// Group steps by step order to handle parallel branches
|
|
stepOrderGroups := make(map[int][]*entity.ApprovalWorkflowSteps)
|
|
|
|
for i, step := range steps {
|
|
// Basic validation for each step
|
|
if step.StepName == "" {
|
|
*errors = append(*errors, fmt.Sprintf("Step %d name is required", i+1))
|
|
}
|
|
|
|
if step.RequiredUserLevelId == 0 {
|
|
*errors = append(*errors, fmt.Sprintf("Step %d must have a required user level", i+1))
|
|
}
|
|
|
|
if step.StepOrder <= 0 {
|
|
*errors = append(*errors, fmt.Sprintf("Step %d must have a valid step order (greater than 0)", i+1))
|
|
}
|
|
|
|
// Validate condition type and value
|
|
if step.ConditionType != nil {
|
|
validConditionTypes := []string{"user_level", "user_level_hierarchy", "always", "custom"}
|
|
isValidConditionType := false
|
|
for _, validType := range validConditionTypes {
|
|
if *step.ConditionType == validType {
|
|
isValidConditionType = true
|
|
break
|
|
}
|
|
}
|
|
if !isValidConditionType {
|
|
*errors = append(*errors, fmt.Sprintf("Step %d has invalid condition type: %s", i+1, *step.ConditionType))
|
|
}
|
|
|
|
// Validate condition value format for specific condition types
|
|
if step.ConditionValue != nil && *step.ConditionValue != "" {
|
|
if *step.ConditionType == "user_level_hierarchy" || *step.ConditionType == "user_level" {
|
|
// Try to parse as JSON to validate format
|
|
var conditionData interface{}
|
|
if err := json.Unmarshal([]byte(*step.ConditionValue), &conditionData); err != nil {
|
|
*errors = append(*errors, fmt.Sprintf("Step %d has invalid condition value format: %s", i+1, *step.ConditionValue))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Group steps by step order
|
|
stepOrderGroups[step.StepOrder] = append(stepOrderGroups[step.StepOrder], step)
|
|
}
|
|
|
|
// Validate step order groups
|
|
maxStepOrder := 0
|
|
for stepOrder, groupSteps := range stepOrderGroups {
|
|
if stepOrder > maxStepOrder {
|
|
maxStepOrder = stepOrder
|
|
}
|
|
|
|
// Check for duplicate branch names within the same step order
|
|
branchNames := make(map[string]bool)
|
|
for _, step := range groupSteps {
|
|
if step.BranchName != nil && *step.BranchName != "" {
|
|
if branchNames[*step.BranchName] {
|
|
*errors = append(*errors, fmt.Sprintf("Duplicate branch name '%s' found in step order %d", *step.BranchName, stepOrder))
|
|
}
|
|
branchNames[*step.BranchName] = true
|
|
}
|
|
}
|
|
|
|
// Validate branch order within the same step order
|
|
branchOrders := make(map[int]bool)
|
|
for _, step := range groupSteps {
|
|
if step.BranchOrder != nil {
|
|
if branchOrders[*step.BranchOrder] {
|
|
*errors = append(*errors, fmt.Sprintf("Duplicate branch order %d found in step order %d", *step.BranchOrder, stepOrder))
|
|
}
|
|
branchOrders[*step.BranchOrder] = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// Validate that we have at least one step with step order 1
|
|
if len(stepOrderGroups[1]) == 0 {
|
|
*errors = append(*errors, "Workflow must have at least one step with step order 1")
|
|
}
|
|
|
|
// Validate that step orders are sequential (no gaps)
|
|
for i := 1; i <= maxStepOrder; i++ {
|
|
if len(stepOrderGroups[i]) == 0 {
|
|
*errors = append(*errors, fmt.Sprintf("Missing step order %d - step orders must be sequential", i))
|
|
}
|
|
}
|
|
}
|
|
|
|
func (_i *approvalWorkflowsService) CanDeleteWorkflow(authToken string, id uint) (canDelete bool, reason string, err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return false, "clientId not found in auth token", errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
// Check if workflow is default
|
|
defaultWorkflow, err := _i.ApprovalWorkflowsRepository.FindDefault(clientId)
|
|
if err != nil {
|
|
return false, "", err
|
|
}
|
|
|
|
if defaultWorkflow != nil && defaultWorkflow.ID == id {
|
|
return false, "Cannot delete default workflow", nil
|
|
}
|
|
|
|
// Check if workflow is being used in active approval flows
|
|
// This would require a method in ArticleApprovalFlowsRepository
|
|
// For now, we'll assume it can be deleted
|
|
// TODO: Implement check for active approval flows
|
|
|
|
return true, "", nil
|
|
}
|
|
|
|
// CreateWorkflowWithClientSettings creates a comprehensive approval workflow with client settings in a single transaction
|
|
func (_i *approvalWorkflowsService) CreateWorkflowWithClientSettings(authToken string, req request.CreateApprovalWorkflowWithClientSettingsRequest) (workflow *entity.ApprovalWorkflows, clientSettings *entity.ClientApprovalSettings, err error) {
|
|
// Extract clientId from authToken
|
|
var clientId *uuid.UUID
|
|
if authToken != "" {
|
|
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken)
|
|
if user != nil && user.ClientId != nil {
|
|
clientId = user.ClientId
|
|
_i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token")
|
|
}
|
|
}
|
|
|
|
if clientId == nil {
|
|
return nil, nil, errors.New("clientId not found in auth token")
|
|
}
|
|
|
|
_i.Log.Info().
|
|
Str("workflowName", req.Name).
|
|
Interface("clientId", clientId).
|
|
Msg("Creating comprehensive approval workflow with client settings")
|
|
|
|
// Convert request to entities
|
|
workflowEntity := req.ToWorkflowEntity()
|
|
stepsEntity := req.ToStepsEntity()
|
|
clientSettingsEntity := req.ToClientApprovalSettingsEntity()
|
|
|
|
// Set client ID for all entities
|
|
workflowEntity.ClientId = clientId
|
|
clientSettingsEntity.ClientId = *clientId
|
|
|
|
// Validate workflow and steps
|
|
isValid, validationErrors, err := _i.ValidateWorkflow(authToken, workflowEntity, stepsEntity)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
if !isValid {
|
|
return nil, nil, errors.New(fmt.Sprintf("Validation failed: %v", validationErrors))
|
|
}
|
|
|
|
// Check if client approval settings already exist
|
|
existingSettings, err := _i.ClientApprovalSettingsRepository.FindByClientId(*clientId)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to check existing client approval settings: %w", err)
|
|
}
|
|
|
|
if existingSettings != nil {
|
|
return nil, nil, errors.New("client approval settings already exist for this client")
|
|
}
|
|
|
|
// Create workflow
|
|
workflow, err = _i.ApprovalWorkflowsRepository.Create(clientId, workflowEntity)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to create workflow: %w", err)
|
|
}
|
|
|
|
_i.Log.Info().
|
|
Uint("workflowId", workflow.ID).
|
|
Str("workflowName", workflow.Name).
|
|
Msg("Workflow created successfully")
|
|
|
|
// Create workflow steps
|
|
for i, step := range stepsEntity {
|
|
step.WorkflowId = workflow.ID
|
|
step.StepOrder = i + 1
|
|
step.ClientId = clientId
|
|
_, err = _i.ApprovalWorkflowStepsRepository.Create(clientId, step)
|
|
if err != nil {
|
|
// Rollback workflow creation if step creation fails
|
|
_i.Log.Error().Err(err).Msg("Failed to create workflow step, rolling back workflow")
|
|
_i.ApprovalWorkflowsRepository.Delete(clientId, workflow.ID)
|
|
return nil, nil, fmt.Errorf("failed to create workflow step %d: %w", i+1, err)
|
|
}
|
|
}
|
|
|
|
_i.Log.Info().
|
|
Uint("workflowId", workflow.ID).
|
|
Int("stepsCount", len(stepsEntity)).
|
|
Msg("All workflow steps created successfully")
|
|
|
|
// Set the workflow as default in client settings if specified
|
|
if req.IsDefault != nil && *req.IsDefault {
|
|
clientSettingsEntity.DefaultWorkflowId = &workflow.ID
|
|
}
|
|
|
|
// Create client approval settings
|
|
clientSettings, err = _i.ClientApprovalSettingsRepository.Create(clientId, clientSettingsEntity)
|
|
if err != nil {
|
|
// Rollback workflow and steps creation if client settings creation fails
|
|
_i.Log.Error().Err(err).Msg("Failed to create client approval settings, rolling back workflow and steps")
|
|
|
|
// Delete workflow steps
|
|
for _, step := range stepsEntity {
|
|
_i.ApprovalWorkflowStepsRepository.Delete(clientId, step.ID)
|
|
}
|
|
|
|
// Delete workflow
|
|
_i.ApprovalWorkflowsRepository.Delete(clientId, workflow.ID)
|
|
|
|
return nil, nil, fmt.Errorf("failed to create client approval settings: %w", err)
|
|
}
|
|
|
|
_i.Log.Info().
|
|
Uint("workflowId", workflow.ID).
|
|
Interface("clientId", clientId).
|
|
Msg("Client approval settings created successfully")
|
|
|
|
// If this workflow is set as default, update the default workflow setting
|
|
if req.IsDefault != nil && *req.IsDefault {
|
|
err = _i.ApprovalWorkflowsRepository.SetDefault(clientId, workflow.ID)
|
|
if err != nil {
|
|
_i.Log.Warn().Err(err).Msg("Failed to set workflow as default, but workflow and settings were created successfully")
|
|
} else {
|
|
_i.Log.Info().
|
|
Uint("workflowId", workflow.ID).
|
|
Msg("Workflow set as default successfully")
|
|
}
|
|
}
|
|
|
|
_i.Log.Info().
|
|
Uint("workflowId", workflow.ID).
|
|
Interface("clientId", clientId).
|
|
Msg("Comprehensive approval workflow with client settings created successfully")
|
|
|
|
return workflow, clientSettings, nil
|
|
}
|