factpulse 2.0.42 → 3.0.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -3
- data/Gemfile.lock +3 -3
- data/README.md +91 -91
- data/docs/{CredentialsAFNOR.md → AFNORCredentials.md} +2 -2
- data/docs/{DestinationAFNOR.md → AFNORDestination.md} +4 -4
- data/docs/AFNORHealthCheckResponse.md +22 -0
- data/docs/AFNORPDPPAApi.md +25 -25
- data/docs/AFNORPDPPADirectoryServiceApi.md +19 -19
- data/docs/AFNORPDPPAFlowServiceApi.md +16 -16
- data/docs/{ResultatAFNOR.md → AFNORResult.md} +5 -5
- data/docs/APIError.md +2 -2
- data/docs/{MontantTva.md → APIProfile.md} +2 -2
- data/docs/{CodeCadreFacturation.md → AcknowledgmentStatus.md} +2 -2
- data/docs/{CodeRaisonReduction.md → AllowanceReasonCode.md} +2 -2
- data/docs/{ModeDepot.md → AmountDue.md} +2 -2
- data/docs/BoundingBoxSchema.md +7 -7
- data/docs/{CategorieTVA.md → CeleryStatus.md} +2 -2
- data/docs/CertificateInfoResponse.md +20 -20
- data/docs/ChorusProApi.md +123 -123
- data/docs/ChorusProDestination.md +20 -0
- data/docs/ChorusProResult.md +22 -0
- data/docs/Destination.md +7 -7
- data/docs/{ModePaiement.md → DocumentType.md} +2 -2
- data/docs/{AdresseElectronique.md → ElectronicAddress.md} +4 -4
- data/docs/EnrichedInvoiceInfo.md +32 -0
- data/docs/FacturXPDFInfo.md +22 -0
- data/docs/FactureElectroniqueRestApiSchemasChorusProChorusProCredentials.md +26 -0
- data/docs/{CredentialsChorusPro.md → FactureElectroniqueRestApiSchemasProcessingChorusProCredentials.md} +4 -4
- data/docs/FactureFacturX.md +30 -30
- data/docs/FieldStatus.md +15 -0
- data/docs/{DirectionFlux.md → FlowDirection.md} +2 -2
- data/docs/FlowProfile.md +15 -0
- data/docs/FlowSummary.md +32 -0
- data/docs/{ProfilFlux.md → FlowSyntax.md} +2 -2
- data/docs/{TypeTVA.md → FlowType.md} +2 -2
- data/docs/GenerateCertificateRequest.md +19 -19
- data/docs/GenerateCertificateResponse.md +8 -8
- data/docs/GetChorusProIdRequest.md +22 -0
- data/docs/GetChorusProIdResponse.md +24 -0
- data/docs/GetInvoiceRequest.md +20 -0
- data/docs/GetInvoiceResponse.md +34 -0
- data/docs/GetStructureRequest.md +22 -0
- data/docs/GetStructureResponse.md +34 -0
- data/docs/GlobalAllowanceAmount.md +15 -0
- data/docs/{SantApi.md → HealthApi.md} +23 -23
- data/docs/IncomingInvoice.md +54 -0
- data/docs/IncomingSupplier.md +32 -0
- data/docs/{FormatFacture.md → InvoiceFormat.md} +2 -2
- data/docs/InvoiceLine.md +46 -0
- data/docs/InvoiceLineAllowanceAmount.md +15 -0
- data/docs/InvoiceNote.md +20 -0
- data/docs/InvoiceProcessingApi.md +831 -0
- data/docs/InvoiceReferences.md +32 -0
- data/docs/{StatutFacture.md → InvoiceStatus.md} +5 -5
- data/docs/InvoiceTotals.md +30 -0
- data/docs/InvoiceTotalsPrepayment.md +15 -0
- data/docs/InvoiceTypeCode.md +15 -0
- data/docs/InvoicingFramework.md +24 -0
- data/docs/InvoicingFrameworkCode.md +15 -0
- data/docs/LineNetAmount.md +15 -0
- data/docs/MandatoryNoteSchema.md +30 -0
- data/docs/ManualRate.md +15 -0
- data/docs/ManualVatRate.md +15 -0
- data/docs/OperationNature.md +15 -0
- data/docs/{FormatSortie.md → OutputFormat.md} +2 -2
- data/docs/PDFValidationResultAPI.md +62 -0
- data/docs/PDFXMLVerificationApi.md +435 -0
- data/docs/PDPCredentials.md +4 -4
- data/docs/PageDimensionsSchema.md +20 -0
- data/docs/{Beneficiaire.md → Payee.md} +5 -5
- data/docs/PaymentMeans.md +15 -0
- data/docs/PostalAddress.md +26 -0
- data/docs/ProcessingOptions.md +24 -0
- data/docs/{Quantite.md → Quantity.md} +2 -2
- data/docs/Recipient.md +28 -0
- data/docs/SearchFlowRequest.md +34 -0
- data/docs/SearchFlowResponse.md +24 -0
- data/docs/SearchServicesResponse.md +24 -0
- data/docs/SearchStructureRequest.md +26 -0
- data/docs/SearchStructureResponse.md +24 -0
- data/docs/SignatureInfo.md +2 -2
- data/docs/SignatureInfoAPI.md +28 -0
- data/docs/SignatureParameters.md +34 -0
- data/docs/SimplifiedInvoiceData.md +34 -0
- data/docs/StructureInfo.md +10 -10
- data/docs/StructureParameters.md +22 -0
- data/docs/StructureService.md +24 -0
- data/docs/SubmissionMode.md +15 -0
- data/docs/SubmitCompleteInvoiceRequest.md +26 -0
- data/docs/SubmitCompleteInvoiceResponse.md +34 -0
- data/docs/SubmitFlowRequest.md +28 -0
- data/docs/SubmitFlowResponse.md +30 -0
- data/docs/SubmitInvoiceRequest.md +46 -0
- data/docs/SubmitInvoiceResponse.md +24 -0
- data/docs/SupplementaryAttachment.md +26 -0
- data/docs/Supplier.md +36 -0
- data/docs/TaskResponse.md +18 -0
- data/docs/TaskStatus.md +22 -0
- data/docs/TaxableAmount.md +15 -0
- data/docs/TotalGrossAmount.md +15 -0
- data/docs/TotalNetAmount.md +15 -0
- data/docs/TotalVATAmount.md +15 -0
- data/docs/UnitNetPrice.md +15 -0
- data/docs/UnitOfMeasure.md +15 -0
- data/docs/UserApi.md +74 -0
- data/docs/VATAccountingCode.md +15 -0
- data/docs/{ProfilAPI.md → VATAmount.md} +2 -2
- data/docs/VATCategory.md +15 -0
- data/docs/VATLine.md +30 -0
- data/docs/ValidationErrorDetail.md +3 -3
- data/docs/ValidationErrorResponse.md +18 -0
- data/docs/ValidationSuccessResponse.md +18 -0
- data/docs/{TypeFlux.md → VatAmount.md} +2 -2
- data/docs/VerificationSuccessResponse.md +36 -0
- data/docs/VerifiedFieldSchema.md +34 -0
- data/factpulse.gemspec +4 -4
- data/lib/factpulse/api/afnorpdppa_api.rb +25 -25
- data/lib/factpulse/api/afnorpdppa_directory_service_api.rb +40 -40
- data/lib/factpulse/api/afnorpdppa_flow_service_api.rb +16 -16
- data/lib/factpulse/api/chorus_pro_api.rb +127 -127
- data/lib/factpulse/api/health_api.rb +136 -0
- data/lib/factpulse/api/invoice_processing_api.rb +835 -0
- data/lib/factpulse/api/pdfxml_verification_api.rb +430 -0
- data/lib/factpulse/api/user_api.rb +79 -0
- data/lib/factpulse/api_client.rb +2 -2
- data/lib/factpulse/api_error.rb +2 -2
- data/lib/factpulse/api_model_base.rb +2 -2
- data/lib/factpulse/configuration.rb +2 -2
- data/lib/factpulse/helpers/client.rb +182 -182
- data/lib/factpulse/helpers/exceptions.rb +2 -2
- data/lib/factpulse/helpers/helpers.rb +5 -5
- data/lib/factpulse/models/acknowledgment_status.rb +41 -0
- data/lib/factpulse/models/afnor_credentials.rb +169 -0
- data/lib/factpulse/models/{destination_afnor.rb → afnor_destination.rb} +10 -10
- data/lib/factpulse/models/{reponse_healthcheck_afnor.rb → afnor_health_check_response.rb} +9 -9
- data/lib/factpulse/models/{resultat_afnor.rb → afnor_result.rb} +13 -13
- data/lib/factpulse/models/allowance_reason_code.rb +45 -0
- data/lib/factpulse/models/amount_due.rb +104 -0
- data/lib/factpulse/models/api_error.rb +5 -5
- data/lib/factpulse/models/api_profile.rb +42 -0
- data/lib/factpulse/models/bounding_box_schema.rb +10 -10
- data/lib/factpulse/models/celery_status.rb +43 -0
- data/lib/factpulse/models/certificate_info_response.rb +164 -164
- data/lib/factpulse/models/{destination_chorus_pro.rb → chorus_pro_destination.rb} +7 -7
- data/lib/factpulse/models/chorus_pro_result.rb +186 -0
- data/lib/factpulse/models/destination.rb +7 -7
- data/lib/factpulse/models/document_type.rb +43 -0
- data/lib/factpulse/models/electronic_address.rb +196 -0
- data/lib/factpulse/models/enriched_invoice_info.rb +348 -0
- data/lib/factpulse/models/error_level.rb +2 -2
- data/lib/factpulse/models/error_source.rb +2 -2
- data/lib/factpulse/models/factur_xpdf_info.rb +205 -0
- data/lib/factpulse/models/{chorus_pro_credentials.rb → facture_electronique_rest_api_schemas_chorus_pro_chorus_pro_credentials.rb} +11 -11
- data/lib/factpulse/models/facture_electronique_rest_api_schemas_processing_chorus_pro_credentials.rb +191 -0
- data/lib/factpulse/models/facture_factur_x.rb +160 -160
- data/lib/factpulse/models/field_status.rb +43 -0
- data/lib/factpulse/models/flow_direction.rb +40 -0
- data/lib/factpulse/models/flow_profile.rb +41 -0
- data/lib/factpulse/models/flow_summary.rb +251 -0
- data/lib/factpulse/models/flow_syntax.rb +43 -0
- data/lib/factpulse/models/flow_type.rb +43 -0
- data/lib/factpulse/models/generate_certificate_request.rb +106 -106
- data/lib/factpulse/models/generate_certificate_response.rb +47 -47
- data/lib/factpulse/models/get_chorus_pro_id_request.rb +188 -0
- data/lib/factpulse/models/get_chorus_pro_id_response.rb +230 -0
- data/lib/factpulse/models/get_invoice_request.rb +176 -0
- data/lib/factpulse/models/get_invoice_response.rb +261 -0
- data/lib/factpulse/models/get_structure_request.rb +188 -0
- data/lib/factpulse/models/get_structure_response.rb +261 -0
- data/lib/factpulse/models/global_allowance_amount.rb +104 -0
- data/lib/factpulse/models/http_validation_error.rb +2 -2
- data/lib/factpulse/models/incoming_invoice.rb +522 -0
- data/lib/factpulse/models/incoming_supplier.rb +236 -0
- data/lib/factpulse/models/invoice_format.rb +41 -0
- data/lib/factpulse/models/invoice_line.rb +389 -0
- data/lib/factpulse/models/invoice_line_allowance_amount.rb +104 -0
- data/lib/factpulse/models/invoice_note.rb +175 -0
- data/lib/factpulse/models/invoice_references.rb +290 -0
- data/lib/factpulse/models/invoice_status.rb +203 -0
- data/lib/factpulse/models/invoice_totals.rb +272 -0
- data/lib/factpulse/models/invoice_totals_prepayment.rb +104 -0
- data/lib/factpulse/models/invoice_type_code.rb +70 -0
- data/lib/factpulse/models/invoicing_framework.rb +217 -0
- data/lib/factpulse/models/invoicing_framework_code.rb +46 -0
- data/lib/factpulse/models/line_net_amount.rb +104 -0
- data/lib/factpulse/models/mandatory_note_schema.rb +265 -0
- data/lib/factpulse/models/manual_rate.rb +104 -0
- data/lib/factpulse/models/manual_vat_rate.rb +104 -0
- data/lib/factpulse/models/operation_nature.rb +52 -0
- data/lib/factpulse/models/output_format.rb +40 -0
- data/lib/factpulse/models/page_dimensions_schema.rb +193 -0
- data/lib/factpulse/models/{beneficiaire.rb → payee.rb} +15 -15
- data/lib/factpulse/models/payment_means.rb +50 -0
- data/lib/factpulse/models/pdf_validation_result_api.rb +523 -0
- data/lib/factpulse/models/pdp_credentials.rb +7 -7
- data/lib/factpulse/models/postal_address.rb +189 -0
- data/lib/factpulse/models/processing_options.rb +207 -0
- data/lib/factpulse/models/quantity.rb +104 -0
- data/lib/factpulse/models/recipient.rb +201 -0
- data/lib/factpulse/models/scheme_id.rb +2 -2
- data/lib/factpulse/models/search_flow_request.rb +306 -0
- data/lib/factpulse/models/search_flow_response.rb +249 -0
- data/lib/factpulse/models/search_services_response.rb +214 -0
- data/lib/factpulse/models/search_structure_request.rb +191 -0
- data/lib/factpulse/models/search_structure_response.rb +216 -0
- data/lib/factpulse/models/signature_info.rb +20 -20
- data/lib/factpulse/models/signature_info_api.rb +216 -0
- data/lib/factpulse/models/signature_parameters.rb +235 -0
- data/lib/factpulse/models/simplified_invoice_data.rb +342 -0
- data/lib/factpulse/models/structure_info.rb +84 -84
- data/lib/factpulse/models/structure_parameters.rb +175 -0
- data/lib/factpulse/models/structure_service.rb +247 -0
- data/lib/factpulse/models/submission_mode.rb +44 -0
- data/lib/factpulse/models/submit_complete_invoice_request.rb +239 -0
- data/lib/factpulse/models/submit_complete_invoice_response.rb +355 -0
- data/lib/factpulse/models/submit_flow_request.rb +238 -0
- data/lib/factpulse/models/submit_flow_response.rb +294 -0
- data/lib/factpulse/models/submit_invoice_request.rb +388 -0
- data/lib/factpulse/models/submit_invoice_response.rb +213 -0
- data/lib/factpulse/models/supplementary_attachment.rb +269 -0
- data/lib/factpulse/models/supplier.rb +257 -0
- data/lib/factpulse/models/task_response.rb +166 -0
- data/lib/factpulse/models/task_status.rb +227 -0
- data/lib/factpulse/models/taxable_amount.rb +104 -0
- data/lib/factpulse/models/total_gross_amount.rb +104 -0
- data/lib/factpulse/models/total_net_amount.rb +104 -0
- data/lib/factpulse/models/total_vat_amount.rb +104 -0
- data/lib/factpulse/models/unit_net_price.rb +104 -0
- data/lib/factpulse/models/unit_of_measure.rb +50 -0
- data/lib/factpulse/models/validation_error.rb +2 -2
- data/lib/factpulse/models/validation_error_detail.rb +6 -6
- data/lib/factpulse/models/validation_error_loc_inner.rb +2 -2
- data/lib/factpulse/models/validation_error_response.rb +168 -0
- data/lib/factpulse/models/validation_success_response.rb +166 -0
- data/lib/factpulse/models/vat_accounting_code.rb +46 -0
- data/lib/factpulse/models/vat_amount.rb +104 -0
- data/lib/factpulse/models/vat_category.rb +47 -0
- data/lib/factpulse/models/vat_line.rb +262 -0
- data/lib/factpulse/models/verification_success_response.rb +343 -0
- data/lib/factpulse/models/verified_field_schema.rb +334 -0
- data/lib/factpulse/version.rb +3 -3
- data/lib/factpulse.rb +99 -99
- metadata +250 -257
- data/docs/AdressePostale.md +0 -26
- data/docs/CadreDeFacturation.md +0 -24
- data/docs/ChampVerifieSchema.md +0 -34
- data/docs/ChorusProCredentials.md +0 -26
- data/docs/ConsulterFactureRequest.md +0 -20
- data/docs/ConsulterFactureResponse.md +0 -34
- data/docs/ConsulterStructureRequest.md +0 -22
- data/docs/ConsulterStructureResponse.md +0 -34
- data/docs/Destinataire.md +0 -28
- data/docs/DestinationChorusPro.md +0 -20
- data/docs/DimensionPageSchema.md +0 -20
- data/docs/DonneesFactureSimplifiees.md +0 -34
- data/docs/FactureEnrichieInfo.md +0 -32
- data/docs/FactureEntrante.md +0 -54
- data/docs/FluxResume.md +0 -32
- data/docs/Fournisseur.md +0 -36
- data/docs/FournisseurEntrant.md +0 -32
- data/docs/InformationSignatureAPI.md +0 -28
- data/docs/LigneDePoste.md +0 -46
- data/docs/LigneDePosteMontantRemiseHt.md +0 -15
- data/docs/LigneDePosteTauxTvaManuel.md +0 -15
- data/docs/LigneDeTVA.md +0 -30
- data/docs/MontantAPayer.md +0 -15
- data/docs/MontantBaseHt.md +0 -15
- data/docs/MontantHtTotal.md +0 -15
- data/docs/MontantRemiseGlobaleTtc.md +0 -15
- data/docs/MontantTotal.md +0 -30
- data/docs/MontantTotalAcompte.md +0 -15
- data/docs/MontantTotalLigneHt.md +0 -15
- data/docs/MontantTtcTotal.md +0 -15
- data/docs/MontantTvaLigne.md +0 -15
- data/docs/MontantTvaTotal.md +0 -15
- data/docs/MontantUnitaireHt.md +0 -15
- data/docs/NatureOperation.md +0 -15
- data/docs/Note.md +0 -20
- data/docs/NoteObligatoireSchema.md +0 -30
- data/docs/ObtenirIdChorusProRequest.md +0 -22
- data/docs/ObtenirIdChorusProResponse.md +0 -24
- data/docs/OptionsProcessing.md +0 -24
- data/docs/PDFFacturXInfo.md +0 -22
- data/docs/ParametresSignature.md +0 -34
- data/docs/ParametresStructure.md +0 -22
- data/docs/PieceJointeComplementaire.md +0 -26
- data/docs/RechercherServicesResponse.md +0 -24
- data/docs/RechercherStructureRequest.md +0 -26
- data/docs/RechercherStructureResponse.md +0 -24
- data/docs/References.md +0 -32
- data/docs/ReponseHealthcheckAFNOR.md +0 -22
- data/docs/ReponseRechercheFlux.md +0 -24
- data/docs/ReponseSoumissionFlux.md +0 -30
- data/docs/ReponseTache.md +0 -18
- data/docs/ReponseValidationErreur.md +0 -18
- data/docs/ReponseValidationSucces.md +0 -18
- data/docs/ReponseVerificationSucces.md +0 -36
- data/docs/RequeteRechercheFlux.md +0 -34
- data/docs/RequeteSoumissionFlux.md +0 -28
- data/docs/ResultatChorusPro.md +0 -22
- data/docs/ResultatValidationPDFAPI.md +0 -62
- data/docs/ServiceStructure.md +0 -24
- data/docs/SoumettreFactureCompleteRequest.md +0 -26
- data/docs/SoumettreFactureCompleteResponse.md +0 -34
- data/docs/SoumettreFactureRequest.md +0 -46
- data/docs/SoumettreFactureResponse.md +0 -24
- data/docs/StatutAcquittement.md +0 -15
- data/docs/StatutCelery.md +0 -15
- data/docs/StatutChampAPI.md +0 -15
- data/docs/StatutTache.md +0 -22
- data/docs/SyntaxeFlux.md +0 -15
- data/docs/Tauxmanuel.md +0 -15
- data/docs/TraitementFactureApi.md +0 -831
- data/docs/TypeDocument.md +0 -15
- data/docs/TypeFacture.md +0 -15
- data/docs/Unite.md +0 -15
- data/docs/UtilisateurApi.md +0 -74
- data/docs/VrificationPDFXMLApi.md +0 -435
- data/lib/factpulse/api/sant_api.rb +0 -136
- data/lib/factpulse/api/traitement_facture_api.rb +0 -835
- data/lib/factpulse/api/utilisateur_api.rb +0 -79
- data/lib/factpulse/api/vrification_pdfxml_api.rb +0 -430
- data/lib/factpulse/models/adresse_electronique.rb +0 -196
- data/lib/factpulse/models/adresse_postale.rb +0 -189
- data/lib/factpulse/models/cadre_de_facturation.rb +0 -217
- data/lib/factpulse/models/categorie_tva.rb +0 -47
- data/lib/factpulse/models/champ_verifie_schema.rb +0 -334
- data/lib/factpulse/models/code_cadre_facturation.rb +0 -42
- data/lib/factpulse/models/code_raison_reduction.rb +0 -45
- data/lib/factpulse/models/consulter_facture_request.rb +0 -176
- data/lib/factpulse/models/consulter_facture_response.rb +0 -261
- data/lib/factpulse/models/consulter_structure_request.rb +0 -188
- data/lib/factpulse/models/consulter_structure_response.rb +0 -261
- data/lib/factpulse/models/credentials_afnor.rb +0 -169
- data/lib/factpulse/models/credentials_chorus_pro.rb +0 -191
- data/lib/factpulse/models/destinataire.rb +0 -201
- data/lib/factpulse/models/dimension_page_schema.rb +0 -193
- data/lib/factpulse/models/direction_flux.rb +0 -40
- data/lib/factpulse/models/donnees_facture_simplifiees.rb +0 -342
- data/lib/factpulse/models/facture_enrichie_info.rb +0 -348
- data/lib/factpulse/models/facture_entrante.rb +0 -522
- data/lib/factpulse/models/flux_resume.rb +0 -251
- data/lib/factpulse/models/format_facture.rb +0 -41
- data/lib/factpulse/models/format_sortie.rb +0 -40
- data/lib/factpulse/models/fournisseur.rb +0 -257
- data/lib/factpulse/models/fournisseur_entrant.rb +0 -236
- data/lib/factpulse/models/information_signature_api.rb +0 -216
- data/lib/factpulse/models/ligne_de_poste.rb +0 -390
- data/lib/factpulse/models/ligne_de_poste_montant_remise_ht.rb +0 -104
- data/lib/factpulse/models/ligne_de_poste_taux_tva_manuel.rb +0 -104
- data/lib/factpulse/models/ligne_de_tva.rb +0 -262
- data/lib/factpulse/models/mode_depot.rb +0 -41
- data/lib/factpulse/models/mode_paiement.rb +0 -44
- data/lib/factpulse/models/montant_a_payer.rb +0 -104
- data/lib/factpulse/models/montant_base_ht.rb +0 -104
- data/lib/factpulse/models/montant_ht_total.rb +0 -104
- data/lib/factpulse/models/montant_remise_globale_ttc.rb +0 -104
- data/lib/factpulse/models/montant_total.rb +0 -272
- data/lib/factpulse/models/montant_total_acompte.rb +0 -104
- data/lib/factpulse/models/montant_total_ligne_ht.rb +0 -104
- data/lib/factpulse/models/montant_ttc_total.rb +0 -104
- data/lib/factpulse/models/montant_tva.rb +0 -104
- data/lib/factpulse/models/montant_tva_ligne.rb +0 -104
- data/lib/factpulse/models/montant_tva_total.rb +0 -104
- data/lib/factpulse/models/montant_unitaire_ht.rb +0 -104
- data/lib/factpulse/models/nature_operation.rb +0 -52
- data/lib/factpulse/models/note.rb +0 -175
- data/lib/factpulse/models/note_obligatoire_schema.rb +0 -265
- data/lib/factpulse/models/obtenir_id_chorus_pro_request.rb +0 -188
- data/lib/factpulse/models/obtenir_id_chorus_pro_response.rb +0 -230
- data/lib/factpulse/models/options_processing.rb +0 -207
- data/lib/factpulse/models/parametres_signature.rb +0 -235
- data/lib/factpulse/models/parametres_structure.rb +0 -175
- data/lib/factpulse/models/pdf_factur_x_info.rb +0 -205
- data/lib/factpulse/models/piece_jointe_complementaire.rb +0 -269
- data/lib/factpulse/models/profil_api.rb +0 -42
- data/lib/factpulse/models/profil_flux.rb +0 -41
- data/lib/factpulse/models/quantite.rb +0 -104
- data/lib/factpulse/models/rechercher_services_response.rb +0 -214
- data/lib/factpulse/models/rechercher_structure_request.rb +0 -191
- data/lib/factpulse/models/rechercher_structure_response.rb +0 -216
- data/lib/factpulse/models/references.rb +0 -290
- data/lib/factpulse/models/reponse_recherche_flux.rb +0 -249
- data/lib/factpulse/models/reponse_soumission_flux.rb +0 -294
- data/lib/factpulse/models/reponse_tache.rb +0 -165
- data/lib/factpulse/models/reponse_validation_erreur.rb +0 -167
- data/lib/factpulse/models/reponse_validation_succes.rb +0 -165
- data/lib/factpulse/models/reponse_verification_succes.rb +0 -343
- data/lib/factpulse/models/requete_recherche_flux.rb +0 -306
- data/lib/factpulse/models/requete_soumission_flux.rb +0 -238
- data/lib/factpulse/models/resultat_chorus_pro.rb +0 -186
- data/lib/factpulse/models/resultat_validation_pdfapi.rb +0 -523
- data/lib/factpulse/models/service_structure.rb +0 -247
- data/lib/factpulse/models/soumettre_facture_complete_request.rb +0 -239
- data/lib/factpulse/models/soumettre_facture_complete_response.rb +0 -355
- data/lib/factpulse/models/soumettre_facture_request.rb +0 -388
- data/lib/factpulse/models/soumettre_facture_response.rb +0 -213
- data/lib/factpulse/models/statut_acquittement.rb +0 -41
- data/lib/factpulse/models/statut_celery.rb +0 -43
- data/lib/factpulse/models/statut_champ_api.rb +0 -43
- data/lib/factpulse/models/statut_facture.rb +0 -203
- data/lib/factpulse/models/statut_tache.rb +0 -226
- data/lib/factpulse/models/syntaxe_flux.rb +0 -43
- data/lib/factpulse/models/tauxmanuel.rb +0 -104
- data/lib/factpulse/models/type_document.rb +0 -43
- data/lib/factpulse/models/type_facture.rb +0 -54
- data/lib/factpulse/models/type_flux.rb +0 -43
- data/lib/factpulse/models/type_tva.rb +0 -42
- data/lib/factpulse/models/unite.rb +0 -44
|
@@ -3,8 +3,8 @@ require 'net/http'; require 'json'; require 'base64'; require 'uri'; require 'se
|
|
|
3
3
|
|
|
4
4
|
module FactPulse
|
|
5
5
|
module Helpers
|
|
6
|
-
#
|
|
7
|
-
#
|
|
6
|
+
# Chorus Pro credentials for Zero-Trust mode.
|
|
7
|
+
# These credentials are passed in each request and are never stored server-side.
|
|
8
8
|
class ChorusProCredentials
|
|
9
9
|
attr_reader :piste_client_id, :piste_client_secret, :chorus_pro_login, :chorus_pro_password, :sandbox
|
|
10
10
|
def initialize(piste_client_id:, piste_client_secret:, chorus_pro_login:, chorus_pro_password:, sandbox: true)
|
|
@@ -17,8 +17,8 @@ module FactPulse
|
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
#
|
|
21
|
-
#
|
|
20
|
+
# AFNOR PDP credentials for Zero-Trust mode.
|
|
21
|
+
# The FactPulse API uses these credentials to authenticate with the AFNOR PDP.
|
|
22
22
|
class AFNORCredentials
|
|
23
23
|
attr_reader :flow_service_url, :token_url, :client_id, :client_secret, :directory_service_url
|
|
24
24
|
def initialize(flow_service_url:, token_url:, client_id:, client_secret:, directory_service_url: nil)
|
|
@@ -33,127 +33,127 @@ module FactPulse
|
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
# Helpers
|
|
37
|
-
module
|
|
38
|
-
def self.
|
|
36
|
+
# Helpers for creating simplified total amounts.
|
|
37
|
+
module AmountHelpers
|
|
38
|
+
def self.amount(value)
|
|
39
39
|
return '0.00' if value.nil?
|
|
40
40
|
return format('%.2f', value) if value.is_a?(Numeric)
|
|
41
41
|
value.is_a?(String) ? value : '0.00'
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def self.
|
|
44
|
+
def self.invoice_totals(excl_tax, vat, incl_tax, amount_due, discount_incl_tax: nil, discount_reason: nil, prepayment: nil)
|
|
45
45
|
result = {
|
|
46
|
-
'
|
|
47
|
-
'
|
|
46
|
+
'totalExclTax' => amount(excl_tax), 'vatAmount' => amount(vat),
|
|
47
|
+
'totalInclTax' => amount(incl_tax), 'amountDue' => amount(amount_due)
|
|
48
48
|
}
|
|
49
|
-
result['
|
|
50
|
-
result['
|
|
51
|
-
result['
|
|
49
|
+
result['globalDiscountInclTax'] = amount(discount_incl_tax) if discount_incl_tax
|
|
50
|
+
result['globalDiscountReason'] = discount_reason if discount_reason
|
|
51
|
+
result['prepayment'] = amount(prepayment) if prepayment
|
|
52
52
|
result
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
#
|
|
56
|
-
def self.
|
|
57
|
-
|
|
55
|
+
# Creates an invoice line (aligned with InvoiceLine in models.py).
|
|
56
|
+
def self.invoice_line(number, description, quantity, unit_price_excl_tax, line_total_excl_tax,
|
|
57
|
+
vat_rate: '20.00', vat_category: 'S', unit: 'LUMP_SUM', **options)
|
|
58
58
|
result = {
|
|
59
|
-
'
|
|
60
|
-
'
|
|
61
|
-
'
|
|
62
|
-
'
|
|
59
|
+
'number' => number, 'description' => description,
|
|
60
|
+
'quantity' => amount(quantity), 'unitPriceExclTax' => amount(unit_price_excl_tax),
|
|
61
|
+
'lineTotalExclTax' => amount(line_total_excl_tax), 'vatRateManual' => amount(vat_rate),
|
|
62
|
+
'vatCategory' => vat_category, 'unit' => unit
|
|
63
63
|
}
|
|
64
64
|
result['reference'] = options[:reference] if options[:reference]
|
|
65
|
-
result['
|
|
66
|
-
result['
|
|
67
|
-
result['
|
|
68
|
-
result['
|
|
69
|
-
result['
|
|
65
|
+
result['discountExclTax'] = amount(options[:discount_excl_tax]) if options[:discount_excl_tax]
|
|
66
|
+
result['discountReasonCode'] = options[:discount_reason_code] if options[:discount_reason_code]
|
|
67
|
+
result['discountReason'] = options[:discount_reason] if options[:discount_reason]
|
|
68
|
+
result['periodStartDate'] = options[:period_start_date] if options[:period_start_date]
|
|
69
|
+
result['periodEndDate'] = options[:period_end_date] if options[:period_end_date]
|
|
70
70
|
result
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
#
|
|
74
|
-
def self.
|
|
73
|
+
# Creates a VAT line (aligned with VatLine in models.py).
|
|
74
|
+
def self.vat_line(rate_manual, base_amount_excl_tax, vat_amount, category: 'S')
|
|
75
75
|
{
|
|
76
|
-
'
|
|
77
|
-
'
|
|
76
|
+
'rateManual' => amount(rate_manual), 'baseAmountExclTax' => amount(base_amount_excl_tax),
|
|
77
|
+
'vatAmount' => amount(vat_amount), 'category' => category
|
|
78
78
|
}
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
#
|
|
82
|
-
def self.
|
|
83
|
-
result = { '
|
|
84
|
-
result['
|
|
85
|
-
result['
|
|
81
|
+
# Creates a postal address for the FactPulse API.
|
|
82
|
+
def self.postal_address(line1, postal_code, city, country: 'FR', line2: nil, line3: nil)
|
|
83
|
+
result = { 'line1' => line1, 'postalCode' => postal_code, 'city' => city, 'countryCode' => country }
|
|
84
|
+
result['line2'] = line2 if line2
|
|
85
|
+
result['line3'] = line3 if line3
|
|
86
86
|
result
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
-
#
|
|
90
|
-
def self.
|
|
91
|
-
{ '
|
|
89
|
+
# Creates an electronic address. scheme_id: "0009"=SIREN, "0225"=SIRET
|
|
90
|
+
def self.electronic_address(identifier, scheme_id: '0009')
|
|
91
|
+
{ 'identifier' => identifier, 'schemeId' => scheme_id }
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
#
|
|
95
|
-
def self.
|
|
94
|
+
# Computes the French intra-community VAT number from a SIREN.
|
|
95
|
+
def self.compute_vat_intra(siren)
|
|
96
96
|
return nil if siren.nil? || siren.length != 9 || !siren.match?(/^\d+$/)
|
|
97
97
|
cle = (12 + 3 * (siren.to_i % 97)) % 97
|
|
98
98
|
format('FR%02d%s', cle, siren)
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
-
#
|
|
102
|
-
def self.
|
|
101
|
+
# Creates a supplier (issuer) with auto-computed SIREN, intra-EU VAT number and addresses.
|
|
102
|
+
def self.supplier(name, siret, address_line1, postal_code, city, **options)
|
|
103
103
|
siren = options[:siren] || (siret.length == 14 ? siret[0, 9] : nil)
|
|
104
|
-
|
|
104
|
+
vat_intra = options[:vat_intra] || (siren ? compute_vat_intra(siren) : nil)
|
|
105
105
|
result = {
|
|
106
|
-
'
|
|
107
|
-
'
|
|
108
|
-
'
|
|
106
|
+
'name' => name, 'supplierId' => options[:supplier_id] || 0, 'siret' => siret,
|
|
107
|
+
'electronicAddress' => electronic_address(siret, scheme_id: '0225'),
|
|
108
|
+
'postalAddress' => postal_address(address_line1, postal_code, city, country: options[:country] || 'FR', line2: options[:address_line2])
|
|
109
109
|
}
|
|
110
110
|
result['siren'] = siren if siren
|
|
111
|
-
result['
|
|
111
|
+
result['vatIntra'] = vat_intra if vat_intra
|
|
112
112
|
result['iban'] = options[:iban] if options[:iban]
|
|
113
|
-
result['
|
|
114
|
-
result['
|
|
113
|
+
result['supplierServiceId'] = options[:service_code] if options[:service_code]
|
|
114
|
+
result['supplierBankCoordinatesCode'] = options[:bank_coordinates_code] if options[:bank_coordinates_code]
|
|
115
115
|
result
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
-
#
|
|
119
|
-
def self.
|
|
118
|
+
# Creates a recipient (customer) with auto-computed SIREN and addresses.
|
|
119
|
+
def self.recipient(name, siret, address_line1, postal_code, city, **options)
|
|
120
120
|
siren = options[:siren] || (siret.length == 14 ? siret[0, 9] : nil)
|
|
121
121
|
result = {
|
|
122
|
-
'
|
|
123
|
-
'
|
|
124
|
-
'
|
|
122
|
+
'name' => name, 'siret' => siret,
|
|
123
|
+
'electronicAddress' => electronic_address(siret, scheme_id: '0225'),
|
|
124
|
+
'postalAddress' => postal_address(address_line1, postal_code, city, country: options[:country] || 'FR', line2: options[:address_line2])
|
|
125
125
|
}
|
|
126
126
|
result['siren'] = siren if siren
|
|
127
|
-
result['
|
|
127
|
+
result['executingServiceCode'] = options[:executing_service_code] if options[:executing_service_code]
|
|
128
128
|
result
|
|
129
129
|
end
|
|
130
130
|
|
|
131
|
-
#
|
|
131
|
+
# Creates a beneficiary (factor) for factoring.
|
|
132
132
|
#
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
# factor (
|
|
133
|
+
# The beneficiary (BG-10 / PayeeTradeParty) is used when payment
|
|
134
|
+
# must be made to a third party different from the supplier, typically
|
|
135
|
+
# a factor (factoring company).
|
|
136
136
|
#
|
|
137
|
-
#
|
|
138
|
-
# -
|
|
139
|
-
# -
|
|
140
|
-
# -
|
|
137
|
+
# For factored invoices, you also need to:
|
|
138
|
+
# - Use a factored document type (393, 396, 501, 502, 472, 473)
|
|
139
|
+
# - Add an ACC note with the subrogation mention
|
|
140
|
+
# - The beneficiary's IBAN will be used for payment
|
|
141
141
|
#
|
|
142
|
-
# @param
|
|
142
|
+
# @param name [String] Factor's business name (BT-59)
|
|
143
143
|
# @param options [Hash] Options: :siret (BT-60), :siren (BT-61), :iban, :bic
|
|
144
|
-
# @return [Hash] Dict
|
|
144
|
+
# @return [Hash] Dict ready to be used in a factored invoice
|
|
145
145
|
#
|
|
146
146
|
# @example
|
|
147
|
-
# factor =
|
|
147
|
+
# factor = beneficiary('FACTOR SAS',
|
|
148
148
|
# siret: '30000000700033',
|
|
149
149
|
# iban: 'FR76 3000 4000 0500 0012 3456 789'
|
|
150
150
|
# )
|
|
151
|
-
def self.
|
|
152
|
-
# Auto-
|
|
151
|
+
def self.beneficiary(name, **options)
|
|
152
|
+
# Auto-compute SIREN from SIRET
|
|
153
153
|
siret = options[:siret]
|
|
154
154
|
siren = options[:siren] || (siret && siret.length == 14 ? siret[0, 9] : nil)
|
|
155
155
|
|
|
156
|
-
result = { '
|
|
156
|
+
result = { 'name' => name }
|
|
157
157
|
result['siret'] = siret if siret
|
|
158
158
|
result['siren'] = siren if siren
|
|
159
159
|
result['iban'] = options[:iban] if options[:iban]
|
|
@@ -175,7 +175,7 @@ module FactPulse
|
|
|
175
175
|
|
|
176
176
|
def chorus_credentials_for_api; @chorus_credentials&.to_h; end
|
|
177
177
|
def afnor_credentials_for_api; @afnor_credentials&.to_h; end
|
|
178
|
-
#
|
|
178
|
+
# Shorter aliases
|
|
179
179
|
def get_chorus_pro_credentials; chorus_credentials_for_api; end
|
|
180
180
|
def get_afnor_credentials; afnor_credentials_for_api; end
|
|
181
181
|
|
|
@@ -197,7 +197,7 @@ module FactPulse
|
|
|
197
197
|
start_time, current_interval = (Time.now.to_f * 1000).to_i, interval_ms.to_f
|
|
198
198
|
loop do
|
|
199
199
|
raise FactPulsePollingTimeout.new(task_id, timeout_ms) if (Time.now.to_f * 1000).to_i - start_time > timeout_ms
|
|
200
|
-
ensure_authenticated; response = http_get(URI("#{@api_url}/api/v1/
|
|
200
|
+
ensure_authenticated; response = http_get(URI("#{@api_url}/api/v1/processing/tasks/#{task_id}/status"))
|
|
201
201
|
reset_auth and next if response.code == '401'
|
|
202
202
|
data = JSON.parse(response.body)
|
|
203
203
|
return data['resultat'] || {} if data['statut'] == 'SUCCESS'
|
|
@@ -210,25 +210,25 @@ module FactPulse
|
|
|
210
210
|
end
|
|
211
211
|
end
|
|
212
212
|
|
|
213
|
-
def self.
|
|
213
|
+
def self.format_amount(m); AmountHelpers.amount(m); end
|
|
214
214
|
|
|
215
|
-
#
|
|
216
|
-
def
|
|
217
|
-
#
|
|
218
|
-
json_data = case
|
|
219
|
-
when String then
|
|
220
|
-
when Hash then JSON.generate(
|
|
215
|
+
# Generates a Factur-X invoice from a dict/hash and a source PDF.
|
|
216
|
+
def generate_facturx(invoice_data, pdf_source, profile: 'EN16931', output_format: 'pdf', sync: true, timeout: nil)
|
|
217
|
+
# Convert data to JSON string
|
|
218
|
+
json_data = case invoice_data
|
|
219
|
+
when String then invoice_data
|
|
220
|
+
when Hash then JSON.generate(invoice_data)
|
|
221
221
|
else
|
|
222
|
-
if
|
|
223
|
-
JSON.generate(
|
|
224
|
-
elsif
|
|
225
|
-
JSON.generate(
|
|
222
|
+
if invoice_data.respond_to?(:to_h)
|
|
223
|
+
JSON.generate(invoice_data.to_h)
|
|
224
|
+
elsif invoice_data.respond_to?(:to_hash)
|
|
225
|
+
JSON.generate(invoice_data.to_hash)
|
|
226
226
|
else
|
|
227
|
-
raise FactPulseValidationError.new("
|
|
227
|
+
raise FactPulseValidationError.new("Unsupported data type: #{invoice_data.class}")
|
|
228
228
|
end
|
|
229
229
|
end
|
|
230
230
|
|
|
231
|
-
#
|
|
231
|
+
# Read source PDF
|
|
232
232
|
pdf_content = case pdf_source
|
|
233
233
|
when String then File.binread(pdf_source)
|
|
234
234
|
when File then pdf_source.read
|
|
@@ -236,20 +236,20 @@ module FactPulse
|
|
|
236
236
|
if pdf_source.respond_to?(:read)
|
|
237
237
|
pdf_source.read
|
|
238
238
|
else
|
|
239
|
-
raise FactPulseValidationError.new("
|
|
239
|
+
raise FactPulseValidationError.new("Unsupported PDF type: #{pdf_source.class}")
|
|
240
240
|
end
|
|
241
241
|
end
|
|
242
|
-
pdf_filename = pdf_source.is_a?(String) ? File.basename(pdf_source) : '
|
|
242
|
+
pdf_filename = pdf_source.is_a?(String) ? File.basename(pdf_source) : 'invoice.pdf'
|
|
243
243
|
|
|
244
244
|
ensure_authenticated
|
|
245
|
-
uri = URI("#{@api_url}/api/v1/
|
|
245
|
+
uri = URI("#{@api_url}/api/v1/processing/generate-invoice")
|
|
246
246
|
|
|
247
|
-
#
|
|
247
|
+
# Build multipart request
|
|
248
248
|
boundary = "----RubyFormBoundary#{SecureRandom.hex(16)}"
|
|
249
249
|
body = build_multipart_body(boundary, [
|
|
250
|
-
{ name: '
|
|
251
|
-
{ name: '
|
|
252
|
-
{ name: '
|
|
250
|
+
{ name: 'invoice_data', content: json_data },
|
|
251
|
+
{ name: 'profile', content: profile },
|
|
252
|
+
{ name: 'output_format', content: output_format },
|
|
253
253
|
{ name: 'source_pdf', content: pdf_content, filename: pdf_filename, content_type: 'application/pdf' }
|
|
254
254
|
])
|
|
255
255
|
|
|
@@ -260,15 +260,15 @@ module FactPulse
|
|
|
260
260
|
end
|
|
261
261
|
|
|
262
262
|
unless response.is_a?(Net::HTTPSuccess)
|
|
263
|
-
#
|
|
264
|
-
error_msg = "
|
|
263
|
+
# Extract error details from response body
|
|
264
|
+
error_msg = "API Error (#{response.code})"
|
|
265
265
|
errors = []
|
|
266
266
|
|
|
267
267
|
begin
|
|
268
268
|
error_data = JSON.parse(response.body)
|
|
269
269
|
# Format FastAPI/Pydantic: {"detail": [{"loc": [...], "msg": "...", "type": "..."}]}
|
|
270
270
|
if error_data['detail'].is_a?(Array)
|
|
271
|
-
error_msg = '
|
|
271
|
+
error_msg = 'Validation error'
|
|
272
272
|
error_data['detail'].each do |err|
|
|
273
273
|
next unless err.is_a?(Hash)
|
|
274
274
|
loc = (err['loc'] || []).map(&:to_s).join(' -> ')
|
|
@@ -286,30 +286,30 @@ module FactPulse
|
|
|
286
286
|
error_msg = error_data['errorMessage']
|
|
287
287
|
end
|
|
288
288
|
rescue JSON::ParserError
|
|
289
|
-
error_msg = "
|
|
289
|
+
error_msg = "API Error (#{response.code}): #{response.body}"
|
|
290
290
|
end
|
|
291
291
|
|
|
292
|
-
warn "
|
|
292
|
+
warn "API Error #{response.code}: #{response.body}"
|
|
293
293
|
raise FactPulseValidationError.new(error_msg, errors)
|
|
294
294
|
end
|
|
295
295
|
|
|
296
296
|
data = JSON.parse(response.body)
|
|
297
297
|
|
|
298
|
-
if sync && data['
|
|
299
|
-
result = poll_task(data['
|
|
298
|
+
if sync && data['task_id']
|
|
299
|
+
result = poll_task(data['task_id'], timeout: timeout)
|
|
300
300
|
if result['contenu_b64']
|
|
301
301
|
return Base64.decode64(result['contenu_b64'])
|
|
302
302
|
elsif result['contenu_xml']
|
|
303
303
|
return result['contenu_xml']
|
|
304
304
|
end
|
|
305
|
-
raise FactPulseValidationError.new("
|
|
305
|
+
raise FactPulseValidationError.new("Unexpected result: #{result.keys.join(', ')}")
|
|
306
306
|
end
|
|
307
307
|
|
|
308
308
|
data
|
|
309
309
|
end
|
|
310
310
|
|
|
311
311
|
# =========================================================================
|
|
312
|
-
# AFNOR PDP - Authentication
|
|
312
|
+
# AFNOR PDP - Authentication and internal helpers
|
|
313
313
|
# =========================================================================
|
|
314
314
|
|
|
315
315
|
private def get_afnor_credentials_internal
|
|
@@ -385,8 +385,8 @@ module FactPulse
|
|
|
385
385
|
|
|
386
386
|
# ==================== AFNOR Flow Service ====================
|
|
387
387
|
|
|
388
|
-
#
|
|
389
|
-
def
|
|
388
|
+
# Submits an invoice to a PDP via the AFNOR API.
|
|
389
|
+
def submit_invoice_afnor(pdf_path, flow_name, **options)
|
|
390
390
|
pdf_content = File.binread(pdf_path)
|
|
391
391
|
sha256 = Digest::SHA256.hexdigest(pdf_content)
|
|
392
392
|
|
|
@@ -404,8 +404,8 @@ module FactPulse
|
|
|
404
404
|
])
|
|
405
405
|
end
|
|
406
406
|
|
|
407
|
-
#
|
|
408
|
-
def
|
|
407
|
+
# Searches for AFNOR invoicing flows.
|
|
408
|
+
def search_flows_afnor(**criteria)
|
|
409
409
|
search_body = {
|
|
410
410
|
'offset' => criteria[:offset] || 0,
|
|
411
411
|
'limit' => criteria[:limit] || 25,
|
|
@@ -417,30 +417,30 @@ module FactPulse
|
|
|
417
417
|
make_afnor_request('POST', '/flow/v1/flows/search', json_data: search_body)
|
|
418
418
|
end
|
|
419
419
|
|
|
420
|
-
#
|
|
421
|
-
def
|
|
420
|
+
# Downloads the PDF file of an AFNOR flow.
|
|
421
|
+
def download_flow_afnor(flow_id)
|
|
422
422
|
result = make_afnor_request('GET', "/flow/v1/flows/#{flow_id}")
|
|
423
423
|
result['_raw'] || ''
|
|
424
424
|
end
|
|
425
425
|
|
|
426
|
-
#
|
|
427
|
-
#
|
|
428
|
-
#
|
|
426
|
+
# Retrieves JSON metadata of an incoming flow (supplier invoice).
|
|
427
|
+
# Downloads an incoming flow from the AFNOR PDP and extracts invoice
|
|
428
|
+
# metadata into a unified JSON format. Supports Factur-X, CII and UBL.
|
|
429
429
|
#
|
|
430
|
-
# Note:
|
|
431
|
-
#
|
|
430
|
+
# Note: This endpoint uses FactPulse JWT authentication (not AFNOR OAuth).
|
|
431
|
+
# The FactPulse server handles calling the PDP with stored credentials.
|
|
432
432
|
#
|
|
433
|
-
# @param flow_id [String]
|
|
434
|
-
# @param include_document [Boolean]
|
|
435
|
-
# @return [Hash]
|
|
433
|
+
# @param flow_id [String] Flow identifier (UUID)
|
|
434
|
+
# @param include_document [Boolean] If true, includes the document in base64
|
|
435
|
+
# @return [Hash] Invoice metadata (supplier, amounts, dates, etc.)
|
|
436
436
|
#
|
|
437
437
|
# @example
|
|
438
|
-
#
|
|
439
|
-
# puts "
|
|
440
|
-
# puts "
|
|
441
|
-
def
|
|
438
|
+
# invoice = client.get_incoming_invoice_afnor("550e8400-...")
|
|
439
|
+
# puts "Supplier: #{invoice['supplier']['name']}"
|
|
440
|
+
# puts "Total incl. tax: #{invoice['total_incl_tax']} #{invoice['currency']}"
|
|
441
|
+
def get_incoming_invoice_afnor(flow_id, include_document: false)
|
|
442
442
|
ensure_authenticated
|
|
443
|
-
uri = URI("#{@api_url}/api/v1/afnor/
|
|
443
|
+
uri = URI("#{@api_url}/api/v1/afnor/incoming-flows/#{flow_id}")
|
|
444
444
|
uri.query = "include_document=true" if include_document
|
|
445
445
|
|
|
446
446
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
@@ -451,29 +451,29 @@ module FactPulse
|
|
|
451
451
|
request['Authorization'] = "Bearer #{@access_token}"
|
|
452
452
|
|
|
453
453
|
response = http.request(request)
|
|
454
|
-
raise FactPulseValidationError.new("
|
|
454
|
+
raise FactPulseValidationError.new("Incoming flow error: #{response.code}") unless response.is_a?(Net::HTTPSuccess)
|
|
455
455
|
JSON.parse(response.body) rescue {}
|
|
456
456
|
end
|
|
457
457
|
|
|
458
|
-
#
|
|
458
|
+
# Checks the availability of the AFNOR Flow Service.
|
|
459
459
|
def healthcheck_afnor
|
|
460
460
|
make_afnor_request('GET', '/flow/v1/healthcheck')
|
|
461
461
|
end
|
|
462
462
|
|
|
463
463
|
# ==================== AFNOR Directory ====================
|
|
464
464
|
|
|
465
|
-
#
|
|
466
|
-
def
|
|
465
|
+
# Searches for a company by SIRET in the AFNOR directory.
|
|
466
|
+
def search_siret_afnor(siret)
|
|
467
467
|
make_afnor_request('GET', "/directory/siret/#{siret}")
|
|
468
468
|
end
|
|
469
469
|
|
|
470
|
-
#
|
|
471
|
-
def
|
|
470
|
+
# Searches for a company by SIREN in the AFNOR directory.
|
|
471
|
+
def search_siren_afnor(siren)
|
|
472
472
|
make_afnor_request('GET', "/directory/siren/#{siren}")
|
|
473
473
|
end
|
|
474
474
|
|
|
475
|
-
#
|
|
476
|
-
def
|
|
475
|
+
# Lists available routing codes for a SIREN.
|
|
476
|
+
def list_routing_codes_afnor(siren)
|
|
477
477
|
make_afnor_request('GET', "/directory/siren/#{siren}/routing-codes")
|
|
478
478
|
end
|
|
479
479
|
|
|
@@ -506,7 +506,7 @@ module FactPulse
|
|
|
506
506
|
JSON.parse(response.body) rescue {}
|
|
507
507
|
end
|
|
508
508
|
|
|
509
|
-
#
|
|
509
|
+
# Searches for structures on Chorus Pro.
|
|
510
510
|
def rechercher_structure_chorus(identifiant_structure: nil, raison_sociale: nil, type_identifiant: 'SIRET', restreindre_privees: true)
|
|
511
511
|
body = { 'restreindre_structures_privees' => restreindre_privees }
|
|
512
512
|
body['identifiant_structure'] = identifiant_structure if identifiant_structure
|
|
@@ -516,27 +516,27 @@ module FactPulse
|
|
|
516
516
|
make_chorus_request('POST', '/structures/rechercher', body)
|
|
517
517
|
end
|
|
518
518
|
|
|
519
|
-
#
|
|
519
|
+
# Gets the details of a Chorus Pro structure.
|
|
520
520
|
def consulter_structure_chorus(id_structure_cpp)
|
|
521
521
|
make_chorus_request('POST', '/structures/consulter', { 'id_structure_cpp' => id_structure_cpp })
|
|
522
522
|
end
|
|
523
523
|
|
|
524
|
-
#
|
|
524
|
+
# Gets the Chorus Pro ID of a structure from its SIRET.
|
|
525
525
|
def obtenir_id_chorus_depuis_siret(siret, type_identifiant: 'SIRET')
|
|
526
526
|
make_chorus_request('POST', '/structures/obtenir-id-depuis-siret', { 'siret' => siret, 'type_identifiant' => type_identifiant })
|
|
527
527
|
end
|
|
528
528
|
|
|
529
|
-
#
|
|
529
|
+
# Lists the services of a Chorus Pro structure.
|
|
530
530
|
def lister_services_structure_chorus(id_structure_cpp)
|
|
531
531
|
make_chorus_request('GET', "/structures/#{id_structure_cpp}/services")
|
|
532
532
|
end
|
|
533
533
|
|
|
534
|
-
#
|
|
534
|
+
# Submits an invoice to Chorus Pro.
|
|
535
535
|
def soumettre_facture_chorus(facture_data)
|
|
536
536
|
make_chorus_request('POST', '/factures/soumettre', facture_data)
|
|
537
537
|
end
|
|
538
538
|
|
|
539
|
-
#
|
|
539
|
+
# Gets the status of a Chorus Pro invoice.
|
|
540
540
|
def consulter_facture_chorus(identifiant_facture_cpp)
|
|
541
541
|
make_chorus_request('POST', '/factures/consulter', { 'identifiant_facture_cpp' => identifiant_facture_cpp })
|
|
542
542
|
end
|
|
@@ -545,20 +545,20 @@ module FactPulse
|
|
|
545
545
|
# Validation
|
|
546
546
|
# =========================================================================
|
|
547
547
|
|
|
548
|
-
#
|
|
549
|
-
# @param pdf_path [String]
|
|
550
|
-
# @param
|
|
551
|
-
# @param use_verapdf [Boolean]
|
|
552
|
-
def
|
|
548
|
+
# Validates a Factur-X PDF.
|
|
549
|
+
# @param pdf_path [String] Path to the PDF file
|
|
550
|
+
# @param profile [String, nil] Factur-X profile (MINIMUM, BASIC, EN16931, EXTENDED). If nil, auto-detected.
|
|
551
|
+
# @param use_verapdf [Boolean] Enable strict PDF/A validation with VeraPDF (default: false)
|
|
552
|
+
def validate_facturx_pdf(pdf_path, profile: nil, use_verapdf: false)
|
|
553
553
|
ensure_authenticated
|
|
554
|
-
uri = URI("#{@api_url}/api/v1/
|
|
554
|
+
uri = URI("#{@api_url}/api/v1/processing/validate-facturx-pdf")
|
|
555
555
|
pdf_content = File.binread(pdf_path)
|
|
556
556
|
|
|
557
557
|
parts = [
|
|
558
|
-
{ name: '
|
|
558
|
+
{ name: 'pdf_file', content: pdf_content, filename: File.basename(pdf_path), content_type: 'application/pdf' },
|
|
559
559
|
{ name: 'use_verapdf', content: use_verapdf.to_s }
|
|
560
560
|
]
|
|
561
|
-
parts << { name: '
|
|
561
|
+
parts << { name: 'profile', content: profile } if profile
|
|
562
562
|
|
|
563
563
|
boundary = "----RubyFormBoundary#{SecureRandom.hex(16)}"
|
|
564
564
|
body = build_multipart_body(boundary, parts)
|
|
@@ -568,15 +568,15 @@ module FactPulse
|
|
|
568
568
|
JSON.parse(response.body) rescue {}
|
|
569
569
|
end
|
|
570
570
|
|
|
571
|
-
#
|
|
572
|
-
def
|
|
571
|
+
# Validates a Factur-X XML.
|
|
572
|
+
def validate_facturx_xml(xml_content, profile: 'EN16931')
|
|
573
573
|
ensure_authenticated
|
|
574
|
-
uri = URI("#{@api_url}/api/v1/
|
|
574
|
+
uri = URI("#{@api_url}/api/v1/processing/validate-xml")
|
|
575
575
|
|
|
576
576
|
boundary = "----RubyFormBoundary#{SecureRandom.hex(16)}"
|
|
577
577
|
body = build_multipart_body(boundary, [
|
|
578
|
-
{ name: '
|
|
579
|
-
{ name: '
|
|
578
|
+
{ name: 'xml_file', content: xml_content, filename: 'invoice.xml', content_type: 'application/xml' },
|
|
579
|
+
{ name: 'profile', content: profile }
|
|
580
580
|
])
|
|
581
581
|
|
|
582
582
|
response = http_multipart_post(uri, body, boundary)
|
|
@@ -584,15 +584,15 @@ module FactPulse
|
|
|
584
584
|
JSON.parse(response.body) rescue {}
|
|
585
585
|
end
|
|
586
586
|
|
|
587
|
-
#
|
|
588
|
-
def
|
|
587
|
+
# Validates the signature of a signed PDF.
|
|
588
|
+
def validate_pdf_signature(pdf_path)
|
|
589
589
|
ensure_authenticated
|
|
590
|
-
uri = URI("#{@api_url}/api/v1/
|
|
590
|
+
uri = URI("#{@api_url}/api/v1/processing/validate-pdf-signature")
|
|
591
591
|
pdf_content = File.binread(pdf_path)
|
|
592
592
|
|
|
593
593
|
boundary = "----RubyFormBoundary#{SecureRandom.hex(16)}"
|
|
594
594
|
body = build_multipart_body(boundary, [
|
|
595
|
-
{ name: '
|
|
595
|
+
{ name: 'pdf_file', content: pdf_content, filename: File.basename(pdf_path), content_type: 'application/pdf' }
|
|
596
596
|
])
|
|
597
597
|
|
|
598
598
|
response = http_multipart_post(uri, body, boundary)
|
|
@@ -604,19 +604,19 @@ module FactPulse
|
|
|
604
604
|
# Signature
|
|
605
605
|
# =========================================================================
|
|
606
606
|
|
|
607
|
-
#
|
|
608
|
-
def
|
|
607
|
+
# Signs a PDF with the server-configured certificate.
|
|
608
|
+
def sign_pdf(pdf_path, **options)
|
|
609
609
|
ensure_authenticated
|
|
610
|
-
uri = URI("#{@api_url}/api/v1/
|
|
610
|
+
uri = URI("#{@api_url}/api/v1/processing/sign-pdf")
|
|
611
611
|
pdf_content = File.binread(pdf_path)
|
|
612
612
|
|
|
613
613
|
parts = [
|
|
614
|
-
{ name: '
|
|
614
|
+
{ name: 'pdf_file', content: pdf_content, filename: File.basename(pdf_path), content_type: 'application/pdf' },
|
|
615
615
|
{ name: 'use_pades_lt', content: (options[:use_pades_lt] ? 'true' : 'false') },
|
|
616
616
|
{ name: 'use_timestamp', content: (options.key?(:use_timestamp) ? (options[:use_timestamp] ? 'true' : 'false') : 'true') }
|
|
617
617
|
]
|
|
618
|
-
parts << { name: '
|
|
619
|
-
parts << { name: '
|
|
618
|
+
parts << { name: 'reason', content: options[:reason] } if options[:reason]
|
|
619
|
+
parts << { name: 'location', content: options[:location] } if options[:location]
|
|
620
620
|
parts << { name: 'contact', content: options[:contact] } if options[:contact]
|
|
621
621
|
|
|
622
622
|
boundary = "----RubyFormBoundary#{SecureRandom.hex(16)}"
|
|
@@ -630,16 +630,16 @@ module FactPulse
|
|
|
630
630
|
Base64.decode64(result['pdf_signe_base64'])
|
|
631
631
|
end
|
|
632
632
|
|
|
633
|
-
#
|
|
634
|
-
def
|
|
633
|
+
# Generates a test certificate (NOT FOR PRODUCTION).
|
|
634
|
+
def generate_test_certificate(**options)
|
|
635
635
|
ensure_authenticated
|
|
636
|
-
uri = URI("#{@api_url}/api/v1/
|
|
636
|
+
uri = URI("#{@api_url}/api/v1/processing/generate-test-certificate")
|
|
637
637
|
body = {
|
|
638
638
|
'cn' => options[:cn] || 'Test Organisation',
|
|
639
639
|
'organisation' => options[:organisation] || 'Test Organisation',
|
|
640
640
|
'email' => options[:email] || 'test@example.com',
|
|
641
|
-
'
|
|
642
|
-
'
|
|
641
|
+
'validity_days' => options[:validity_days] || 365,
|
|
642
|
+
'key_size' => options[:key_size] || 2048
|
|
643
643
|
}
|
|
644
644
|
|
|
645
645
|
response = http_post_json(uri, body)
|
|
@@ -651,21 +651,21 @@ module FactPulse
|
|
|
651
651
|
# Workflow complet
|
|
652
652
|
# =========================================================================
|
|
653
653
|
|
|
654
|
-
#
|
|
655
|
-
def
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
654
|
+
# Generates a complete Factur-X PDF with optional validation, signature and submission.
|
|
655
|
+
def generate_complete_facturx(invoice, pdf_source_path, **options)
|
|
656
|
+
profile = options[:profile] || 'EN16931'
|
|
657
|
+
validate = options.fetch(:validate, true)
|
|
658
|
+
sign = options.fetch(:sign, false)
|
|
659
|
+
submit_afnor = options.fetch(:submit_afnor, false)
|
|
660
660
|
timeout = options[:timeout] || 120000
|
|
661
661
|
|
|
662
662
|
result = {}
|
|
663
663
|
|
|
664
|
-
# 1.
|
|
665
|
-
pdf_bytes =
|
|
664
|
+
# 1. Generation
|
|
665
|
+
pdf_bytes = generate_facturx(invoice, pdf_source_path, profile: profile, output_format: 'pdf', sync: true, timeout: timeout)
|
|
666
666
|
result[:pdf_bytes] = pdf_bytes
|
|
667
667
|
|
|
668
|
-
#
|
|
668
|
+
# Create a temporary file for subsequent operations
|
|
669
669
|
temp_file = Tempfile.new(['facturx_', '.pdf'])
|
|
670
670
|
begin
|
|
671
671
|
temp_file.binmode
|
|
@@ -673,10 +673,10 @@ module FactPulse
|
|
|
673
673
|
temp_file.flush
|
|
674
674
|
|
|
675
675
|
# 2. Validation
|
|
676
|
-
if
|
|
677
|
-
validation =
|
|
676
|
+
if validate
|
|
677
|
+
validation = validate_facturx_pdf(temp_file.path, profile: profile)
|
|
678
678
|
result[:validation] = validation
|
|
679
|
-
unless validation['
|
|
679
|
+
unless validation['is_compliant']
|
|
680
680
|
if options[:output_path]
|
|
681
681
|
File.binwrite(options[:output_path], pdf_bytes)
|
|
682
682
|
result[:pdf_path] = options[:output_path]
|
|
@@ -686,25 +686,25 @@ module FactPulse
|
|
|
686
686
|
end
|
|
687
687
|
|
|
688
688
|
# 3. Signature
|
|
689
|
-
if
|
|
690
|
-
pdf_bytes =
|
|
689
|
+
if sign
|
|
690
|
+
pdf_bytes = sign_pdf(temp_file.path, **options)
|
|
691
691
|
result[:pdf_bytes] = pdf_bytes
|
|
692
|
-
result[:signature] = { '
|
|
692
|
+
result[:signature] = { 'signed' => true }
|
|
693
693
|
temp_file.rewind
|
|
694
694
|
temp_file.write(pdf_bytes)
|
|
695
695
|
temp_file.flush
|
|
696
696
|
end
|
|
697
697
|
|
|
698
|
-
# 4.
|
|
699
|
-
if
|
|
700
|
-
|
|
701
|
-
flow_name = options[:afnor_flow_name] || "
|
|
702
|
-
tracking_id = options[:afnor_tracking_id] ||
|
|
703
|
-
afnor_result =
|
|
698
|
+
# 4. AFNOR submission
|
|
699
|
+
if submit_afnor
|
|
700
|
+
invoice_number = invoice['invoiceNumber'] || invoice['invoice_number'] || 'INVOICE'
|
|
701
|
+
flow_name = options[:afnor_flow_name] || "Invoice #{invoice_number}"
|
|
702
|
+
tracking_id = options[:afnor_tracking_id] || invoice_number
|
|
703
|
+
afnor_result = submit_invoice_afnor(temp_file.path, flow_name, tracking_id: tracking_id)
|
|
704
704
|
result[:afnor] = afnor_result
|
|
705
705
|
end
|
|
706
706
|
|
|
707
|
-
#
|
|
707
|
+
# Final save
|
|
708
708
|
if options[:output_path]
|
|
709
709
|
File.binwrite(options[:output_path], pdf_bytes)
|
|
710
710
|
result[:pdf_path] = options[:output_path]
|