Table des matières

Documentation pour écrire un script custom (LUA)

Squelette du script

-- script title
--- FR = script name in french
--- EN = script name in english
-- ...
-- parameters
--# param1: string | FR = parameter name in french | EN = parameter name in english | ...
--# param2: boolean = True | FR = parameter name in french | EN = parameter name in english | ...
-- ...
-- modules
--% module1 | FR = module name in french | EN = module name in english | ...
--% module1 = True | FR = module name in french | EN = module name in english | ...
-- ...

-- business code


return true or false

Titre du script

--- country_alpha2 = title
--- country_alpha2 = title
...

example

--- EN = My title
--- FR = Mon titre
--- ES = Mi título

Si la langue cible n'est pas disponible, EN est utilisé, sinon le premier disponible est utilisé

Paramètres

--% module | country_alpha2 = name | country_alpha2 = name
--% module2 = bool | country_alpha2 = name | country_alpha2 = name
...

params_name: Nom de variable compatible LUA

Un paramètre est une variable accessible dans le script de la même facon qu'un paramètre de fonction d'un langage de programmation

Il ne sert pas a définir les tests (cf. Module), ils servent a définir le comportement du code

Modules (référence pour les script)

--# abc | FR = name | EN = name
--# def = true | ES = name | AU = name
...

un module n'est PAS une variable accessible, c'est une référence pour les tests

Il définissent les tests qui seront enregistrés dans le rapport archivé

Une référence peut être utilisée plusieurs fois dans le script, le résultat final sera un OU logique entre tous les retours de la référence

Le nom final d'une référence est consitué de tous ces composants nécéssaires + le nom de la référence

exemple

  1. un script travaillant sur IDENTITY_DOCUMENT avec une référence nommé name et first_name aura comme noms de références IDENTITY_DOCUMENT.name et IDENTITY_DOCUMENT.first_name
  2. un script travaillant sur IDENTITY_DOCUMENT et la donnée name avec une référence nommé name et first_name aura comme noms de références IDENTITY_DOCUMENT.name.name et IDENTITY_DOCUMENT.name.first_name
  3. un script travaillant sur X et Y et la donnée i rt j avec une référence nommé name et first_name aura comme noms de références X.Y.i.j.name et X.Y.i.j.first_name

Services

Un service permet l'appel à des compsants externes pour certains traitements particuliers

Ci-dessous la liste des services disponibles ainsi que leur documentation extraite automatiquement

Exemple:

services.email.verify(input.data.email[0], false, false)

email

services.email.verify(email: Any, check_mx: Any = True, check_server_respond: Any = False)

Verify the regex and domain of an email

inpi

services.inpi.by_siret(siret: str)

Get the information on a company from INPI

services.inpi.by_siren(siren: str)

Get the information on a company from INPI

country

services.country.country_exists(country: Any)

From the name of a country, find all the real country that match the name

Données fournies en entrée du script

Les données fournies par le moteur sont dans le champ input

local name = input.data.name

Données pouvant être fournies en sortie du script

Les données fournies au moteur sont dans le champ output

output.identity.name = real_name
output.valid[doc.name] = true

Functions utilisables dans le script

check

check(
	doc: PersonalDetails | MRZDocument | DocumentWrapper
	field: str | list[str]
	fn: bool (list[str] | Any)
	ref: str
	parse: bool = False
	hide: bool = False
	all_values: bool = False
)

Verify the validity of a field with the function given

check_concat

check_concat(
	doc: DocumentWrapper
	field: str | list[str]
	fn: bool (list[str] | Any)
	ref: str
	hide: bool = False
	parse: bool = False
	allow_missing_field: bool = False
)

Verify the validity of the concatenation of multiple field with the function given

compare

compare(
	doc1: PersonalDetails | MRZDocument | dict
	field1: str | list[str]
	doc2: DocumentWrapper | dict
	field2: str | list[str]
	fn: float (str | str)
	tr: int
	ref: str
	parse: bool = False
	hide: bool = False
)

Compare 2 fields from 2 different document

contains

contains(
	_list: list[Any]
	item: Any
)

Test if y is contains in x

correct

correct(
	ref: str = ""
	doc: DocumentWrapper
	field: str | list[str]
	fn: str (str)
	ref: str = ""
	hide: bool = False
)

Correct a field in a document following the function given. The result of the correction replace the old value

create_date_mask

create_date_mask(
	d: str
	date_format: Any = "%y%m%d"
)

Create a valid mask for the date given (ex: 1990 -> YYYY, 901212 -> YYMMDD)

custom_info

custom_info(
	infos: list[tuple[str | Any]]
	is_valid: Any
	ref: Any
	threshold: Any = None
	score: Any = None
)

