Udostępnij za pośrednictwem


Dołączanie fakturowania elektronicznego w Arabii Saudyjskiej

Onboarding jest obowiązkowy dla wszystkich podatników, którzy podlegają fakturowaniu elektronicznemu w Arabii Saudyjskiej. W wyniku procesu onboardingu podatnicy uzyskują identyfikatory pieczęci kryptograficznej (CSID). Identyfikatory CSID są wymagane do integracji z portalem fakturowania elektronicznego zarządzanego przez urząd skarbowy Arabii Saudyjskiej (ZATCA) oraz do dalszego przesyłania faktur elektronicznych.

W tym artykule wyjaśniono, jak dołączyć podatników i ich oprogramowanie do fakturowania elektronicznego do urzędów skarbowych Arabii Saudyjskiej.

Wymagania wstępne

Proces wdrażania

Proces onboardingu składa się z dwóch kroków:

  1. Uzyskaj identyfikator CSID zgodności (CCSID), który ZATCA przypisuje do przeprowadzania kontroli zgodności rozwiązań do generowania faktur elektronicznych (EGS).
  2. Uzyskaj produkcyjny identyfikator CSID (PCSID), który ZATCA przypisuje do zgodnych EGS.

Przepływ pracy związany z wdrażaniem.

Uzyskiwanie identyfikatora CCSID

  1. W portalu podatkowym Arabii Saudyjskiej (ERAD) przejdź do portalu dołączania i zarządzania, wybierając odpowiedni kafelek.

  2. Na głównej stronie docelowej portalu dołączania i zarządzania wybierz kafelek Dołączanie nowej jednostki/urządzenia rozwiązania, a następnie wybierz pozycję Generuj kod OTP. Kod OTP jest ważny tylko przez godzinę po wygenerowaniu. Upewnij się, że jest używany w tym czasie.

  3. Wybierz liczbę kodów haseł jednorazowych (OTP) do wygenerowania. Liczba ta zależy od liczby jednostek wytwórczych (urządzeń) e-fakturowania, które zostaną wykorzystane.

  4. Zapisz wygenerowane kody OTP, aby móc ich użyć w późniejszych krokach.

  5. Przygotuj plik konfiguracyjny dla żądania podpisania certyfikatu. Ten plik konfiguracyjny powinien mieć postać zwykłego pliku tekstowego, który zawiera następujące dane.

    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. Zapisz plik w tej samej lokalizacji, w której znajduje się skrypt dołączania o nazwie,csr_config.txt .

  7. W pliku konfiguracji zaktualizuj wartość emailAddress i następujące określone dane.

    Kod opis Specyfikacja
    F Kod kraju/regionu. Kod dwuliterowy (ISO 3166 Alpha-2)
    OU Nazwa jednostki organizacyjnej. Dla zwykłych podatników wartość jest dowolna. W przypadku grup podatku VAT zidentyfikuj wartość za pomocą jedenastej cyfry identyfikatora organizacji „1”. Sprawdź, czy dane wejściowe są 10-cyfrowym numerem identyfikacji podatkowej (NIP).
    O Nazwa organizacji lub podatnika. Dowolny tekst
    CN Unikatowa nazwa rozwiązania lub jednostki. Dowolny tekst
    SN Unikatowy kod identyfikacyjny rozwiązania. Dowolny tekst
    Identyfikator UID Numer identyfikacji podatkowej podatnika w zakresie podatku VAT. Piętnaście cyfr. Ta liczba zaczyna się od „3” i kończy na „3”.
    tytuł Typ dokumentu, który zostanie wystawiony przez jednostkę rozwiązania podatnika. Czterocyfrowe dane wejściowe numeryczne, które używają „0” i „1” zamapowanych na „TSCZ”: 0 = Fałsz/Nieobsługiwane, 1 = Prawda/Obsługiwane. T = Faktura VAT (standardowa), S = Uproszczona faktura VAT, C = Do wykorzystania w przyszłości, Z = Do wykorzystania w przyszłości.
    registeredAddress (adres rejestracyjny) Adres oddziału lub lokalizacji, w której głównie znajduje się urządzenie lub jednostka rozwiązania. Dowolny tekst
    Kategoria biznesowa Branża lub sektor, dla którego urządzenie lub rozwiązanie będzie generować faktury. Dowolny tekst

    Banknot

    Wartości CN i certificateTemplateName w pliku konfiguracji są różne w przypadku korzystania z portalu symulacji .

    W portalu symulacyjnym:

    • CN- PREZATCA-Podpisywanie kodu
    • certificateTemplateName - ASN1:PRINTABLESTRING:PREZATCA-Code-Signing

    W każdym innym przypadku użyj wartości zgodnie z powyższymi instrukcjami.

  8. Uruchom skrypt dołączania, który zostanie udostępniony w dalszej części tego artykułu. Określ OTP i plik konfiguracyjny jako parametry wejściowe. Oto przykład: Skrypt ma dwa możliwe punkty końcowe symulacji i prod.

    .\OnboardingScript.ps1 -action getComplianceCSID -endpoint prod -otp 123345 -csrconfig .\csr_config.txt -password 123

    Banknot

    Parametr hasła jest opcjonalny i można go pominąć. Jeśli zostanie uwzględniony, wygenerowany certyfikat będzie miał określone hasło.

  9. Identyfikator CCSID jest odbierany jako plik certyfikatu „CCSID.pfx”, a klucz tajny dla identyfikatora CCSID jest zapisywany jako plik txt „CCSIDSecret.txt”. Zapisz ten plik certyfikatu CCSID w certyfikacie Microsoft Azure magazynu kluczy i zapisz wpis tajny w Microsoft Azure kluczu tajnym magazynu kluczy. Aby uzyskać więcej informacji, zobacz Certyfikaty i klucze tajne klienta.

  10. Skonfiguruj powiązaną konfigurację funkcji w funkcji fakturowania elektronicznego ZATCA (SA) w Arabii Saudyjskiej i odwołaj się do certyfikatu CCSID zapisanego w magazynie kluczy. Certyfikat będzie wykorzystywany do komunikacji z portalem fakturowania elektronicznego ZATCA.

