Intégration de la facturation électronique en Arabie saoudite
L’intégration est obligatoire pour tous les contribuables soumis à la facturation électronique en Arabie saoudite. À la suite du processus d’intégration, les contribuables obtiennent des identificateurs de timbres cryptographiques (CSID). Les CSID sont nécessaires pour l’intégration au portail de facturation électronique géré par l’administration fiscale saoudienne (ZATCA) et pour la soumission ultérieure des factures électroniques.
Cet article explique comment intégrer les contribuables et leur logiciel de facturation électronique auprès des autorités fiscales saoudiennes.
Logiciels requis
- L’entité juridique doit être enregistrée en tant que contribuable en Arabie saoudite et disposer d’un numéro d’enregistrement de taxe sur la valeur ajoutée (TVA) valide.
- L’entité juridique doit avoir accès au Portail fiscal saoudien (ERAD).
Processus de l'intégration
Le processus d’intégration comprend deux étapes :
- Obtenir un CSID de conformité (CCSID), que ZATCA attribue pour effectuer des contrôles de conformité des solutions de génération de factures électroniques (EGS).
- Obtenir un CSID de production (PCSID), que ZATCA attribue aux EGS conformes.
Obtenir un CCSID
Dans le Portail fiscal saoudien (ERAD), accédez au portail d’intégration et de gestion en sélectionnant la vignette appropriée.
Sur la page d’accueil principale du portail d’intégration et de gestion, Sélectionnez la vignette Nouvelle unité de solution/appareil intégré, puis SélectionnezGénérer du code OTP. Le code OTP n’est valide que pendant une heure après avoir été généré. Assurez-vous qu’il est utilisé dans ce cadre d’exécution.
Sélectionnez le nombre de codes de mot de passe à usage unique à générer. Ce nombre dépend du nombre d’unités de génération de facturation électronique (appareils) qui seront utilisées.
Enregistrez les codes OTP générés afin de pouvoir les utiliser lors d’étapes ultérieures.
Préparez un fichier de configuration pour la demande de signature de certificat. Ce fichier de configuration doit se présenter sous la forme d’un fichier texte brut contenant les données suivantes.
oid_section = OIDs [OIDs] certificateTemplateName = 1.3.6.1.4.1.311.20.2 [req] default_bits = 2048 emailAddress = MyEmail@email.com req_extensions = v3_req x509_extensions = v3_ca prompt = no default_md = sha 256 req_extensions = req_ext distinguished_name = dn [dn] C=SA OU=Riyad Branch O=Contoso CN=EA123456789 [v3_req] basicConstraints = CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment [req_ext] certificateTemplateName = ASN1:PRINTABLESTRING:ZATCA-Code-Signing subjectAltName = dirName:alt_names [alt_names] SN=1-TST|2-TST|3-ed22f1d8-e6a2-1118-9b58-d9a8f11e445f UID=310122393500003 title=1100 registeredAddress= MyAddress businessCategory=Industry
Enregistrez le fichier au même emplacement que le script d’intégration avec le nom csr_config.txt.
Dans le fichier de configuration, mettez à jour la valeur emailAddress et les données spécifiques suivantes.
Code Description Spécification C Code pays/région. Un code à deux lettres (ISO 3166 alpha-2) OU Nom de l’unité d’organisation. Pour les contribuables normaux, la valeur est le texte libre. Pour les groupes TVA, identifiez la valeur par le onzième chiffre de l’identificateur de l’organisation "1". Vérifiez que l’entrée est un numéro d’identification fiscale (TIN) à 10 chiffres. O Le nom de l’organisation ou du contribuable. Texte libre CN Le nom unique de la solution ou de l’unité. Texte libre SN Code d’identification unique de la solution. Texte libre Uid Le numéro d’identification intracommunautaire du contribuable. Quinze chiffres. Ce numéro commence par "3" et se termine par "3". titre Le type de document que l’unité de solution du contribuable émettra. Entrée numérique à quatre chiffres utilisant "0" et "1" mappés à "TSCZ" : 0 = Faux/Non pris en charge, 1 = Vrai/Pris en charge. T = Facture fiscale (standard), S = Facture fiscale simplifiée, C = Pour une utilisation future, Z = Pour une utilisation future. registeredAddress Adresse de la succursale ou de l’emplacement où l’unité d’appareil ou de solution est principalement située. Texte libre businessCategory Secteur pour lequel l’appareil ou la solution va générer des factures. Texte libre Note
Les valeurs de CN et certificateTemplateName dans le fichier config diffèrent selon que vous utilisez le portail de simulation.
Dans le portail de simulation :
- CN- PREZATCA-Signature-de-code
- certificateTemplateName - ASN1 :PRINTABLESTRING :PREZATCA-Code-Signing
Dans les autres cas, utilisez les valeurs indiquées ci-dessus.
Exécutez le script d’intégration fourni plus loin dans cet article. Spécifiez l’OTP et le fichier de configuration comme paramètres d’entrée. Voici un exemple : le script a deux points de terminaison possibles : simulation et production.
.\OnboardingScript.ps1 -action getComplianceCSID -endpoint prod -otp 123345 -csrconfig .\csr_config.txt -password 123
Note
Le paramètre mot de passe est facultatif et peut être omis. S’il est inclus, le certificat généré comportera le mot de passe spécifié.
Le CCSID est reçu en tant que fichier de certificat "CCSID.pfx" et la clé secrète du CCSID est enregistrée en tant que fichier txt "CCSIDSecret.txt". Enregistrez ce fichier de certificat CCSID dans le certificat Key Vault, puis enregistrez la clé secrète dans Microsoft Azure le Microsoft Azure secret Key Vault. Pour plus d’informations, voir Certificats et secrets des clients.
Configurez la configuration des fonctionnalités associées dans la fonctionnalité de facturation électronique de vérification de la conformité ZATCA (SA) d’Arabie saoudite et référencez le certificat CCSID que vous avez enregistré dans le coffre de clés. Le certificat sera utilisé pour la communication avec le portail de facturation électronique ZATCA.
Contrôle de conformité
Une fois que vous avez obtenu le CSID de conformité à l’aide du script PowerShell, ZATCA vous oblige à effectuer certains contrôles de conformité en soumettant des exemples de factures. Cette étape est une condition préalable pour demander un CSID de production.
Assurez-vous que tous les types d’exemples de factures qui ont été configurés dans le fichier de configuration de la demande de signature de certificat (CSR) sont correctement soumis à ZATCA. Utiliser le processus standard d’émission de factures électroniques. Pour plus de détails, voir Émettre des factures électroniques dans Finance et chaîne d’approvisionnement Management.
Utilisez la fonctionnalité "Contrôle de conformité ZATCA (SA) en Arabie saoudite" dans RCS et suivez les étapes de la section Configuration spécifique au pays/à la région à l’aide du CSID de conformité que vous avez obtenu.
Une fois les contrôles de conformité terminés avec succès, utilisez le script PowerShell pour obtenir le CSID de production (reportez-vous au script d’intégration).
Note
Dans le champ Titre , si le type de document du fichier de configuration est défini sur 1 000, trois exemples de factures doivent être soumis pour le contrôle de conformité :
- Facture fiscale standard
- Note de débit standard
- Avoir standard
Dans le champ Titre , si le type de document du fichier de configuration est défini sur 0100, trois exemples de factures doivent être soumis pour le contrôle de conformité :
- Facture fiscale simplifiée
- Note de débit simplifiée
- Avoir simplifié
Si le type de document est défini sur 1100, les six exemples de factures doivent être soumis pour le contrôle de conformité.
Obtenir un IDPC
Pour obtenir un PCSID, vous devez configurer correctement la solution de génération et de soumission de factures électroniques, et la solution doit être entièrement fonctionnelle. Pour obtenir ce résultat, vous devez effectuer toutes les étapes de configuration préliminaires requises. Pour en savoir plus, consultez Prise en main de la facturation électronique pour l’Arabie saoudite.
Assurez-vous que toutes les factures électroniques sont soumises avec succès à ZATCA.
Exécutez le script d’intégration fourni plus loin dans cet article. Spécifiez le CCSID comme paramètre d’entrée. Voici un exemple : Le script a deux points de terminaison possibles : simulation & prod
.\OnboardingScript.ps1 -action getProductionCSID -endpoint prod -password 123
Note
Le paramètre mot de passe est facultatif et peut être omis. S’il est inclus, le certificat généré comportera le mot de passe spécifié.
Le PCSID est reçu sous la forme d’un fichier de certificat au format PFX. Enregistrez ce certificat PCSID et ce fichier secret dans le coffre de clés Azure ;.
Configurez le paramétrage des fonctionnalités associées dans la fonctionnalité de facturation électronique Soumission Zatca (SA) d’Arabie saoudite. Inclure le certificat et la clé secrète PCSID dans les paramètres Key Vault de RCS.
Une fois toutes les étapes de configuration terminées, le système est prêt à être utilisé en mode production.
Pour examiner les CSID obtenus côté ZATCA, utilisez la vignette Examiner les identificateurs de timbre cryptographique (CSID) existants sur la page d’accueil du portail d’intégration et de gestion. Ce portail est accessible à partir du portail principal de la fiscalité saoudienne (ERAD).
Script d’intégration
Note
Les exemples de scripts ne sont pris en charge dans le cadre d’aucun programme ou service de support standard Microsoft. Les exemples de scripts sont fournis EN L’ÉTAT, sans garantie d’aucune sorte. Microsoft décline en outre toute garantie implicite, y compris, sans s’y limiter, toute garantie implicite de qualité marchande ou d’adéquation à un usage particulier. Vous assumez toujours l’intégralité des risques liés à l’utilisation ou à la performance des exemples de scripts et de la documentation. En aucun cas, Microsoft, ses auteurs, ou toute autre personne impliquée dans la création, la production ou la livraison des scripts ne pourront être tenus responsables de quelque dommage que ce soit (y compris, sans s’y limiter, les dommages pour perte de profits commerciaux, interruption d’activité, perte d’informations commerciales ou toute autre perte pécuniaire) résultant de l’utilisation ou de l’incapacité d’utiliser les exemples de scripts ou de documentation, même si Microsoft a été informé de la possibilité de tels dommages.
Utilisez le script Windows PowerShell suivant pour obtenir un CCSID et un PCSID.
#Saudi Arabian electronic invoice onboarding script #Version 1.1 param($action, $endpoint, $otp, $csrconfig, $password) $env:path = $env:path + ";C:\Program Files\Git\usr\bin" $simulationEndpoint = 'https://gw-fatoora.zatca.gov.sa/e-invoicing/simulation' $prodEndpoint = 'https://gw-fatoora.zatca.gov.sa/e-invoicing/core' if ($endpoint -eq "simulation") { $serviceEndpoint = $simulationEndpoint } elseif ($endpoint -eq "prod") { $serviceEndpoint = $prodEndpoint } else { Write-Host "`nMissing parameter (with values simulation/prod): endpoint" Break } if ($action -eq "getComplianceCSID") { if (-not (Test-Path -Path $csrconfig)) { throw "CSR configuration file does not exist, please make sure to provide a valid file path for the '-csrconfig' parameter." } if ($otp -eq $null) { throw "OTP code is not provided, please carry correct parameters." } #Generate private key openssl ecparam -name secp256k1 -genkey -noout -out privatekey.pem Write-Host "Private key generated." #Generate public key openssl ec -in privatekey.pem -pubout -conv_form compressed -out publickey.pem Write-Host "Public key generated." #Generate CSR(Certificate signing request) openssl base64 -d -in publickey.pem -out publickey.bin openssl req -new -sha256 -key privatekey.pem -extensions v3_req -config $csrconfig -out .\taxpayer.csr openssl base64 -in taxpayer.csr -out taxpayerCSRbase64Encoded.txt $CSRbase64Encoded = Get-Content -path taxpayerCSRbase64Encoded.txt -Raw $CSRbase64Encoded = $CSRbase64Encoded -replace "`n","" $CSRbase64Encoded = $CSRbase64Encoded -replace "`r","" #Init request for CCSID $postParams = @{"csr"=$CSRbase64Encoded} | ConvertTo-Json $postHeader = @{ "Accept"="application/json" "OTP"=$otp "Content-Type"="application/json" "Accept-Version"="V2"} echo $CSRbase64Encoded try { $response = Invoke-WebRequest -Uri $serviceEndpoint'/compliance' -Method POST -Body $postParams -Headers $postHeader } catch { $respStream = $_.Exception.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($respStream) $respBody = $reader.ReadToEnd() $reader.Close() Write-Host "`nZatca service communication error:" Write-Host $_.Exception.Message Write-Host "Detailed error message: " $respBody Write-Host "The process of obtaining a Compliance CSID (CCSID) is interrupted." } if ($response -ne $null) { $response = $response | ConvertFrom-Json $requestId = $response.requestID Write-Host "Request ID:" Write-Host $requestId $requestId | Out-File -FilePath .\requestId.txt -Encoding utf8 -NoNewline $CCSIDbase64 = $response.binarySecurityToken Write-Host "`nCompliance CSID received from Zatca:" Write-Host $CCSIDbase64 $CCSID = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($CCSIDbase64)) $CCSIDCertString = "-----BEGIN CERTIFICATE-----`n" + $CCSID + "`n" + "-----END CERTIFICATE-----" $CCSIDSecret = $response.secret Write-Host "`nCompliance CSID secret received from Zatca:" Write-Host $CCSIDSecret $CCSIDStringFileName = "CCSIDString.txt" $CCSIDSecretFileName = "CCSIDSecret.txt" $CCSIDCertFileName = "CCSID.pem" $CCSIDFolderPath = Get-Location $CCSIDCertFilePath = Join-Path $CCSIDFolderPath $CCSIDCertFileName $CCSIDStringFilePath = Join-Path $CCSIDFolderPath $CCSIDStringFileName $CCSIDSecretFilePath = Join-Path $CCSIDFolderPath $CCSIDSecretFileName $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False [System.IO.File]::WriteAllLines($CCSIDCertFilePath, $CCSIDCertString, $Utf8NoBomEncoding) [System.IO.File]::WriteAllLines($CCSIDStringFilePath, $CCSIDbase64, $Utf8NoBomEncoding) [System.IO.File]::WriteAllLines($CCSIDSecretFilePath, $CCSIDSecret, $Utf8NoBomEncoding) openssl pkcs12 -inkey privatekey.pem -in CCSID.pem -export -passout pass:$password -out CCSID.pfx Write-Host "`nCertificate is saved to CCSID.pfx file and secret is saved to CCSIDSecret.txt file." Write-Host "The process of obtaining a Compliance CSID (CCSID) is complete, please process the compliance check and do not delete or move any created files before getting PCSID." } } if ($action -eq "getProductionCSID") { if (-not (Test-Path -Path requestId.txt)) { throw "'requestId.txt' file is missing, please make sure you're running the script in the same location where the results of getting the CCSID are stored." } if (-not (Test-Path -Path CCSIDString.txt)) { throw "'CCSIDString.txt' file is missing, please make sure you're running the script in the same location where the results of getting the CCSID are stored." } if (-not (Test-Path -Path CCSIDSecret.txt)) { throw "'CCSIDSecret.txt' file is missing, please make sure you're running the script in the same location where the results of getting the CCSID are stored." } $requestId = Get-Content -path requestId.txt -Raw $requestId = $requestId -replace "`n","" $requestId = $requestId -replace "`r","" Write-Host "Request ID is:" $requestId $CCSID = Get-Content -path CCSIDString.txt -Raw $CCSID = $CCSID -replace "`n","" $CCSID = $CCSID -replace "`r","" Write-Host "`nCompliance CSID read locally:" Write-Host $CCSID $CCSIDSecretString = Get-Content -path CCSIDSecret.txt -Raw $CCSIDSecretString = $CCSIDSecretString -replace "`n","" $CCSIDSecretString = $CCSIDSecretString -replace "`r","" Write-Host "`nCompliance CSID secret read locally:" Write-Host $CCSIDSecretString $AuthTokenString = $CCSID + ":" + $CCSIDSecretString $BasicAuthToken = "Basic " + [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($AuthTokenString)) #Init request for Production CSID (PCSID) $postParams = @{"compliance_request_id"=$requestId} | ConvertTo-Json $postHeader = @{ "Accept"="application/json" "Authorization"=$BasicAuthToken "Content-Type"="application/json" "Accept-Version"="V2"} try { $response = Invoke-WebRequest -Uri $serviceEndpoint'/production/csids' -Method POST -Body $postParams -Headers $postHeader } catch { $respStream = $_.Exception.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($respStream) $respBody = $reader.ReadToEnd() $reader.Close() Write-Host "`nZatca service communication error:" Write-Host $_.Exception.Message Write-Host "Detailed error message: " $respBody Write-Host "Please make sure the compliance check process has been done before obtaining a Production CSID (PCSID)." Write-Host "The process of obtaining a Production CSID (PCSID) is interrupted." } if ($response -ne $null) { $response = $response | ConvertFrom-Json $PCSIDbase64 = $response.binarySecurityToken Write-Host "`nProduction CSID received from Zatca:" Write-Host $PCSIDbase64 $PCSID = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($PCSIDbase64)) $PCSIDCertString = "-----BEGIN CERTIFICATE-----`n" + $PCSID + "`n" + "-----END CERTIFICATE-----" $PCSIDSecret = $response.secret Write-Host "`nProduction CSID secret received from Zatca:" Write-Host $PCSIDSecret $PCSIDCertFileName = "PCSID.pem" $PCSIDSecretFileName = "PCSIDSecret.txt" $PCSIDFolderPath = Get-Location $PCSIDCertFilePath = Join-Path $PCSIDFolderPath $PCSIDCertFileName $PCSIDSecretFilePath = Join-Path $PCSIDFolderPath $PCSIDSecretFileName $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False [System.IO.File]::WriteAllLines($PCSIDCertFilePath, $PCSIDCertString, $Utf8NoBomEncoding) [System.IO.File]::WriteAllLines($PCSIDSecretFilePath, $PCSIDSecret, $Utf8NoBomEncoding) # Sandbox API will get error: openssl : No certificate matches private key openssl pkcs12 -inkey privatekey.pem -in PCSID.pem -export -passout pass:$password -out PCSID.pfx if (Test-Path -Path PCSID.pfx) { Write-Host "`nCertificate is saved to PCSID.pfx file and secret is saved to PCSIDSecret.txt file." Write-Host "The process of obtaining a Production CSID (PCSID) is complete." } else { Write-Host "`nThe process of obtaining a Production CSID (PCSID) is interrupted." } } }
Enregistrez le fichier de certificat .pfx de sortie reçu dans le coffre de clés.