myFAB Tracabilité documentaire

Le module myFAB Traçabilité documentaire permet de composer une liasse à partir d'un enregistrement Open-Prod et des enregistrements qui lui sont liés.

Une liasse peut contenir :

La liasse peut ensuite être :


Exemple depuis un bon de livraison : récupérer les documents des articles et des étiquettes, imprimer les ordres de fabrication et ajouter les documents de contrôle qualité dans une liasse stockée sur le BL.

Note attention en v9 toutes les fonctionnalités ne sont pas disponibles

myFAB Tracabilité documentaire

1. Présentation

Le module myFAB Traçabilité documentaire permet de composer une liasse à partir d'un enregistrement Open-Prod et des enregistrements qui lui sont liés.

Une liasse peut contenir :

La liasse peut ensuite être :

Exemple depuis un bon de livraison : récupérer les documents des articles et des étiquettes, imprimer les ordres de fabrication et ajouter les documents de contrôle qualité dans une liasse stockée sur le BL.

3. Créer une configuration

Menu : Configuration > Rapport > Liasse documentaire.

image.png

3.1 Paramètres généraux

Paramètre Description
Nom Nom de la configuration et de l'action serveur générée.
Modèle Modèle Open-Prod sur lequel la liasse peut être exécutée, par exemple stock.picking ou mrp.manufacturingorder.
Mode de génération Stockage, Impression ou Stockage + impression.
Désactiver mise à jour Empêche les mises à jour de documents lors des traitements SQL qui le prévoient.
Exécution automatique Exécute la liasse directement sans ouvrir l'assistant.

3.2 Stockage GED

Ces paramètres sont disponibles pour les modes Stockage et Stockage + impression.

Paramètre Description
Champ Champ many2many de type document.openprod dans lequel les documents générés sont ajoutés.
Type de génération Fusion PDF, ZIP ou Documents séparés.
Nom du fichier généré Expression Python utilisée pour calculer le nom du PDF ou du ZIP.
Répertoire GED Répertoire document.directory utilisé pour les documents créés. La valeur par défaut reste le répertoire 1.
Type Type GED affecté au PDF ou au ZIP créé.
Tags Tags GED affectés au PDF ou au ZIP créé.

L'expression de nommage dispose des variables object et time :

object.display_name + " - " + time.strftime("%d-%m-%Y %H:%M")

Par défaut, le nom reprend le libellé de l'objet, suivi de la date et de l'heure. Les caractères / et \\ sont remplacés pour produire un nom de fichier valide.

3.3 Impression

Ces paramètres sont disponibles pour les modes Impression et Stockage + impression.

Une imprimante ou un type d'imprimante est obligatoire pour une configuration qui imprime. Une imprimante peut aussi être définie sur chaque ligne de la liasse. La configuration de ligne est prioritaire.

3.4 Liste des documents

Chaque ligne définit une source de contenu.

Type Utilisation
Récupérer un document Open-Prod Récupère les documents dont les identifiants sont renvoyés par la source.
Imprimer un rapport Génère un rapport pour les enregistrements renvoyés par la source. L'option Un document par enregistrement permet de produire un fichier par enregistrement.
Générer une sous-liasse Exécute une autre configuration de liasse pour chaque enregistrement renvoyé.

Une source peut être basée sur :

4. Sources SQL et Python

4.1 Requête SQL

La requête doit retourner les identifiants des documents ou des enregistrements du rapport. Deux variables sont disponibles :

Exemple :

select doc.id
from stock_picking as bl
join stock_move as sm on sm.picking_id = bl.id
join internal_plan_document_openprod_rel as rel on rel.product_id = sm.product_id
join document_openprod as doc on rel.document_id = doc.id
where bl.id = %object_id

Équivalent Python :

object.move_ids.product_id.internal_plan_ids

Pour une source de rapport, la requête doit retourner les identifiants du modèle porté par le rapport. Pour une source de document, elle doit retourner des identifiants document.openprod.

4.2 Expression Python

L'expression est évaluée pour chaque enregistrement source. Les variables disponibles sont :

L'expression doit retourner des enregistrements du modèle attendu. Elle doit rester une expression unique : les affectations comme documents = ... ne sont pas autorisées.

Exemples :

object.move_ids.product_id.internal_plan_ids
object.move_ids.product_id.internal_plan_ids.filtered(
    lambda document: document.state != 'obsolete'
)

