Repository: ctreminiom/go-atlassian
Pull request #299 (2024-08-03 18:59:10)

:sparkles: Added the Jira Workflow APIS


Patch:
diff --git a/jira/internal/workflow_impl.go b/jira/internal/workflow_impl.go
index 1b95ca7..57235ec 100644
--- a/jira/internal/workflow_impl.go
+++ b/jira/internal/workflow_impl.go
@@ -74,11 +74,308 @@ func (w *WorkflowService) Delete(ctx context.Context, workflowID string) (*model
 	return w.internalClient.Delete(ctx, workflowID)
 }
 
+// Search searches for workflows based on specified criteria.
+//
+// This method returns a paginated list of workflows that match the search criteria provided in the `options` parameter.
+//
+// The search can be expanded to include additional details, such as transition links, by specifying the `expand` and `transitionLinks` parameters.
+//
+// When search criteria are provided in the `options` parameter, only workflows matching those criteria are returned.
+// If no criteria are specified, all workflows are returned.
+//
+// GET /rest/api/{2-3}/workflow/search
+//
+// https://docs.go-atlassian.io/jira-software-cloud/workflow#bulk-get-workflows
+func (w *WorkflowService) Search(ctx context.Context, options *model.WorkflowSearchCriteria, expand []string, transitionLinks bool) (*model.WorkflowReadResponseScheme, *model.ResponseScheme, error) {
+	return w.internalClient.Search(ctx, options, expand, transitionLinks)
+}
+
+// Capabilities Get the list of workflow capabilities for a specific workflow using either the workflow ID, or the project and issue type ID pair.
+//
+// The response includes the scope of the workflow, defined as global/project-based, and a list of project types that the workflow is scoped to.
+//
+// It also includes all rules organised into their broad categories (conditions, validators, actions, triggers, screens) as well as the source location (Atlassian-provided, Connect, Forge).
+//
+// GET /rest/api/{2-3}/workflows/capabilities
+//
+// https://docs.go-atlassian.io/jira-software-cloud/workflow#get-workflow-capabilities
+func (w *WorkflowService) Capabilities(ctx context.Context, workflowID, projectID, issueTypeID string) (*model.WorkflowCapabilitiesScheme, *model.ResponseScheme, error) {
+	return w.internalClient.Capabilities(ctx, workflowID, projectID, issueTypeID)
+}
+
+// Creates create workflows and related statuses.
+//
+// This method allows you to create a workflow by defining transition rules
+// using the shapes detailed in the Atlassian REST API documentation.
+// If no transition rules are specified, the default system transition rules
+// will be used.
+//
+// POST /rest/api/{2-3}/workflows
+//
+// For more details, refer to:
+// https://docs.go-atlassian.io/jira-software-cloud/workflow#bulk-create-workflows
+//
+// Example:
+//
+//	payload := &models.WorkflowCreatesPayload{
+//		Scope: &models.WorkflowScopeScheme{Type: "GLOBAL"},
+//		// The workflows to create, with transition rules.
+//	}
+//
+//	response, respScheme, err := client.Workflow.Creates(ctx, payload)
+//	if err != nil {
+//		log.Fatalf("Failed to create workflow: %v", err)
+//	}
+//
+//	fmt.Printf("Workflow created with ID: %s", response.ID)
+func (w *WorkflowService) Creates(ctx context.Context, payload *model.WorkflowCreatesPayload) (*model.WorkflowCreateResponseScheme, *model.ResponseScheme, error) {
+	return w.internalClient.Creates(ctx, payload)
+}
+
+// ValidateCreateWorkflows validates workflows before creating them.
+//
+// This method allows you to validate the configuration of one or more workflows
+// before they are created in Jira. It helps ensure that the workflows adhere
+// to the defined rules and constraints.
+//
+// The validation checks will include all aspects of the workflows, such as transitions,
+// statuses, and any related conditions or validators.
+//
+// POST /rest/api/{2-3}/workflows/create/validation
+//
+// For more details, refer to:
+// https://docs.go-atlassian.io/jira-software-cloud/workflow#validate-create-workflows
+//
+// Example:
+//
+//	 ctx := context.Background()
+//	 payload := &model.ValidationOptionsForCreateScheme{
+//	     Payload: payload,
+//	    Options: &models.ValidationOptionsLevelScheme{
+//			  Levels: []string{"ERROR", "WARNING"},
+//		  }
+//
+//	 validationResult, response, err := client.Workflow.ValidateCreateWorkflows(ctx, payload)
+//	 if err != nil {
+//	     log.Fatalf("Failed to validate workflow: %v", err)
+//	 }
+//
+//	 if validationResult != nil {
+//	     log.Printf("Workflow validation errors: %v", validationResult.Errors)
+//	 }
+//
+//	 log.Printf("Validation response: %v", response)
+func (w *WorkflowService) ValidateCreateWorkflows(ctx context.Context, payload *model.ValidationOptionsForCreateScheme) (*model.WorkflowValidationErrorListScheme, *model.ResponseScheme, error) {
+	return w.internalClient.ValidateCreateWorkflows(ctx, payload)
+}
+
+// Updates updates workflows.
+//
+// This method allows you to update workflows by providing a payload containing the details
+// of the updates. You can expand specific fields using the 'expand' parameter.
+//
+// The update follows the API detailed in the Atlassian documentation.
+//
+// POST /rest/api/{2-3}/workflows/update
+//
+// For more details, refer to:
+// https://docs.go-atlassian.io/jira-software-cloud/workflow#bulk-update-workflows
+func (w *WorkflowService) Updates(ctx context.Context, payload *model.WorkflowUpdatesPayloadScheme, expand []string) (*model.WorkflowUpdateResponseScheme, *model.ResponseScheme, error) {
+	return w.internalClient.Updates(ctx, payload, expand)
+}
+
+// ValidateUpdateWorkflows validates the update of one or more workflows.
+//
+// This method allows you to validate changes to workflows before they are applied.
+// The validation checks for potential issues that could prevent the workflows from being updated successfully.
+//
+// The validation process will check for conditions such as:
+//
+//	1.Whether the transitions are valid.
+//	2. Whether the status and transition names are unique within the workflow.
+//	3. If the validation fails, a list of validation errors is returned, which should be resolved before applying the changes.
+//
+// POST /rest/api/{2-3}/workflows/update/validation
+//
+// For more details, refer to:
+// https://docs.go-atlassian.io/jira-software-cloud/workflow#validate-update-workflows
+//
+// Example:
+//
+//	options := &model.ValidationOptionsForUpdateScheme{
+//	    // populate the validation options here
+//	}
+//
+//	result, response, err := client.Workflow.ValidateUpdateWorkflows(ctx, options)
+//	if err != nil {
+//	    log.Fatalf("Validation failed: %v", err)
+//	}
+//
+//	if len(result.Errors) > 0 {
+//	    log.Printf("Validation errors: %v", result.Errors)
+//	} else {
+//	    log.Println("Validation passed, you can proceed with the update.")
+//	}
+func (w *WorkflowService) ValidateUpdateWorkflows(ctx context.Context, payload *model.ValidationOptionsForUpdateScheme) (*model.WorkflowValidationErrorListScheme, *model.ResponseScheme, error) {
+	return w.internalClient.ValidateUpdateWorkflows(ctx, payload)
+}
+
 type internalWorkflowImpl struct {
 	c       service.Connector
 	version string
 }
 
