Skip to main content
Version: Next

Actions Library - Quality Document Manager

Overview

The QDM actions library contains all the server handlers that manage the lifecycle of quality documents. These handlers are triggered by user actions in the web interface.

Covered functionalities

This library enables the following business operations:

  1. Document management

    • Create a new document with automatic reference calculation
    • Retrieve and apply document type configuration
    • Manage document versions and archiving
    • Search and display parent documents
  2. Training management

    • Automatically create a training session for a document
    • Verify that training is published before validation
    • Delete obsolete training
  3. Binder management (document collections)

    • Add or remove documents from a binder
    • Reorganize document order in a binder
    • Generate consolidated PDF of all binder documents
  4. Distribution management

    • Send a document to a group of recipients
    • Track acknowledgments of receipt
    • Remind users who haven't confirmed reading
    • Generate distribution vouchers
  5. Export and printing

    • Export attachments to ZIP archive
    • Compare two document versions as PDF
    • Generate Excel or PDF exports of document lists

Operating principle

Each user action (document validation, training creation, distribution sending) triggers a server handler. These handlers are organized in .ashx files (handlers) that execute the necessary operations and return the result to the user interface.


Actions structure

File locations

Action files are organized by module:

2.Avancé/Web/Custom/
├── QDM/
│ ├── Document/
│ │ └── DocumentManager.ashx # Main document manager
│ ├── Classeur/
│ │ └── BinderHandler.ashx # Binder management
│ ├── TableauxDeDetails/
│ │ └── TabManager.ashx # Detail tables management
│ └── QDMLSHandler.ashx # Document collection manager
├── EXTEND/
│ ├── ModuleBureautique/Office/
│ │ ├── Actions.ashx # Office module actions
│ │ ├── Auth.ashx # Office authentication
│ │ ├── Handler.ashx # Main Office handler
│ │ ├── OfficeTemplate.ashx # Office template management
│ │ └── PluginHandler.ashx # Office plugin handler
│ ├── ViewLink/
│ │ └── Actions.ashx # View actions
│ ├── Survey/
│ │ └── Handlers/
│ │ └── SurveyHandler.ashx # Survey management
│ ├── CompareFile/
│ │ └── PDFExport.ashx # PDF comparison export
│ ├── ExportPJs/
│ │ └── ZipHandler.ashx # Attachment ZIP export
│ └── Help/
│ └── OnlineHelp.ashx # Online help
└── Modules/Distribution/
└── DistributionActions.ashx # Distribution actions

Main QDM actions

DocumentManager.ashx

Path: Custom/QDM/Document/DocumentManager.ashx

Business functionalities: This handler centralizes all quality document lifecycle operations.

Covered business needs

1. Automatic configuration by document type

Need: Each document type (Procedure, Instruction, Form) has specific rules (classification level, validity duration, validation workflow).

Solution: The system automatically retrieves these rules and applies them to the document.

2. Automatic document referencing

Need: Each document must have a unique reference calculated according to business rules (prefix by type, sequential numbering, etc.).

Solution: The system automatically calculates the reference during creation.

Need: Certain critical documents require mandatory training before implementation.

Solution: The system automatically creates the training session and verifies it's published before document validation.

4. Obsolete document archiving

Need: Maintain complete history of documents and their versions for audits.

Solution: The system archives the document and all its versions while preserving traceability.

Available actions

ActionParametersDescriptionReturn
GetConfigtype (string)Retrieves document type configurationJSON: {isExist, NIVEAU}
GetTrainingRefDoc (string)Retrieves training associated with documentJSON: {isExist, isPublished, reference}
CreateTrainingIdDoc, RefDocAutomatically creates a training sessionJSON: {success, trainingId}
DeleteTrainingRefDocDeletes associated trainingJSON: {success}
GetDocumentParentIdDocRetrieves parent documentJSON: Parent document
CalculateReferenceIdType, NiveauCalculates reference for new documentJSON: {reference}
GetPreviousVersionIdDocRetrieves previous document versionJSON: Previous version
ArchiveDocumentIdDocArchives document and its versionsJSON: {success}

Usage examples

Example 1: Automatic application of document type configuration

Business scenario

A quality manager creates a new "Procedure" type document. The system must automatically apply the rules defined for this type (classification level "Confidential", validity duration 2 years, etc.).

