diff --git a/examples/jre/build.gradle b/examples/jre/build.gradle index 821fdb0..91a4db5 100644 --- a/examples/jre/build.gradle +++ b/examples/jre/build.gradle @@ -12,7 +12,11 @@ repositories { } dependencies { - implementation 'com.fiskaly.sdk:fiskaly-sdk:1.2.200-jre' + //implementation 'com.fiskaly.sdk:fiskaly-sdk:1.2.200-jre' + implementation files('../../build/libs/fiskaly-sdk-1.2.200.jar') + implementation "com.google.code.gson:gson:2.8.6" + implementation "net.iharder:base64:2.3.9" + implementation "net.java.dev.jna:jna:5.5.0" } application { diff --git a/examples/jre/readme.md b/examples/jre/readme.md index b64b49c..d5475ab 100644 --- a/examples/jre/readme.md +++ b/examples/jre/readme.md @@ -14,6 +14,18 @@ $ ./gradlew build ## Run example +First, if you want to test the V1 API, set environment variables `FISKALY_API_KEY` and `FISKALY_API_SECRET` to your API key and secret: + +```bash +export FISKALY_API_KEY=yourAPIkey + export FISKALY_API_SECRET=yourAPIsecret + ``` + If you want to test the V2 API, set environment variables `FISKALY_API_KEY_V2` and `FISKALY_API_SECRET_V2` to your API key and secret for V2, in the same way. + + If you want to use an existing TSS for V2 instead of creating a new one (e.g. because you have reached the limit of active TSS), also set `FISKALY_TSS_UUID_V2` to the UUID of that TSS. If you do this, you will need to either set `FISKALY_TSS_ADMIN_PIN` to the admin PIN of that TSS, or set `FISKALY_TSS_PUK` to the admin PUK of that TSS. The PUK will only be used if the PIN is empty. + + Next, run the sample: + ```bash $ ./gradlew run ``` diff --git a/examples/jre/src/main/java/com/fiskaly/sdk/demo/jre/Main.java b/examples/jre/src/main/java/com/fiskaly/sdk/demo/jre/Main.java index 382c295..bac0ba7 100644 --- a/examples/jre/src/main/java/com/fiskaly/sdk/demo/jre/Main.java +++ b/examples/jre/src/main/java/com/fiskaly/sdk/demo/jre/Main.java @@ -2,13 +2,294 @@ import com.fiskaly.sdk.*; +import java.io.IOException; +import java.util.Collections; +import java.util.UUID; + +import com.fiskaly.sdk.factories.GsonFactory; +import com.google.gson.Gson; + public class Main { + static UUID tssUUID = null; + static UUID clientUUID = null; + static String adminPUK = ""; + static FiskalyHttpClient client = null; + static String adminPIN = "0123456789"; + static String transactionUUID = ""; + static int transactionRevision = 0; + private static final Gson GSON = GsonFactory.createGson(); + public static void main(String[] args) throws Exception { final String apiKey = System.getenv("FISKALY_API_KEY"); final String apiSecret = System.getenv("FISKALY_API_SECRET"); - final FiskalyHttpClient client = - new FiskalyHttpClient(apiKey, apiSecret, "https://kassensichv.io/api/v1"); + client = + new FiskalyHttpClient(apiKey, apiSecret, "https://kassensichv.io/api/v1"); + listTSS(); + createTSSV1(); + createClient(); + createTransactionV1(); + finishTransactionV1(); + + //now do something similar on v2 + final String apiKeyv2 = System.getenv("FISKALY_API_KEY_V2"); + final String apiSecretv2 = System.getenv("FISKALY_API_SECRET_V2"); + //set these to use an existing TSS instead of creating a new one + final String existingTSS = System.getenv("FISKALY_TSS_UUID_V2"); + //set either a PIN (if the TSS already has one set) or a PUK (if the TSS doesn't have a PIN set) + final String existingTSSAdminPIN = System.getenv("FISKALY_TSS_ADMIN_PIN"); + final String existingTSSPUK = System.getenv("FISKALY_TSS_PUK"); + client = + new FiskalyHttpClient(apiKeyv2, apiSecretv2, "https://kassensichv.fiskaly.com/api/v2", "https://kassensichv-middleware.fiskaly.com"); + listTSS(); + final Boolean useExistingTSS = existingTSS != null && !existingTSS.isEmpty(); + if (!useExistingTSS) { + createTSS(); + } else { + tssUUID = UUID.fromString(existingTSS); + adminPUK = existingTSSPUK; + System.out.println("Using existing TSS '"+existingTSS+"' with PIN '"+existingTSSAdminPIN+"' and PUK '"+existingTSSPUK+"'"); + } + if (!useExistingTSS || existingTSSAdminPIN == null || existingTSSAdminPIN.isEmpty()) { + personalizeTSS(); + changeAdminPIN(); + } else if (useExistingTSS) { + adminPIN = existingTSSAdminPIN; + } + authenticateAdmin(); + initializeTSS(); + createClient(); + updateClient(); + createTransaction(); + updateTransaction(); + finishTransaction(); + //don't disable a TSS we didn't create + if (existingTSS == null) { + disableTSS(); + } + } + + private static void listTSS() throws IOException, FiskalyHttpException, FiskalyClientException, FiskalyHttpTimeoutException { final FiskalyHttpResponse response = client.request("GET", "/tss"); + System.out.println("List TSS response:"); + System.out.println(response); + } + + public static void createTSS() throws Exception { + tssUUID = UUID.randomUUID(); + final FiskalyHttpResponse response = client.request("PUT", "/tss/" + tssUUID, "{}".getBytes()); + System.out.println("Create TSS response:"); + System.out.println(response); + final String decodedBody = new String(response.body); + final CreateTSSResponse body = GSON.fromJson(decodedBody, CreateTSSResponse.class); + System.out.println("admin puk = "+body.admin_puk); + adminPUK = body.admin_puk; + } + + public static void setTSSState(String state) throws Exception { + final String body = "{ \"state\" : \""+state+"\" }"; + System.out.println("Setting TSS state to "+state); + System.out.println(body); + final FiskalyHttpResponse response = client.request("PATCH", "/tss/" + tssUUID, body.getBytes()); + System.out.println("Set TSS state response:"); + System.out.println(response); + } + + public static void personalizeTSS() throws Exception { + setTSSState("UNINITIALIZED"); + } + + public static void changeAdminPIN() throws Exception { + final String body = "{ \"admin_puk\" : \""+ adminPUK +"\", \"new_admin_pin\" : \""+adminPIN+"\" }"; + System.out.println("Setting admin PIN to "+adminPIN); + System.out.println(body); + final FiskalyHttpResponse response = client.request("PATCH", "/tss/" + tssUUID + "/admin", body.getBytes()); + System.out.println("Set admin PIN response:"); + System.out.println(response); + } + + public static void authenticateAdmin() throws Exception { + final String body = "{ \"admin_pin\" : \""+adminPIN+"\" }"; + System.out.println("Authenticating admin"); + System.out.println(body); + final FiskalyHttpResponse response = client.request("POST", "/tss/" + tssUUID + "/admin/auth", body.getBytes()); + System.out.println("Authenticate admin response:"); + System.out.println(response); + } + + public static void initializeTSS() throws Exception { + setTSSState("INITIALIZED"); + } + + public static void createClient() throws Exception { + clientUUID = UUID.randomUUID(); + final String body = "{ \"serial_number\": \"JRE Test Client Serial\"}"; + System.out.println("Creating client"); + System.out.println(body); + final FiskalyHttpResponse response = client.request("PUT", "/tss/" + tssUUID + "/client/" + clientUUID, body.getBytes()); + System.out.println("Create Client response:"); + System.out.println(response); + } + + public static void updateClient() throws Exception { + final String body = "{ \"state\": \"REGISTERED\", \"metadata\": {\"custom_field\": \"custom_value\"}}"; + System.out.println("Updating client"); + System.out.println(body); + final FiskalyHttpResponse response = client.request("PATCH", "/tss/" + tssUUID + "/client/" + clientUUID, body.getBytes()); + System.out.println("Update Client response:"); + System.out.println(response); + } + + public static FiskalyHttpResponse transactionRequest(String body) throws Exception { + transactionRevision++; //transaction revision number starts at 1 + return client.request("PUT", "/tss/" + tssUUID + "/tx/" + transactionUUID, body.getBytes(), Collections.singletonMap("tx_revision", transactionRevision)); + } + + public static void createTransaction() throws Exception { + UUID uuid = UUID.randomUUID(); + transactionUUID = uuid.toString(); + final String body = "{\"state\": \"ACTIVE\",\n" + + " \"client_id\": \"" + clientUUID + "\"\n" + + " }"; + System.out.println("Creating transaction"); + System.out.println(body); + transactionRevision = 0; + final FiskalyHttpResponse response = transactionRequest(body); + System.out.println("Create Transaction response:"); + System.out.println(response); + } + + public static void updateTransaction() throws Exception { + final String body = "{\n" + + " \"schema\": {\n" + + " \"standard_v1\": {\n" + + " \"receipt\": {\n" + + " \"receipt_type\": \"RECEIPT\",\n" + + " \"amounts_per_vat_rate\": [\n" + + " {\n" + + " \"vat_rate\": \"NORMAL\",\n" + + " \"amount\": \"21.42\"\n" + + " }\n" + + " ],\n" + + " \"amounts_per_payment_type\": [\n" + + " {\n" + + " \"payment_type\": \"NON_CASH\",\n" + + " \"amount\": \"21.42\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + " },\n" + + " \"state\": \"ACTIVE\",\n" + + " \"client_id\": \"" + clientUUID + "\"\n" + + " }"; + System.out.println("Updating transaction"); + System.out.println(body); + final FiskalyHttpResponse response = transactionRequest(body); + System.out.println("Update Transaction response:"); + System.out.println(response); + } + + public static void finishTransaction() throws Exception { + final String body = "{\n" + + " \"schema\": {\n" + + " \"standard_v1\": {\n" + + " \"receipt\": {\n" + + " \"receipt_type\": \"RECEIPT\",\n" + + " \"amounts_per_vat_rate\": [\n" + + " {\n" + + " \"vat_rate\": \"NORMAL\",\n" + + " \"amount\": \"21.42\"\n" + + " }\n" + + " ],\n" + + " \"amounts_per_payment_type\": [\n" + + " {\n" + + " \"payment_type\": \"NON_CASH\",\n" + + " \"amount\": \"21.42\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + " },\n" + + " \"state\": \"FINISHED\",\n" + + " \"client_id\": \"" + clientUUID+ "\"\n" + + " }"; + System.out.println("Finishing transaction"); + System.out.println(body); + final FiskalyHttpResponse response = transactionRequest(body); + System.out.println("Finish Transaction response:"); + System.out.println(response); + } + + public static void disableTSS() throws Exception { + setTSSState("DISABLED"); + } + + ///V1 versions + public static void createTSSV1() throws Exception { + tssUUID = UUID.randomUUID(); + final String body = "{\n" + + " \"description\": \"JRE Test TSS\",\n" + + " \"state\": \"INITIALIZED\"\n" + + " }"; + final FiskalyHttpResponse response = client.request("PUT", "/tss/" + tssUUID, body.getBytes()); + System.out.println("Create TSS response:"); System.out.println(response); } + + public static void createTransactionV1() throws Exception { + UUID uuid = UUID.randomUUID(); + transactionUUID = uuid.toString(); + final String body = "{\"state\": \"ACTIVE\",\n" + + " \"client_id\": \"" + clientUUID +"\"\n" + + " }"; + System.out.println("Creating V1 transaction"); + System.out.println(body); + transactionRevision = 0; + final FiskalyHttpResponse response = client.request("PUT", "/tss/" + tssUUID + "/tx/" + transactionUUID, body.getBytes()); + + System.out.println("Create V1 Transaction response:"); + System.out.println(response); + } + + public static void finishTransactionV1() throws Exception { + final String body = "{\n" + + " \"state\": \"FINISHED\",\n" + + " \"client_id\": \"" + clientUUID + "\",\n" + + " \"schema\": {\n" + + " \"standard_v1\": {\n" + + " \"receipt\": {\n" + + " \"receipt_type\": \"RECEIPT\",\n" + + " \"amounts_per_vat_rate\": [\n" + + " {\"vat_rate\": \"19\", \"amount\": \"14.28\"}\n" + + " ],\n" + + " \"amounts_per_payment_type\": [\n" + + " {\"payment_type\": \"NON_CASH\", \"amount\": \"14.28\"}\n" + + " ]\n" + + " }\n" + + " }\n" + + " }\n" + + " }"; + System.out.println("Finishing transaction"); + System.out.println(body); + final FiskalyHttpResponse response = client.request("PUT", "/tss/" + tssUUID + "/tx/" + transactionUUID, body.getBytes(), Collections.singletonMap("last_revision", 1)); + System.out.println("Finish Transaction response:"); + System.out.println(response); + } + +} + +class CreateTSSResponse { + public final String admin_puk; + + public CreateTSSResponse(final String admin_puk) { + this.admin_puk = admin_puk; + } + + @Override + public String toString() { + return "Response{" + + "admin_puk=" + + admin_puk + + '}'; + } } diff --git a/examples/jre/src/main/resources/readme.md b/examples/jre/src/main/resources/readme.md index cc2a9cc..4f407d6 100644 --- a/examples/jre/src/main/resources/readme.md +++ b/examples/jre/src/main/resources/readme.md @@ -5,4 +5,5 @@ First, go to https://developer.fiskaly.com/downloads and download the client lib - Put `com.fiskaly.client-linux-386-vX.Y.Z.so` into `linux-x86/` - Put `com.fiskaly.client-linux-amd64-vX.Y.Z.so` into `linux-x86-64/` - Put `com.fiskaly.client-windows-386-vX.Y.Z.so` into `win32-x86/` -- Put `com.fiskaly.client-windiws-amd64-vX.Y.Z.so` into `win32-x86-64/` +- Put `com.fiskaly.client-windows-amd64-vX.Y.Z.so` into `win32-x86-64/` +- Put `com.fiskaly.client-darwin-amd64-vX.Y.Z.dylib` into `darwin/` and rename it to `libcom.fiskaly.client-darwin-amd64-vX.Y.Z.dylib` diff --git a/src/main/java/com/fiskaly/sdk/FiskalyHttpClient.java b/src/main/java/com/fiskaly/sdk/FiskalyHttpClient.java index 5c0fb2a..cc65b47 100644 --- a/src/main/java/com/fiskaly/sdk/FiskalyHttpClient.java +++ b/src/main/java/com/fiskaly/sdk/FiskalyHttpClient.java @@ -25,12 +25,13 @@ public FiskalyHttpClient( final String email, final String password, final String organizationId, - final String environment) + final String environment, + final URI miceUrl) throws IOException, FiskalyHttpTimeoutException, FiskalyClientException, FiskalyHttpException { final ParamCreateContext params = new ParamCreateContext( - apiKey, apiSecret, baseUrl, email, password, organizationId, environment); + apiKey, apiSecret, baseUrl, email, password, organizationId, environment, miceUrl); final JsonRpcRequest request = new JsonRpcRequest("create-context", params); final JsonRpcResponse response = doInvoke(request, ResultCreateContext.class); @@ -45,13 +46,20 @@ public FiskalyHttpClient( final String password) throws IOException, FiskalyHttpTimeoutException, FiskalyClientException, FiskalyHttpException { - this(apiKey, apiSecret, baseUrl, email, password, "", ""); + this(apiKey, apiSecret, baseUrl, email, password, "", "", null); } public FiskalyHttpClient(final String apiKey, final String apiSecret, final URI baseUrl) throws IOException, FiskalyHttpTimeoutException, FiskalyClientException, FiskalyHttpException { - this(apiKey, apiSecret, baseUrl, "", "", "", ""); + this(apiKey, apiSecret, baseUrl, "", "", "", "", null); + } + + public FiskalyHttpClient( + final String apiKey, final String apiSecret, final URI baseUrl, final URI miceUrl) + throws IOException, FiskalyHttpTimeoutException, FiskalyClientException, + FiskalyHttpException { + this(apiKey, apiSecret, baseUrl, "", "", "", "", miceUrl); } public FiskalyHttpClient(final String apiKey, final String apiSecret, final String baseUrl) @@ -60,6 +68,13 @@ public FiskalyHttpClient(final String apiKey, final String apiSecret, final Stri this(apiKey, apiSecret, new URI(baseUrl)); } + public FiskalyHttpClient( + final String apiKey, final String apiSecret, final String baseUrl, final String miceUrl) + throws IOException, URISyntaxException, FiskalyHttpException, FiskalyClientException, + FiskalyHttpTimeoutException { + this(apiKey, apiSecret, new URI(baseUrl), new URI(miceUrl)); + } + public ResultVersion version() throws FiskalyHttpException, FiskalyHttpTimeoutException, FiskalyClientException, IOException { diff --git a/src/main/java/com/fiskaly/sdk/factories/ExceptionFactory.java b/src/main/java/com/fiskaly/sdk/factories/ExceptionFactory.java index 6585179..bffe819 100644 --- a/src/main/java/com/fiskaly/sdk/factories/ExceptionFactory.java +++ b/src/main/java/com/fiskaly/sdk/factories/ExceptionFactory.java @@ -7,6 +7,7 @@ import com.fiskaly.sdk.results.FiskalyApiError; import com.google.gson.Gson; import java.io.IOException; +import java.util.List; import net.iharder.Base64; public abstract class ExceptionFactory { @@ -17,7 +18,15 @@ private ExceptionFactory() {} public static FiskalyHttpException buildHttpException(final JsonRpcResponse response) throws IOException { final ErrorData errorData = GSON.fromJson(GSON.toJson(response.error.data), ErrorData.class); - final String requestId = (String) errorData.response.headers.get("x-request-id").get(0); + String requestId = null; + // request id is in x-request-id header in v1, request-id in v2. + List requestIds = errorData.response.headers.get("x-request-id"); + if (requestIds == null) { + requestIds = errorData.response.headers.get("request-id"); + } + if (requestIds != null) { + requestId = (String) requestIds.get(0); + } final String decodedBody = new String(Base64.decode(errorData.response.body), "UTF-8"); final FiskalyApiError errorBody = GSON.fromJson(decodedBody, FiskalyApiError.class); diff --git a/src/main/java/com/fiskaly/sdk/params/ParamCreateContext.java b/src/main/java/com/fiskaly/sdk/params/ParamCreateContext.java index 67060e8..09760c6 100644 --- a/src/main/java/com/fiskaly/sdk/params/ParamCreateContext.java +++ b/src/main/java/com/fiskaly/sdk/params/ParamCreateContext.java @@ -6,6 +6,7 @@ public class ParamCreateContext { public final String apiKey; public final String apiSecret; public final URI baseUrl; + public final URI miceUrl; public final String email; public final String password; public final String organizationId; @@ -18,7 +19,8 @@ public ParamCreateContext( final String email, final String password, final String organizationId, - final String environment) { + final String environment, + final URI miceUrl) { if (email == null || email.isEmpty()) { if (apiKey == null || apiKey.isEmpty()) { throw new IllegalArgumentException("Missing or empty \"apiKey\" parameter"); @@ -41,6 +43,7 @@ public ParamCreateContext( throw new IllegalArgumentException("Missing or empty \"baseUrl\" parameter"); } this.baseUrl = baseUrl; + this.miceUrl = miceUrl; this.email = email == null ? "" : email; this.password = password == null ? "" : password; @@ -71,6 +74,9 @@ public String toString() { + '\'' + ", baseUrl=" + baseUrl + + '\'' + + ", miceUrl=" + + miceUrl + '}'; } } diff --git a/src/test/java/com/fiskaly/sdk/FiskalyHttpClientTest.java b/src/test/java/com/fiskaly/sdk/FiskalyHttpClientTest.java index 67b2751..1b4cd45 100644 --- a/src/test/java/com/fiskaly/sdk/FiskalyHttpClientTest.java +++ b/src/test/java/com/fiskaly/sdk/FiskalyHttpClientTest.java @@ -19,7 +19,11 @@ public class FiskalyHttpClientTest { public FiskalyHttpClient createClient() throws IOException, URISyntaxException, FiskalyHttpTimeoutException, FiskalyClientException, FiskalyHttpException { - return new FiskalyHttpClient(API_KEY, API_SECRET, "https://kassensichv.io/api/v1"); + return new FiskalyHttpClient( + API_KEY, + API_SECRET, + "https://kassensichv.fiskaly.com/api/v2", + "https://kassensichv-middleware.fiskaly.com"); } @Test