Good morning, I’d like to share a small Node.js script that bulk-closes all the error tasks in a workflow. This saves you from having to open each individual task, close it, and confirm manually. Hope it comes in handy. Have a great day! 


const axios = require("axios");
const { wrapper } = require("axios-cookiejar-support");
const { CookieJar } = require("tough-cookie");
const qs = require("qs");

const DOCUWARE_BASE = "https://yourdocuwareurl/DocuWare/Platform";
const USERNAME = "whatever";
const PASSWORD = "whatever";
const HOST_ID = "5e2aff28-c837-4484-acb8-e13fabca410c"; //just any valid guid 
const workflowGuid= "7aedfb48-8ae5-4f41-aadd-c07724c93d77"; //workflow guid

axios.defaults.timeout = 30000; // aumenta la tolleranza

const jar = new CookieJar();

const client = wrapper(
  axios.create({
    baseURL: DOCUWARE_BASE,
    jar,
    withCredentials: true,
    headers: {
      "Accept": "application/json"
    }
  })
);

// ------------------------------------------------------------
// RETRY AUTOMATICO con attesa progressiva
// ------------------------------------------------------------
async function safeRequest(requestFn, maxRetries = 5, delayMs = 2000) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await requestFn();
    } catch (err) {
      const code = err.code;
      const status = err.response?.status;

      const isNetworkError =
        code === "ETIMEDOUT" ||
        code === "ECONNRESET" ||
        code === "EAI_AGAIN";

      const isServerError =
        status === 500 ||
        status === 502 ||
        status === 503 ||
        status === 504;

      if (isNetworkError || isServerError) {
        console.log(
          `⚠️ attempt ${attempt}/${maxRetries} failed (${code || status}).`
        );
        console.log(`⏳ wait ${delayMs}ms and retry...`);

        await new Promise((resolve) => setTimeout(resolve, delayMs));

        delayMs = Math.floor(delayMs * 1.5);
        continue;
      }
      throw err;
    }
  }

  throw new Error("❌ Too many attempts failed.");
}

// ------------------------------------------------------------
// LOGIN
// ------------------------------------------------------------
async function docuwareLogin() {
  const formBody = qs.stringify({
    UserName: USERNAME,
    Password: PASSWORD,
    Organization: "",
    RedirectToMyselfInCaseOfError: false,
    RememberMe: false,
    HostID: HOST_ID,
    LicenseType: "PlatformService"
  });

  try {
    await safeRequest(() =>
      client.post("/Account/Logon", formBody, {
        headers: {
          "Content-Type": "application/x-www-form-urlencoded",
          "Accept": "application/json"
        }
      })
    );

    console.log("🔐 Login OK");
  } catch (err) {
    console.log("❌ Login failed:", err.response?.data || err.message);
    process.exit(1);
  }
}

// ------------------------------------------------------------
// LOGOUT
// ------------------------------------------------------------
async function logout() {
  try {
    await safeRequest(() => client.get("/Account/Logoff"));
    console.log("🚪 Logout OK");
  } catch (err) {
    console.log("⚠️ Logout failed:", err.response?.data || err.message);
  }
}

// ------------------------------------------------------------
// get 200 TASK
// ------------------------------------------------------------
async function getNextTasksPage(url) {
  const res = await safeRequest(() => client.get(url));

  const tasks = res.data.Task || [];
  const nextLink = res.data.Links?.find((l) => l.rel === "next");

  let nextUrl = null;
  if (nextLink) {
    nextUrl = nextLink.href
      .replace("/DocuWare/Platform", "")
      .replace("count=50", "count=200");
  }

  return { tasks, nextUrl };
}

// ------------------------------------------------------------
// PROCESS TASK
// ------------------------------------------------------------
async function processTask(task, workflowGuid) {
  console.log(`\n➡️ Task: ${task.Id} — ${task.DisplayName}`);

  const instanceRes = await safeRequest(() =>
    client.get(
      `/Workflow/Workflows/${workflowGuid}/Instances/${task.InstanceId}/Tasks/${task.Id}`
    )
  );

  //console.log("   Stato:", instanceRes.data.State);
  console.log("   ⛔ close task…");

  let linkCloseAction =
    instanceRes.data.Decisions[2].DecisionOperations.BaseDecisionOperations
      .Links[0].href;

  linkCloseAction = linkCloseAction.replace("/DocuWare/Platform", "");

  const confirmscreen = await safeRequest(() => client.get(linkCloseAction));

  let confirmAction =
    confirmscreen.data.DecisionOperations.ExtendedDecisionOperations.Links[0]
      .href;

  confirmAction = confirmAction.replace("/DocuWare/Platform", "");

  const jsonBody = { ConfirmedFields: [] };

  await safeRequest(() =>
    client.post(confirmAction, jsonBody, {
      headers: {
        "Content-Type": "application/json",
        "Accept": "application/json",
        "X-Requested-With": "XMLHttpRequest"
      }
    })
  );

  console.log("   ✅ Task chiusa");
}

async function processAllTasks(workflowGuid) {
  let nextUrl = `/Workflow/Workflows/${workflowGuid}/Tasks?count=200`;
  let page = 1;

  while (nextUrl) {
    console.log(`\n📦 Pagina ${page}: load tasks block…`);

    const { tasks, nextUrl: newNextUrl } = await getNextTasksPage(nextUrl);

    console.log(`➡️ ${tasks.length} task trovate`);

    for (const task of tasks) {
      await processTask(task, workflowGuid);
    }

    nextUrl = newNextUrl;
    page++;
  }

  console.log("\n🎉 Task completed!");
}

// ------------------------------------------------------------
// MAIN
// ------------------------------------------------------------
async function main() {
  await docuwareLogin();

  try {
    await processAllTasks(workflowGuid);
  } catch (err) {
    console.error("\n❌ ERRORE GENERALE:", err.response?.data || err.message);
  } finally {
    await logout();
  }
}

main();