Kontrola zgodności

Po uzyskaniu identyfikatora CSID zgodności przy użyciu skryptu PowerShell ZATCA wymaga przeprowadzenia pewnych kontroli zgodności poprzez przesłanie przykładowych faktur. Ten krok jest wymaganiem wstępnym do złożenia wniosku o identyfikator CSID produkcji.

Upewnij się, że wszystkie typy przykładowych faktur, które zostały skonfigurowane w pliku konfiguracyjnym żądania podpisania certyfikatu (CSR), zostały pomyślnie przesłane do ZATCA. Użyj standardowego procesu wystawiania faktur elektronicznych. Aby uzyskać więcej szczegółów, zobacz Wystawianie faktur elektronicznych w rozwiązaniach Finance i łańcuch dostaw.

Użyj funkcji „Sprawdzanie zgodności ZATCA (SA) Arabii Saudyjskiej” w RCS i postępuj zgodnie z instrukcjami sekcji Konfiguracja specyficzna dla kraju/regionu, korzystając z uzyskanego identyfikatora CSID zgodności.

Po pomyślnym zakończeniu kontroli zgodności użyj skryptu PowerShell, aby uzyskać identyfikator CSID produkcji (zobacz skrypt dołączania).

Banknot

W polu Tytuł , jeśli typ dokumentu pliku konfiguracyjnego jest ustawiony na 1000, należy przesłać trzy przykładowe faktury w celu sprawdzenia zgodności:

  • Standardowa faktura VAT
  • Standardowa nota obciążeniowa
  • Standardowa faktura korygująca

