Partager via


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 :

  1. 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).
  2. Obtenir un CSID de production (PCSID), que ZATCA attribue aux EGS conformes.

Flux de travail d’intégration.

Obtenir un CCSID

  1. Dans le Portail fiscal saoudien (ERAD), accédez au portail d’intégration et de gestion en sélectionnant la vignette appropriée.

  2. 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.

  3. 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.

  4. Enregistrez les codes OTP générés afin de pouvoir les utiliser lors d’étapes ultérieures.

  5. 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
    
  6. Enregistrez le fichier au même emplacement que le script d’intégration avec le nom csr_config.txt.

  7. 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.

  8. 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é.

  9. 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.

  10. 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.

  1. Assurez-vous que toutes les factures électroniques sont soumises avec succès à ZATCA.

  2. 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é.

  3. 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 ;.

  4. 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.

  1. 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."
     		}
     	}
     }
    
  2. Enregistrez le fichier de certificat .pfx de sortie reçu dans le coffre de clés.

Ressources supplémentaires