Giter Site home page Giter Site logo

fiskaly-sdk-dotnet's Introduction

fiskaly SDK for .NET

The fiskaly SDK includes an HTTP client that is needed1 for accessing the kassensichv.io API that implements a cloud-based, virtual CTSS (Certified Technical Security System) / TSE (Technische Sicherheitseinrichtung) as defined by the German KassenSichV (Kassen­sich­er­ungsver­ord­nung).

Supported Versions

  • .NET Standard 2.0+ (and therefore also .NET Framework 4.6.1+)
  • .NET Framework 4.0

Features

  • Automatic authentication handling (fetch/refresh JWT and re-authenticate upon 401 errors).
  • Automatic retries on failures (server errors or network timeouts/issues).
  • Automatic JSON parsing and serialization of request and response bodies.
  • Future: [1] compliance regarding BSI CC-PP-0105-2019 which mandates a locally executed SMA component for creating signed log messages.
  • Future: Automatic offline-handling (collection and documentation according to Anwendungserlass zu § 146a AO)

Integration

NuGet

Nuget

The .NET SDK is available for download on NuGet.

Package Manager

PM> Install-Package fiskaly-dotnet-sdk -Version 1.2.200

.NET (dotnet) CLI

$ dotnet add package fiskaly-dotnet-sdk --version 1.2.200

Client

Additionaly to the SDK, you'll also need the fiskaly client. Follow these steps to integrate it into your project:

  1. Go to https://developer.fiskaly.com/downloads
  2. Download the appropriate client build for your platform
  3. Move the client into your project output directory or somewhere within the OS search path

Manually building the project

When using the dotnet CLI, use the following command to build the project:

[Fiskaly/SDK]$ dotnet build SDK.standard.csproj

If you are using and older version than the earliest supported version, there is also a legacy build configuration that supports .NET Framework versions as early as .NET Framework 2.0.

[Fiskaly/SDK]$ dotnet build SDK.legacy.csproj

Usage

Demo

using System;
using System.Text;
using Fiskaly;
using Fiskaly.Client;
using Fiskaly.Client.Models;

namespace Demo
{
    static class Demo
    {
        // create your own API key and secret at https://dashboard.fiskaly.com
        public static String FiskalyApiKey = Environment.GetEnvironmentVariable("API_KEY");
        public static String FiskalyApiSecret = Environment.GetEnvironmentVariable("API_SECRET");

        public static string TSS_ID = Guid.NewGuid().ToString();
        public static string CLIENT_ID = Guid.NewGuid().ToString();


        public static FiskalyHttpClient client =
            new FiskalyHttpClient(FiskalyApiKey, FiskalyApiSecret, "https://kassensichv.io/api/v1");

        public static void Main(string[] args)
        {
            InitializeTss();

            var startTxResponse = StartTransaction();
        }

        public static void CreateClient()
        {
            var clientSerial = "fiskaly-dotnet-sdk-test-client";
            var createTssPayload = "{ \"serial_number\": \"" + clientSerial + "\" }";
            var bodyBytes = Encoding.UTF8.GetBytes(createTssPayload);

            var response = client
                .Request("PUT", "/tss/" + TSS_ID + "/client/" + CLIENT_ID, bodyBytes, null, null);
            var decodedBody = Encoding.UTF8.GetString(response.Body);
            var body = JsonConvert
                .DeserializeObject<Dictionary<string, object>>(decodedBody);
        }

        public static void CreateTss()
        {
            var descriptionContent = "TSS created by .NET SDK CreateClient at "
                + DateTime.Now.ToString();
            var createClientPayload = "{ \"description\": \""
                + descriptionContent + "\", \"state\": \"UNINITIALIZED\" }";

            var bodyBytes = Encoding.UTF8.GetBytes(createClientPayload);

            var response = client
                .Request("PUT", "/tss/" + TSS_ID, bodyBytes, null, null);

            var decodedBody = Encoding.UTF8.GetString(response.Body);
            var body = JsonConvert
                .DeserializeObject<Dictionary<string, object>>(decodedBody);

            var initializeTssPayload = "{ \"state\": \"INITIALIZED\" }";
            bodyBytes = Encoding.UTF8.GetBytes(initializeTssPayload);

            var initializeResponse = client
                .Request("PUT", "/tss/" + TSS_ID, bodyBytes, null, null);
        }