Exemple d'accès à un modèle avec env :

env['traceability.link'].search([
    ('in_uc_label_id', 'in', object.move_ids.move_traceability_ids.uc_label_id.ids),
]).mapped('mo_id')

Les chemins one2many et many2many peuvent retourner plusieurs enregistrements. Le type retourné est contrôlé avant la génération afin d'éviter d'utiliser une expression sur un modèle incompatible.

5. Exécuter une liasse

Depuis le modèle configuré, l'action serveur associée est disponible dans les actions du document.

image.png

5.1 Assistant

L'assistant permet de :

  1. choisir le mode et le format de génération ;
  2. décocher les sources qui ne doivent pas être exécutées ;
  3. cliquer sur Charger pour calculer les documents et rapports ;
  4. décocher individuellement les résultats à exclure ;
  5. télécharger le PDF fusionné ou le ZIP ;
  6. imprimer les résultats sélectionnés ;
  7. valider pour stocker les documents dans le champ configuré.

Le chargement est facultatif : si l'utilisateur valide directement, les résultats sont chargés automatiquement.

image.png

5.2 Formats de sortie

La fusion PDF nécessite que chaque contenu puisse être converti en PDF. Les conversions des formats bureautiques utilisent le module d'impression et, si disponible, LibreOffice ou soffice.

Attention : La génération d'un ZIP ou PDF fusionné présente l'avantage de figer les données dans le système à un instant T. Elle a cependant pour effet de dupliquer les documents GED : une fois à leur emplacement d'origine et une fois dans le ZIP/PDF. Il faut donc surveiller l'espace disque du serveur hébergeant la GED et son filestore.

5.3 Doublons GED

Lorsqu'un nouveau fichier est créé dans la GED, son nom est rendu unique dans le répertoire et pour la même extension. En cas de doublon, le module ajoute un suffixe numérique avant l'extension :

Liasse BL.pdf
Liasse BL (1).pdf
Liasse BL (2).pdf

Les documents marqués comme obsolètes ne bloquent pas la réutilisation du nom.

Les documents Open-Prod déjà existants sont réutilisés en mode Documents séparés. Les rapports nouvellement générés reçoivent un document GED avec le répertoire configuré.

6. Sous-liasses

Une ligne de type Générer une sous-liasse permet de réutiliser une configuration existante pour les enregistrements retournés par la source.

Les sous-liasses peuvent produire des documents séparés, un PDF ou un ZIP. Les références circulaires sont refusées. Une sous-liasse en mode impression peut imprimer son propre contenu sans l'ajouter au résultat stocké de la liasse parente.

Une liasse PDF ne peut pas contenir une sous-liasse ZIP, car une archive ne peut pas être intégrée dans un PDF fusionné.

7. Action serveur et exécution automatique

Le bouton Ajouter l'action crée une action serveur sur le modèle choisi. Le bouton Supprimer l'action retire l'action associée.

L'option Exécution automatique permet désormais de lancer directement la liasse depuis son action serveur. Il n'est donc plus nécessaire de créer manuellement le wizard ni de reconstruire son contexte.

Exemple de choix dynamique depuis le partenaire

bundle = object.partner_id.x_liasse_doc_partenaire_id or env['mf.docu.bundle'].browse(1)
action = bundle.mf_execute_action(objects)

La méthode mf_execute_action(objects) utilise la configuration sélectionnée et retourne l'action de l'assistant. Si Exécution automatique est activée, elle exécute directement la liasse et retourne False.

8. Exemple de configuration BL

La configuration livrée avec le module, Liasse documentaire BL, est basée sur stock.picking et peut inclure :

La configuration peut être adaptée en remplaçant les requêtes SQL par des expressions Python lorsque les relations Open-Prod sont accessibles directement depuis l'objet.

8.1 Bibliothèque de requêtes SQL

Les requêtes doivent retourner une seule colonne contenant les identifiants attendus par la ligne de liasse. Le placeholder %object_id est remplacé par l'identifiant du BL ou de l'OF en cours de traitement.

Documents liés aux étiquettes du BL

Type de ligne : Récupérer un document Open-Prod.

