Barcode
Camunda

Barcode
Camunda


Download Barcode_C8.ts.zip file ⤳ case study requires Node.js TypeScript

Requirements

From the barcode photography of a food product, the BPMN process extracts the barcode (EAN-13 format for simplification) as a string

If extraction succeeds then the checksum is computed and checked against the 13th number in the barcode

If checksum is correct then the country of the food product is computed from a BPMN business rule task, which is itself backed by a DMN diagram including a decision table

In parallel, the nutri-score of the food product is retrieved from https://world.openfoodfacts.org

Camunda Modeler process application

│   .barcode # Node.js environment var. including the location of Camunda 8 Run
│   .process-application # Camunda Modeler config. file to deploy all BPMN/DMN files in one shot
│   package.json # Node.js config. file using quaggaJS lib. (https://serratus.github.io/quaggaJS)
│   README.md
│   tsconfig.json # TypeScript compiler options
│
├───resources
│       Barcode.bpmn # Once Camunda 8 Run launched, deploy and next instantiate it in Camunda Modeler
│       Get_barcode_country.dmn # Automatically deployed when deploying "Barcode.bpmn"
│
└───ts # TypeScript code as client app. of Camunda 8 Run
        Barcode.ts # Main program
        Extract_barcode_EAN_13_from_photography.ts # Use of quaggaJS lib.
        Globals.d.ts # TypeScript compiler shim for quaggaJS lib.

DMNDecision Requirement Diagram -DRD-

DMN ⤳ decision table (rule order hit policy*)

*As an example, “France” (rule 2) and “Monaco” (rule 4) share the same rule premise; rule order hit policy then generates a list: [{“France”, 250}, {“Monaco”, 492}]

DMN ⤳ input of decision table

DMN ⤳ output of decision table

BPMN ⤳ diagram

Business rule task

Product ⤳ and

Data ⤳

Process variable

Job worker ⤳ diagram

BPMN error

Job workerNode.js code

class Photography extends Dto.LosslessDto { photography?: string }
class Barcode_EAN_13 extends Dto.LosslessDto { barcode_EAN_13?: string }
const Extract_barcode_EAN_13_from_photography = client.createJobWorker<Photography, Barcode_EAN_13>({
    type: 'Extract_barcode_EAN_13_from_photography', // 'type' field in model...
    timeout: 10000, // Timeout for the job worker to complete the job before it is available for another worker poll...
    maxJobsToActivate: 5, // Maximum number of jobs to process concurrently...
    worker: 'Extract_barcode_EAN_13_from_photography worker',
    jobHandler: async (job, log) => {
        console.assert(job.variables.photography, "'job.variables.photography' untrue");
        const barcode_EAN_13: null | string = await _Extract_barcode_EAN_13_from_photography(job.variables.photography);
        if (barcode_EAN_13) return job.complete({barcode_EAN_13: barcode_EAN_13});
        return job.error({variables: {}, errorCode: "extraction_error"}); // BPMN error...
    }
});

Rest outbound connector ⤳ URL

Rest outbound connector ⤳ result (nutri_score)

Rest outbound connector ⤳ execution listener

Execution listenerNode.js code

class Nutri_Score extends Dto.LosslessDto { nutri_score?: string; }
const Retrieve_Nutri_Score = client.createJobWorker<Nutri_Score, any>({
    type: 'Retrieve_Nutri_Score',
    timeout: 10000,
    maxJobsToActivate: 5,
    worker: 'Retrieve_Nutri_Score END execution listener',
    jobHandler: (execution_listener, log) => {
        console.assert(execution_listener.variables.nutri_score, "'execution_listener.variables.nutri_score' untrue");
        console.info("Nutri-Score: " + execution_listener.variables.nutri_score);
        return execution_listener.complete();
    }
});

BPMN ⤳ execution

© BarbierDarnal.com