W polu Tytuł , jeśli typ dokumentu pliku konfiguracyjnego jest ustawiony na 0100, należy przesłać trzy przykładowe faktury w celu sprawdzenia zgodności:

  • Uproszczona faktura VAT
  • Uproszczona nota obciążeniowa
  • Uproszczona faktura korygująca

Jeśli typ dokumentu jest ustawiony na 1100, wszystkie sześć przykładowych faktur musi zostać przesłanych do kontroli zgodności.

Uzyskiwanie identyfikatora PCSID

Aby uzyskać identyfikator PCSID, należy poprawnie skonfigurować rozwiązanie do elektronicznego generowania i przesyłania faktur, a rozwiązanie musi być w pełni funkcjonalne. Aby osiągnąć ten wynik, należy wykonać wszystkie wymagane wstępne kroki konfiguracji. Aby uzyskać więcej informacji, zobacz Wprowadzenie do fakturowania elektronicznego dla Arabii Saudyjskiej.

  1. Upewnij się, że wszystkie faktury elektroniczne zostały pomyślnie przesłane do ZATCA.

  2. Uruchom skrypt dołączania, który zostanie udostępniony w dalszej części tego artykułu. Określ identyfikator CCSID jako parametr wejściowy. Oto przykład: Skrypt ma dwa możliwe punkty końcowe simulation & prod

    .\OnboardingScript.ps1 -action getProductionCSID -endpoint prod -password 123

    Banknot

    Parametr hasła jest opcjonalny i można go pominąć. Jeśli zostanie uwzględniony, wygenerowany certyfikat będzie miał określone hasło.

  3. Identyfikator PCSID jest odbierany jako plik certyfikatu w formacie PFX. Zapisz ten certyfikat PCSID i plik wpisu tajnego w magazynie kluczy Azure.

  4. Skonfiguruj konfigurację powiązanej funkcji w funkcji przesyłania Zatca (SA) w Arabii Saudyjskiej Funkcja fakturowania elektronicznego . Uwzględnij certyfikat PCSID i wpis tajny w parametrach magazynu kluczy w RCS.

Po wykonaniu wszystkich kroków konfiguracji system jest gotowy do użycia w trybie produkcyjnym.

Aby przejrzeć uzyskane identyfikatory CSID po stronie ZATCA, użyj kafelka Przejrzyj istniejący identyfikator stempla kryptograficznego (CSID) na stronie docelowej portalu dołączania i zarządzania. Portal ten jest dostępny z głównego portalu podatkowego Arabii Saudyjskiej (ERAD).

Skrypt dołączania

Banknot

Przykładowe skrypty nie są obsługiwane w ramach żadnego Microsoft standardowego programu pomocy technicznej ani usługi. Przykładowe skrypty są dostarczane TAK JAK JEST, bez jakiejkolwiek gwarancji. Microsoft ponadto zrzeka się wszelkich dorozumianych gwarancji, w tym między innymi wszelkich dorozumianych gwarancji przydatności handlowej lub przydatności do określonego celu. Całe ryzyko wynikające z użycia lub wykonania przykładowych skryptów i dokumentacji pozostaje po stronie użytkownika. W żadnym wypadku Microsoft, jego autorzy ani nikt inny zaangażowany w tworzenie, produkcję lub dostarczanie skryptów nie ponosi odpowiedzialności za jakiekolwiek szkody (w tym, bez ograniczeń, szkody z tytułu utraty zysków biznesowych, przerw w działalności, utraty informacji biznesowych lub innych strat pieniężnych) wynikające z użycia lub niemożności korzystania z przykładowych skryptów lub dokumentacji, nawet jeśli Microsoft został poinformowany o możliwości wystąpienia takich szkód.

  1. Użyj następującego skryptu systemu Windows PowerShell, aby uzyskać identyfikator CCSID i identyfikator 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. Zapisz wyjściowy plik certyfikatu pfx, który jest odbierany w magazynie kluczy.

Dodatkowe zasoby