// When the user selects "Procedure" type from the dropdown
var type = APSGetFieldValueByName("ApsType");

// System queries the database to retrieve rules for this type
var config = JSON.parse(
HandlerRequest("Custom/QDM/Document/DocumentManager", "GetConfig",
"&type=" + encodeURI(type))
);

// If rules exist for this type, they are automatically applied
if (!config.isError && config.data.isExist) {
APSSetFieldValueByName("Niveau", config.data.NIVEAU);
console.log("Configuration loaded for type: " + type);
}

Business benefit: The quality manager doesn't need to memorize all the rules. The system applies them automatically, ensuring compliance and avoiding input errors.

Example 2: Verify training existence

// Verify training existence
var ref = APSGetFieldValueByName("reference");
var training = JSON.parse(
HandlerRequest("Custom/QDM/Document/DocumentManager", "GetTraining",
"&RefDoc=" + ref)
);

if (!training.isError && training.data.isExist) {
console.log("Training found: " + training.data.reference);
}

Standard response format

{
"isError": false,
"message": "",
"data": {
// Action-specific data
}
}

BinderHandler.ashx

Path: Custom/QDM/Classeur/BinderHandler.ashx

Objective: Management of document binders (document collections).

Available actions

ActionParametersDescriptionReturn
GetBinderDocumentsIdBinderRetrieves list of documents in a binderJSON: Document list
AddDocumentToBinderIdBinder, IdDocAdds document to binderJSON: {success}
RemoveDocumentFromBinderIdBinder, IdDocRemoves document from binderJSON: {success}
ReorderDocumentsIdBinder, order[]Reorders binder documentsJSON: {success}
GenerateBinderPDFIdBinderGenerates consolidated binder PDFJSON: {success, fileUrl}

TabManager.ashx

Path: Custom/QDM/TableauxDeDetails/TabManager.ashx

Objective: Management of detail tables in forms.

Available actions

ActionParametersDescriptionReturn
GetTableDataIdDoc, TableNameRetrieves table dataJSON: Table data
AddRowIdDoc, TableName, dataAdds row to tableJSON: {success, rowId}
UpdateRowIdDoc, TableName, rowId, dataUpdates a rowJSON: {success}
DeleteRowIdDoc, TableName, rowIdDeletes a rowJSON: {success}

EXTEND actions

ModuleBureautique - Actions.ashx

Path: Custom/EXTEND/ModuleBureautique/Office/Actions.ashx

Objective: Actions related to Office document editing in the browser.

Available actions

ActionParametersDescriptionReturn
OpenDocumentIdDoc, FileNameOpens Office document for editingJSON: {url, token}
SaveDocumentIdDoc, FileName, contentSaves edited documentJSON: {success}
CheckOutIdDoc, FileNameLocks document for editingJSON: {success, lockedBy}
CheckInIdDoc, FileNameUnlocks document after editingJSON: {success}
CancelCheckOutIdDoc, FileNameCancels lock without savingJSON: {success}
GetTemplatesformularIdRetrieves available Office templatesJSON: Template list
GenerateFromTemplateIdDoc, templateIdGenerates document from templateJSON: {success, fileUrl}

Usage example

// Open Word document for editing
var response = JSON.parse(
HandlerRequest("Custom/EXTEND/ModuleBureautique/Office/Actions",
"OpenDocument",
"&IdDoc=" + IdDoc + "&FileName=" + encodeURI(fileName))
);

if (!response.isError) {
window.open(response.data.url, '_blank');
}

Survey - SurveyHandler.ashx

Path: Custom/EXTEND/Survey/Handlers/SurveyHandler.ashx

Objective: Management of surveys and evaluations.

Available actions

ActionParametersDescriptionReturn
GetQuestionsIdSurveyRetrieves survey questionsJSON: Question list
SaveResponseIdSurvey, IdUser, responsesSaves user responsesJSON: {success, score}
GetResultsIdSurvey, IdUserRetrieves user resultsJSON: Detailed results
CalculateScoreIdSurvey, responsesCalculates survey scoreJSON: {score, isPassed}
GenerateCertificateIdSurvey, IdUserGenerates success certificateJSON: {success, certificateUrl}

Path: Custom/EXTEND/ViewLink/Actions.ashx

Objective: Custom actions on views (document lists).