Write a bloc to indicate the state of a custom verification

error_type

error_type(
	error: Exception
)

Get the name of a python exception

fuzzy

fuzzy(
	x: str
	y: str
	ignore_special_chars: bool = True
)

Do a string compare with the algorithme fuzzy search

generator

generator(
	co: list[Any]
)

Make a python coroutine usable. Available: #(...), .first(), .all()

get_value

get_value(
	doc: DocumentWrapper
	field: str | list[str]
	parse: bool = False
)

Get the value of a field in a document

is_available

is_available(
	doc: DocumentWrapper
	field: str
)

Determine if the field is available in a document

list

list(
	x: list[Any]
)

convert a list from lua to python

parse_date

parse_date(
	
)

save_error

save_error(
	codes: list[tuple[EnrollmentStatusCodeEnum | str] | ErrorCodeException | EnrollmentStatusCode]
)

throw

throw(
	code: EnrollmentStatusCodeEnum
	msg: str = ""
)

Raise a python ErrorCodeException containing an EnrollmentStatusCode created with the code and message given

to_lua

to_lua(
	x: Any
)

convert an object from python to LUA

Enums

EnrollmentStatusCodeEnum

MRZDocumentType

Lua modules allowed

Définition des classes utilisés pour les données pivots

BANK_DETAILS

BANK_DETAILS(
	services: dict[str | dict] | null, 
	iban: str | null, 
	full_name: str | null, 
	bic: str | null, 
	dmx_full_name: str | null, 
	dmx_iban: str | null, 
	dmx_bic: str | null
)

CAR_REGISTRATION

CAR_REGISTRATION(
	services: dict[str | dict] | null, 
	mrz_document_format: str | null, 
	mrz_issuing_country: str | null, 
	mrz_type: str | null, 
	mrz_valid: str | null, 
	mrz_line1: str | null, 
	mrz_line2: str | null, 
	mrz_document_number: str | null, 
	mrz_id_vehicle_number: str | null, 
	mrz_registration_date: date | null, 
	mrz_national_type: str | null, 
	mrz_vehicle_body: str | null, 
	mrz_brand: str | null, 
	mrz_denomination: str | null, 
	mrz_last_digit: str | null, 
	mrz_formula_number: str | null, 
	A: str | null, 
	B: date | null, 
	C1: str | null, 
	C3: str | null, 
	C41_n_owners: str | null, 
	C41_co_owner: str | null, 
	D1: str | null, 
	D2: str | null, 
	D21: str | null, 
	D3: str | null, 
	E: str | null, 
	F1: str | null, 
	F2: str | null, 
	F3: str | null, 
	G: str | null, 
	G1: str | null, 
	H: str | null, 
	I: date | null, 
	J: str | null, 
	J1: str | null, 
	J2: str | null, 
	J3: str | null, 
	K: str | null, 
	P1: str | null, 
	P2: str | null, 
	P3: str | null, 
	P6: str | null, 
	Q: str | null, 
	S1: str | null, 
	S2: str | null, 
	U1: str | null, 
	U2: str | null, 
	V7: str | null, 
	V9: str | null, 
	X1: date | null, 
	Y1: str | null, 
	Y2: str | null, 
	Y3: str | null, 
	Y4: str | null, 
	Y5: str | null, 
	Y6: str | null, 
	Z1: str | null, 
	Z2: str | null, 
	Z3: str | null, 
	Z4: str | null
)

DIGITAL_IDENTITY

DIGITAL_IDENTITY(
	services: dict[str | dict] | null, 
	type: str | null, 
	name: str | null, 
	email: str | null, 
	phone_number: str | null, 
	birth_name: str | null, 
	first_name: str | null, 
	first_names: list[str] | null, 
	address: str | null, 
	zip_code: str | null, 
	city: str | null, 
	country: str | null, 
	birth_date: date | null, 
	birth_date_mask: str | null, 
	gender: str | null, 
	birth_place: str | null, 
	birth_country: str | null, 
	nationality: str | null, 
	dmx_first_names: list[str] | null, 
	dmx_name: str | null, 
	dmx_nationality: str | null, 
	dmx_gender: str | null, 
	dmx_type: str | null, 
	dmx_birth_country: str | null, 
	extra: IdentityExtractedDataExtra | null, 
	nfc_compatible: bool | null
)

DIGITAL_IDENTITY_EXTRA

DIGITAL_IDENTITY_EXTRA(
	id_number: str | null, 
	issuing_date: datetime | null, 
	expiration_date: datetime | null, 
	issuing_country: str | null, 
	issuer: str | null, 
	address: str | null, 
	dmx_id_number: str | null, 
	dmx_signature_status: str | null, 
	mrz_line_1: str | null, 
	mrz_line_2: str | null, 
	mrz_line_3: str | null, 
	nfc_compatible: bool | null
)