        public static void InitializeTss()
        {
            CreateTss();
            CreateClient();
        }

        public static FiskalyHttpResponse StartTransaction()
        {
            var txId = Guid.NewGuid().ToString();
            var payload = "{ \"state\": \"ACTIVE\", \"client_id\": \"" + CLIENT_ID + "\" }";

            var bodyBytes = Encoding.UTF8.GetBytes(payload);

            var response = client
                .Request("PUT", "/tss/" + TSS_ID + "/tx/" + txId, bodyBytes, null, null);

            return response;
        }
    }
}

Client Configuration

The SDK is built on the fiskaly Client which can be configured through the SDK.

A reason why you would do this, is to enable the debug mode.

Enabling the debug mode

The following code snippet demonstrates how to enable the debug mode in the client.

public static void Main(string[] args)
{
    var client = new FiskalyHttpClient(
        FiskalyApiKey,
        FiskalyApiSecret,
        "https://kassensichv.io/api/v1"
    );

    var configuration = new ClientConfiguration
    {
        DebugLevel = DebugLevel.EVERYTHING
    };

    client.ConfigureClient(configuration);
}

Related

fiskaly-sdk-dotnet's People

Contributors

auxdevelopment avatar casimirr-buch avatar johannesferner avatar pgaubatz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fiskaly-sdk-dotnet's Issues

Automatic JSON parsing and serialization of request and response bodies.

Someone work on it? If not I could make pull request for this functionality and hardtyped object cause we already made this internally. Did you plan to accept any pull requests?
Idea in our implementation is to have version related hardtyped model for all objects which is used in your api.

Difference between client_timeout and smaers_timeout

Hi!
Not a bug, but a question - I hope it's okay to ask here, maybe others can profit from the answer as well:
In your documentation, you describe the two parameters client_timeout and smaers_timeout. To us, it's not 100% clear what the difference between those two is, could you maybe give us a quick example?

Thanks in advance, and have a nice weekend!
Tom

Parse Error unter Linux/Mono bei Requests in schneller Abfolge

Beim Auslösen von mehrerer Requests hintereinander scheinen manche unter Linux (mit mono) mit einem FiskalyClientError/ParseError (Exception: Message: "Parse Error", Code: "-32700" Error: encoding error (expected utf8)) zu scheitern.

Die Requests an sich sind jedes mal valides JSON in UTF8. Wovon das SDK selbst einen Teil durch Transformer.cs erledigt.
In unserem Szenario starten wir eine neue Transaktion und updaten sie anschließend mit den Belegdaten. Der zweite Aufruf zum Updaten schlägt in diesem Fall dann manchmal fehl. Sobald eine größere Verzögerungen zwischen den Aufrufen liegt (z.B. durch Tracing aufrufe), funktioniert es allerdings.

Invalid Params

GET-Request wie in der Readme funktioniert. Aber ich bekomme keine PUT-Requests zum Laufen. Ich erhalte immer einen Fehler -32602 "Invalid Params".

Hier mein Code:

var revision = 0;
var txId = Guid.NewGuid();
var url = $"tss/{config.TseId}/tx/{txId}";
var query = new Dictionary<string, string>() { { "last_revision", revision.ToString() } };
var transaction = new Transaction(receipt, (Guid)config.ClientId);
var data = JsonConvert.SerializeObject(transaction);
var response = client.Request("PUT", url, Encoding.UTF8.GetBytes(data), null, query);

Was mache ich hier falsch?

Rate Limit exceeding - Diffent kinds of errors and no clear status code in exception

I did a test generating 1000 documents (Start-Update-Finish) as data for an export and received two different kinds of HTTP 429.

One was returned by the API
{"statusCode":429,"error":"Too Many Requests","message":"Rate limit exceeded, retry in 1 minute"}
which keeps the FiskalyHttpError.Code empty.