Available actions

ActionParametersDescriptionReturn
BulkValidateIdDocs[]Validates multiple documents in bulkJSON: {success, count}
BulkArchiveIdDocs[]Archives multiple documents in bulkJSON: {success, count}
BulkDistributeIdDocs[], recipientsDistributes multiple documents in bulkJSON: {success, count}
ExportToExcelviewId, filtersExcel export of view with filtersExcel file
ExportToPDFviewId, filtersPDF export of view with filtersPDF file

Distribution actions

DistributionActions.ashx

Path: Modules/Distribution/DistributionActions.ashx

Objective: Management of document distribution actions.

Available actions

ActionParametersDescriptionReturn
SendDistributionIdDoc, recipients[], typeSends a distributionJSON: {success, distributionId}
GetDistributionStatusdistributionIdDistribution statusJSON: Detailed status
GetAcknowledgementsIdDoc, distributionIdList of distribution acknowledgmentsJSON: AR list
RemindUsersdistributionId, userIds[]Reminds users for acknowledgmentJSON: {success, remindedCount}
CancelDistributiondistributionIdCancels a distributionJSON: {success}
GenerateVoucherdistributionIdGenerates paper distribution voucherPDF

Utility actions

PDFExport.ashx

Path: Custom/EXTEND/CompareFile/PDFExport.ashx

Objective: PDF document export and comparison.

Available actions

ActionParametersDescriptionReturn
ComparePDFfile1, file2Compares two PDF versionsPDF with differences
ExportWithWatermarkIdDoc, watermarkExports PDF with watermarkPDF
MergePDFsfiles[]Merges multiple PDFsMerged PDF

ZipHandler.ashx

Path: Custom/EXTEND/ExportPJs/ZipHandler.ashx

Objective: Export attachments to ZIP archive.

Available actions

ActionParametersDescriptionReturn
ExportAttachmentsIdDocExports all attachments of a documentZIP file
ExportMultipleDocumentsIdDocs[]Exports multiple documents and their attachmentsZIP file

Security and best practices

Authentication

Business challenge: Ensure only authorized users can perform actions on quality documents (creation, modification, validation, archiving). This meets audit and traceability requirements of quality standards (ISO 9001, etc.).

Control implemented: All handlers verify user identity before executing any operation.

// Systematic authentication control
if (!Context.User.Identity.IsAuthenticated)
{
// Access denied if user is not identified
return JsonResponse.Error("User not authenticated");
}

Use cases:

  • User tries to validate document without being logged in → Action refused
  • Logged-in user initiates distribution → Action authorized and logged with their identity
  • Session expires during input → User must reconnect before saving

Parameter validation

Why it's important: Data sent from the browser can be incorrect or even malicious. Always verify it's valid before use, like checking a phone number contains only digits.

Received parameters must always be validated before use:

// Document ID validation
int idDoc;
// Try to convert parameter to integer
if (!int.TryParse(Context.Request["IdDoc"], out idDoc) || idDoc <= 0)
{
// If conversion fails or number is negative, refuse
return JsonResponse.Error("Invalid document ID");
}

What is verified:

  • Does the parameter exist?
  • Is it the correct type? (text, number, date, etc.)
  • Is it within acceptable value range?
  • Does it contain no dangerous characters?

Error handling

Why it's important: When something doesn't go as expected, clearly inform the user interface what went wrong. This allows displaying an understandable error message to the user instead of simply "crashing".

Standardized error response format used by all handlers:

{
"isError": true,
"message": "Error description",
"data": null
}

Response structure:

  • isError: a boolean (true/false) indicating if an error occurred
  • message: explanatory text of the error (e.g., "Document not found", "Insufficient rights")
  • data: requested data (null in case of error)

Concrete example: If a user tries to open a non-existent document, the handler returns {"isError": true, "message": "Document #12345 does not exist", "data": null} and the interface can display a clear message to the user.

Logs

Why record logs?

Logs are like an application logbook. They allow tracing who did what and when, which is essential for debugging, security, and auditing. If a problem occurs, logs help trace the sequence of events to understand what happened.

Important actions must be recorded in logs:

// Record important information
Logger.Info($"Document {idDoc} validated by user {Context.User.Identity.Name}");