HEALTH_INSURANCE_CARD

HEALTH_INSURANCE_CARD(
	services: dict[str | dict] | null, 
	full_name: str | null, 
	amc: str | null, 
	csr: str | null, 
	adherent_number: str | null, 
	convention: str | null, 
	starting_date: date | null, 
	ending_date: date | null
)

IDENTITY

IDENTITY(
	services: dict[str | dict] | null, 
	type: str | null, 
	name: str | null, 
	email: str | null, 
	phone_number: str | null, 
	birth_name: str | null, 
	first_name: str | null, 
	first_names: list[str] | null, 
	address: str | null, 
	zip_code: str | null, 
	city: str | null, 
	country: str | null, 
	birth_date: date | null, 
	birth_date_mask: str | null, 
	gender: str | null, 
	birth_place: str | null, 
	birth_country: str | null, 
	nationality: str | null, 
	dmx_first_names: list[str] | null, 
	dmx_name: str | null, 
	dmx_nationality: str | null, 
	dmx_gender: str | null, 
	dmx_type: str | null, 
	dmx_birth_country: str | null, 
	extra: IdentityExtractedDataExtra | null, 
	nfc_compatible: bool | null
)

IDENTITY_EXTRA

IDENTITY_EXTRA(
	id_number: str | null, 
	issuing_date: datetime | null, 
	expiration_date: datetime | null, 
	issuing_country: str | null, 
	issuer: str | null, 
	address: str | null, 
	dmx_id_number: str | null, 
	dmx_signature_status: str | null, 
	mrz_line_1: str | null, 
	mrz_line_2: str | null, 
	mrz_line_3: str | null, 
	nfc_compatible: bool | null
)

IDENTITY_DOCUMENT

IDENTITY_DOCUMENT(
	services: dict[str | dict] | null, 
	type: str | null, 
	name: str | null, 
	email: str | null, 
	phone_number: str | null, 
	birth_name: str | null, 
	first_name: str | null, 
	first_names: list[str] | null, 
	address: str | null, 
	zip_code: str | null, 
	city: str | null, 
	country: str | null, 
	birth_date: date | null, 
	birth_date_mask: str | null, 
	gender: str | null, 
	birth_place: str | null, 
	birth_country: str | null, 
	nationality: str | null, 
	dmx_first_names: list[str] | null, 
	dmx_name: str | null, 
	dmx_nationality: str | null, 
	dmx_gender: str | null, 
	dmx_type: str | null, 
	dmx_birth_country: str | null, 
	extra: IdentityExtractedDataExtra | null, 
	nfc_compatible: bool | null
)

IDENTITY_DOCUMENT_EXTRA

IDENTITY_DOCUMENT_EXTRA(
	id_number: str | null, 
	issuing_date: datetime | null, 
	expiration_date: datetime | null, 
	issuing_country: str | null, 
	issuer: str | null, 
	address: str | null, 
	dmx_id_number: str | null, 
	dmx_signature_status: str | null, 
	mrz_line_1: str | null, 
	mrz_line_2: str | null, 
	mrz_line_3: str | null, 
	nfc_compatible: bool | null
)

INCOME_TAX

INCOME_TAX(
	services: dict[str | dict] | null, 
	type: str | null, 
	full_name_1: str | null, 
	full_name_2: str | null, 
	due_date: date | null, 
	reference: str | null, 
	year: str | null, 
	tax_payer_id_number_1: str | null, 
	tax_payer_id_number_2: str | null, 
	taxable_income_reference: int | null, 
	signature_status: str | null
)

KBIS

KBIS(
	services: dict[str | dict] | null, 
	name: str | null, 
	address: str | null, 
	directions: list[dict], 
	issuing_date: date | null, 
	registration_date: date | null, 
	siren: str | null, 
	legal_form: str | null
)

PAY_SLIP

PAY_SLIP(
	services: dict[str | dict] | null, 
	siret: str | null, 
	ape: str | null, 
	nir: str | null, 
	hire_date: date | null, 
	period: date | null, 
	gross_income: float | null, 
	net_income: float | null, 
	net_taxable_income: float | null, 
	full_name: str | null, 
	address: str | null, 
	zip_code: str | null, 
	city: str | null, 
	company_address_1: str | null, 
	company_address_2: str | null, 
	company_address_3: str | null
)

PROOF_OF_ADDRESS

PROOF_OF_ADDRESS(
	services: dict[str | dict] | null, 
	full_name: str | null, 
	address_1: str | null, 
	address_2: str | null, 
	address_3: str | null, 
	zip_code: str | null, 
	city: str | null, 
	date: null, 
	dmx_full_name: str | null, 
	dmx_address_street: str | null, 
	dmx_address_complement: str | null, 
	dmx_zip_code: str | null, 
	dmx_city: str | null, 
	dmx_date: null
)

