Version de développement
Cette documentation décrit la version « next » (develop), non encore publiée. Pour la version stable, basculez sur « v5 » dans l'en-tête.
Interface

Personnalisation avancée du constructeur de format d'impression

Personnalisation avancée du constructeur de format d'impression

Cette page décrit les fonctionnalités avancées et les personnalisations techniques du constructeur de format d'impression. Elle s'adresse aux administrateurs système et aux développeurs souhaitant étendre ou modifier le comportement du constructeur.

Système de brouillons

Le constructeur de format d'impression intègre un système de brouillons pour permettre des modifications sécurisées et progressives. Cette fonctionnalité est implémentée côté serveur et client pour garantir la cohérence des données.

Architecture technique

  • Stockage des brouillons : Les brouillons sont stockés dans la base de données sous forme de documents JSON dans le champ draft_data du doctype Print Format.
  • Token de révision : Chaque brouillon est associé à un token de révision (revision_token) pour éviter les conflits entre plusieurs éditeurs.
  • Autosauvegarde : Les modifications sont sauvegardées automatiquement via une requête API toutes les 30 secondes. La méthode autosave_draft dans print_format.py gère cette logique.
  • Verrouillage : Le système utilise un verrou (draft_lock) pour empêcher les sauvegardes concurrentes et garantir la cohérence des données.

Méthodes API

MéthodeDescriptionParamètres
autosave_draftSauvegarde automatiquement les modifications dans un brouillon.docname (nom du format), draft_data (données du brouillon), revision_token (token de révision)
save_and_applyApplique le brouillon au format actif.docname (nom du format), revision_token (token de révision)
discard_draftSupprime le brouillon et restaure le format actif.docname (nom du format)
get_draftRécupère le brouillon actuel pour un format.docname (nom du format)

Exemple d'utilisation des méthodes API

// Sauvegarder un brouillon
frappe.call({
    method: "frappe.printing.doctype.print_format.print_format.autosave_draft",
    args: {
        docname: "Facture standard",
        draft_data: {
            sections: [/* données du brouillon */],
            styles: { /* styles du brouillon */ }
        },
        revision_token: "abc123"
    },
    callback: function(r) {
        if (r.message) {
            console.log("Brouillon sauvegardé avec le token:", r.message.revision_token);
        }
    }
});

// Appliquer un brouillon
frappe.call({
    method: "frappe.printing.doctype.print_format.print_format.save_and_apply",
    args: {
        docname: "Facture standard",
        revision_token: "abc123"
    },
    callback: function(r) {
        if (r.message) {
            console.log("Brouillon appliqué avec succès");
        }
    }
});

Personnalisation du comportement des brouillons

Vous pouvez personnaliser le comportement du système de brouillons en modifiant les paramètres suivants dans le fichier hooks.py de votre application :

# hooks.py
app_include_js = [
    "print_format_builder_overrides.js"
]

# Durée de vie des brouillons (en jours)
draft_expiry_days = 7

# Intervalle d'autosauvegarde (en secondes)
autosave_interval = 30

Désactivation du suivi des versions

Le système de brouillons désactive automatiquement le suivi des versions (track_changes) pour les formats d'impression. Cela permet d'éviter la création de versions inutiles à chaque autosauvegarde, ce qui réduisait les performances et occupait inutilement de l'espace disque.

Pour réactiver le suivi des versions (non recommandé), ajoutez le code suivant dans un script personnalisé :

frappe.ui.form.on("Print Format", {
    refresh: function(frm) {
        frm.toggle_track_changes(true);
    }
});
La réactivation du suivi des versions peut entraîner une dégradation des performances et une augmentation significative de la taille de la base de données. :::

Personnalisation de l'interface du constructeur

Le constructeur de format d'impression utilise le framework Vue.js pour son interface utilisateur. Vous pouvez personnaliser son apparence et son comportement en surchargeant les composants ou en ajoutant des styles CSS personnalisés.

Structure des composants

