factpulse 1.0.9__py3-none-any.whl → 3.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of factpulse might be problematic. Click here for more details.
- factpulse/__init__.py +275 -203
- factpulse/api/__init__.py +5 -3
- factpulse/api/afnorpdppa_api.py +559 -9
- factpulse/api/afnorpdppa_directory_service_api.py +4313 -66
- factpulse/api/afnorpdppa_flow_service_api.py +23 -23
- factpulse/api/chorus_pro_api.py +362 -404
- factpulse/api/{signature_lectronique_api.py → document_conversion_api.py} +519 -371
- factpulse/api/health_api.py +526 -0
- factpulse/api/invoice_processing_api.py +3437 -0
- factpulse/api/pdfxml_verification_api.py +1719 -0
- factpulse/api/{sant_api.py → user_api.py} +18 -17
- factpulse/api_client.py +6 -6
- factpulse/configuration.py +6 -4
- factpulse/exceptions.py +8 -5
- factpulse/models/__init__.py +133 -99
- factpulse/models/acknowledgment_status.py +38 -0
- factpulse/models/additional_document.py +115 -0
- factpulse/models/afnor_credentials.py +106 -0
- factpulse/models/afnor_destination.py +127 -0
- factpulse/models/afnor_health_check_response.py +91 -0
- factpulse/models/afnor_result.py +105 -0
- factpulse/models/allowance_charge.py +147 -0
- factpulse/models/allowance_reason_code.py +42 -0
- factpulse/models/allowance_total_amount.py +145 -0
- factpulse/models/amount.py +139 -0
- factpulse/models/amount_due.py +139 -0
- factpulse/models/api_error.py +104 -0
- factpulse/models/async_task_status.py +97 -0
- factpulse/models/base_amount.py +145 -0
- factpulse/models/bounding_box_schema.py +100 -0
- factpulse/models/celery_status.py +40 -0
- factpulse/models/certificate_info_response.py +24 -24
- factpulse/models/charge_total_amount.py +145 -0
- factpulse/models/chorus_pro_destination.py +108 -0
- factpulse/models/chorus_pro_result.py +101 -0
- factpulse/models/contact.py +113 -0
- factpulse/models/convert_error_response.py +105 -0
- factpulse/models/convert_pending_input_response.py +114 -0
- factpulse/models/convert_resume_request.py +87 -0
- factpulse/models/convert_success_response.py +126 -0
- factpulse/models/convert_validation_failed_response.py +120 -0
- factpulse/models/delivery_party.py +121 -0
- factpulse/models/destination.py +27 -27
- factpulse/models/document_type_info.py +91 -0
- factpulse/models/electronic_address.py +90 -0
- factpulse/models/enriched_invoice_info.py +133 -0
- factpulse/models/error_level.py +37 -0
- factpulse/models/error_source.py +43 -0
- factpulse/models/extraction_info.py +93 -0
- factpulse/models/factur_x_invoice.py +320 -0
- factpulse/models/factur_x_profile.py +39 -0
- factpulse/models/factur_xpdf_info.py +91 -0
- factpulse/models/facture_electronique_rest_api_schemas_chorus_pro_chorus_pro_credentials.py +95 -0
- factpulse/models/facture_electronique_rest_api_schemas_processing_chorus_pro_credentials.py +115 -0
- factpulse/models/field_status.py +40 -0
- factpulse/models/file_info.py +94 -0
- factpulse/models/files_info.py +106 -0
- factpulse/models/flow_direction.py +37 -0
- factpulse/models/flow_profile.py +38 -0
- factpulse/models/flow_summary.py +131 -0
- factpulse/models/flow_syntax.py +40 -0
- factpulse/models/flow_type.py +40 -0
- factpulse/models/generate_certificate_request.py +26 -26
- factpulse/models/generate_certificate_response.py +15 -15
- factpulse/models/get_chorus_pro_id_request.py +100 -0
- factpulse/models/get_chorus_pro_id_response.py +98 -0
- factpulse/models/get_invoice_request.py +98 -0
- factpulse/models/get_invoice_response.py +142 -0
- factpulse/models/get_structure_request.py +100 -0
- factpulse/models/get_structure_response.py +142 -0
- factpulse/models/global_allowance_amount.py +139 -0
- factpulse/models/gross_unit_price.py +145 -0
- factpulse/models/http_validation_error.py +2 -2
- factpulse/models/incoming_invoice.py +196 -0
- factpulse/models/incoming_supplier.py +144 -0
- factpulse/models/invoice_format.py +38 -0
- factpulse/models/invoice_line.py +354 -0
- factpulse/models/invoice_line_allowance_amount.py +145 -0
- factpulse/models/invoice_note.py +94 -0
- factpulse/models/invoice_references.py +194 -0
- factpulse/models/invoice_status.py +96 -0
- factpulse/models/invoice_totals.py +177 -0
- factpulse/models/invoice_totals_prepayment.py +145 -0
- factpulse/models/invoice_type_code.py +51 -0
- factpulse/models/invoicing_framework.py +110 -0
- factpulse/models/invoicing_framework_code.py +39 -0
- factpulse/models/line_net_amount.py +145 -0
- factpulse/models/line_total_amount.py +145 -0
- factpulse/models/mandatory_note_schema.py +124 -0
- factpulse/models/manual_rate.py +139 -0
- factpulse/models/manual_vat_rate.py +139 -0
- factpulse/models/missing_field.py +107 -0
- factpulse/models/operation_nature.py +49 -0
- factpulse/models/output_format.py +37 -0
- factpulse/models/page_dimensions_schema.py +89 -0
- factpulse/models/payee.py +168 -0
- factpulse/models/payment_card.py +99 -0
- factpulse/models/payment_means.py +41 -0
- factpulse/models/pdf_validation_result_api.py +169 -0
- factpulse/models/pdp_credentials.py +20 -13
- factpulse/models/percentage.py +145 -0
- factpulse/models/postal_address.py +134 -0
- factpulse/models/price_allowance_amount.py +145 -0
- factpulse/models/price_basis_quantity.py +145 -0
- factpulse/models/processing_options.py +94 -0
- factpulse/models/product_characteristic.py +89 -0
- factpulse/models/product_classification.py +101 -0
- factpulse/models/quantity.py +139 -0
- factpulse/models/recipient.py +167 -0
- factpulse/models/rounding_amount.py +145 -0
- factpulse/models/scheme_id.py +14 -8
- factpulse/models/search_flow_request.py +143 -0
- factpulse/models/search_flow_response.py +101 -0
- factpulse/models/search_services_response.py +101 -0
- factpulse/models/search_structure_request.py +119 -0
- factpulse/models/search_structure_response.py +101 -0
- factpulse/models/signature_info.py +6 -6
- factpulse/models/signature_info_api.py +122 -0
- factpulse/models/signature_parameters.py +133 -0
- factpulse/models/simplified_invoice_data.py +124 -0
- factpulse/models/structure_info.py +14 -14
- factpulse/models/structure_parameters.py +91 -0
- factpulse/models/structure_service.py +93 -0
- factpulse/models/submission_mode.py +38 -0
- factpulse/models/submit_complete_invoice_request.py +116 -0
- factpulse/models/submit_complete_invoice_response.py +145 -0
- factpulse/models/submit_flow_request.py +123 -0
- factpulse/models/submit_flow_response.py +109 -0
- factpulse/models/submit_gross_amount.py +139 -0
- factpulse/models/submit_invoice_request.py +176 -0
- factpulse/models/submit_invoice_response.py +103 -0
- factpulse/models/submit_net_amount.py +139 -0
- factpulse/models/submit_vat_amount.py +139 -0
- factpulse/models/supplementary_attachment.py +95 -0
- factpulse/models/supplier.py +225 -0
- factpulse/models/task_response.py +87 -0
- factpulse/models/tax_representative.py +95 -0
- factpulse/models/taxable_amount.py +139 -0
- factpulse/models/total_gross_amount.py +139 -0
- factpulse/models/total_net_amount.py +139 -0
- factpulse/models/total_vat_amount.py +139 -0
- factpulse/models/unit_net_price.py +139 -0
- factpulse/models/unit_of_measure.py +41 -0
- factpulse/models/validation_error.py +2 -2
- factpulse/models/validation_error_detail.py +107 -0
- factpulse/models/validation_error_loc_inner.py +2 -2
- factpulse/models/validation_error_response.py +87 -0
- factpulse/models/validation_info.py +105 -0
- factpulse/models/validation_success_response.py +87 -0
- factpulse/models/vat_accounting_code.py +39 -0
- factpulse/models/vat_amount.py +139 -0
- factpulse/models/vat_category.py +44 -0
- factpulse/models/vat_line.py +140 -0
- factpulse/models/vat_point_date_code.py +38 -0
- factpulse/models/vat_rate.py +145 -0
- factpulse/models/verification_success_response.py +135 -0
- factpulse/models/verified_field_schema.py +129 -0
- factpulse/rest.py +9 -4
- factpulse-3.0.7.dist-info/METADATA +292 -0
- factpulse-3.0.7.dist-info/RECORD +168 -0
- factpulse-3.0.7.dist-info/top_level.txt +2 -0
- factpulse_helpers/__init__.py +96 -0
- factpulse_helpers/client.py +2111 -0
- factpulse_helpers/exceptions.py +253 -0
- factpulse/api/processing_endpoints_unifis_api.py +0 -592
- factpulse/api/traitement_facture_api.py +0 -3439
- factpulse/api/utilisateur_api.py +0 -282
- factpulse/models/adresse_electronique.py +0 -90
- factpulse/models/adresse_postale.py +0 -120
- factpulse/models/body_ajouter_fichier_api_v1_chorus_pro_transverses_ajouter_fichier_post.py +0 -104
- factpulse/models/body_completer_facture_api_v1_chorus_pro_factures_completer_post.py +0 -104
- factpulse/models/body_lister_services_structure_api_v1_chorus_pro_structures_id_structure_cpp_services_get.py +0 -102
- factpulse/models/body_rechercher_factures_destinataire_api_v1_chorus_pro_factures_rechercher_destinataire_post.py +0 -104
- factpulse/models/body_rechercher_factures_fournisseur_api_v1_chorus_pro_factures_rechercher_fournisseur_post.py +0 -104
- factpulse/models/body_recycler_facture_api_v1_chorus_pro_factures_recycler_post.py +0 -104
- factpulse/models/body_telecharger_groupe_factures_api_v1_chorus_pro_factures_telecharger_groupe_post.py +0 -104
- factpulse/models/body_traiter_facture_recue_api_v1_chorus_pro_factures_traiter_facture_recue_post.py +0 -104
- factpulse/models/body_valideur_consulter_facture_api_v1_chorus_pro_factures_valideur_consulter_post.py +0 -104
- factpulse/models/body_valideur_rechercher_factures_api_v1_chorus_pro_factures_valideur_rechercher_post.py +0 -104
- factpulse/models/body_valideur_traiter_facture_api_v1_chorus_pro_factures_valideur_traiter_post.py +0 -104
- factpulse/models/cadre_de_facturation.py +0 -102
- factpulse/models/categorie_tva.py +0 -44
- factpulse/models/chorus_pro_credentials.py +0 -95
- factpulse/models/code_cadre_facturation.py +0 -39
- factpulse/models/code_raison_reduction.py +0 -42
- factpulse/models/consulter_facture_request.py +0 -98
- factpulse/models/consulter_facture_response.py +0 -142
- factpulse/models/consulter_structure_request.py +0 -100
- factpulse/models/consulter_structure_response.py +0 -142
- factpulse/models/credentials_afnor.py +0 -106
- factpulse/models/credentials_chorus_pro.py +0 -115
- factpulse/models/destinataire.py +0 -116
- factpulse/models/destination_afnor.py +0 -127
- factpulse/models/destination_chorus_pro.py +0 -108
- factpulse/models/direction_flux.py +0 -37
- factpulse/models/donnees_facture_simplifiees.py +0 -124
- factpulse/models/facture_enrichie_info_input.py +0 -123
- factpulse/models/facture_enrichie_info_output.py +0 -133
- factpulse/models/facture_factur_x.py +0 -173
- factpulse/models/flux_resume.py +0 -131
- factpulse/models/format_sortie.py +0 -37
- factpulse/models/fournisseur.py +0 -146
- factpulse/models/information_signature_api.py +0 -122
- factpulse/models/ligne_de_poste.py +0 -188
- factpulse/models/ligne_de_poste_montant_remise_ht.py +0 -145
- factpulse/models/ligne_de_poste_montant_total_ligne_ht.py +0 -145
- factpulse/models/ligne_de_poste_taux_tva_manuel.py +0 -145
- factpulse/models/ligne_de_tva.py +0 -118
- factpulse/models/mode_depot.py +0 -38
- factpulse/models/mode_paiement.py +0 -41
- factpulse/models/montant_ht_total.py +0 -139
- factpulse/models/montant_total.py +0 -138
- factpulse/models/montant_total_acompte.py +0 -145
- factpulse/models/montant_total_montant_remise_globale_ttc.py +0 -145
- factpulse/models/montant_ttc_total.py +0 -139
- factpulse/models/montant_tva.py +0 -139
- factpulse/models/montantapayer.py +0 -139
- factpulse/models/montantbaseht.py +0 -139
- factpulse/models/montanthttotal.py +0 -139
- factpulse/models/montantttctotal.py +0 -139
- factpulse/models/montanttva.py +0 -139
- factpulse/models/montanttva1.py +0 -139
- factpulse/models/montantunitaireht.py +0 -139
- factpulse/models/obtenir_id_chorus_pro_request.py +0 -100
- factpulse/models/obtenir_id_chorus_pro_response.py +0 -98
- factpulse/models/options_processing.py +0 -94
- factpulse/models/parametres_signature.py +0 -133
- factpulse/models/parametres_structure.py +0 -91
- factpulse/models/pdf_factur_x_info.py +0 -91
- factpulse/models/piece_jointe_complementaire.py +0 -95
- factpulse/models/profil_api.py +0 -39
- factpulse/models/profil_flux.py +0 -38
- factpulse/models/quantite.py +0 -139
- factpulse/models/quota_info.py +0 -95
- factpulse/models/rechercher_services_response.py +0 -101
- factpulse/models/rechercher_structure_request.py +0 -119
- factpulse/models/rechercher_structure_response.py +0 -101
- factpulse/models/references.py +0 -124
- factpulse/models/reponse_healthcheck_afnor.py +0 -91
- factpulse/models/reponse_recherche_flux.py +0 -101
- factpulse/models/reponse_soumission_flux.py +0 -109
- factpulse/models/reponse_tache.py +0 -87
- factpulse/models/reponse_validation_erreur.py +0 -87
- factpulse/models/reponse_validation_succes.py +0 -87
- factpulse/models/requete_recherche_flux.py +0 -143
- factpulse/models/requete_soumission_flux.py +0 -123
- factpulse/models/resultat_afnor.py +0 -105
- factpulse/models/resultat_chorus_pro.py +0 -101
- factpulse/models/resultat_validation_pdfapi.py +0 -169
- factpulse/models/service_structure.py +0 -93
- factpulse/models/soumettre_facture_complete_request.py +0 -116
- factpulse/models/soumettre_facture_complete_response.py +0 -145
- factpulse/models/soumettre_facture_request.py +0 -164
- factpulse/models/soumettre_facture_response.py +0 -103
- factpulse/models/statut_acquittement.py +0 -38
- factpulse/models/statut_facture.py +0 -96
- factpulse/models/statut_tache.py +0 -99
- factpulse/models/syntaxe_flux.py +0 -40
- factpulse/models/tauxmanuel.py +0 -139
- factpulse/models/type_facture.py +0 -37
- factpulse/models/type_flux.py +0 -40
- factpulse/models/type_tva.py +0 -39
- factpulse/models/unite.py +0 -41
- factpulse/models/utilisateur.py +0 -128
- factpulse-1.0.9.dist-info/METADATA +0 -182
- factpulse-1.0.9.dist-info/RECORD +0 -131
- factpulse-1.0.9.dist-info/top_level.txt +0 -1
- {factpulse-1.0.9.dist-info → factpulse-3.0.7.dist-info}/WHEEL +0 -0
- {factpulse-1.0.9.dist-info → factpulse-3.0.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
FactPulse REST API
|
|
5
|
+
|
|
6
|
+
REST API for electronic invoicing in France: Factur-X, AFNOR PDP/PA, electronic signatures. ## 🎯 Main Features ### 📄 Factur-X Invoice Generation - **Formats**: XML only or PDF/A-3 with embedded XML - **Profiles**: MINIMUM, BASIC, EN16931, EXTENDED - **Standards**: EN 16931 (EU directive 2014/55), ISO 19005-3 (PDF/A-3), CII (UN/CEFACT) - **🆕 Simplified Format**: Generation from SIRET + auto-enrichment (Chorus Pro API + Business Search) ### ✅ Validation and Compliance - **XML Validation**: Schematron (45 to 210+ rules depending on profile) - **PDF Validation**: PDF/A-3, Factur-X XMP metadata, electronic signatures - **VeraPDF**: Strict PDF/A validation (146+ ISO 19005-3 rules) - **Asynchronous Processing**: Celery support for heavy validations (VeraPDF) ### 📡 AFNOR PDP/PA Integration (XP Z12-013) - **Flow Submission**: Send invoices to Partner Dematerialization Platforms - **Flow Search**: View submitted invoices - **Download**: Retrieve PDF/A-3 with XML - **Directory Service**: Company search (SIREN/SIRET) - **Multi-client**: Support for multiple PDP configs per user (stored credentials or zero-storage) ### ✍️ PDF Electronic Signature - **Standards**: PAdES-B-B, PAdES-B-T (RFC 3161 timestamping), PAdES-B-LT (long-term archival) - **eIDAS Levels**: SES (self-signed), AdES (commercial CA), QES (QTSP) - **Validation**: Cryptographic integrity and certificate verification - **Certificate Generation**: Self-signed X.509 certificates for testing ### 🔄 Asynchronous Processing - **Celery**: Asynchronous generation, validation and signing - **Polling**: Status tracking via `/tasks/{task_id}/status` - **No timeout**: Ideal for large files or heavy validations ## 🔒 Authentication All requests require a **JWT token** in the Authorization header: ``` Authorization: Bearer YOUR_JWT_TOKEN ``` ### How to obtain a JWT token? #### 🔑 Method 1: `/api/token/` API (Recommended) **URL:** `https://www.factpulse.fr/api/token/` This method is **recommended** for integration in your applications and CI/CD workflows. **Prerequisites:** Having set a password on your account **For users registered via email/password:** - You already have a password, use it directly **For users registered via OAuth (Google/GitHub):** - You must first set a password at: https://www.factpulse.fr/accounts/password/set/ - Once the password is created, you can use the API **Request example:** ```bash curl -X POST https://www.factpulse.fr/api/token/ \\ -H \"Content-Type: application/json\" \\ -d '{ \"username\": \"your_email@example.com\", \"password\": \"your_password\" }' ``` **Optional `client_uid` parameter:** To select credentials for a specific client (PA/PDP, Chorus Pro, signing certificates), add `client_uid`: ```bash curl -X POST https://www.factpulse.fr/api/token/ \\ -H \"Content-Type: application/json\" \\ -d '{ \"username\": \"your_email@example.com\", \"password\": \"your_password\", \"client_uid\": \"550e8400-e29b-41d4-a716-446655440000\" }' ``` The `client_uid` will be included in the JWT and allow the API to automatically use: - AFNOR/PDP credentials configured for this client - Chorus Pro credentials configured for this client - Electronic signature certificates configured for this client **Response:** ```json { \"access\": \"eyJ0eXAiOiJKV1QiLCJhbGc...\", // Access token (validity: 30 min) \"refresh\": \"eyJ0eXAiOiJKV1QiLCJhbGc...\" // Refresh token (validity: 7 days) } ``` **Advantages:** - ✅ Full automation (CI/CD, scripts) - ✅ Programmatic token management - ✅ Refresh token support for automatic access renewal - ✅ Easy integration in any language/tool #### 🖥️ Method 2: Dashboard Generation (Alternative) **URL:** https://www.factpulse.fr/dashboard/ This method is suitable for quick tests or occasional use via the graphical interface. **How it works:** - Log in to the dashboard - Use the \"Generate Test Token\" or \"Generate Production Token\" buttons - Works for **all** users (OAuth and email/password), without requiring a password **Token types:** - **Test Token**: 24h validity, 1000 calls/day quota (free) - **Production Token**: 7 days validity, quota based on your plan **Advantages:** - ✅ Quick for API testing - ✅ No password required - ✅ Simple visual interface **Disadvantages:** - ❌ Requires manual action - ❌ No refresh token - ❌ Less suited for automation ### 📚 Full Documentation For more information on authentication and API usage: https://www.factpulse.fr/documentation-api/
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pprint
|
|
17
|
+
import re # noqa: F401
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, ConfigDict, StrictInt, StrictStr
|
|
21
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
|
22
|
+
from factpulse.models.additional_document import AdditionalDocument
|
|
23
|
+
from factpulse.models.allowance_charge import AllowanceCharge
|
|
24
|
+
from factpulse.models.delivery_party import DeliveryParty
|
|
25
|
+
from factpulse.models.invoice_line import InvoiceLine
|
|
26
|
+
from factpulse.models.invoice_note import InvoiceNote
|
|
27
|
+
from factpulse.models.invoice_references import InvoiceReferences
|
|
28
|
+
from factpulse.models.invoice_totals import InvoiceTotals
|
|
29
|
+
from factpulse.models.invoicing_framework import InvoicingFramework
|
|
30
|
+
from factpulse.models.payee import Payee
|
|
31
|
+
from factpulse.models.payment_card import PaymentCard
|
|
32
|
+
from factpulse.models.recipient import Recipient
|
|
33
|
+
from factpulse.models.submission_mode import SubmissionMode
|
|
34
|
+
from factpulse.models.supplementary_attachment import SupplementaryAttachment
|
|
35
|
+
from factpulse.models.supplier import Supplier
|
|
36
|
+
from factpulse.models.tax_representative import TaxRepresentative
|
|
37
|
+
from factpulse.models.vat_line import VATLine
|
|
38
|
+
from typing import Optional, Set
|
|
39
|
+
from typing_extensions import Self
|
|
40
|
+
|
|
41
|
+
class FacturXInvoice(BaseModel):
|
|
42
|
+
"""
|
|
43
|
+
Data model for an invoice to be converted to Factur-X.
|
|
44
|
+
""" # noqa: E501
|
|
45
|
+
invoice_number: StrictStr
|
|
46
|
+
payment_due_date: StrictStr
|
|
47
|
+
invoice_date: Optional[StrictStr] = None
|
|
48
|
+
submission_mode: SubmissionMode
|
|
49
|
+
recipient: Recipient
|
|
50
|
+
supplier: Supplier
|
|
51
|
+
invoicing_framework: InvoicingFramework
|
|
52
|
+
references: InvoiceReferences
|
|
53
|
+
totals: InvoiceTotals
|
|
54
|
+
invoice_lines: Optional[List[InvoiceLine]] = None
|
|
55
|
+
vat_lines: Optional[List[VATLine]] = None
|
|
56
|
+
notes: Optional[List[InvoiceNote]] = None
|
|
57
|
+
comment: Optional[StrictStr] = None
|
|
58
|
+
current_user_id: Optional[StrictInt] = None
|
|
59
|
+
supplementary_attachments: Optional[List[SupplementaryAttachment]] = None
|
|
60
|
+
payee: Optional[Payee] = None
|
|
61
|
+
delivery_party: Optional[DeliveryParty] = None
|
|
62
|
+
tax_representative: Optional[TaxRepresentative] = None
|
|
63
|
+
delivery_date: Optional[StrictStr] = None
|
|
64
|
+
billing_period_start: Optional[StrictStr] = None
|
|
65
|
+
billing_period_end: Optional[StrictStr] = None
|
|
66
|
+
payment_reference: Optional[StrictStr] = None
|
|
67
|
+
creditor_reference_id: Optional[StrictStr] = None
|
|
68
|
+
direct_debit_mandate_id: Optional[StrictStr] = None
|
|
69
|
+
debtor_iban: Optional[StrictStr] = None
|
|
70
|
+
payment_terms: Optional[StrictStr] = None
|
|
71
|
+
allowances_charges: Optional[List[AllowanceCharge]] = None
|
|
72
|
+
additional_documents: Optional[List[AdditionalDocument]] = None
|
|
73
|
+
buyer_accounting_reference: Optional[StrictStr] = None
|
|
74
|
+
payment_card: Optional[PaymentCard] = None
|
|
75
|
+
__properties: ClassVar[List[str]] = ["invoice_number", "payment_due_date", "invoice_date", "submission_mode", "recipient", "supplier", "invoicing_framework", "references", "totals", "invoice_lines", "vat_lines", "notes", "comment", "current_user_id", "supplementary_attachments", "payee", "delivery_party", "tax_representative", "delivery_date", "billing_period_start", "billing_period_end", "payment_reference", "creditor_reference_id", "direct_debit_mandate_id", "debtor_iban", "payment_terms", "allowances_charges", "additional_documents", "buyer_accounting_reference", "payment_card"]
|
|
76
|
+
|
|
77
|
+
model_config = ConfigDict(
|
|
78
|
+
populate_by_name=True,
|
|
79
|
+
validate_assignment=True,
|
|
80
|
+
protected_namespaces=(),
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def to_str(self) -> str:
|
|
85
|
+
"""Returns the string representation of the model using alias"""
|
|
86
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
|
87
|
+
|
|
88
|
+
def to_json(self) -> str:
|
|
89
|
+
"""Returns the JSON representation of the model using alias"""
|
|
90
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
|
91
|
+
return json.dumps(self.to_dict())
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
|
95
|
+
"""Create an instance of FacturXInvoice from a JSON string"""
|
|
96
|
+
return cls.from_dict(json.loads(json_str))
|
|
97
|
+
|
|
98
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
99
|
+
"""Return the dictionary representation of the model using alias.
|
|
100
|
+
|
|
101
|
+
This has the following differences from calling pydantic's
|
|
102
|
+
`self.model_dump(by_alias=True)`:
|
|
103
|
+
|
|
104
|
+
* `None` is only added to the output dict for nullable fields that
|
|
105
|
+
were set at model initialization. Other fields with value `None`
|
|
106
|
+
are ignored.
|
|
107
|
+
"""
|
|
108
|
+
excluded_fields: Set[str] = set([
|
|
109
|
+
])
|
|
110
|
+
|
|
111
|
+
_dict = self.model_dump(
|
|
112
|
+
by_alias=True,
|
|
113
|
+
exclude=excluded_fields,
|
|
114
|
+
exclude_none=True,
|
|
115
|
+
)
|
|
116
|
+
# override the default output from pydantic by calling `to_dict()` of recipient
|
|
117
|
+
if self.recipient:
|
|
118
|
+
_dict['recipient'] = self.recipient.to_dict()
|
|
119
|
+
# override the default output from pydantic by calling `to_dict()` of supplier
|
|
120
|
+
if self.supplier:
|
|
121
|
+
_dict['supplier'] = self.supplier.to_dict()
|
|
122
|
+
# override the default output from pydantic by calling `to_dict()` of invoicing_framework
|
|
123
|
+
if self.invoicing_framework:
|
|
124
|
+
_dict['invoicing_framework'] = self.invoicing_framework.to_dict()
|
|
125
|
+
# override the default output from pydantic by calling `to_dict()` of references
|
|
126
|
+
if self.references:
|
|
127
|
+
_dict['references'] = self.references.to_dict()
|
|
128
|
+
# override the default output from pydantic by calling `to_dict()` of totals
|
|
129
|
+
if self.totals:
|
|
130
|
+
_dict['totals'] = self.totals.to_dict()
|
|
131
|
+
# override the default output from pydantic by calling `to_dict()` of each item in invoice_lines (list)
|
|
132
|
+
_items = []
|
|
133
|
+
if self.invoice_lines:
|
|
134
|
+
for _item_invoice_lines in self.invoice_lines:
|
|
135
|
+
if _item_invoice_lines:
|
|
136
|
+
_items.append(_item_invoice_lines.to_dict())
|
|
137
|
+
_dict['invoice_lines'] = _items
|
|
138
|
+
# override the default output from pydantic by calling `to_dict()` of each item in vat_lines (list)
|
|
139
|
+
_items = []
|
|
140
|
+
if self.vat_lines:
|
|
141
|
+
for _item_vat_lines in self.vat_lines:
|
|
142
|
+
if _item_vat_lines:
|
|
143
|
+
_items.append(_item_vat_lines.to_dict())
|
|
144
|
+
_dict['vat_lines'] = _items
|
|
145
|
+
# override the default output from pydantic by calling `to_dict()` of each item in notes (list)
|
|
146
|
+
_items = []
|
|
147
|
+
if self.notes:
|
|
148
|
+
for _item_notes in self.notes:
|
|
149
|
+
if _item_notes:
|
|
150
|
+
_items.append(_item_notes.to_dict())
|
|
151
|
+
_dict['notes'] = _items
|
|
152
|
+
# override the default output from pydantic by calling `to_dict()` of each item in supplementary_attachments (list)
|
|
153
|
+
_items = []
|
|
154
|
+
if self.supplementary_attachments:
|
|
155
|
+
for _item_supplementary_attachments in self.supplementary_attachments:
|
|
156
|
+
if _item_supplementary_attachments:
|
|
157
|
+
_items.append(_item_supplementary_attachments.to_dict())
|
|
158
|
+
_dict['supplementary_attachments'] = _items
|
|
159
|
+
# override the default output from pydantic by calling `to_dict()` of payee
|
|
160
|
+
if self.payee:
|
|
161
|
+
_dict['payee'] = self.payee.to_dict()
|
|
162
|
+
# override the default output from pydantic by calling `to_dict()` of delivery_party
|
|
163
|
+
if self.delivery_party:
|
|
164
|
+
_dict['delivery_party'] = self.delivery_party.to_dict()
|
|
165
|
+
# override the default output from pydantic by calling `to_dict()` of tax_representative
|
|
166
|
+
if self.tax_representative:
|
|
167
|
+
_dict['tax_representative'] = self.tax_representative.to_dict()
|
|
168
|
+
# override the default output from pydantic by calling `to_dict()` of each item in allowances_charges (list)
|
|
169
|
+
_items = []
|
|
170
|
+
if self.allowances_charges:
|
|
171
|
+
for _item_allowances_charges in self.allowances_charges:
|
|
172
|
+
if _item_allowances_charges:
|
|
173
|
+
_items.append(_item_allowances_charges.to_dict())
|
|
174
|
+
_dict['allowances_charges'] = _items
|
|
175
|
+
# override the default output from pydantic by calling `to_dict()` of each item in additional_documents (list)
|
|
176
|
+
_items = []
|
|
177
|
+
if self.additional_documents:
|
|
178
|
+
for _item_additional_documents in self.additional_documents:
|
|
179
|
+
if _item_additional_documents:
|
|
180
|
+
_items.append(_item_additional_documents.to_dict())
|
|
181
|
+
_dict['additional_documents'] = _items
|
|
182
|
+
# override the default output from pydantic by calling `to_dict()` of payment_card
|
|
183
|
+
if self.payment_card:
|
|
184
|
+
_dict['payment_card'] = self.payment_card.to_dict()
|
|
185
|
+
# set to None if comment (nullable) is None
|
|
186
|
+
# and model_fields_set contains the field
|
|
187
|
+
if self.comment is None and "comment" in self.model_fields_set:
|
|
188
|
+
_dict['comment'] = None
|
|
189
|
+
|
|
190
|
+
# set to None if current_user_id (nullable) is None
|
|
191
|
+
# and model_fields_set contains the field
|
|
192
|
+
if self.current_user_id is None and "current_user_id" in self.model_fields_set:
|
|
193
|
+
_dict['current_user_id'] = None
|
|
194
|
+
|
|
195
|
+
# set to None if supplementary_attachments (nullable) is None
|
|
196
|
+
# and model_fields_set contains the field
|
|
197
|
+
if self.supplementary_attachments is None and "supplementary_attachments" in self.model_fields_set:
|
|
198
|
+
_dict['supplementary_attachments'] = None
|
|
199
|
+
|
|
200
|
+
# set to None if payee (nullable) is None
|
|
201
|
+
# and model_fields_set contains the field
|
|
202
|
+
if self.payee is None and "payee" in self.model_fields_set:
|
|
203
|
+
_dict['payee'] = None
|
|
204
|
+
|
|
205
|
+
# set to None if delivery_party (nullable) is None
|
|
206
|
+
# and model_fields_set contains the field
|
|
207
|
+
if self.delivery_party is None and "delivery_party" in self.model_fields_set:
|
|
208
|
+
_dict['delivery_party'] = None
|
|
209
|
+
|
|
210
|
+
# set to None if tax_representative (nullable) is None
|
|
211
|
+
# and model_fields_set contains the field
|
|
212
|
+
if self.tax_representative is None and "tax_representative" in self.model_fields_set:
|
|
213
|
+
_dict['tax_representative'] = None
|
|
214
|
+
|
|
215
|
+
# set to None if delivery_date (nullable) is None
|
|
216
|
+
# and model_fields_set contains the field
|
|
217
|
+
if self.delivery_date is None and "delivery_date" in self.model_fields_set:
|
|
218
|
+
_dict['delivery_date'] = None
|
|
219
|
+
|
|
220
|
+
# set to None if billing_period_start (nullable) is None
|
|
221
|
+
# and model_fields_set contains the field
|
|
222
|
+
if self.billing_period_start is None and "billing_period_start" in self.model_fields_set:
|
|
223
|
+
_dict['billing_period_start'] = None
|
|
224
|
+
|
|
225
|
+
# set to None if billing_period_end (nullable) is None
|
|
226
|
+
# and model_fields_set contains the field
|
|
227
|
+
if self.billing_period_end is None and "billing_period_end" in self.model_fields_set:
|
|
228
|
+
_dict['billing_period_end'] = None
|
|
229
|
+
|
|
230
|
+
# set to None if payment_reference (nullable) is None
|
|
231
|
+
# and model_fields_set contains the field
|
|
232
|
+
if self.payment_reference is None and "payment_reference" in self.model_fields_set:
|
|
233
|
+
_dict['payment_reference'] = None
|
|
234
|
+
|
|
235
|
+
# set to None if creditor_reference_id (nullable) is None
|
|
236
|
+
# and model_fields_set contains the field
|
|
237
|
+
if self.creditor_reference_id is None and "creditor_reference_id" in self.model_fields_set:
|
|
238
|
+
_dict['creditor_reference_id'] = None
|
|
239
|
+
|
|
240
|
+
# set to None if direct_debit_mandate_id (nullable) is None
|
|
241
|
+
# and model_fields_set contains the field
|
|
242
|
+
if self.direct_debit_mandate_id is None and "direct_debit_mandate_id" in self.model_fields_set:
|
|
243
|
+
_dict['direct_debit_mandate_id'] = None
|
|
244
|
+
|
|
245
|
+
# set to None if debtor_iban (nullable) is None
|
|
246
|
+
# and model_fields_set contains the field
|
|
247
|
+
if self.debtor_iban is None and "debtor_iban" in self.model_fields_set:
|
|
248
|
+
_dict['debtor_iban'] = None
|
|
249
|
+
|
|
250
|
+
# set to None if payment_terms (nullable) is None
|
|
251
|
+
# and model_fields_set contains the field
|
|
252
|
+
if self.payment_terms is None and "payment_terms" in self.model_fields_set:
|
|
253
|
+
_dict['payment_terms'] = None
|
|
254
|
+
|
|
255
|
+
# set to None if allowances_charges (nullable) is None
|
|
256
|
+
# and model_fields_set contains the field
|
|
257
|
+
if self.allowances_charges is None and "allowances_charges" in self.model_fields_set:
|
|
258
|
+
_dict['allowances_charges'] = None
|
|
259
|
+
|
|
260
|
+
# set to None if additional_documents (nullable) is None
|
|
261
|
+
# and model_fields_set contains the field
|
|
262
|
+
if self.additional_documents is None and "additional_documents" in self.model_fields_set:
|
|
263
|
+
_dict['additional_documents'] = None
|
|
264
|
+
|
|
265
|
+
# set to None if buyer_accounting_reference (nullable) is None
|
|
266
|
+
# and model_fields_set contains the field
|
|
267
|
+
if self.buyer_accounting_reference is None and "buyer_accounting_reference" in self.model_fields_set:
|
|
268
|
+
_dict['buyer_accounting_reference'] = None
|
|
269
|
+
|
|
270
|
+
# set to None if payment_card (nullable) is None
|
|
271
|
+
# and model_fields_set contains the field
|
|
272
|
+
if self.payment_card is None and "payment_card" in self.model_fields_set:
|
|
273
|
+
_dict['payment_card'] = None
|
|
274
|
+
|
|
275
|
+
return _dict
|
|
276
|
+
|
|
277
|
+
@classmethod
|
|
278
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
|
279
|
+
"""Create an instance of FacturXInvoice from a dict"""
|
|
280
|
+
if obj is None:
|
|
281
|
+
return None
|
|
282
|
+
|
|
283
|
+
if not isinstance(obj, dict):
|
|
284
|
+
return cls.model_validate(obj)
|
|
285
|
+
|
|
286
|
+
_obj = cls.model_validate({
|
|
287
|
+
"invoice_number": obj.get("invoice_number"),
|
|
288
|
+
"payment_due_date": obj.get("payment_due_date"),
|
|
289
|
+
"invoice_date": obj.get("invoice_date"),
|
|
290
|
+
"submission_mode": obj.get("submission_mode"),
|
|
291
|
+
"recipient": Recipient.from_dict(obj["recipient"]) if obj.get("recipient") is not None else None,
|
|
292
|
+
"supplier": Supplier.from_dict(obj["supplier"]) if obj.get("supplier") is not None else None,
|
|
293
|
+
"invoicing_framework": InvoicingFramework.from_dict(obj["invoicing_framework"]) if obj.get("invoicing_framework") is not None else None,
|
|
294
|
+
"references": InvoiceReferences.from_dict(obj["references"]) if obj.get("references") is not None else None,
|
|
295
|
+
"totals": InvoiceTotals.from_dict(obj["totals"]) if obj.get("totals") is not None else None,
|
|
296
|
+
"invoice_lines": [InvoiceLine.from_dict(_item) for _item in obj["invoice_lines"]] if obj.get("invoice_lines") is not None else None,
|
|
297
|
+
"vat_lines": [VATLine.from_dict(_item) for _item in obj["vat_lines"]] if obj.get("vat_lines") is not None else None,
|
|
298
|
+
"notes": [InvoiceNote.from_dict(_item) for _item in obj["notes"]] if obj.get("notes") is not None else None,
|
|
299
|
+
"comment": obj.get("comment"),
|
|
300
|
+
"current_user_id": obj.get("current_user_id"),
|
|
301
|
+
"supplementary_attachments": [SupplementaryAttachment.from_dict(_item) for _item in obj["supplementary_attachments"]] if obj.get("supplementary_attachments") is not None else None,
|
|
302
|
+
"payee": Payee.from_dict(obj["payee"]) if obj.get("payee") is not None else None,
|
|
303
|
+
"delivery_party": DeliveryParty.from_dict(obj["delivery_party"]) if obj.get("delivery_party") is not None else None,
|
|
304
|
+
"tax_representative": TaxRepresentative.from_dict(obj["tax_representative"]) if obj.get("tax_representative") is not None else None,
|
|
305
|
+
"delivery_date": obj.get("delivery_date"),
|
|
306
|
+
"billing_period_start": obj.get("billing_period_start"),
|
|
307
|
+
"billing_period_end": obj.get("billing_period_end"),
|
|
308
|
+
"payment_reference": obj.get("payment_reference"),
|
|
309
|
+
"creditor_reference_id": obj.get("creditor_reference_id"),
|
|
310
|
+
"direct_debit_mandate_id": obj.get("direct_debit_mandate_id"),
|
|
311
|
+
"debtor_iban": obj.get("debtor_iban"),
|
|
312
|
+
"payment_terms": obj.get("payment_terms"),
|
|
313
|
+
"allowances_charges": [AllowanceCharge.from_dict(_item) for _item in obj["allowances_charges"]] if obj.get("allowances_charges") is not None else None,
|
|
314
|
+
"additional_documents": [AdditionalDocument.from_dict(_item) for _item in obj["additional_documents"]] if obj.get("additional_documents") is not None else None,
|
|
315
|
+
"buyer_accounting_reference": obj.get("buyer_accounting_reference"),
|
|
316
|
+
"payment_card": PaymentCard.from_dict(obj["payment_card"]) if obj.get("payment_card") is not None else None
|
|
317
|
+
})
|
|
318
|
+
return _obj
|
|
319
|
+
|
|
320
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
FactPulse REST API
|
|
5
|
+
|
|
6
|
+
REST API for electronic invoicing in France: Factur-X, AFNOR PDP/PA, electronic signatures. ## 🎯 Main Features ### 📄 Factur-X Invoice Generation - **Formats**: XML only or PDF/A-3 with embedded XML - **Profiles**: MINIMUM, BASIC, EN16931, EXTENDED - **Standards**: EN 16931 (EU directive 2014/55), ISO 19005-3 (PDF/A-3), CII (UN/CEFACT) - **🆕 Simplified Format**: Generation from SIRET + auto-enrichment (Chorus Pro API + Business Search) ### ✅ Validation and Compliance - **XML Validation**: Schematron (45 to 210+ rules depending on profile) - **PDF Validation**: PDF/A-3, Factur-X XMP metadata, electronic signatures - **VeraPDF**: Strict PDF/A validation (146+ ISO 19005-3 rules) - **Asynchronous Processing**: Celery support for heavy validations (VeraPDF) ### 📡 AFNOR PDP/PA Integration (XP Z12-013) - **Flow Submission**: Send invoices to Partner Dematerialization Platforms - **Flow Search**: View submitted invoices - **Download**: Retrieve PDF/A-3 with XML - **Directory Service**: Company search (SIREN/SIRET) - **Multi-client**: Support for multiple PDP configs per user (stored credentials or zero-storage) ### ✍️ PDF Electronic Signature - **Standards**: PAdES-B-B, PAdES-B-T (RFC 3161 timestamping), PAdES-B-LT (long-term archival) - **eIDAS Levels**: SES (self-signed), AdES (commercial CA), QES (QTSP) - **Validation**: Cryptographic integrity and certificate verification - **Certificate Generation**: Self-signed X.509 certificates for testing ### 🔄 Asynchronous Processing - **Celery**: Asynchronous generation, validation and signing - **Polling**: Status tracking via `/tasks/{task_id}/status` - **No timeout**: Ideal for large files or heavy validations ## 🔒 Authentication All requests require a **JWT token** in the Authorization header: ``` Authorization: Bearer YOUR_JWT_TOKEN ``` ### How to obtain a JWT token? #### 🔑 Method 1: `/api/token/` API (Recommended) **URL:** `https://www.factpulse.fr/api/token/` This method is **recommended** for integration in your applications and CI/CD workflows. **Prerequisites:** Having set a password on your account **For users registered via email/password:** - You already have a password, use it directly **For users registered via OAuth (Google/GitHub):** - You must first set a password at: https://www.factpulse.fr/accounts/password/set/ - Once the password is created, you can use the API **Request example:** ```bash curl -X POST https://www.factpulse.fr/api/token/ \\ -H \"Content-Type: application/json\" \\ -d '{ \"username\": \"your_email@example.com\", \"password\": \"your_password\" }' ``` **Optional `client_uid` parameter:** To select credentials for a specific client (PA/PDP, Chorus Pro, signing certificates), add `client_uid`: ```bash curl -X POST https://www.factpulse.fr/api/token/ \\ -H \"Content-Type: application/json\" \\ -d '{ \"username\": \"your_email@example.com\", \"password\": \"your_password\", \"client_uid\": \"550e8400-e29b-41d4-a716-446655440000\" }' ``` The `client_uid` will be included in the JWT and allow the API to automatically use: - AFNOR/PDP credentials configured for this client - Chorus Pro credentials configured for this client - Electronic signature certificates configured for this client **Response:** ```json { \"access\": \"eyJ0eXAiOiJKV1QiLCJhbGc...\", // Access token (validity: 30 min) \"refresh\": \"eyJ0eXAiOiJKV1QiLCJhbGc...\" // Refresh token (validity: 7 days) } ``` **Advantages:** - ✅ Full automation (CI/CD, scripts) - ✅ Programmatic token management - ✅ Refresh token support for automatic access renewal - ✅ Easy integration in any language/tool #### 🖥️ Method 2: Dashboard Generation (Alternative) **URL:** https://www.factpulse.fr/dashboard/ This method is suitable for quick tests or occasional use via the graphical interface. **How it works:** - Log in to the dashboard - Use the \"Generate Test Token\" or \"Generate Production Token\" buttons - Works for **all** users (OAuth and email/password), without requiring a password **Token types:** - **Test Token**: 24h validity, 1000 calls/day quota (free) - **Production Token**: 7 days validity, quota based on your plan **Advantages:** - ✅ Quick for API testing - ✅ No password required - ✅ Simple visual interface **Disadvantages:** - ❌ Requires manual action - ❌ No refresh token - ❌ Less suited for automation ### 📚 Full Documentation For more information on authentication and API usage: https://www.factpulse.fr/documentation-api/
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import json
|
|
17
|
+
from enum import Enum
|
|
18
|
+
from typing_extensions import Self
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class FacturXProfile(str, Enum):
|
|
22
|
+
"""
|
|
23
|
+
Profil Factur-X pour la reponse API. Note: Simplifie par rapport a utils/facturx.FacturXProfile qui contient aussi les configurations XSLT. Celui-ci est pour l'API.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
allowed enum values
|
|
28
|
+
"""
|
|
29
|
+
MINIMUM = 'MINIMUM'
|
|
30
|
+
BASIC = 'BASIC'
|
|
31
|
+
EN16931 = 'EN16931'
|
|
32
|
+
EXTENDED = 'EXTENDED'
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def from_json(cls, json_str: str) -> Self:
|
|
36
|
+
"""Create an instance of FacturXProfile from a JSON string"""
|
|
37
|
+
return cls(json.loads(json_str))
|
|
38
|
+
|
|
39
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
FactPulse REST API
|
|
5
|
+
|
|
6
|
+
REST API for electronic invoicing in France: Factur-X, AFNOR PDP/PA, electronic signatures. ## 🎯 Main Features ### 📄 Factur-X Invoice Generation - **Formats**: XML only or PDF/A-3 with embedded XML - **Profiles**: MINIMUM, BASIC, EN16931, EXTENDED - **Standards**: EN 16931 (EU directive 2014/55), ISO 19005-3 (PDF/A-3), CII (UN/CEFACT) - **🆕 Simplified Format**: Generation from SIRET + auto-enrichment (Chorus Pro API + Business Search) ### ✅ Validation and Compliance - **XML Validation**: Schematron (45 to 210+ rules depending on profile) - **PDF Validation**: PDF/A-3, Factur-X XMP metadata, electronic signatures - **VeraPDF**: Strict PDF/A validation (146+ ISO 19005-3 rules) - **Asynchronous Processing**: Celery support for heavy validations (VeraPDF) ### 📡 AFNOR PDP/PA Integration (XP Z12-013) - **Flow Submission**: Send invoices to Partner Dematerialization Platforms - **Flow Search**: View submitted invoices - **Download**: Retrieve PDF/A-3 with XML - **Directory Service**: Company search (SIREN/SIRET) - **Multi-client**: Support for multiple PDP configs per user (stored credentials or zero-storage) ### ✍️ PDF Electronic Signature - **Standards**: PAdES-B-B, PAdES-B-T (RFC 3161 timestamping), PAdES-B-LT (long-term archival) - **eIDAS Levels**: SES (self-signed), AdES (commercial CA), QES (QTSP) - **Validation**: Cryptographic integrity and certificate verification - **Certificate Generation**: Self-signed X.509 certificates for testing ### 🔄 Asynchronous Processing - **Celery**: Asynchronous generation, validation and signing - **Polling**: Status tracking via `/tasks/{task_id}/status` - **No timeout**: Ideal for large files or heavy validations ## 🔒 Authentication All requests require a **JWT token** in the Authorization header: ``` Authorization: Bearer YOUR_JWT_TOKEN ``` ### How to obtain a JWT token? #### 🔑 Method 1: `/api/token/` API (Recommended) **URL:** `https://www.factpulse.fr/api/token/` This method is **recommended** for integration in your applications and CI/CD workflows. **Prerequisites:** Having set a password on your account **For users registered via email/password:** - You already have a password, use it directly **For users registered via OAuth (Google/GitHub):** - You must first set a password at: https://www.factpulse.fr/accounts/password/set/ - Once the password is created, you can use the API **Request example:** ```bash curl -X POST https://www.factpulse.fr/api/token/ \\ -H \"Content-Type: application/json\" \\ -d '{ \"username\": \"your_email@example.com\", \"password\": \"your_password\" }' ``` **Optional `client_uid` parameter:** To select credentials for a specific client (PA/PDP, Chorus Pro, signing certificates), add `client_uid`: ```bash curl -X POST https://www.factpulse.fr/api/token/ \\ -H \"Content-Type: application/json\" \\ -d '{ \"username\": \"your_email@example.com\", \"password\": \"your_password\", \"client_uid\": \"550e8400-e29b-41d4-a716-446655440000\" }' ``` The `client_uid` will be included in the JWT and allow the API to automatically use: - AFNOR/PDP credentials configured for this client - Chorus Pro credentials configured for this client - Electronic signature certificates configured for this client **Response:** ```json { \"access\": \"eyJ0eXAiOiJKV1QiLCJhbGc...\", // Access token (validity: 30 min) \"refresh\": \"eyJ0eXAiOiJKV1QiLCJhbGc...\" // Refresh token (validity: 7 days) } ``` **Advantages:** - ✅ Full automation (CI/CD, scripts) - ✅ Programmatic token management - ✅ Refresh token support for automatic access renewal - ✅ Easy integration in any language/tool #### 🖥️ Method 2: Dashboard Generation (Alternative) **URL:** https://www.factpulse.fr/dashboard/ This method is suitable for quick tests or occasional use via the graphical interface. **How it works:** - Log in to the dashboard - Use the \"Generate Test Token\" or \"Generate Production Token\" buttons - Works for **all** users (OAuth and email/password), without requiring a password **Token types:** - **Test Token**: 24h validity, 1000 calls/day quota (free) - **Production Token**: 7 days validity, quota based on your plan **Advantages:** - ✅ Quick for API testing - ✅ No password required - ✅ Simple visual interface **Disadvantages:** - ❌ Requires manual action - ❌ No refresh token - ❌ Less suited for automation ### 📚 Full Documentation For more information on authentication and API usage: https://www.factpulse.fr/documentation-api/
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pprint
|
|
17
|
+
import re # noqa: F401
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr
|
|
21
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
|
22
|
+
from typing import Optional, Set
|
|
23
|
+
from typing_extensions import Self
|
|
24
|
+
|
|
25
|
+
class FacturXPDFInfo(BaseModel):
|
|
26
|
+
"""
|
|
27
|
+
Information about the generated Factur-X PDF.
|
|
28
|
+
""" # noqa: E501
|
|
29
|
+
size: StrictInt = Field(description="PDF size in bytes")
|
|
30
|
+
profile: StrictStr = Field(description="Factur-X profile used")
|
|
31
|
+
signed: Optional[StrictBool] = Field(default=False, description="PDF electronically signed")
|
|
32
|
+
__properties: ClassVar[List[str]] = ["size", "profile", "signed"]
|
|
33
|
+
|
|
34
|
+
model_config = ConfigDict(
|
|
35
|
+
populate_by_name=True,
|
|
36
|
+
validate_assignment=True,
|
|
37
|
+
protected_namespaces=(),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def to_str(self) -> str:
|
|
42
|
+
"""Returns the string representation of the model using alias"""
|
|
43
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
|
44
|
+
|
|
45
|
+
def to_json(self) -> str:
|
|
46
|
+
"""Returns the JSON representation of the model using alias"""
|
|
47
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
|
48
|
+
return json.dumps(self.to_dict())
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
|
52
|
+
"""Create an instance of FacturXPDFInfo from a JSON string"""
|
|
53
|
+
return cls.from_dict(json.loads(json_str))
|
|
54
|
+
|
|
55
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
56
|
+
"""Return the dictionary representation of the model using alias.
|
|
57
|
+
|
|
58
|
+
This has the following differences from calling pydantic's
|
|
59
|
+
`self.model_dump(by_alias=True)`:
|
|
60
|
+
|
|
61
|
+
* `None` is only added to the output dict for nullable fields that
|
|
62
|
+
were set at model initialization. Other fields with value `None`
|
|
63
|
+
are ignored.
|
|
64
|
+
"""
|
|
65
|
+
excluded_fields: Set[str] = set([
|
|
66
|
+
])
|
|
67
|
+
|
|
68
|
+
_dict = self.model_dump(
|
|
69
|
+
by_alias=True,
|
|
70
|
+
exclude=excluded_fields,
|
|
71
|
+
exclude_none=True,
|
|
72
|
+
)
|
|
73
|
+
return _dict
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
|
77
|
+
"""Create an instance of FacturXPDFInfo from a dict"""
|
|
78
|
+
if obj is None:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
if not isinstance(obj, dict):
|
|
82
|
+
return cls.model_validate(obj)
|
|
83
|
+
|
|
84
|
+
_obj = cls.model_validate({
|
|
85
|
+
"size": obj.get("size"),
|
|
86
|
+
"profile": obj.get("profile"),
|
|
87
|
+
"signed": obj.get("signed") if obj.get("signed") is not None else False
|
|
88
|
+
})
|
|
89
|
+
return _obj
|
|
90
|
+
|
|
91
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
FactPulse REST API
|
|
5
|
+
|
|
6
|
+
REST API for electronic invoicing in France: Factur-X, AFNOR PDP/PA, electronic signatures. ## 🎯 Main Features ### 📄 Factur-X Invoice Generation - **Formats**: XML only or PDF/A-3 with embedded XML - **Profiles**: MINIMUM, BASIC, EN16931, EXTENDED - **Standards**: EN 16931 (EU directive 2014/55), ISO 19005-3 (PDF/A-3), CII (UN/CEFACT) - **🆕 Simplified Format**: Generation from SIRET + auto-enrichment (Chorus Pro API + Business Search) ### ✅ Validation and Compliance - **XML Validation**: Schematron (45 to 210+ rules depending on profile) - **PDF Validation**: PDF/A-3, Factur-X XMP metadata, electronic signatures - **VeraPDF**: Strict PDF/A validation (146+ ISO 19005-3 rules) - **Asynchronous Processing**: Celery support for heavy validations (VeraPDF) ### 📡 AFNOR PDP/PA Integration (XP Z12-013) - **Flow Submission**: Send invoices to Partner Dematerialization Platforms - **Flow Search**: View submitted invoices - **Download**: Retrieve PDF/A-3 with XML - **Directory Service**: Company search (SIREN/SIRET) - **Multi-client**: Support for multiple PDP configs per user (stored credentials or zero-storage) ### ✍️ PDF Electronic Signature - **Standards**: PAdES-B-B, PAdES-B-T (RFC 3161 timestamping), PAdES-B-LT (long-term archival) - **eIDAS Levels**: SES (self-signed), AdES (commercial CA), QES (QTSP) - **Validation**: Cryptographic integrity and certificate verification - **Certificate Generation**: Self-signed X.509 certificates for testing ### 🔄 Asynchronous Processing - **Celery**: Asynchronous generation, validation and signing - **Polling**: Status tracking via `/tasks/{task_id}/status` - **No timeout**: Ideal for large files or heavy validations ## 🔒 Authentication All requests require a **JWT token** in the Authorization header: ``` Authorization: Bearer YOUR_JWT_TOKEN ``` ### How to obtain a JWT token? #### 🔑 Method 1: `/api/token/` API (Recommended) **URL:** `https://www.factpulse.fr/api/token/` This method is **recommended** for integration in your applications and CI/CD workflows. **Prerequisites:** Having set a password on your account **For users registered via email/password:** - You already have a password, use it directly **For users registered via OAuth (Google/GitHub):** - You must first set a password at: https://www.factpulse.fr/accounts/password/set/ - Once the password is created, you can use the API **Request example:** ```bash curl -X POST https://www.factpulse.fr/api/token/ \\ -H \"Content-Type: application/json\" \\ -d '{ \"username\": \"your_email@example.com\", \"password\": \"your_password\" }' ``` **Optional `client_uid` parameter:** To select credentials for a specific client (PA/PDP, Chorus Pro, signing certificates), add `client_uid`: ```bash curl -X POST https://www.factpulse.fr/api/token/ \\ -H \"Content-Type: application/json\" \\ -d '{ \"username\": \"your_email@example.com\", \"password\": \"your_password\", \"client_uid\": \"550e8400-e29b-41d4-a716-446655440000\" }' ``` The `client_uid` will be included in the JWT and allow the API to automatically use: - AFNOR/PDP credentials configured for this client - Chorus Pro credentials configured for this client - Electronic signature certificates configured for this client **Response:** ```json { \"access\": \"eyJ0eXAiOiJKV1QiLCJhbGc...\", // Access token (validity: 30 min) \"refresh\": \"eyJ0eXAiOiJKV1QiLCJhbGc...\" // Refresh token (validity: 7 days) } ``` **Advantages:** - ✅ Full automation (CI/CD, scripts) - ✅ Programmatic token management - ✅ Refresh token support for automatic access renewal - ✅ Easy integration in any language/tool #### 🖥️ Method 2: Dashboard Generation (Alternative) **URL:** https://www.factpulse.fr/dashboard/ This method is suitable for quick tests or occasional use via the graphical interface. **How it works:** - Log in to the dashboard - Use the \"Generate Test Token\" or \"Generate Production Token\" buttons - Works for **all** users (OAuth and email/password), without requiring a password **Token types:** - **Test Token**: 24h validity, 1000 calls/day quota (free) - **Production Token**: 7 days validity, quota based on your plan **Advantages:** - ✅ Quick for API testing - ✅ No password required - ✅ Simple visual interface **Disadvantages:** - ❌ Requires manual action - ❌ No refresh token - ❌ Less suited for automation ### 📚 Full Documentation For more information on authentication and API usage: https://www.factpulse.fr/documentation-api/
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pprint
|
|
17
|
+
import re # noqa: F401
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr
|
|
21
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
|
22
|
+
from typing import Optional, Set
|
|
23
|
+
from typing_extensions import Self
|
|
24
|
+
|
|
25
|
+
class FactureElectroniqueRestApiSchemasChorusProChorusProCredentials(BaseModel):
|
|
26
|
+
"""
|
|
27
|
+
Chorus Pro credentials for Zero-Trust mode. **Zero-Trust Mode**: Credentials are passed in each request and are NEVER stored. **Security**: - Credentials are never persisted in the database - They are used only for the duration of the request - Secure transmission via HTTPS **Use cases**: - High-security environments (banks, administrations) - Strict GDPR compliance - Tests with temporary credentials - Users who don't want to store their credentials
|
|
28
|
+
""" # noqa: E501
|
|
29
|
+
piste_client_id: StrictStr = Field(description="PISTE Client ID (government API portal)", alias="pisteClientId")
|
|
30
|
+
piste_client_secret: StrictStr = Field(description="PISTE Client Secret", alias="pisteClientSecret")
|
|
31
|
+
chorus_pro_login: StrictStr = Field(description="Chorus Pro login", alias="chorusProLogin")
|
|
32
|
+
chorus_pro_password: StrictStr = Field(description="Chorus Pro password", alias="chorusProPassword")
|
|
33
|
+
sandbox: Optional[StrictBool] = Field(default=True, description="Use sandbox environment (true) or production (false)")
|
|
34
|
+
__properties: ClassVar[List[str]] = ["pisteClientId", "pisteClientSecret", "chorusProLogin", "chorusProPassword", "sandbox"]
|
|
35
|
+
|
|
36
|
+
model_config = ConfigDict(
|
|
37
|
+
populate_by_name=True,
|
|
38
|
+
validate_assignment=True,
|
|
39
|
+
protected_namespaces=(),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def to_str(self) -> str:
|
|
44
|
+
"""Returns the string representation of the model using alias"""
|
|
45
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
|
46
|
+
|
|
47
|
+
def to_json(self) -> str:
|
|
48
|
+
"""Returns the JSON representation of the model using alias"""
|
|
49
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
|
50
|
+
return json.dumps(self.to_dict())
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
|
54
|
+
"""Create an instance of FactureElectroniqueRestApiSchemasChorusProChorusProCredentials from a JSON string"""
|
|
55
|
+
return cls.from_dict(json.loads(json_str))
|
|
56
|
+
|
|
57
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
58
|
+
"""Return the dictionary representation of the model using alias.
|
|
59
|
+
|
|
60
|
+
This has the following differences from calling pydantic's
|
|
61
|
+
`self.model_dump(by_alias=True)`:
|
|
62
|
+
|
|
63
|
+
* `None` is only added to the output dict for nullable fields that
|
|
64
|
+
were set at model initialization. Other fields with value `None`
|
|
65
|
+
are ignored.
|
|
66
|
+
"""
|
|
67
|
+
excluded_fields: Set[str] = set([
|
|
68
|
+
])
|
|
69
|
+
|
|
70
|
+
_dict = self.model_dump(
|
|
71
|
+
by_alias=True,
|
|
72
|
+
exclude=excluded_fields,
|
|
73
|
+
exclude_none=True,
|
|
74
|
+
)
|
|
75
|
+
return _dict
|
|
76
|
+
|
|
77
|
+
@classmethod
|
|
78
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
|
79
|
+
"""Create an instance of FactureElectroniqueRestApiSchemasChorusProChorusProCredentials from a dict"""
|
|
80
|
+
if obj is None:
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
if not isinstance(obj, dict):
|
|
84
|
+
return cls.model_validate(obj)
|
|
85
|
+
|
|
86
|
+
_obj = cls.model_validate({
|
|
87
|
+
"pisteClientId": obj.get("pisteClientId"),
|
|
88
|
+
"pisteClientSecret": obj.get("pisteClientSecret"),
|
|
89
|
+
"chorusProLogin": obj.get("chorusProLogin"),
|
|
90
|
+
"chorusProPassword": obj.get("chorusProPassword"),
|
|
91
|
+
"sandbox": obj.get("sandbox") if obj.get("sandbox") is not None else True
|
|
92
|
+
})
|
|
93
|
+
return _obj
|
|
94
|
+
|
|
95
|
+
|