+func (i *internalWorkflowImpl) Search(ctx context.Context, options *model.WorkflowSearchCriteria, expand []string, transitionLinks bool) (*model.WorkflowReadResponseScheme, *model.ResponseScheme, error) {
+	params := url.Values{}
+
+	if len(expand) != 0 {
+		params.Add("expand", strings.Join(expand, ","))
+	}
+
+	if transitionLinks {
+		params.Add("useTransitionLinksFormat", "true")
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("rest/api/%v/workflows", i.version))
+
+	if params.Encode() != "" {
+		endpoint.WriteString(fmt.Sprintf("?%v", params.Encode()))
+	}
+
+	request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint.String(), "", options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	page := new(model.WorkflowReadResponseScheme)
+	response, err := i.c.Call(request, page)
+	if err != nil {
+		return nil, response, err
+	}
+
+	return page, response, nil
+}
+
+func (i *internalWorkflowImpl) Capabilities(ctx context.Context, workflowID, projectID, issueTypeID string) (*model.WorkflowCapabilitiesScheme, *model.ResponseScheme, error) {
+
+	params := url.Values{}
+
+	if workflowID != "" {
+		params.Add("workflowId", workflowID)
+	}
+
+	if projectID != "" {
+		params.Add("projectId", projectID)
+	}
+
+	if issueTypeID != "" {
+		params.Add("issueTypeId", issueTypeID)
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("rest/api/%v/workflows/capabilities", i.version))
+
+	if params.Encode() != "" {
+		endpoint.WriteString(fmt.Sprintf("?%v", params.Encode()))
+	}
+
+	request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint.String(), "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	capabilities := new(model.WorkflowCapabilitiesScheme)
+	response, err := i.c.Call(request, capabilities)
+	if err != nil {
+		return nil, response, err
+	}
+
+	return capabilities, response, nil
+}
+
+func (i *internalWorkflowImpl) Creates(ctx context.Context, payload *model.WorkflowCreatesPayload) (*model.WorkflowCreateResponseScheme, *model.ResponseScheme, error) {
+
+	endpoint := fmt.Sprintf("rest/api/%v/workflows/create", i.version)
+
+	request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	result := new(model.WorkflowCreateResponseScheme)
+	response, err := i.c.Call(request, result)
+	if err != nil {
+		return nil, response, err
+	}
+
+	return result, response, nil
+}
+
+func (i *internalWorkflowImpl) ValidateCreateWorkflows(ctx context.Context, payload *model.ValidationOptionsForCreateScheme) (*model.WorkflowValidationErrorListScheme, *model.ResponseScheme, error) {
+
+	endpoint := fmt.Sprintf("rest/api/%v/workflows/create/validation", i.version)
+
+	request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	errorList := new(model.WorkflowValidationErrorListScheme)
+	response, err := i.c.Call(request, errorList)
+	if err != nil {
+		return nil, response, err
+	}
+
+	return errorList, response, nil
+}
+
+func (i *internalWorkflowImpl) Updates(ctx context.Context, payload *model.WorkflowUpdatesPayloadScheme, expand []string) (*model.WorkflowUpdateResponseScheme, *model.ResponseScheme, error) {
+
+	params := url.Values{}
+	if len(expand) != 0 {
+		params.Add("expand", strings.Join(expand, ","))
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("rest/api/%v/workflows/update", i.version))
+
+	if params.Encode() != "" {
+		endpoint.WriteString(fmt.Sprintf("?%v", params.Encode()))
+	}
+
+	request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint.String(), "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	result := new(model.WorkflowUpdateResponseScheme)
+	response, err := i.c.Call(request, result)
+	if err != nil {
+		return nil, response, err
+	}
+
+	return result, response, nil
+}
+
+func (i *internalWorkflowImpl) ValidateUpdateWorkflows(ctx context.Context, payload *model.ValidationOptionsForUpdateScheme) (*model.WorkflowValidationErrorListScheme, *model.ResponseScheme, error) {
+
+	endpoint := fmt.Sprintf("rest/api/%v/workflows/update/validation", i.version)
+
+	request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	errorList := new(model.WorkflowValidationErrorListScheme)
+	response, err := i.c.Call(request, errorList)
+	if err != nil {
+		return nil, response, err
+	}
+
+	return errorList, response, nil
+}
+
 func (i *internalWorkflowImpl) Create(ctx context.Context, payload *model.WorkflowPayloadScheme) (*model.WorkflowCreatedResponseScheme, *model.ResponseScheme, error) {
 
 	endpoint := fmt.Sprintf("rest/api/%v/workflow", i.version)
diff --git a/pkg/infra/models/jira_workflow.go b/pkg/infra/models/jira_workflow.go
index 99767b8..7e39e51 100644
--- a/pkg/infra/models/jira_workflow.go
+++ b/pkg/infra/models/jira_workflow.go
@@ -1,5 +1,7 @@
 package models
 
+import "fmt"
+
 // WorkflowSearchOptions represents the search options for a workflow in Jira.
 type WorkflowSearchOptions struct {
 	WorkflowName []string // The names of the workflows to search for.
@@ -36,15 +38,50 @@ type WorkflowPublishedIDScheme struct {
 }
 
 // WorkflowTransitionScheme represents a transition in a workflow in Jira.
+// Note that a transition can have either the deprecated to/from fields or the toStatusReference/links fields,
+// but never both nor a combination.
 type WorkflowTransitionScheme struct {
-	ID          string                          `json:"id,omitempty"`          // The ID of the transition.
-	Name        string                          `json:"name,omitempty"`        // The name of the transition.
-	Description string                          `json:"description,omitempty"` // The description of the transition.
-	From        []string                        `json:"from,omitempty"`        // The statuses from which this transition can be executed.
-	To          string                          `json:"to,omitempty"`          // The status to which this transition goes.
-	Type        string                          `json:"type,omitempty"`        // The type of the transition.
-	Screen      *WorkflowTransitionScreenScheme `json:"screen,omitempty"`      // The screen associated with the transition.
-	Rules       *WorkflowTransitionRulesScheme  `json:"rules,omitempty"`       // The rules of the transition.
+	Actions            []*WorkflowRuleConfigurationScheme `json:"actions,omitempty"`
+	Conditions         *ConditionGroupConfigurationScheme `json:"conditions,omitempty"`
+	CustomIssueEventID string                             `json:"customIssueEventId,omitempty"`
+	Description        string                             `json:"description,omitempty"`
+	From               []*WorkflowStatusAndPortScheme     `json:"from,omitempty"` // This field is deprecated - use toStatusReference/links instead.
+	ID                 string                             `json:"id,omitempty"`
+	Links              []*WorkflowTransitionLinkScheme    `json:"links,omitempty"`
+	Name               string                             `json:"name,omitempty"` // The name of the transition.
+	To                 *WorkflowStatusAndPortScheme       `json:"to,omitempty"`   // The status to which this transition goes.
+	ToStatusReference  string                             `json:"toStatusReference,omitempty"`
+	TransitionScreen   *WorkflowRuleConfigurationScheme   `json:"transitionScreen,omitempty"`
+	Triggers           []*WorkflowTriggerScheme           `json:"triggers,omitempty"`
+	Type               string                             `json:"type,omitempty"` // The type of the transition.
+	Validators         []*WorkflowRuleConfigurationScheme `json:"validators,omitempty"`
+}
+
+type WorkflowRuleConfigurationScheme struct {
+	ID      string `json:"id,omitempty"`
+	RuleKey string `json:"ruleKey,omitempty"`
+}
+
+type ConditionGroupConfigurationScheme struct {
+	ConditionGroups []*ConditionGroupConfigurationScheme `json:"conditionGroups,omitempty"`
+	Conditions      []*WorkflowRuleConfigurationScheme   `json:"conditions,omitempty"`
+	Operation       string                               `json:"operation,omitempty"`
+}
+
+type WorkflowStatusAndPortScheme struct {
+	Port            int    `json:"port,omitempty"`
+	StatusReference string `json:"statusReference,omitempty"`
+}
+
+type WorkflowTransitionLinkScheme struct {
+	FromPort            int    `json:"fromPort,omitempty"`
+	FromStatusReference string `json:"fromStatusReference,omitempty"`
+	ToPort              int    `json:"toPort,omitempty"`
+}
+
+type WorkflowTriggerScheme struct {
+	ID      string `json:"id,omitempty"`
+	RuleKey string `json:"ruleKey,omitempty"`
 }
 
 // WorkflowTransitionScreenScheme represents a screen associated with a transition in a workflow in Jira.
@@ -123,3 +160,309 @@ type WorkflowConditionScheme struct {
 	Operator      string                     `json:"operator,omitempty"`      // The operator of the condition.
 	Type          string                     `json:"type,omitempty"`          // The type of the condition.
 }
+
+type WorkflowSearchCriteria struct {
+	ProjectAndIssueTypes []*WorkflowSearchProjectIssueTypeMapping `json:"projectAndIssueTypes,omitempty"`
+	WorkflowIDs          []string                                 `json:"workflowIds,omitempty"`
+	WorkflowNames        []string                                 `json:"workflowNames,omitempty"`
+}
+
+type WorkflowSearchProjectIssueTypeMapping struct {
+	IssueTypeID string `json:"issueTypeId,omitempty"`
+	ProjectID   string `json:"projectId,omitempty"`
+}
+
+type WorkflowReadResponseScheme struct {
+	Statuses  []*WorkflowStatusDetailScheme `json:"statuses,omitempty"`
+	Workflows []*JiraWorkflowScheme         `json:"workflows,omitempty"`
+}
+
+type JiraWorkflowScheme struct {
+	Description      string                           `json:"description,omitempty"`
+	ID               string                           `json:"id,omitempty"`
+	IsEditable       bool                             `json:"isEditable,omitempty"`
+	Name             string                           `json:"name,omitempty"`
+	Scope            *WorkflowStatusScopeScheme       `json:"scope,omitempty"`
+	StartPointLayout *WorkflowLayoutScheme            `json:"startPointLayout,omitempty"`
+	Statuses         []*WorkflowReferenceStatusScheme `json:"statuses,omitempty"`
+	TaskID           string                           `json:"taskId,omitempty"`
+	Transitions      []*WorkflowTransitionScheme      `json:"transitions,omitempty"`
+	Usages           []*ProjectIssueTypesScheme       `json:"usages,omitempty"`
+	Version          *WorkflowDocumentVersionScheme   `json:"version,omitempty"`
+}
+
+type WorkflowLayoutScheme struct {
+	X float64 `json:"x,omitempty"`
+	Y float64 `json:"y,omitempty"`
+}
+
+type WorkflowReferenceStatusScheme struct {
+	Deprecated      bool                  `json:"deprecated,omitempty"`
+	Layout          *WorkflowLayoutScheme `json:"layout,omitempty"`
+	StatusReference string                `json:"statusReference,omitempty"`
+}
+
+type WorkflowDocumentVersionScheme struct {
+	ID            string `json:"id,omitempty"`
+	VersionNumber int    `json:"versionNumber,omitempty"`
+}
+
+type WorkflowCapabilitiesScheme struct {
+	ConnectRules []*AvailableWorkflowConnectRuleScheme `json:"connectRules,omitempty"`
+	EditorScope  string                                `json:"editorScope,omitempty"`
+	ForgeRules   []*AvailableWorkflowForgeRuleScheme   `json:"forgeRules,omitempty"`
+	ProjectTypes []string                              `json:"projectTypes,omitempty"`
+	SystemRules  []*AvailableWorkflowSystemRuleScheme  `json:"systemRules,omitempty"`
+	TriggerRules []*AvailableWorkflowTriggers          `json:"triggerRules,omitempty"`
+}
+
+type AvailableWorkflowConnectRuleScheme struct {
+	AddonKey    string `json:"addonKey,omitempty"`
+	CreateURL   string `json:"createUrl,omitempty"`
+	Description string `json:"description,omitempty"`
+	EditURL     string `json:"editUrl,omitempty"`
+	ModuleKey   string `json:"moduleKey,omitempty"`
+	Name        string `json:"name,omitempty"`
+	RuleKey     string `json:"ruleKey,omitempty"`
+	RuleType    string `json:"ruleType,omitempty"`
+	ViewURL     string `json:"viewUrl,omitempty"`
+}
+
+type AvailableWorkflowForgeRuleScheme struct {
+	Description string `json:"description,omitempty"`
+	ID          string `json:"id,omitempty"`
+	Name        string `json:"name,omitempty"`
+	RuleKey     string `json:"ruleKey,omitempty"`
+	RuleType    string `json:"ruleType,omitempty"`
+}
+
+type AvailableWorkflowSystemRuleScheme struct {
+	Description                     string   `json:"description,omitempty"`
+	IncompatibleRuleKeys            []string `json:"incompatibleRuleKeys,omitempty"`
+	IsAvailableForInitialTransition bool     `json:"isAvailableForInitialTransition,omitempty"`
+	IsVisible                       bool     `json:"isVisible,omitempty"`
+	Name                            string   `json:"name,omitempty"`
+	RuleKey                         string   `json:"ruleKey,omitempty"`
+	RuleType                        string   `json:"ruleType,omitempty"`
+}
+
+type AvailableWorkflowTriggers struct {
+	AvailableTypes []*AvailableWorkflowTriggerTypeScheme `json:"availableTypes,omitempty"`
+	RuleKey        string                                `json:"ruleKey,omitempty"`
+}
+
+type AvailableWorkflowTriggerTypeScheme struct {
+	Description string `json:"description,omitempty"`
+	Name        string `json:"name,omitempty"`
+	Type        string `json:"type,omitempty"`
+}
+
+type WorkflowCreatesPayload struct {
+	Scope     *WorkflowScopeScheme          `json:"scope,omitempty"`
+	Statuses  []*WorkflowStatusUpdateScheme `json:"statuses,omitempty"`
+	Workflows []*WorkflowCreateScheme       `json:"workflows,omitempty"`
+}
+
+// AddWorkflow adds a new workflow and its statuses to the payload, ensuring no duplicate statuses.
+func (w *WorkflowCreatesPayload) AddWorkflow(workflow *WorkflowCreateScheme) error {
+
+	// Check if the status references are present in the payload
+	for _, referenceID := range workflow.Statuses {
+		found := false
+		for _, status := range w.Statuses {
+			if referenceID.StatusReference == status.StatusReference {
+				found = true
+				break
+			}
+		}
+		if !found {
+			return fmt.Errorf("status reference %s not found", referenceID.StatusReference)
+		}
+	}
+
+	w.Workflows = append(w.Workflows, workflow)
+	return nil
+}
+
+func (w *WorkflowCreatesPayload) AddStatus(status *WorkflowStatusUpdateScheme) {
+	w.Statuses = append(w.Statuses, status)
+}
+
+type WorkflowScopeScheme struct {
+	Project *WorkflowScopeProjectScheme `json:"project,omitempty"`
+	Type    string                      `json:"type,omitempty"`
+}
+
+type WorkflowScopeProjectScheme struct {
+	ID string `json:"id,omitempty"`
+}
+
+type WorkflowStatusUpdateScheme struct {
+	Description     string `json:"description,omitempty"`
+	ID              string `json:"id,omitempty"`
+	Name            string `json:"name,omitempty"`
+	StatusCategory  string `json:"statusCategory,omitempty"`
+	StatusReference string `json:"statusReference,omitempty"`
+}
+
+type WorkflowCreateScheme struct {
+	Description      string                       `json:"description,omitempty"`
+	Name             string                       `json:"name,omitempty"`
+	StartPointLayout *WorkflowLayoutScheme        `json:"startPointLayout,omitempty"`
+	Statuses         []*StatusLayoutUpdateScheme  `json:"statuses,omitempty"`
+	Transitions      []*TransitionUpdateDTOScheme `json:"transitions,omitempty"`
+}
+
+func (w *WorkflowCreateScheme) AddStatus(status *StatusLayoutUpdateScheme) {
+	w.Statuses = append(w.Statuses, status)
+}
+
+func (w *WorkflowCreateScheme) AddTransition(transition *TransitionUpdateDTOScheme) error {
+	if !w.isStatusReferenceAdded(transition.To.StatusReference) {
+		return fmt.Errorf("status reference %s not found", transition.To.StatusReference)
+	}
+
+	w.Transitions = append(w.Transitions, transition)
+	return nil
+}
+
+func (w *WorkflowCreateScheme) isStatusReferenceAdded(statusReference string) bool {
+	for _, status := range w.Statuses {
+		if status.StatusReference == statusReference {
+			return true
+		}
+	}
+	return false
+}
+
+type StatusLayoutUpdateScheme struct {
+	Layout          *WorkflowLayoutScheme `json:"layout,omitempty"`
+	StatusReference string                `json:"statusReference"`
+}
+
+type TransitionUpdateDTOScheme struct {
+	Actions            []*WorkflowRuleConfigurationScheme `json:"actions,omitempty"`
+	Conditions         *ConditionGroupUpdateScheme        `json:"conditions,omitempty"`
+	CustomIssueEventID string                             `json:"customIssueEventId,omitempty"`
+	Description        string                             `json:"description,omitempty"`
+	From               []*StatusReferenceAndPortScheme    `json:"from,omitempty"`
+	ID                 string                             `json:"id,omitempty"`
+	Links              []*WorkflowTransitionLinkScheme    `json:"links,omitempty"`
+	Name               string                             `json:"name,omitempty"`
+	To                 *StatusReferenceAndPortScheme      `json:"to,omitempty"`
+	ToStatusReference  string                             `json:"toStatusReference,omitempty"`
+	TransitionScreen   *WorkflowRuleConfigurationScheme   `json:"transitionScreen,omitempty"`
+	Triggers           []*WorkflowTriggerScheme           `json:"triggers,omitempty"`
+	Type               string                             `json:"type,omitempty"`
+	Validators         []*WorkflowRuleConfigurationScheme `json:"validators,omitempty"`
+}
+
+type ConditionGroupUpdateScheme struct {
+	ConditionGroups []*ConditionGroupUpdateScheme      `json:"conditionGroups,omitempty"`
+	Conditions      []*WorkflowRuleConfigurationScheme `json:"conditions,omitempty"`
+	Operation       string                             `json:"operation,omitempty"`
+}
+
+type StatusReferenceAndPortScheme struct {
+	Port            int    `json:"port,omitempty"`
+	StatusReference string `json:"statusReference,omitempty"`
+}
+
+type WorkflowCreateResponseScheme struct {
+	Statuses  []*JiraWorkflowStatusScheme `json:"statuses,omitempty"`
+	Workflows []*JiraWorkflowScheme       `json:"workflows,omitempty"`
+}
+
+type JiraWorkflowStatusScheme struct {
+	Description     string                     `json:"description,omitempty"`
+	ID              string                     `json:"id,omitempty"`
+	Name            string                     `json:"name,omitempty"`
+	Scope           *WorkflowScopeScheme       `json:"scope,omitempty"`
+	StatusCategory  string                     `json:"statusCategory,omitempty"`
+	StatusReference string                     `json:"statusReference,omitempty"`
+	Usages          []*ProjectIssueTypesScheme `json:"usages,omitempty"`
+}
+
+type ValidationOptionsForCreateScheme struct {
+	Payload *WorkflowCreatesPayload       `json:"payload,omitempty"`
+	Options *ValidationOptionsLevelScheme `json:"validationOptions"`
+}
+
+type ValidationOptionsLevelScheme struct {
+	Levels []string `json:"levels,omitempty"`
+}
+
+type WorkflowValidationErrorListScheme struct {
+	Errors []*WorkflowValidationErrorScheme `json:"errors,omitempty"`
+}
+
+type WorkflowValidationErrorScheme struct {
+	Code             string                          `json:"code,omitempty"`
+	ElementReference *WorkflowElementReferenceScheme `json:"elementReference,omitempty"`
+	Level            string                          `json:"level,omitempty"`
+	Message          string                          `json:"message,omitempty"`
+	Type             string                          `json:"type,omitempty"`
+}
+
+type WorkflowElementReferenceScheme struct {
+	PropertyKey            string                         `json:"propertyKey,omitempty"`
+	RuleID                 string                         `json:"ruleId,omitempty"`
+	StatusMappingReference *ProjectAndIssueTypePairScheme `json:"statusMappingReference,omitempty"`
+	StatusReference        string                         `json:"statusReference,omitempty"`
+	TransitionID           string                         `json:"transitionId,omitempty"`
+}
+
+type ProjectAndIssueTypePairScheme struct {
+	IssueTypeID string `json:"issueTypeId,omitempty"`
+	ProjectID   string `json:"projectId,omitempty"`
+}
+
+type WorkflowUpdatesPayloadScheme struct {
+	Statuses  []*WorkflowStatusUpdateScheme `json:"statuses,omitempty"`
+	Workflows []*WorkflowUpdateScheme       `json:"workflows,omitempty"`
+}
+
+func (w *WorkflowUpdatesPayloadScheme) InjectWorkflow(workflow *JiraWorkflowScheme) {
+
+	w.Workflows = append(w.Workflows, &WorkflowUpdateScheme{
+		Description:      workflow.Description,
+		ID:               workflow.ID,
+		StartPointLayout: workflow.StartPointLayout,
+		Version:          workflow.Version,
+	})
+}
+
+type WorkflowUpdateScheme struct {
+	DefaultStatusMappings []*StatusMigrationScheme       `json:"defaultStatusMappings,omitempty"`
+	Description           string                         `json:"description,omitempty"`
+	ID                    string                         `json:"id,omitempty"`
+	StartPointLayout      *WorkflowLayoutScheme          `json:"startPointLayout,omitempty"`
+	StatusMappings        []*StatusMappingDTOScheme      `json:"statusMappings,omitempty"`
+	Statuses              []*StatusLayoutUpdateScheme    `json:"statuses,omitempty"`
+	Transitions           []*TransitionUpdateDTOScheme   `json:"transitions,omitempty"`
+	Version               *WorkflowDocumentVersionScheme `json:"version,omitempty"`
+}
+
+type StatusMigrationScheme struct {
+	NewStatusReference string `json:"newStatusReference,omitempty"`
+	OldStatusReference string `json:"oldStatusReference,omitempty"`
+}
+
+type StatusMappingDTOScheme struct {
+	IssueTypeID      string                       `json:"issueTypeId,omitempty"`
+	ProjectID        string                       `json:"projectId,omitempty"`
+	StatusMigrations []*StatusMigrationScheme     `json:"statusMigrations,omitempty"`
+	Statuses         []*StatusLayoutUpdateScheme  `json:"statuses,omitempty"`
+	Transitions      []*TransitionUpdateDTOScheme `json:"transitions,omitempty"`
+}
+
+type WorkflowUpdateResponseScheme struct {
+	Statuses  []*JiraWorkflowStatusScheme `json:"statuses,omitempty"`
+	TaskID    string                      `json:"taskId,omitempty"`
+	Workflows []*JiraWorkflowScheme       `json:"workflows,omitempty"`
+}
+
+type ValidationOptionsForUpdateScheme struct {
+	Payload *WorkflowUpdatesPayloadScheme `json:"payload,omitempty"`
+	Options *ValidationOptionsLevelScheme `json:"validationOptions,omitempty"`
+}
diff --git a/service/jira/workflow.go b/service/jira/workflow.go
index b32584e..e3135f3 100644
--- a/service/jira/workflow.go
+++ b/service/jira/workflow.go
@@ -42,6 +42,139 @@ type WorkflowConnector interface {
 	//
 	// https://docs.go-atlassian.io/jira-software-cloud/workflow#search-workflows
 	Delete(ctx context.Context, workflowId string) (*model.ResponseScheme, error)
+
+	// Search searches for workflows based on specified criteria.
+	//
+	// This method returns a paginated list of workflows that match the search criteria provided in the `options` parameter.
+	//
+	// The search can be expanded to include additional details, such as transition links, by specifying the `expand` and `transitionLinks` parameters.
+	//
+	// When search criteria are provided in the `options` parameter, only workflows matching those criteria are returned.
+	// If no criteria are specified, all workflows are returned.
+	//
+	// GET /rest/api/{2-3}/workflow/search
+	//
+	// https://docs.go-atlassian.io/jira-software-cloud/workflow#bulk-get-workflows
+	Search(ctx context.Context, options *model.WorkflowSearchCriteria, expand []string, transitionLinks bool) (*model.WorkflowReadResponseScheme, *model.ResponseScheme, error)
+
+	// Capabilities Get the list of workflow capabilities for a specific workflow using either the workflow ID, or the project and issue type ID pair.
+	//
+	// The response includes the scope of the workflow, defined as global/project-based, and a list of project types that the workflow is scoped to.
+	//
+	// It also includes all rules organised into their broad categories (conditions, validators, actions, triggers, screens) as well as the source location (Atlassian-provided, Connect, Forge).
+	//
+	// GET /rest/api/{2-3}/workflows/capabilities
+	//
+	// https://docs.go-atlassian.io/jira-software-cloud/workflow#get-workflow-capabilities
+	Capabilities(ctx context.Context, workflowID, projectID, issueTypeID string) (*model.WorkflowCapabilitiesScheme, *model.ResponseScheme, error)
+
+	// Creates create workflows and related statuses.
+	//
+	// This method allows you to create a workflow by defining transition rules
+	// using the shapes detailed in the Atlassian REST API documentation.
+	// If no transition rules are specified, the default system transition rules
+	// will be used.
+	//
+	// POST /rest/api/{2-3}/workflows
+	//
+	// For more details, refer to:
+	// https://docs.go-atlassian.io/jira-software-cloud/workflow#bulk-create-workflows
+	//
+	// Example:
+	//
+	//	payload := &models.WorkflowCreatesPayload{
+	//		Scope: &models.WorkflowScopeScheme{Type: "GLOBAL"},
+	//		// The workflows to create, with transition rules.
+	//	}
+	//
+	//	response, respScheme, err := client.Workflow.Creates(ctx, payload)
+	//	if err != nil {
+	//		log.Fatalf("Failed to create workflow: %v", err)
+	//	}
+	//
+	//	fmt.Printf("Workflow created with ID: %s", response.ID)
+	Creates(ctx context.Context, payload *model.WorkflowCreatesPayload) (*model.WorkflowCreateResponseScheme, *model.ResponseScheme, error)
+
+	// ValidateCreateWorkflows validates workflows before creating them.
+	//
+	// This method allows you to validate the configuration of one or more workflows
+	// before they are created in Jira. It helps ensure that the workflows adhere
+	// to the defined rules and constraints.
+	//
+	// The validation checks will include all aspects of the workflows, such as transitions,
+	// statuses, and any related conditions or validators.
+	//
+	// POST /rest/api/{2-3}/workflows/create/validation
+	//
+	// For more details, refer to:
+	// https://docs.go-atlassian.io/jira-software-cloud/workflow#validate-create-workflows
+	//
+	// Example:
+	//  ctx := context.Background()
+	//  payload := &model.ValidationOptionsForCreateScheme{
+	//      Payload: payload,
+	//     Options: &models.ValidationOptionsLevelScheme{
+	//		  Levels: []string{"ERROR", "WARNING"},
+	//	  }
+	//
+	//  validationResult, response, err := client.Workflow.ValidateCreateWorkflows(ctx, payload)
+	//  if err != nil {
+	//      log.Fatalf("Failed to validate workflow: %v", err)
+	//  }
+	//
+	//  if validationResult != nil {
+	//      log.Printf("Workflow validation errors: %v", validationResult.Errors)
+	//  }
+	//
+	//  log.Printf("Validation response: %v", response)
+	ValidateCreateWorkflows(ctx context.Context, payload *model.ValidationOptionsForCreateScheme) (*model.WorkflowValidationErrorListScheme, *model.ResponseScheme, error)
+
+	// Updates updates workflows.
+	//
+	// This method allows you to update workflows by providing a payload containing the details
+	// of the updates. You can expand specific fields using the 'expand' parameter.
+	//
+	// The update follows the API detailed in the Atlassian documentation.
+	//
+	// POST /rest/api/{2-3}/workflows/update
+	//
+	// For more details, refer to:
+	// https://docs.go-atlassian.io/jira-software-cloud/workflow#bulk-update-workflows
+	Updates(ctx context.Context, payload *model.WorkflowUpdatesPayloadScheme, expand []string) (*model.WorkflowUpdateResponseScheme, *model.ResponseScheme, error)
+
+	// ValidateUpdateWorkflows validates the update of one or more workflows.
+	//
+	// This method allows you to validate changes to workflows before they are applied.
+	// The validation checks for potential issues that could prevent the workflows from being updated successfully.
+	//
+	// The validation process will check for conditions such as:
+	//
+	// 		1.Whether the transitions are valid.
+	// 		2. Whether the status and transition names are unique within the workflow.
+	// 		3. If the validation fails, a list of validation errors is returned, which should be resolved before applying the changes.
+	//
+	// POST /rest/api/{2-3}/workflows/update/validation
+	//
+	// For more details, refer to:
+	// https://docs.go-atlassian.io/jira-software-cloud/workflow#validate-update-workflows
+	//
+	// Example:
+	//
+	//     options := &model.ValidationOptionsForUpdateScheme{
+	//         // populate the validation options here
+	//     }
+	//
+	//     result, response, err := client.Workflow.ValidateUpdateWorkflows(ctx, options)
+	//     if err != nil {
+	//         log.Fatalf("Validation failed: %v", err)
+	//     }
+	//
+	//     if len(result.Errors) > 0 {
+	//         log.Printf("Validation errors: %v", result.Errors)
+	//     } else {
+	//         log.Println("Validation passed, you can proceed with the update.")
+	//     }
+	ValidateUpdateWorkflows(ctx context.Context, payload *model.ValidationOptionsForUpdateScheme) (*model.WorkflowValidationErrorListScheme, *model.ResponseScheme, error)
 }
 
 type WorkflowSchemeConnector interface {


Test patch:
diff --git a/jira/internal/workflow_impl_test.go b/jira/internal/workflow_impl_test.go
index 82ba743..9b506f2 100644
--- a/jira/internal/workflow_impl_test.go
+++ b/jira/internal/workflow_impl_test.go
@@ -3,6 +3,8 @@ package internal
 import (
 	"context"
 	"errors"
+	"fmt"
+	"log"
 	"net/http"
 	"testing"
 
@@ -524,3 +526,902 @@ func Test_NewWorkflowService(t *testing.T) {
 		})
 	}
 }
+
+func Test_internalWorkflowImpl_Search(t *testing.T) {
+	type fields struct {
+		c       service.Connector
+		version string
+	}
+	type args struct {
+		ctx             context.Context
+		options         *model.WorkflowSearchCriteria
+		expand          []string
+		transitionLinks bool
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		want    *model.WorkflowReadResponseScheme
+		want1   *model.ResponseScheme
+		wantErr assert.ErrorAssertionFunc
+	}{
+		{
+			name: "when search is successful",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:             context.Background(),
+				options:         &model.WorkflowSearchCriteria{},
+				expand:          []string{"transitions"},
+				transitionLinks: true,
+			},
+
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows?expand=transitions&useTransitionLinksFormat=true",
+					"", &model.WorkflowSearchCriteria{}).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowReadResponseScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+			want:    &model.WorkflowReadResponseScheme{},
+			want1:   &model.ResponseScheme{},
+			wantErr: assert.NoError,
+		},
+		{
+			name: "when search fails due to request creation error",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:             context.Background(),
+				options:         &model.WorkflowSearchCriteria{},
+				expand:          []string{"transitions"},
+				transitionLinks: true,
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows?expand=transitions&useTransitionLinksFormat=true",
+					"", &model.WorkflowSearchCriteria{}).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+			},
+			want:    nil,
+			want1:   nil,
+			wantErr: assert.Error,
+		},
+		{
+			name: "when search fails due to API call error",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:             context.Background(),
+				options:         &model.WorkflowSearchCriteria{},
+				expand:          []string{"transitions"},
+				transitionLinks: true,
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows?expand=transitions&useTransitionLinksFormat=true",
+					"", &model.WorkflowSearchCriteria{}).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowReadResponseScheme{}).
+					Return(nil, errors.New("error, API call failed"))
+			},
+			want:    nil,
+			want1:   nil,
+			wantErr: assert.Error,
+		},
+		{
+			name: "when search returns no results",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:             context.Background(),
+				options:         &model.WorkflowSearchCriteria{},
+				expand:          []string{"transitions"},
+				transitionLinks: true,
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows?expand=transitions&useTransitionLinksFormat=true",
+					"", &model.WorkflowSearchCriteria{}).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowReadResponseScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+			},
+			want:    &model.WorkflowReadResponseScheme{},
+			want1:   &model.ResponseScheme{},
+			wantErr: assert.NoError,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+
+			if tt.on != nil {
+				tt.on(&tt.fields)
+			}
+
+			newService, err := NewWorkflowService(tt.fields.c, tt.fields.version, nil, nil)
+			assert.NoError(t, err)
+
+			got, got1, err := newService.Search(tt.args.ctx, tt.args.options, tt.args.expand, tt.args.transitionLinks)
+			if !tt.wantErr(t, err, fmt.Sprintf("Search(%v, %v, %v, %v)", tt.args.ctx, tt.args.options, tt.args.expand, tt.args.transitionLinks)) {
+				return
+			}
+			assert.Equalf(t, tt.want, got, "Search(%v, %v, %v, %v)", tt.args.ctx, tt.args.options, tt.args.expand, tt.args.transitionLinks)
+			assert.Equalf(t, tt.want1, got1, "Search(%v, %v, %v, %v)", tt.args.ctx, tt.args.options, tt.args.expand, tt.args.transitionLinks)
+		})
+	}
+}
+
+func Test_internalWorkflowImpl_Capabilities(t *testing.T) {
+	type fields struct {
+		c       service.Connector
+		version string
+	}
+	type args struct {
+		ctx         context.Context
+		workflowID  string
+		projectID   string
+		issueTypeID string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		want    *model.WorkflowCapabilitiesScheme
+		want1   *model.ResponseScheme
+		wantErr assert.ErrorAssertionFunc
+	}{
+		{
+			name: "when capabilities are successfully retrieved",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:         context.Background(),
+				workflowID:  "123",
+				projectID:   "456",
+				issueTypeID: "789",
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"rest/api/3/workflows/capabilities?issueTypeId=789&projectId=456&workflowId=123",
+					"", nil).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowCapabilitiesScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+			},
+			want:    &model.WorkflowCapabilitiesScheme{},
+			want1:   &model.ResponseScheme{},
+			wantErr: assert.NoError,
+		},
+		{
+			name: "when request creation fails",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:         context.Background(),
+				workflowID:  "123",
+				projectID:   "456",
+				issueTypeID: "789",
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"rest/api/3/workflows/capabilities?issueTypeId=789&projectId=456&workflowId=123",
+					"", nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+			},
+			want:    nil,
+			want1:   nil,
+			wantErr: assert.Error,
+		},
+		{
+			name: "when API call fails",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:         context.Background(),
+				workflowID:  "123",
+				projectID:   "456",
+				issueTypeID: "789",
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"rest/api/3/workflows/capabilities?issueTypeId=789&projectId=456&workflowId=123",
+					"", nil).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowCapabilitiesScheme{}).
+					Return(nil, errors.New("error, API call failed"))
+			},
+			want:    nil,
+			want1:   nil,
+			wantErr: assert.Error,
+		},
+		{
+			name: "when no parameters are provided",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx: context.Background(),
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"rest/api/3/workflows/capabilities",
+					"", nil).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowCapabilitiesScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+			},
+			want:    &model.WorkflowCapabilitiesScheme{},
+			want1:   &model.ResponseScheme{},
+			wantErr: assert.NoError,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+
+			if tt.on != nil {
+				tt.on(&tt.fields)
+			}
+
+			newService, err := NewWorkflowService(tt.fields.c, tt.fields.version, nil, nil)
+			assert.NoError(t, err)
+
+			got, got1, err := newService.Capabilities(tt.args.ctx, tt.args.workflowID, tt.args.projectID, tt.args.issueTypeID)
+			if !tt.wantErr(t, err, fmt.Sprintf("Capabilities(%v, %v, %v, %v)", tt.args.ctx, tt.args.workflowID, tt.args.projectID, tt.args.issueTypeID)) {
+				return
+			}
+			assert.Equalf(t, tt.want, got, "Capabilities(%v, %v, %v, %v)", tt.args.ctx, tt.args.workflowID, tt.args.projectID, tt.args.issueTypeID)
+			assert.Equalf(t, tt.want1, got1, "Capabilities(%v, %v, %v, %v)", tt.args.ctx, tt.args.workflowID, tt.args.projectID, tt.args.issueTypeID)
+		})
+	}
+}
+
+func Test_internalWorkflowImpl_Creates(t *testing.T) {
+
+	payload := &model.WorkflowCreatesPayload{
+		Scope: &model.WorkflowScopeScheme{Type: "GLOBAL"},
+	}
+
+	// Add the status references on the payload
+	statuses := []struct {
+		ID, Name, StatusCategory, StatusReference string
+	}{
+		{"10012", "To Do", "TODO", "f0b24de5-25e7-4fab-ab94-63d81db6c0c0"},
+		{"3", "In Progress", "IN_PROGRESS", "c7a35bf0-c127-4aa6-869f-4033730c61d8"},
+		{"10002", "Done", "DONE", "6b3fc04d-3316-46c5-a257-65751aeb8849"},
+	}
+
+	for _, status := range statuses {
+		payload.AddStatus(&model.WorkflowStatusUpdateScheme{
+			ID:              status.ID,
+			Name:            status.Name,
+			StatusCategory:  status.StatusCategory,
+			StatusReference: status.StatusReference,
+		})
+	}
+
+	epicWorkflow := &model.WorkflowCreateScheme{
+		Description: "This workflow represents the process of software development related to epics.",
+		Name:        "Epic Software Development Workflow V4",
+	}
+
+	// Add the statuses to the workflow using the referenceID and the layout
+	layouts := []struct {
+		X, Y            float64
+		StatusReference string
+	}{
+		{114.99993896484375, -16, "f0b24de5-25e7-4fab-ab94-63d81db6c0c0"},
+		{317.0000915527344, -16, "c7a35bf0-c127-4aa6-869f-4033730c61d8"},
+		{508.000244140625, -16, "6b3fc04d-3316-46c5-a257-65751aeb8849"},
+	}
+
+	for _, layout := range layouts {
+		epicWorkflow.AddStatus(&model.StatusLayoutUpdateScheme{
+			Layout:          &model.WorkflowLayoutScheme{X: layout.X, Y: layout.Y},
+			StatusReference: layout.StatusReference,
+		})
+	}
+
+	// Add the transitions to the workflow
+	transitions := []struct {
+		ID, Type, Name, StatusReference string
+	}{
+		{"1", "INITIAL", "Create", "f0b24de5-25e7-4fab-ab94-63d81db6c0c0"},
+		{"21", "GLOBAL", "In Progress", "c7a35bf0-c127-4aa6-869f-4033730c61d8"},
+		{"31", "GLOBAL", "Done", "6b3fc04d-3316-46c5-a257-65751aeb8849"},
+	}
+
+	for _, transition := range transitions {
+		err := epicWorkflow.AddTransition(&model.TransitionUpdateDTOScheme{
+			ID:   transition.ID,
+			Type: transition.Type,
+			Name: transition.Name,
+			To: &model.StatusReferenceAndPortScheme{
+				StatusReference: transition.StatusReference,
+			},
+		})
+
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+
+	// You can multiple workflows on the same payload
+	if err := payload.AddWorkflow(epicWorkflow); err != nil {
+		log.Fatal(err)
+	}
+
+	type fields struct {
+		c       service.Connector
+		version string
+	}
+	type args struct {
+		ctx     context.Context
+		payload *model.WorkflowCreatesPayload
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		want    *model.WorkflowCreateResponseScheme
+		want1   *model.ResponseScheme
+		wantErr assert.ErrorAssertionFunc
+	}{
+		{
+			name: "when workflow is successfully created",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: payload,
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/create",
+					"", payload).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowCreateResponseScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+			},
+			want:    &model.WorkflowCreateResponseScheme{},
+			want1:   &model.ResponseScheme{},
+			wantErr: assert.NoError,
+		},
+		{
+			name: "when request creation fails",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: payload,
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/create",
+					"", payload).
+					Return(nil, errors.New("error, unable to create the http request"))
+			},
+			want:    nil,
+			want1:   nil,
+			wantErr: assert.Error,
+		},
+		{
+			name: "when API call fails",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: payload,
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/create",
+					"", payload).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowCreateResponseScheme{}).
+					Return(nil, errors.New("error, API call failed"))
+			},
+			want:    nil,
+			want1:   nil,
+			wantErr: assert.Error,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+
+			if tt.on != nil {
+				tt.on(&tt.fields)
+			}
+
+			newService, err := NewWorkflowService(tt.fields.c, tt.fields.version, nil, nil)
+			assert.NoError(t, err)
+
+			got, got1, err := newService.Creates(tt.args.ctx, tt.args.payload)
+			if !tt.wantErr(t, err, fmt.Sprintf("Creates(%v, %v)", tt.args.ctx, tt.args.payload)) {
+				return
+			}
+			assert.Equalf(t, tt.want, got, "Creates(%v, %v)", tt.args.ctx, tt.args.payload)
+			assert.Equalf(t, tt.want1, got1, "Creates(%v, %v)", tt.args.ctx, tt.args.payload)
+		})
+	}
+}
+
+func Test_internalWorkflowImpl_Updates(t *testing.T) {
+	type fields struct {
+		c       service.Connector
+		version string
+	}
+	type args struct {
+		ctx     context.Context
+		payload *model.WorkflowUpdatesPayloadScheme
+		expand  []string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		want    *model.WorkflowUpdateResponseScheme
+		want1   *model.ResponseScheme
+		wantErr assert.ErrorAssertionFunc
+	}{
+		{
+			name: "when workflow is successfully updated",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: &model.WorkflowUpdatesPayloadScheme{
+					// populate the payload fields
+				},
+				expand: []string{"transitions"},
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/update?expand=transitions",
+					"", &model.WorkflowUpdatesPayloadScheme{}).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowUpdateResponseScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+			},
+			want:    &model.WorkflowUpdateResponseScheme{},
+			want1:   &model.ResponseScheme{},
+			wantErr: assert.NoError,
+		},
+		{
+			name: "when request creation fails",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: &model.WorkflowUpdatesPayloadScheme{
+					// populate the payload fields
+				},
+				expand: []string{"transitions"},
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/update?expand=transitions",
+					"", &model.WorkflowUpdatesPayloadScheme{}).
+					Return(nil, errors.New("error, unable to create the http request"))
+			},
+			want:    nil,
+			want1:   nil,
+			wantErr: assert.Error,
+		},
+		{
+			name: "when API call fails",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: &model.WorkflowUpdatesPayloadScheme{
+					// populate the payload fields
+				},
+				expand: []string{"transitions"},
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/update?expand=transitions",
+					"", &model.WorkflowUpdatesPayloadScheme{}).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowUpdateResponseScheme{}).
+					Return(nil, errors.New("error, API call failed"))
+			},
+			want:    nil,
+			want1:   nil,
+			wantErr: assert.Error,
+		},
+		{
+			name: "when no expand parameters are provided",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: &model.WorkflowUpdatesPayloadScheme{
+					// populate the payload fields
+				},
+				expand: []string{},
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/update",
+					"", &model.WorkflowUpdatesPayloadScheme{}).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowUpdateResponseScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+			},
+			want:    &model.WorkflowUpdateResponseScheme{},
+			want1:   &model.ResponseScheme{},
+			wantErr: assert.NoError,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+
+			if tt.on != nil {
+				tt.on(&tt.fields)
+			}
+
+			newService, err := NewWorkflowService(tt.fields.c, tt.fields.version, nil, nil)
+			assert.NoError(t, err)
+
+			got, got1, err := newService.Updates(tt.args.ctx, tt.args.payload, tt.args.expand)
+			if !tt.wantErr(t, err, fmt.Sprintf("Updates(%v, %v, %v)", tt.args.ctx, tt.args.payload, tt.args.expand)) {
+				return
+			}
+			assert.Equalf(t, tt.want, got, "Updates(%v, %v, %v)", tt.args.ctx, tt.args.payload, tt.args.expand)
+			assert.Equalf(t, tt.want1, got1, "Updates(%v, %v, %v)", tt.args.ctx, tt.args.payload, tt.args.expand)
+		})
+	}
+}
+
+func Test_internalWorkflowImpl_ValidateCreateWorkflows(t *testing.T) {
+	type fields struct {
+		c       service.Connector
+		version string
+	}
+	type args struct {
+		ctx     context.Context
+		payload *model.ValidationOptionsForCreateScheme
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		want    *model.WorkflowValidationErrorListScheme
+		want1   *model.ResponseScheme
+		wantErr assert.ErrorAssertionFunc
+	}{
+		{
+			name: "when validation is successful",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: &model.ValidationOptionsForCreateScheme{
+					// populate the payload fields
+				},
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/create/validation",
+					"", &model.ValidationOptionsForCreateScheme{}).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowValidationErrorListScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+			},
+			want:    &model.WorkflowValidationErrorListScheme{},
+			want1:   &model.ResponseScheme{},
+			wantErr: assert.NoError,
+		},
+		{
+			name: "when request creation fails",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: &model.ValidationOptionsForCreateScheme{
+					// populate the payload fields
+				},
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/create/validation",
+					"", &model.ValidationOptionsForCreateScheme{}).
+					Return(nil, errors.New("error, unable to create the http request"))
+			},
+			want:    nil,
+			want1:   nil,
+			wantErr: assert.Error,
+		},
+		{
+			name: "when API call fails",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: &model.ValidationOptionsForCreateScheme{
+					// populate the payload fields
+				},
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/create/validation",
+					"", &model.ValidationOptionsForCreateScheme{}).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowValidationErrorListScheme{}).
+					Return(nil, errors.New("error, API call failed"))
+			},
+			want:    nil,
+			want1:   nil,
+			wantErr: assert.Error,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+
+			if tt.on != nil {
+				tt.on(&tt.fields)
+			}
+
+			newService, err := NewWorkflowService(tt.fields.c, tt.fields.version, nil, nil)
+			assert.NoError(t, err)
+
+			got, got1, err := newService.ValidateCreateWorkflows(tt.args.ctx, tt.args.payload)
+			if !tt.wantErr(t, err, fmt.Sprintf("ValidateCreateWorkflows(%v, %v)", tt.args.ctx, tt.args.payload)) {
+				return
+			}
+			assert.Equalf(t, tt.want, got, "ValidateCreateWorkflows(%v, %v)", tt.args.ctx, tt.args.payload)
+			assert.Equalf(t, tt.want1, got1, "ValidateCreateWorkflows(%v, %v)", tt.args.ctx, tt.args.payload)
+		})
+	}
+}
+
+func Test_internalWorkflowImpl_ValidateUpdateWorkflows(t *testing.T) {
+	type fields struct {
+		c       service.Connector
+		version string
+	}
+	type args struct {
+		ctx     context.Context
+		payload *model.ValidationOptionsForUpdateScheme
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		want    *model.WorkflowValidationErrorListScheme
+		want1   *model.ResponseScheme
+		wantErr assert.ErrorAssertionFunc
+	}{
+		{
+			name: "when validation is successful",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: &model.ValidationOptionsForUpdateScheme{
+					// populate the payload fields
+				},
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/update/validation",
+					"", &model.ValidationOptionsForUpdateScheme{}).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowValidationErrorListScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+			},
+			want:    &model.WorkflowValidationErrorListScheme{},
+			want1:   &model.ResponseScheme{},
+			wantErr: assert.NoError,
+		},
+		{
+			name: "when request creation fails",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: &model.ValidationOptionsForUpdateScheme{
+					// populate the payload fields
+				},
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/update/validation",
+					"", &model.ValidationOptionsForUpdateScheme{}).
+					Return(nil, errors.New("error, unable to create the http request"))
+			},
+			want:    nil,
+			want1:   nil,
+			wantErr: assert.Error,
+		},
+		{
+			name: "when API call fails",
+			fields: fields{
+				c:       mocks.NewConnector(t),
+				version: "3",
+			},
+			args: args{
+				ctx:     context.Background(),
+				payload: &model.ValidationOptionsForUpdateScheme{
+					// populate the payload fields
+				},
+			},
+			on: func(fields *fields) {
+				client := fields.c.(*mocks.Connector)
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"rest/api/3/workflows/update/validation",
+					"", &model.ValidationOptionsForUpdateScheme{}).
+					Return(&http.Request{}, nil)
+				client.On("Call",
+					&http.Request{},
+					&model.WorkflowValidationErrorListScheme{}).
+					Return(nil, errors.New("error, API call failed"))
+			},
+			want:    nil,
+			want1:   nil,
+			wantErr: assert.Error,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+
+			if tt.on != nil {
+				tt.on(&tt.fields)
+			}
+
+			newService, err := NewWorkflowService(tt.fields.c, tt.fields.version, nil, nil)
+			assert.NoError(t, err)
+
+			got, got1, err := newService.ValidateUpdateWorkflows(tt.args.ctx, tt.args.payload)
+			if !tt.wantErr(t, err, fmt.Sprintf("ValidateUpdateWorkflows(%v, %v)", tt.args.ctx, tt.args.payload)) {
+				return
+			}
+			assert.Equalf(t, tt.want, got, "ValidateUpdateWorkflows(%v, %v)", tt.args.ctx, tt.args.payload)
+			assert.Equalf(t, tt.want1, got1, "ValidateUpdateWorkflows(%v, %v)", tt.args.ctx, tt.args.payload)
+		})
+	}
+}