ComposantCheminDescription
PrintFormat.vuefrappe/public/js/print_format_builder/components/editor/PrintFormat.vueComposant principal du constructeur.
PrintFormatSection.vuefrappe/public/js/print_format_builder/components/editor/PrintFormatSection.vueGère l'affichage et l'édition des sections.
PrintFormatControls.vuefrappe/public/js/print_format_builder/components/PrintFormatControls.vueBarre d'outils et contrôles du constructeur.
PrintSettingsPanel.vuefrappe/public/js/print_format_builder/components/PrintSettingsPanel.vuePanneau latéral de configuration.

Exemple : Ajout d'un bouton personnalisé

Pour ajouter un bouton personnalisé dans la barre d'outils du constructeur, créez un fichier print_format_builder_overrides.js dans votre application :
// print_format_builder_overrides.js
frappe.provide("frappe.print_format_builder");

frappe.print_format_builder.PrintFormatControls = class CustomPrintFormatControls extends frappe.print_format_builder.PrintFormatControls {
    make() {
        super.make();
        this.add_custom_button();
    }

    add_custom_button() {
        this.controls.addCustomButton({
            label: __("Exporter en JSON"),
            icon: "fa fa-download",
            action: () => this.export_to_json()
        });
    }

    export_to_json() {
        const data = this.frm.doc;
        const json = JSON.stringify(data, null, 2);
        const blob = new Blob([json], { type: "application/json" });
        const url = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = url;
        a.download = `${this.frm.docname}.json`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    }
};

Personnalisation des styles

Pour personnaliser les styles du constructeur, ajoutez un fichier CSS dans votre application :
/* print_format_builder_custom.css */
.print-format-builder {
    --primary-color: #3b82f6;
    --secondary-color: #1e40af;
    --accent-color: #f59e0b;
}

.print-format-builder .section {
    border: 1px solid var(--primary-color);
}

.print-format-builder .field-drag-handle {
    background-color: var(--accent-color);
}
Puis chargez ce fichier dans votre hooks.py :
# hooks.py
app_include_css = [
    "print_format_builder_custom.css"
]

Intégration avec des champs personnalisés

Le constructeur de format d'impression prend en charge les champs personnalisés ajoutés aux documents. Pour que ces champs soient disponibles dans le constructeur, assurez-vous qu'ils sont correctement configurés dans le doctype parent.

Exemple : Ajout d'un champ personnalisé

  1. Créez un champ personnalisé dans le doctype Sales Invoice (par exemple, custom_qr_code).
  2. Configurez le champ avec les propriétés suivantes :
    • Type : Data ou Link
    • Options : Laissez vide ou spécifiez le doctype lié.
  3. Ouvrez le constructeur pour un format d'impression lié à Sales Invoice.
  4. Le champ personnalisé apparaîtra dans la liste des champs disponibles et pourra être ajouté au canevas.

Prise en charge des champs dynamiques