and one that seems to come from some reverse proxy or loadbalancer that is a plain HTTP 429 (no json RPC):

<html>
<head><title>429 Too Many Requests</title></head>
<body>
<center><h1>429 Too Many Requests</h1></center>
<hr><center>openresty</center>
</body>
</html>

and thus cannot be deserialized resulting in an JsonReaderException when trying to decode the base64 content in

CreateFiskalyHttpError(JsonRpcResponse response){
...

FiskalyApiError errorBody = JsonConvert
.DeserializeObject(
Transformer.DecodeBase64Body(errorData.Response.Body));

...
}

  • Catch JsonReaderException and return a proper FiskalyHttpError

  • Add Error Code for rate limit to allow handling situation in code

  • Proposal: Add Error Code enum for possible errors

processType "SonstigerVorgang"

Es kann kein "SonstigerVorgang" über das SDK 1.1.301 in Verbindung mit com.fiskaly.client-windows-386-v1.1.300.dll gestartet werden.

Bestellungen oder Belege funktionieren ohne Probleme.

Payload:

{
  "state": "ACTIVE",
  "client_id": "76e239a5-8f03-41fc-8114-0618b1a00e83",
  "schema": {
    "standard_v1": {
      "other": {}
    }
  }
}

Fehler:

Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: (. Path '', line 0, position 0.
   bei Newtonsoft.Json.JsonTextReader.ParseValue()
   bei Newtonsoft.Json.JsonTextReader.Read()
   bei Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
   bei Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   bei Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   bei Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   bei Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   bei Fiskaly.FiskalyHttpClient.CreateFiskalyHttpError[T](JsonRpcResponse`1 response)
   bei Fiskaly.FiskalyHttpClient.ThrowOnError[T](JsonRpcResponse`1 response)
   bei Fiskaly.FiskalyHttpClient.Request(String method, String path, Byte[] body, Dictionary`2 headers, Dictionary`2 query)

Inhalt des Debug-File:

[ERROR] 2020/04/18 15:33:01 request.go:179: HTTP error: {Status: 400, Headers: {"X-Request-Id":["0123456789"]}, Body: (root): Must validate one and only one schema (oneOf)
other: Invalid type. Expected: object, given: string
}

Im Postman funktioniert dies problemlos.

Wrong debug level number mapping in DebugLevel enum

According to the documentation valid debug levels are:

-1 (no output), 1 (errors only), 2 (errors+warnings) and 3 (errors+warnings+info)

But the numbers in DebugLevel enum differ by one digit:

public enum DebugLevel { NO_OUTPUT = -1, ERRORS_ONLY = 0, ERRORS_AND_WARNINGS = 1, EVERYTHING = 2 }

When setting configuration.DebugLevel = (DebugLevel)3 all information is being logged correctly so documentation seems to be right and mapping in DebugLevel enum should be fixed.

Is the FiskalyHttpClient.Request() method thread safe?

Hello,

I am currently using the .NET SDK to send requests to Fiskaly from a mutlithreaded program. In the example on your GitHub page, you are using the client in a static variable, but I can't quite deduce from the source code whether the FiskalyHttpClient or the FiskalyHttpClient's request method is really thread safe. Could you please help me here?

Thanks in advance.

SDK sucht unter Xamarin.Android nach Linux-Library

Hallo,
wir haben das SDK unter Xamarin.Android via Nuget eingebunden. Dabei zeigte sich jedoch, dass das SDK nach einer falschen Bibliothek sucht. Statt nach der Android-Library libcom.fiskaly.client-v1.1.600.so wird nach einer Linux-Library gesucht:

[Mono] DllImport unable to load library 'com.fiskaly.client-linux-amd64-v1.1.600.so'.
[Mono] DllImport unable to load library 'com.fiskaly.client-linux-386-v1.1.600.so'.
[Mono] DllImport unable to load library 'com.fiskaly.client-linux-amd64-v1.1.600.so'.

Getestet auf einem Huawei MediaPad T3 unter Android 7.

Wir haben es nun so gelöst, dass wir einen Wrapper um das SDK mit einer Erweiterung des FiskalyHttpClient erzeugt haben. Statt einer Evaluierung des Projekttyps über ein Compilerflag injekten wir den jeweils notwendingen Client über eine Plattformabstraktion.
Im Projekt muss zur Initialisierung lediglich Fiskaly.Platform.Init() aufgerufen werden. Zusätzlich lassen sich so auch direkt die nativen SMAERS-Komponenten einbinden (runtimes/android-(arm|arm64|x86|x86_64)/native/libcom.fiskaly.client-v1.1.600.so).
Dies ist funktional, jedoch nicht optimal, da jede Aktualisierung, die hier im SDK vorgenommen wird, händisch eingepflegt werden muss.
Ein Multiplatform-Nuget-Package wäre bestimmt im Interesse vieler Kunden.

Get a TSS throws an Exception

Hi,

why does
var getTseResponse = _fiskalyHttpClient.Request("GET", $"/tss/{tssId.ToString()}", null, null, null);
throws an Exception? I think it would be much nicer to check for the StatusCode instead of using catch clauses and the exception don't get the StatusCode so I must the Code field where the strings are not described anywhere.

netSDK wirft Fehler beim parsen von Serverantwort

Moin,

beim Aufruf der Methode Request des FiskalyHttpClients, wird folgender Fehler geworfen:

After parsing a value an unexpected character was encountered: 1. Path 'message', line 1, position 176.

Folgender Stacktrace dazu:

bei Newtonsoft.Json.JsonTextReader.ParsePostValue(Boolean ignoreComments)
bei Newtonsoft.Json.JsonTextReader.Read()
bei Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
bei Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
bei Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
bei Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
bei Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
bei Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
bei Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
bei Fiskaly.FiskalyHttpClient.CreateFiskalyHttpError[T](JsonRpcResponse1 response) bei Fiskaly.FiskalyHttpClient.ThrowOnError[T](JsonRpcResponse1 response)
bei Fiskaly.FiskalyHttpClient.Request(String method, String path, Byte[] body, Dictionary2 headers, Dictionary2 query)

Ich wollte via StartTransaction mir einen Beleg mittels folgenden payload ausstellen lassen:

"{"state":"ACTIVE","client_id":"ClientId entfernt","schema":{"standard_v1":{"receipt":{"receipt_type":"RECEIPT","amounts_per_vat_rate":[{"vat_rate":"19.00","amount":"23.42"}],"amounts_per_payment_type":[{"payment_type":"CASH","amount":"23.42","currency_code":"EUR"}]}}}}"

Es scheint, dass der Server mir etwas mitteilen möchte, aber das parsen der Antwort schlägt fehl. Mögt ihr einmal schauen, was da schief läuft.

Gruß und Danke im voraus.

Fehlender "strong name" für SDK Assembly

Ich versuche die Fiskaly SDK dll in Dynamics NAV zu verwenden. Dazu habe ich im DotNet einen Wrapper erstellt, der auf die Fiskaly SDK dll verweist. Wenn ich nun allerdings meinen DotNet-Wrapper in Dynamics NAV verwende, erscheint folgender Fehler:
fiskaly_sdk_error
Der Fiskaly SDK dll fehlt ein "strong name" und kann deshalb nicht in Dynamics NAV verwendet werden. Kann der Fiskaly SDK dll noch ein "strong name" hinzugefügt werden?

FiskalyHttpResponse should provide a way to access the response body as a stream instead of a byte array

This is crucial for handling downloads of DSFinV-K exports (https://developer.fiskaly.com/api/dsfinvk/v0/#operation/getExportDownload). We want to basically pass the response stream through our application without being forced to hold the potentially large export file in memory. Retrieving a fiskaly download url for the export file is not an option as we need to handle access permissions on our own.

Error on put Transaction

„token's 'exp' has passed or could not parsed 'somerandomnumber'

The transaction ist created successfully.
Wenn Updating/finishing the Transaction, the error sometimes ist beeing thrown by the server.
Transaction remeins active.

Not reproducible, next transaction fully ok.

I did write an Email on 12.08.2020 but didn't get any response.

Version: com.fiskaly.client-windows-386-v1.2.000.dll

SmaersVersion hashes are null

After invoking the Version() method on FiskalyHttpClient, the CommitHash and SourceHash strings within SmaersVersion are null.

The version string ("0.1.0") itself, the whole ClientVersion and SdkVersion properties all are fine (filled with data).

Internal Error nach Update auf Version 1.2.100

Hallo,

wir haben auf die Version 1.2.100 geupdated und erhalten nun wenn wir z.B. die TSE Informationen abrufen wollen einen Internal Error.
Der Fehler ist:
failed to fetch remote JWK: Get "https://auth.fiskaly.com/auth/realms/fiskaly/protocol/openid-connect/certs": dial tcp 35.198.188.136:443: connectex: Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat.

Ich vermute das die Proxy Daten nicht genutzt werden in dieser Version.

Version liefert:

{SDK: {
	Version: dotnet-v1.2.100
}
Client: {
	Version: 1.2.100,
	CommitHash: 0a8a3c6e83c4c44433d480560f1a3f1a12566e11,
	SourceHash: 0c28227cea801e8fdc811d3a4c72c199763d6254fde1df4be9e51e299b63a672
}
Smaers: {
	Version: 0.1.0,
	CommitHash: ,
	SourceHash: 
}
}
    ClientVersion: {{
	Version: 1.2.100,
	CommitHash: 0a8a3c6e83c4c44433d480560f1a3f1a12566e11,
	SourceHash: 0c28227cea801e8fdc811d3a4c72c199763d6254fde1df4be9e51e299b63a672
}}
    SdkVersion: "dotnet-v1.2.100"
    SmaersVersion: {{
	Version: 0.1.0,
	CommitHash: ,
	SourceHash: 
}}

HealthCheck:

{{
	Proxy: {
	Status: http://10.1.254.254:800
}
	Smaers: {
	Status: OK
}
	Backend: {
	Status: OK
}
}}
    Backend: {{
	Status: OK
}}
    Proxy: {{
	Status: http://10.1.254.254:800
}}
    Smaers: {{
	Status: OK
}}

Payment_type and vat_rate

Hi there,

sorry, I have one more question:

What are valid values for payment_type and vat_rate?

Is there somewhere a list?

Best regards and thank you very, very much in advance!!

Phileas

PLEASE, help me - FinishTransaction

Hi there,
I know, this might sound stupid, but I am trying to finish a transaction with this small demo code:

public static FiskalyHttpResponse FinishTransaction()
{
var payload = "{ "schema": { "standard_v1": { "receipt": { "receipt_type": "RECEIPT", "amounts_per_vat_rate": [ { "vat_rate": "NORMAL", "amount": "21.42" } ], "amounts_per_payment_type": [{ "payment_type": "NON_CASH", "amount": "21.42" } ] } } }, "state": "FINISHED", "client_id": "" + CLIENT_ID + "" }";

        var bodyBytes = Encoding.UTF8.GetBytes(payload);

        var response = client.Request("PUT", "/tss/" + TSS_ID + "/tx/" + TX_ID + "?last_revision=1", bodyBytes, null, null);

        return response;
    }

I have problems with "?last_revision" and I am not sure, if my payload is correct.

Can anybody help me, or provide a small example, that works?

THANK YOU VERY, VERY MUCH!!!

Phileas

Fiskaly.Errors.FiskalyHttpError: token's 'exp' has passed or could not parsed

O.g. Fehler kommt immer mal wieder.
Wenn ich den gleichen Request sofort erneut schicke klappt er.
Passiert sehr unregelmäßig und war bisher nicht reproduzierbar.

Ich hab nun alle Aufrufe in eine RetryPolicy gepackt. Beim zweiten Versuch klappt der Request dann.

Log sagt: [ERROR] 2020/07/15 15:32:53 debug.go:21: http-status not okay: 401

Version 1.2.000

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.