PROOF_OF_AGE

PROOF_OF_AGE(
	services: dict[str | dict] | null, 
	is_of_age: bool | null, 
	minimum_age: int | null
)

PROPERTY_TAX

PROPERTY_TAX(
	services: dict[str | dict] | null, 
	name: str | null, 
	first_name: str | null, 
	address_1: str | null, 
	address_2: str | null, 
	address_3: str | null, 
	zip_code: str | null, 
	city: str | null, 
	year: str | null
)

SOCIAL_SECURITY

SOCIAL_SECURITY(
	services: dict[str | dict] | null, 
	full_name: str | null, 
	social_security_number: str | null, 
	delivery_date: date | null, 
	expiration_date: date | null, 
	birth_date: date | null, 
	full_name_right_holder: str | null, 
	social_security_number_right_holder: str | null, 
	rgx_first_name: list[str], 
	rgx_surname: list[str], 
	rxg_birth_date: list[date], 
	rgx_social_security_number: list[str]
)

Définition des objets utilisés dans les scripts

DocumentWrapper

EnrollmentStatusCode

ErrorCodeException

IdentityDocument

IdentityExtractedDataExtra

PersonalDetails

Exemple

--- EN = Extract and verify the bank details
--- FR = Extraire et vérifier le RIB
--% iban_country | FR = Vérifier la validité du code pays de l'IBAN | EN = Check if IBAN country is valid
--% iban = True | FR = Vérifier que l'IBAN est correctement formé | EN = Verify that the IBAN is correctly formed
 
local uc= "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
local pc= "abcdefghijklmnopqrstuvwxyz"
local corrs = {}
for i = 1, #uc do
    corrs[uc:sub(i,i)] = i + 9
    corrs[pc:sub(i,i)] = i + 9
end
local function verify_iban(iban)
    -- How to MOD97
    -- https://www.iban.fr/calcul-chiffre-de-controle.html
    iban = iban:gsub("% ","")
    local iban_prep = iban:sub(5) .. iban:sub(0,2) .. "00"
    local verif = iban:sub(3,4)
    local mod97_str = {}
    for i = 1, #iban_prep do
        local c = iban_prep:sub(i,i)
        if c ~= " " then
            if corrs[c] ~= nil then
                table.insert(mod97_str, corrs[c])
            else
                table.insert(mod97_str, c)
            end
            if #(mod97_str) == 10 then
                local num = tonumber(table.concat(mod97_str)) % 97
                local num_str = string.format("%02d",num)
                mod97_str = { }
                for j = 1, #num_str do
                    table.insert(mod97_str,num_str:sub(j,j))
                end
            end
        end
    end
    local num = tonumber(table.concat(mod97_str)) % 97
    return verif + num - 98 == 0
end
 
local function verify_bank_details(bank_details)
    if bank_details.ignore_validation then
        return true
    end
    local full_name = get_value(bank_details, "FULL_NAME").first()
    local iban = get_value(bank_details, "IBAN").first()
    local bic = get_value(bank_details, "BIC").first()
    local dmx_full_name = get_value(bank_details, "DMX_FULL_NAME").first()
    local dmx_iban = get_value(bank_details, "DMX_IBAN").first()
    local dmx_bic = get_value(bank_details, "DMX_BIC").first()
 
    BANK_DETAILS(
            bank_details,
            iban,
            full_name,
            bic,
            dmx_full_name,
            dmx_iban,
            dmx_bic
    )
    local enrollment_valid = true
    local iban_key = dmx_iban ~= nil and "DMX_IBAN" or "IBAN"
    local iban = get_value(bank_details, iban_key).first()
    enrollment_valid = check(bank_details, iban_key, verify_iban, "iban") and enrollment_valid
    if iban ~= nil then
        local country = services.country.country_exists(iban:sub(1, 2))
        enrollment_valid = custom_info({ { "country", country } }, country ~= nil, "iban_country") and enrollment_valid
    else
        enrollment_valid = false
    end
    output.valid[bank_details.name] = enrollment_valid
    return enrollment_valid
end
 
local enrollment_valid = false
for _, group_of_docs in pairs(to_lua(input.BANK_DETAILS)) do
    local errors = {}
    local group_bd_valid = false
    local lua_group_of_docs = to_lua(group_of_docs)
    for _, bank_details in pairs(lua_group_of_docs) do
        local bd_valid = verify_bank_details(bank_details)
        group_bd_valid = group_bd_valid or bd_valid
    end
    enrollment_valid = enrollment_valid or group_bd_valid
end
return enrollment_valid