Pour les champs calculés dynamiquement (par exemple, un champ qui dépend d'autres valeurs), utilisez la visibilité conditionnelle pour contrôler leur affichage :
  1. Sélectionnez le champ dans le canevas.
  2. Dans le panneau latéral Inspecteur, ouvrez l'onglet Visibilité.
  3. Activez l'option Conditionnel.
  4. Saisissez une expression JavaScript dans le champ Visible si (exemple : doc.custom_field === "VIP").

Dépannage

Problèmes courants et solutions

ProblèmeCause possibleSolution
Le constructeur ne se charge pasConflit avec une extension navigateur ou un script personnalisé.Désactivez les extensions navigateur et vérifiez la console pour les erreurs JavaScript.
Les modifications ne sont pas sauvegardéesProblème de verrouillage ou de token de révision.Rafraîchissez la page et vérifiez que le token de révision est correctement mis à jour.
Le brouillon ne s'applique pasConflit avec un autre utilisateur ou token de révision invalide.Vérifiez que le token de révision correspond à celui du brouillon actuel.
Les champs personnalisés n'apparaissent pasLe champ n'est pas correctement configuré dans le doctype parent.Vérifiez que le champ est marqué comme "Imprimable" dans les propriétés du doctype.
L'aperçu ne se met pas à jourProblème de cache ou de rendu.Rafraîchissez l'aperçu ou basculez entre les modes Flux et Pages.

Journalisation et débogage

Pour activer la journalisation détaillée du constructeur, ajoutez le code suivant dans votre fichier site_config.json :
{
    "logger": {
        "print_format_builder": {
            "level": "debug"
        }
    }
}
Les logs seront disponibles dans le fichier logs/print_format_builder.log.

Réinitialisation d'un format d'impression

Si un format d'impression est corrompu ou ne fonctionne plus correctement, vous pouvez le réinitialiser en suivant ces étapes :
  1. Ouvrez le Format d'impression dans le mode formulaire.
  2. Cliquez sur le menu Actions et sélectionnez Réinitialiser le format.
  3. Confirmez la réinitialisation.
La réinitialisation supprime toutes les modifications apportées au format et restaure la version par défaut. Cette action est irréversible. :::

Bonnes pratiques pour les développeurs

  • Testez les modifications : Avant d'appliquer un brouillon, testez-le avec différents documents pour vous assurer qu'il fonctionne dans tous les cas.
  • Documentez les changements : Ajoutez une description des modifications dans le champ Description du format d'impression pour informer les autres utilisateurs.
  • Évitez les conflits : Si plusieurs utilisateurs travaillent sur le même format, communiquez pour éviter les conflits de brouillons.
  • Optimisez les performances : Limitez le nombre de sections et de champs dans un format pour éviter les ralentissements lors de l'édition ou de l'impression.
  • Utilisez les styles personnalisés avec parcimonie : Privilégiez les options de style intégrées au constructeur pour garantir la compatibilité avec les futures mises à jour.

Exemple de personnalisation avancée

Ajout d'un bloc personnalisé

Pour ajouter un nouveau type de bloc (par exemple, un bloc Signature), suivez ces étapes :
  1. Créez un composant Vue pour le bloc :
// frappe/public/js/print_format_builder/components/blocks/CustomSignatureBlock.vue
<template>
    <div class="signature-block" :style="style">
        <div class="signature-label">{{ label }}</div>
        <div class="signature-line"></div>
    </div>
</template>

<script>
export default {
    props: {
        label: {
            type: String,
            default: "Signature"
        },
        style: {
            type: Object,
            default: () => ({})
        }
    }
}
</script>

<style scoped>
.signature-block {
    margin: 10px 0;
    padding: 10px;
    border-top: 1px dashed #ccc;
}

.signature-label {
    font-size: 12px;
    color: #666;
}

.signature-line {
    height: 1px;
    background-color: #000;
    margin-top: 20px;
}
</style>
  1. Enregistrez le bloc dans le constructeur :
// print_format_builder_overrides.js
frappe.provide("frappe.print_format_builder");

frappe.print_format_builder.blocks = {
    ...frappe.print_format_builder.blocks,
    "Signature": {
        label: __("Signature"),
        component: () => import("./components/blocks/CustomSignatureBlock.vue"),
        icon: "fa fa-pencil"
    }
};
  1. Chargez le composant dans votre hooks.py :
# hooks.py
app_include_js = [
    "print_format_builder_overrides.js"
]
  1. Le bloc Signature apparaîtra désormais dans la palette de blocs du constructeur et pourra être ajouté au canevas.

Intégration avec un champ personnalisé

Pour lier le bloc Signature à un champ personnalisé (par exemple, custom_signature), modifiez le composant comme suit :
// CustomSignatureBlock.vue
<template>
    <div class="signature-block" :style="style">
        <div class="signature-label">{{ label }}</div>
        <div class="signature-line" v-if="!doc[fieldname]"></div>
        <img :src="doc[fieldname]" v-if="doc[fieldname]" class="signature-image" />
    </div>
</template>

<script>
export default {
    props: {
        label: {
            type: String,
            default: "Signature"
        },
        style: {
            type: Object,
            default: () => ({})
        },
        fieldname: {
            type: String,
            default: "custom_signature"
        },
        doc: {
            type: Object,
            default: () => ({})
        }
    }
}
</script>

<style scoped>
.signature-image {
    max-width: 200px;
    max-height: 100px;
}
</style>
Puis configurez le bloc dans print_format_builder_overrides.js :
frappe.print_format_builder.blocks["Signature"] = {
    label: __("Signature"),
    component: () => import("./components/blocks/CustomSignatureBlock.vue"),
    icon: "fa fa-pencil",
    props: {
        fieldname: "custom_signature"
    }
};