Les codes-barres et QR codes sont devenus indispensables dans les processus métier modernes. Ils accélèrent la saisie de données, réduisent les erreurs et permettent une traçabilité complète. Dans ABAP Cloud, il existe différentes approches pour générer ces codes - des solutions ABAP natives aux services cloud externes.
Vue d’ensemble des types de codes-barres
Selon le cas d’usage, différents formats de codes-barres sont utilisés :
| Type de code-barre | Capacité de données | Domaine d’application |
|---|---|---|
| Code128 | Alphanumérique, variable | Logistique, expédition, identification interne |
| EAN-13 | 13 chiffres | Commerce de détail, produits de consommation |
| EAN-8 | 8 chiffres | Petits emballages |
| Code39 | Alphanumérique | Industrie, automobile |
| QR Code | Jusqu’à 4 296 caractères | URLs, données de contact, factures |
| DataMatrix | Jusqu’à 2 335 caractères | Pharmacie, électronique, petits composants |
Codes 1D vs 2D
┌─────────────────────────────────────────────────────────────────────┐│ Classification des codes-barres ││ ││ ┌────────────────────────────┐ ┌────────────────────────────┐ ││ │ Codes-barres 1D │ │ Codes 2D │ ││ │ │ │ │ ││ │ ║║█║║█║║║█║█║║█║║ │ │ ▓▓▓▓▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓ │ ││ │ Code128, EAN, Code39 │ │ ▓ ▓ ▓▓▓ ▓ ▓ │ ││ │ │ │ ▓ ▓▓▓ ▓ ▓▓ ▓ ▓▓▓ ▓ │ ││ │ - Linéaire │ │ ▓ ▓▓▓ ▓ ▓▓ ▓ ▓▓▓ ▓ │ ││ │ - Info horizontale seul. │ │ ▓ ▓ ▓ ▓ ▓ ▓ │ ││ │ - Scanner/Lecteur │ │ ▓▓▓▓▓▓▓ ▓ ▓ ▓▓▓▓▓▓▓ │ ││ │ │ │ QR Code, DataMatrix │ ││ │ │ │ │ ││ │ │ │ - Basé sur matrice │ ││ │ │ │ - Haute capacité │ ││ │ │ │ - Caméra/Smartphone │ ││ └────────────────────────────┘ └────────────────────────────┘ │└─────────────────────────────────────────────────────────────────────┘Options de génération dans ABAP Cloud
Dans ABAP Cloud, plusieurs méthodes sont disponibles pour la génération de codes-barres :
| Option | Description | Avantages | Inconvénients |
|---|---|---|---|
| APIs REST externes | Services cloud de codes-barres | Flexible, nombreux formats | Dépendance réseau, coûts |
| Génération ABAP native | Algorithme implémenté en ABAP | Aucune dépendance | Complexe, formats limités |
| SAP Forms Service | Codes-barres dans templates PDF | Intégré | Uniquement pour PDFs |
| JavaScript dans Fiori | Génération côté frontend | Rapide, hors ligne | Affichage UI uniquement |
Génération de QR Code avec service externe
La méthode la plus simple et flexible consiste à utiliser un service de QR Code externe :
Client HTTP pour API QR Code
CLASS zcl_qr_code_generator DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. TYPES: BEGIN OF ty_qr_result, image_base64 TYPE string, content_type TYPE string, success TYPE abap_bool, message TYPE string, END OF ty_qr_result.
METHODS generate_qr_code IMPORTING iv_content TYPE string iv_size TYPE i DEFAULT 200 iv_format TYPE string DEFAULT 'PNG" RETURNING VALUE(rs_result) TYPE ty_qr_result.
PRIVATE SECTION. METHODS get_http_client RETURNING VALUE(ro_client) TYPE REF TO if_web_http_client.
ENDCLASS.
CLASS zcl_qr_code_generator IMPLEMENTATION.
METHOD generate_qr_code. DATA: lo_client TYPE REF TO if_web_http_client, lo_response TYPE REF TO if_web_http_response, lv_url TYPE string.
TRY. " Construire l'URL avec paramètres " Exemple avec goqr.me API (gratuit) lv_url = |https://api.qrserver.com/v1/create-qr-code/| && |?data={ cl_web_utility=>escape_url( iv_content ) }| && |&size={ iv_size }x{ iv_size }| && |&format={ iv_format }|.
" Créer le client HTTP lo_client = cl_web_http_client_manager=>create_by_http_destination( i_destination = cl_http_destination_provider=>create_by_url( lv_url ) ).
" Envoyer la requête lo_response = lo_client->execute( if_web_http_client=>get ).
" Évaluer la réponse IF lo_response->get_status( )-code = 200. rs_result-image_base64 = cl_web_utility=>encode_base64( lo_response->get_binary( ) ). rs_result-content_type = |image/{ to_lower( iv_format ) }|. rs_result-success = abap_true. ELSE. rs_result-success = abap_false. rs_result-message = |HTTP Error: { lo_response->get_status( )-code }|. ENDIF.
lo_client->close( ).
CATCH cx_web_http_client_error INTO DATA(lx_http). rs_result-success = abap_false. rs_result-message = lx_http->get_text( ). CATCH cx_root INTO DATA(lx_error). rs_result-success = abap_false. rs_result-message = lx_error->get_text( ). ENDTRY. ENDMETHOD.
METHOD get_http_client. " Alternative : utiliser une destination depuis Communication Arrangement ro_client = cl_web_http_client_manager=>create_by_http_destination( i_destination = cl_http_destination_provider=>create_by_comm_arrangement( comm_scenario = 'Z_QR_CODE_SERVICE" service_id = 'Z_QR_CODE_OUTBOUND" ) ). ENDMETHOD.
ENDCLASS.Configuration du Communication Arrangement
Pour les systèmes de production, vous devriez utiliser une destination :
1. Créer un Communication System (SAP BTP Cockpit) - Name: QR_CODE_SERVICE - Host: api.qrserver.com - Port: 443 - Protocol: HTTPS
2. Créer un Communication Arrangement - Scenario: Z_QR_CODE_SERVICE - Outbound Service: Z_QR_CODE_OUTBOUND - Authentication: None (API publique)
3. Définition du Outbound Service (ABAP)" Service Consumption Model (ABAP)@EndUserText.label: 'QR Code Service"define service ZS_QR_CODE_SERVICE { expose zcl_qr_code_generator as QRCodeGenerator;}Génération de code-barre (Code128)
Code128 est un code-barre 1D largement utilisé pour la logistique et l’expédition :
Algorithme pour Code128
CLASS zcl_code128_generator DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. TYPES: BEGIN OF ty_barcode_result, barcode_string TYPE string, check_digit TYPE i, success TYPE abap_bool, message TYPE string, END OF ty_barcode_result.
METHODS generate_code128b IMPORTING iv_data TYPE string RETURNING VALUE(rs_result) TYPE ty_barcode_result.
METHODS generate_barcode_image IMPORTING iv_data TYPE string iv_width TYPE i DEFAULT 300 iv_height TYPE i DEFAULT 100 RETURNING VALUE(rv_base64) TYPE string.
PRIVATE SECTION. CONSTANTS: BEGIN OF gc_code128b, start_code TYPE i VALUE 104, stop_code TYPE i VALUE 106, END OF gc_code128b.
CLASS-DATA: gt_code128_patterns TYPE STANDARD TABLE OF string WITH EMPTY KEY.
CLASS-METHODS class_constructor.
METHODS calculate_check_digit IMPORTING iv_data TYPE string RETURNING VALUE(rv_checksum) TYPE i.
ENDCLASS.
CLASS zcl_code128_generator IMPLEMENTATION.
METHOD class_constructor. " Initialiser les motifs de code-barre Code128 " Chaque motif se compose de 6 barres/espaces gt_code128_patterns = VALUE #( ( |11011001100| ) " 0 ( |11001101100| ) " 1 ( |11001100110| ) " 2 " ... autres motifs ). ENDMETHOD.
METHOD generate_code128b. DATA: lv_checksum TYPE i, lv_index TYPE i.
" Validation IF strlen( iv_data ) = 0. rs_result-success = abap_false. rs_result-message = 'Aucune donnée spécifiée'. RETURN. ENDIF.
" Calculer la somme de contrôle lv_checksum = calculate_check_digit( iv_data ).
rs_result-check_digit = lv_checksum. rs_result-success = abap_true.
" Construire la chaîne de code-barre (simplifié) rs_result-barcode_string = |{ gc_code128b-start_code }|.
DO strlen( iv_data ) TIMES. lv_index = sy-index - 1. rs_result-barcode_string = rs_result-barcode_string && cl_abap_conv_codepage=>convert_to( source = substring( val = iv_data off = lv_index len = 1 ) ). ENDDO.
rs_result-barcode_string = rs_result-barcode_string && |{ lv_checksum }{ gc_code128b-stop_code }|. ENDMETHOD.
METHOD calculate_check_digit. DATA: lv_sum TYPE i, lv_char TYPE c LENGTH 1, lv_value TYPE i.
" Commencer avec le code de démarrage lv_sum = gc_code128b-start_code.
" Ajouter chaque caractère avec pondération DO strlen( iv_data ) TIMES. lv_char = iv_data+( sy-index - 1 )(1).
" Valeur ASCII - 32 donne la valeur Code128B lv_value = cl_abap_conv_codepage=>convert_to( source = CONV string( lv_char ) )-1 - 32.
lv_sum = lv_sum + ( lv_value * sy-index ). ENDDO.
" Modulo 103 rv_checksum = lv_sum MOD 103. ENDMETHOD.
METHOD generate_barcode_image. " Utiliser un service externe pour la génération d'images DATA(lo_qr_gen) = NEW zcl_qr_code_generator( ).
" URL du service de code-barre (exemple avec barcodeapi.org) DATA(lv_url) = |https://barcodeapi.org/api/128/{ cl_web_utility=>escape_url( iv_data ) }|.
TRY. DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination( i_destination = cl_http_destination_provider=>create_by_url( lv_url ) ).
DATA(lo_response) = lo_client->execute( if_web_http_client=>get ).
IF lo_response->get_status( )-code = 200. rv_base64 = cl_web_utility=>encode_base64( lo_response->get_binary( ) ). ENDIF.
lo_client->close( ).
CATCH cx_root. CLEAR rv_base64. ENDTRY. ENDMETHOD.
ENDCLASS.Intégration dans des documents PDF
Les codes-barres sont fréquemment nécessaires dans les PDFs comme les bons de livraison ou les factures :
Template XSL-FO avec code-barre intégré
<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="/"> <fo:root> <fo:layout-master-set> <fo:simple-page-master master-name="delivery-note" page-height="297mm" page-width="210mm" margin-top="20mm" margin-bottom="20mm" margin-left="20mm" margin-right="20mm"> <fo:region-body/> </fo:simple-page-master> </fo:layout-master-set>
<fo:page-sequence master-reference="delivery-note"> <fo:flow flow-name="xsl-region-body">
<!-- Zone d'en-tête avec code-barre --> <fo:block-container position="absolute" top="0mm" right="0mm"> <fo:block> <!-- Code-barre en image Base64 --> <fo:external-graphic src="url('data:image/png;base64,{/document/barcode_image}')" content-height="15mm" scaling="uniform"/> </fo:block> <fo:block font-size="8pt" text-align="center"> <xsl:value-of select="/document/delivery_number"/> </fo:block> </fo:block-container>
<!-- QR Code pour URL de suivi --> <fo:block-container position="absolute" top="50mm" right="0mm"> <fo:block> <fo:external-graphic src="url('data:image/png;base64,{/document/qr_code_image}')" content-height="25mm" scaling="uniform"/> </fo:block> <fo:block font-size="7pt" text-align="center"> Scanner pour suivi </fo:block> </fo:block-container>
<!-- Contenu du document --> <fo:block font-size="18pt" font-weight="bold" margin-bottom="10mm"> Bon de livraison </fo:block>
<!-- Autres contenus... -->
</fo:flow> </fo:page-sequence> </fo:root> </xsl:stylesheet>Génération de PDF avec code-barre
CLASS zcl_delivery_note_pdf DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. METHODS generate_delivery_note IMPORTING is_delivery TYPE zdelivery_data RETURNING VALUE(rv_pdf) TYPE xstring RAISING cx_transformation_error.
PRIVATE SECTION. METHODS prepare_xml_data IMPORTING is_delivery TYPE zdelivery_data RETURNING VALUE(rv_xml) TYPE string.
METHODS add_barcode_images IMPORTING is_delivery TYPE zdelivery_data EXPORTING ev_barcode_b64 TYPE string ev_qrcode_b64 TYPE string.
ENDCLASS.
CLASS zcl_delivery_note_pdf IMPLEMENTATION.
METHOD generate_delivery_note. DATA: lv_xml TYPE string, lv_barcode_b64 TYPE string, lv_qrcode_b64 TYPE string, lv_xslfo TYPE string, lv_pdf TYPE xstring.
" Générer les codes-barres add_barcode_images( EXPORTING is_delivery = is_delivery IMPORTING ev_barcode_b64 = lv_barcode_b64 ev_qrcode_b64 = lv_qrcode_b64 ).
" Préparer les données XML lv_xml = prepare_xml_data( is_delivery ).
" Insérer les images de codes-barres dans XML REPLACE ALL OCCURRENCES OF '{BARCODE_IMAGE}' IN lv_xml WITH lv_barcode_b64. REPLACE ALL OCCURRENCES OF '{QRCODE_IMAGE}' IN lv_xml WITH lv_qrcode_b64.
" Transformation XSL-FO CALL TRANSFORMATION z_delivery_note_xslfo SOURCE XML lv_xml RESULT XML lv_xslfo.
" Convertir XSL-FO en PDF " (nécessite un service FOP ou un moteur de rendu PDF externe) rv_pdf = zcl_pdf_renderer=>render_xslfo( lv_xslfo ). ENDMETHOD.
METHOD add_barcode_images. DATA(lo_barcode_gen) = NEW zcl_code128_generator( ). DATA(lo_qr_gen) = NEW zcl_qr_code_generator( ).
" Code-barre Code128 pour le numéro de livraison ev_barcode_b64 = lo_barcode_gen->generate_barcode_image( iv_data = is_delivery-delivery_number iv_width = 300 iv_height = 80 ).
" QR Code avec URL de suivi DATA(lv_tracking_url) = |https://tracking.example.com/{ is_delivery-delivery_number }|.
DATA(ls_qr_result) = lo_qr_gen->generate_qr_code( iv_content = lv_tracking_url iv_size = 200 ).
IF ls_qr_result-success = abap_true. ev_qrcode_b64 = ls_qr_result-image_base64. ENDIF. ENDMETHOD.
METHOD prepare_xml_data. " Construire la structure XML pour le PDF rv_xml = |<?xml version="1.0" encoding="UTF-8"?>| && |<document>| && | <delivery_number>{ is_delivery-delivery_number }</delivery_number>| && | <customer_name>{ is_delivery-customer_name }</customer_name>| && | <barcode_image>{BARCODE_IMAGE}</barcode_image>| && | <qr_code_image>{QRCODE_IMAGE}</qr_code_image>| && | <items>|.
LOOP AT is_delivery-items INTO DATA(ls_item). rv_xml = rv_xml && | <item>| && | <material>{ ls_item-material }</material>| && | <quantity>{ ls_item-quantity }</quantity>| && | </item>|. ENDLOOP.
rv_xml = rv_xml && | </items>| && |</document>|. ENDMETHOD.
ENDCLASS.Affichage dans une application Fiori
Pour afficher des codes-barres dans des applications Fiori, il existe deux approches :
Images générées côté backend
Le code-barre est généré dans le backend et envoyé au frontend en tant que chaîne Base64 :
" Action RAP pour la génération de code-barremanaged implementation in class zbp_i_product unique;strict ( 2 );
define behavior for ZI_Product alias Product{ // Action pour générer le code-barre du produit action generateBarcode result [1] $self;
// Champ virtuel pour l'image du code-barre field ( readonly ) BarcodeImage;}CLASS zbp_i_product DEFINITION LOCAL. PRIVATE SECTION. METHODS generateBarcode FOR MODIFY IMPORTING keys FOR ACTION Product~generateBarcode RESULT result.ENDCLASS.
CLASS zbp_i_product IMPLEMENTATION.
METHOD generateBarcode. " Lire les produits READ ENTITIES OF zi_product IN LOCAL MODE ENTITY Product FIELDS ( ProductId ProductName ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_products).
LOOP AT lt_products ASSIGNING FIELD-SYMBOL(<ls_product>). " Générer le code-barre DATA(lo_barcode) = NEW zcl_code128_generator( ). DATA(lv_barcode_b64) = lo_barcode->generate_barcode_image( iv_data = CONV string( <ls_product>-ProductId ) ).
" Mettre à jour le produit avec l'image du code-barre MODIFY ENTITIES OF zi_product IN LOCAL MODE ENTITY Product UPDATE FIELDS ( BarcodeImage ) WITH VALUE #( ( %tky = <ls_product>-%tky BarcodeImage = lv_barcode_b64 ) ). ENDLOOP.
" Retourner le résultat READ ENTITIES OF zi_product IN LOCAL MODE ENTITY Product ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_result).
result = VALUE #( FOR ls_prod IN lt_result ( %tky = ls_prod-%tky %param = ls_prod ) ). ENDMETHOD.
ENDCLASS.Vue CDS avec champ de code-barre
@EndUserText.label: 'Produit avec code-barre"@Metadata.allowExtensions: truedefine view entity ZC_Product as projection on ZI_Product{ @UI: { lineItem: [{ position: 10 }], identification: [{ position: 10 }] } key ProductId,
@UI: { lineItem: [{ position: 20 }], identification: [{ position: 20 }] } ProductName,
@UI: { identification: [{ position: 30, label: 'Code-barre" }] } @UI.dataPoint: { visualization: #STANDARD } @Semantics.imageUrl: true BarcodeImageUrl,
@UI.hidden: true BarcodeImage}Calcul de l’URL du code-barre
define view entity ZI_Product as select from zproduct{ key product_id as ProductId, product_name as ProductName,
-- URL pour l'API de code-barre concat( 'https://barcodeapi.org/api/128/', product_id ) as BarcodeImageUrl,
-- Placeholder pour l'image générée cast( '' as abap.string ) as BarcodeImage}Services externes vs solutions ABAP natives
Comparaison des approches
| Critère | Services externes | ABAP native |
|---|---|---|
| Effort de configuration | Faible | Élevé |
| Formats supportés | Nombreux | Limité |
| Performance | Latence réseau | Rapide |
| Capacité hors ligne | Non | Oui |
| Coûts | Éventuels coûts API | Aucun |
| Maintenance | Chez le fournisseur | Responsabilité propre |
Recommandation selon le cas d’usage
┌─────────────────────────────────────────────────────────────────────┐│ Arbre de décision ││ ││ Avez-vous besoin de nombreux formats de codes-barres ? ││ │ ││ ├── Oui ──► Service externe (ex: barcodeapi.org) ││ │ ││ └── Non ││ │ ││ └── La capacité hors ligne est-elle importante ? ││ │ ││ ├── Oui ──► Implémentation ABAP native ││ │ ││ └── Non ││ │ ││ └── Volumes élevés (>1000/minute) ? ││ │ ││ ├── Oui ──► ABAP native ou auto-hébergé ││ │ ││ └── Non ──► Service externe │└─────────────────────────────────────────────────────────────────────┘APIs de codes-barres externes populaires
| Service | URL | Modèle de coûts |
|---|---|---|
| goQR.me | api.qrserver.com | Gratuit |
| Barcode API | barcodeapi.org | Gratuit |
| Zxing | zxing.org | Open Source |
| QRCode Monkey | qrcode-monkey.com | Freemium |
Bonnes pratiques
Optimisation de la performance
" Mettre en cache la génération de codes-barresCLASS zcl_barcode_cache DEFINITION PUBLIC FINAL CREATE PRIVATE.
PUBLIC SECTION. CLASS-METHODS get_instance RETURNING VALUE(ro_instance) TYPE REF TO zcl_barcode_cache.
METHODS get_barcode IMPORTING iv_content TYPE string iv_type TYPE string DEFAULT 'QR" RETURNING VALUE(rv_base64) TYPE string.
PRIVATE SECTION. CLASS-DATA: go_instance TYPE REF TO zcl_barcode_cache.
TYPES: BEGIN OF ty_cache_entry, content TYPE string, type TYPE string, image TYPE string, created TYPE timestamp, END OF ty_cache_entry.
DATA: mt_cache TYPE HASHED TABLE OF ty_cache_entry WITH UNIQUE KEY content type.
CONSTANTS: gc_cache_ttl_sec TYPE i VALUE 3600. " 1 heure
ENDCLASS.
CLASS zcl_barcode_cache IMPLEMENTATION.
METHOD get_instance. IF go_instance IS NOT BOUND. go_instance = NEW #( ). ENDIF. ro_instance = go_instance. ENDMETHOD.
METHOD get_barcode. DATA: ls_cache TYPE ty_cache_entry, lv_now TYPE timestamp.
GET TIME STAMP FIELD lv_now.
" Rechercher dans le cache READ TABLE mt_cache INTO ls_cache WITH KEY content = iv_content type = iv_type.
IF sy-subrc = 0. " Vérifier si toujours valide IF lv_now - ls_cache-created < gc_cache_ttl_sec. rv_base64 = ls_cache-image. RETURN. ELSE. " Expiré - supprimer du cache DELETE mt_cache WHERE content = iv_content AND type = iv_type. ENDIF. ENDIF.
" Générer à nouveau CASE iv_type. WHEN 'QR'. DATA(lo_qr) = NEW zcl_qr_code_generator( ). DATA(ls_result) = lo_qr->generate_qr_code( iv_content ). IF ls_result-success = abap_true. rv_base64 = ls_result-image_base64. ENDIF.
WHEN 'CODE128'. DATA(lo_barcode) = NEW zcl_code128_generator( ). rv_base64 = lo_barcode->generate_barcode_image( iv_content ). ENDCASE.
" Sauvegarder dans le cache IF rv_base64 IS NOT INITIAL. INSERT VALUE #( content = iv_content type = iv_type image = rv_base64 created = lv_now ) INTO TABLE mt_cache. ENDIF. ENDMETHOD.
ENDCLASS.Gestion des erreurs
" Génération de code-barre robuste avec fallbackMETHODS generate_with_fallback IMPORTING iv_content TYPE string RETURNING VALUE(rv_base64) TYPE string.
METHOD generate_with_fallback. " Essayer le service principal TRY. DATA(lo_qr) = NEW zcl_qr_code_generator( ). DATA(ls_result) = lo_qr->generate_qr_code( iv_content ).
IF ls_result-success = abap_true. rv_base64 = ls_result-image_base64. RETURN. ENDIF.
CATCH cx_root INTO DATA(lx_error). " Logger l'erreur zcl_logger=>log_error( iv_message = |Échec de génération QR: { lx_error->get_text( ) }| ). ENDTRY.
" Fallback : service alternatif TRY. rv_base64 = zcl_barcode_fallback=>generate( iv_content ). CATCH cx_root. " Dernier fallback : image placeholder rv_base64 = zcl_barcode_fallback=>get_placeholder( ). ENDTRY.ENDMETHOD.Résumé
| Aspect | Recommandation |
|---|---|
| QR Codes | API externe (goQR.me) pour intégration simple |
| Codes-barres 1D | API externe ou ABAP native pour Code128 |
| Intégration PDF | Images encodées Base64 dans XSL-FO |
| Affichage Fiori | Génération backend avec @Semantics.imageUrl |
| Performance | Mise en cache pour appels répétés |
| Tolérance aux erreurs | Implémenter des mécanismes de fallback |
Le choix entre services externes et solutions ABAP natives dépend de vos exigences. Pour la plupart des cas d’usage, les APIs externes offrent le meilleur équilibre entre fonctionnalité et effort d’implémentation.
Sujets connexes
- Génération de PDF dans ABAP Cloud - Créer des documents PDF avec codes-barres
- Client HTTP - Appeler des APIs REST
- Actions et fonctions RAP - Logique métier pour la génération de codes-barres