select distinct doc.id
from stock_picking as bl
join stock_move as sm on sm.picking_id = bl.id
join stock_move_traceability as smt on sm.id = smt.move_id
join stock_label as sl on sl.id = smt.uc_label_id
join document_openprod_stock_label_rel as rel
    on rel.stock_label_id = smt.uc_label_id
join document_openprod as doc on rel.document_openprod_id = doc.id
where bl.id = %object_id

Équivalent Python :

object.move_ids.move_traceability_ids.uc_label_id.document_ids

Ordres de fabrication liés aux étiquettes du BL

Type de ligne : Imprimer un rapport. La ligne peut être configurée avec Un document par enregistrement.

select distinct tl.mo_id
from stock_picking as bl
join stock_move as sm on sm.picking_id = bl.id
join stock_move_traceability as smt on sm.id = smt.move_id
join stock_label as sl on sl.id = smt.uc_label_id
join traceability_link as tl on tl.in_uc_label_id = sl.id
where bl.id = %object_id

Équivalent Python :

env['traceability.link'].search([
    ('in_uc_label_id', 'in', object.move_ids.move_traceability_ids.uc_label_id.ids),
]).mapped('mo_id')

Documents des étiquettes consommées dans les OF du BL

Type de ligne : Récupérer un document Open-Prod.

select distinct doc.id
from stock_picking as bl
join stock_move as sm on sm.picking_id = bl.id
join stock_move_traceability as smt on sm.id = smt.move_id
join stock_label as sl on sl.id = smt.uc_label_id
join traceability_link as tl on tl.in_uc_label_id = sl.id
join document_openprod_stock_label_rel as rel
    on rel.stock_label_id = tl.out_uc_label_id
join document_openprod as doc on rel.document_openprod_id = doc.id
where bl.id = %object_id

Équivalent Python :

env['traceability.link'].search([
    ('in_uc_label_id', 'in', object.move_ids.move_traceability_ids.uc_label_id.ids),
]).mapped('out_uc_label_id.document_ids')

Documents des contrôles qualité terminés du BL

Type de ligne : Récupérer un document Open-Prod.

select distinct doc.id
from stock_picking as bl
join stock_move as sm on sm.picking_id = bl.id
join stock_move_traceability as smt on sm.id = smt.move_id
join stock_label as sl on sl.id = smt.uc_label_id
join traceability_link as tl on tl.in_uc_label_id = sl.id
join mrp_workorder as wo on tl.mo_id = wo.mo_id
join quality_control_declaration as qcd
    on qcd.wo_id = wo.id and qcd.state = 'done'
join quality_control_document_openprod_rel as rel on qcd.id = rel.qcd_id
join document_openprod as doc on rel.document_id = doc.id
where bl.id = %object_id

Équivalent Python :

env['quality.control.declaration'].search([
    ('wo_id', 'in', env['mrp.workorder'].search([
        ('mo_id', 'in', env['traceability.link'].search([
            ('in_uc_label_id', 'in', object.move_ids.move_traceability_ids.uc_label_id.ids),
        ]).mapped('mo_id').ids),
    ]).ids),
    ('state', '=', 'done'),
]).mapped('document_ids')

Contrôles qualité terminés d'un OF

Type de ligne : Imprimer un rapport. La requête retourne les identifiants du modèle porté par le rapport.

select distinct qcd.id
from mrp_workorder as wo
join quality_control_declaration as qcd
    on qcd.wo_id = wo.id and qcd.state = 'done'
where wo.mo_id = %object_id

Équivalent Python :

env['quality.control.declaration'].search([('wo_id', 'in', env['mrp.workorder'].search([('mo_id', '=', object.id),]).ids),('state', '=', 'done'),])

Documents d'un OF filtrés par tag

Type de ligne : Récupérer un document Open-Prod. Cette variante est utile lorsque les documents de l'OF sont classés par tag GED.

select distinct docrel.document_id
from mrp_manufacturingorder as mo
join mo_document_openprod_rel as docrel on docrel.mo_id = mo.id
join document_openprod as doc on doc.id = docrel.document_id
join document_tag_rel as tag_rel on tag_rel.document_id = doc.id
join tracker_tag as tag on tag.id = tag_rel.tag_id
where mo.id = %object_id
  and tag.name = 'CLIENT'

Équivalent Python :

object.internal_plan_ids.filtered(lambda document: 'CLIENT' in document.tag_ids.mapped('name'))

9. Bonnes pratiques