When to log?

  • When a document is created, modified, validated, archived
  • When a user performs an important action
  • When an error occurs (with error details)
  • When a sensitive operation is performed (rights change, deletion, etc.)

Different log levels:

  • Logger.Info(): Normal operation (e.g., "Document created")
  • Logger.Warning(): Abnormal but non-blocking situation (e.g., "Missing training")
  • Logger.Error(): Error preventing operation (e.g., "Cannot access database")

Creating a new action

Basic handler structure

File: CustomAction.ashx

<%@ WebHandler Language="C#" Class="CustomAction" %>

using System;
using System.Web;
using Avanteam.Kernel;
using Avanteam.Documents;

public class CustomAction : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
try
{
// Authentication verification
if (!context.User.Identity.IsAuthenticated)
{
context.Response.Write(JsonResponse.Error("Not authenticated"));
return;
}

// Retrieve requested action
string action = context.Request["action"];

switch (action)
{
case "GetData":
GetData(context);
break;
case "SaveData":
SaveData(context);
break;
default:
context.Response.Write(JsonResponse.Error("Unknown action"));
break;
}
}
catch (Exception ex)
{
Logger.Error($"CustomAction error: {ex.Message}", ex);
context.Response.Write(JsonResponse.Error(ex.Message));
}
}

private void GetData(HttpContext context)
{
// GetData action implementation
int idDoc = int.Parse(context.Request["IdDoc"]);

// Data retrieval
var data = DocumentHelper.GetDocument(idDoc);

// JSON return
context.Response.Write(JsonResponse.Success(data));
}

private void SaveData(HttpContext context)
{
// SaveData action implementation
int idDoc = int.Parse(context.Request["IdDoc"]);
string value = context.Request["value"];

// Save
DocumentHelper.UpdateField(idDoc, "FieldName", value);

// JSON return
context.Response.Write(JsonResponse.Success(new { saved = true }));
}

public bool IsReusable
{
get { return false; }
}
}

JavaScript call

// GetData action call
var result = JSON.parse(
HandlerRequest("Custom/Module/CustomAction", "GetData",
"&IdDoc=" + idDoc)
);

if (!result.isError) {
console.log("Data retrieved", result.data);
} else {
console.error("Error", result.message);
}

Utility class: JsonResponse

Location: App_Code/JsonResponse.cs

Helper class to standardize JSON responses.

Available methods

public static class JsonResponse
{
// Success response
public static string Success(object data)
{
return Serialize(new { isError = false, message = "", data });
}

// Error response
public static string Error(string message)
{
return Serialize(new { isError = true, message, data = (object)null });
}

// Custom response
public static string Custom(bool isError, string message, object data)
{
return Serialize(new { isError, message, data });
}

private static string Serialize(object obj)
{
return Newtonsoft.Json.JsonConvert.SerializeObject(obj);
}
}

Usage

// Success
context.Response.Write(JsonResponse.Success(new {
id = 123,
name = "Document"
}));

// Error
context.Response.Write(JsonResponse.Error("Document not found"));

// Custom
context.Response.Write(JsonResponse.Custom(false, "Warning", warningData));

Action debugging

Developer console

Handler calls can be viewed in the console:

console.log("Handler call:", "CustomAction", "GetData", params);
var result = HandlerRequest("Custom/Module/CustomAction", "GetData", params);
console.log("Result:", result);

Server logs

Server logs are located in:

  • App_Data/Logs/ for application logs
  • IIS logs for HTTP requests

Browser network tools

Use the "Network" tab of developer tools to see:

  • Sent parameters
  • JSON response
  • Processing time
  • Any HTTP errors

Performance and optimization

Cache

Use cache for frequently accessed data:

string cacheKey = $"Config_{type}";
var config = HttpContext.Current.Cache[cacheKey];
if (config == null)
{
config = LoadConfigFromDatabase(type);
HttpContext.Current.Cache.Insert(cacheKey, config, null,
DateTime.Now.AddMinutes(30), Cache.NoSlidingExpiration);
}
return config;

Asynchronous requests

For long processes, prefer asynchronous requests:

// Start long process
var jobId = StartLongProcess();

// Status polling
var interval = setInterval(function() {
var status = CheckJobStatus(jobId);
if (status.isCompleted) {
clearInterval(interval);
console.log("Process completed");
}
}, 1000);

Navigation: