Skip to content

Commit 31ebec0

Browse files
committed
release 3.0.20
1 parent 2231b74 commit 31ebec0

22 files changed

Lines changed: 593 additions & 71 deletions

RELEASE_NOTES.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1951,3 +1951,53 @@
19511951
| 🔧 zmienione | 32 |
19521952
| ➖ usunięte | 0 |
19531953

1954+
1955+
# Changelog zmian - `## 3.0.20 (2026-03-17)`- `API: 2.2.1`
1956+
1957+
## 1. ksef-client
1958+
1959+
### 1.1 system
1960+
- **FilesUtil.java**: 🔧 dla metody `splitAndEncryptZipStream` zmiana parametru `cryptographyService` na interfejs
1961+
1962+
### 1.2 api
1963+
- **DefaultKsefClient.java**: 🔧 do response z błędem dodano informacje z url i method, dodanie obsługi mapowań dla kodów http 401 i 403 dla formatu Problem Details `(application/problem+json)`
1964+
- **DefaultLighthouseKsefClient.java**: 🔧 do response z błędem dodano informacje z url i method
1965+
1966+
### 1.3 client
1967+
- **Headers.java**: 🔧 dodanie pola `String APPLICATION_PROBLEM_JSON = "application/problem+json"`
1968+
1969+
### 1.4 api.services
1970+
- **DefaultCryptographyService.java**: 🔧 dodanie metody `Exception getOfflineModeCause()` dającej informacje o powodzie przejścia w tryb offline
1971+
1972+
### 1.5 api.client.interfaces
1973+
- **CryptographyService.java**: 🔧 zmiany zgodnie z implementacja w `DefaultCryptographyService.java`
1974+
1975+
### 1.6 api.client.model
1976+
- **ApiException.java**: 🔧 dodanie pól `String url` i `String method`, zmiana na klasę abstrakcyjną
1977+
- **model/session/SchemaVersion.java**: 🔧 dodanie enuma `VERSION_1_1E("1-1E")`
1978+
- **UnauthorizedProblemDetails.java**: ➕ dodanie klasy
1979+
- **ForbiddenProblemDetails.java**: ➕ dodanie klasy
1980+
- **UnauthorizedApiException.java**: ➕ dodanie klasy, rozszerzającej `ApiException`
1981+
- **ForbiddenApiException.java**: ➕ dodanie klasy, rozszerzającej `ApiException`
1982+
- **KsefApiException.java**: ➕ dodanie klasy, rozszerzającej `ApiException`
1983+
1984+
## 2. demo-web-app
1985+
1986+
### 2.1 integrationTest
1987+
- **QrCodeOnlineIntegrationTest.java.java**: 🔧 drobne zmiany w asercji
1988+
- **RrInvoiceIntegrationTest.java.java**: 🔧 użycie nowej wersji schemy RR `SchemaVersion.VERSION_1_1E`
1989+
- **KsefTokenIntegrationTest.java.java**: 🔧 zmiany kosmetyczne w assercji
1990+
- **ExceptionsApiIntegrationTest.java.java**: ➕ dodanie scenariusza do obsługi kodów http 401 i 403 z API
1991+
1992+
### 2.1.1 integrationTest.resources
1993+
- **invoice-template-fa-rr-1.xml**: 🔧 aktualizacja pod nową wersję schemy RR
1994+
1995+
---
1996+
## 3. Podsumowanie
1997+
1998+
| Typ zmiany | Liczba plików |
1999+
|-------------|---------------|
2000+
| ➕ dodane | 6 |
2001+
| 🔧 zmienione | 12 |
2002+
| ➖ usunięte | 0 |
2003+

demo-web-app/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ plugins {
88
}
99

1010
group = "pl.akmf.ksef"
11-
version = "3.0.19"
11+
version = "3.0.20"
1212

1313
java {
1414
toolchain {
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package pl.akmf.ksef.sdk;
2+
3+
import jakarta.xml.bind.JAXBException;
4+
import org.junit.jupiter.api.Assertions;
5+
import org.junit.jupiter.api.Test;
6+
import pl.akmf.ksef.sdk.api.builders.permission.entity.GrantEntityPermissionsRequestBuilder;
7+
import pl.akmf.ksef.sdk.client.model.ApiException;
8+
import pl.akmf.ksef.sdk.client.model.ForbiddenApiException;
9+
import pl.akmf.ksef.sdk.client.model.ForbiddenProblemDetails;
10+
import pl.akmf.ksef.sdk.client.model.UnauthorizedApiException;
11+
import pl.akmf.ksef.sdk.client.model.UnauthorizedProblemDetails;
12+
import pl.akmf.ksef.sdk.client.model.permission.OperationResponse;
13+
import pl.akmf.ksef.sdk.client.model.permission.PermissionStatusInfo;
14+
import pl.akmf.ksef.sdk.client.model.permission.entity.EntityPermission;
15+
import pl.akmf.ksef.sdk.client.model.permission.entity.EntityPermissionType;
16+
import pl.akmf.ksef.sdk.client.model.permission.entity.GrantEntityPermissionsRequest;
17+
import pl.akmf.ksef.sdk.client.model.permission.entity.SubjectIdentifier;
18+
import pl.akmf.ksef.sdk.configuration.BaseIntegrationTest;
19+
import pl.akmf.ksef.sdk.util.IdentifierGeneratorUtils;
20+
21+
import java.io.IOException;
22+
import java.time.Duration;
23+
import java.util.List;
24+
import java.util.Map;
25+
26+
import static java.util.concurrent.TimeUnit.SECONDS;
27+
import static org.awaitility.Awaitility.await;
28+
import static org.junit.jupiter.api.Assertions.assertThrows;
29+
import static pl.akmf.ksef.sdk.api.Url.GRANT_INVOICE_SUBJECT_PERMISSION;
30+
31+
class ExceptionsApiIntegrationTest extends BaseIntegrationTest {
32+
33+
@Test
34+
void forbiddenTest() throws JAXBException, IOException, ApiException {
35+
String contextNip = IdentifierGeneratorUtils.generateRandomNIP();
36+
String subjectNip = IdentifierGeneratorUtils.generateRandomNIP();
37+
String thirdNip = IdentifierGeneratorUtils.generateRandomNIP();
38+
String accessToken = authWithCustomNip(contextNip, contextNip).accessToken();
39+
40+
String grantReferenceNumber = grantPermission(subjectNip, accessToken);
41+
42+
await().pollDelay(Duration.ZERO)
43+
.atMost(30, SECONDS)
44+
.pollInterval(2, SECONDS)
45+
.until(() -> isOperationFinish(grantReferenceNumber, accessToken));
46+
47+
String accessTokenSubject = authWithCustomNip(contextNip, subjectNip).accessToken();
48+
49+
ApiException apiException = assertThrows(ApiException.class, () ->
50+
grantPermission(thirdNip, accessTokenSubject));
51+
Assertions.assertEquals(403, apiException.getCode());
52+
Assertions.assertEquals("POST", apiException.getMethod());
53+
Assertions.assertTrue(apiException.getUrl().contains(GRANT_INVOICE_SUBJECT_PERMISSION.getUrl()));
54+
ForbiddenApiException forbiddenApiException = (ForbiddenApiException) apiException;
55+
Assertions.assertNotNull(forbiddenApiException);
56+
ForbiddenProblemDetails forbiddenProblemDetails = forbiddenApiException.getForbiddenProblemDetails();
57+
Assertions.assertNotNull(forbiddenProblemDetails);
58+
Assertions.assertEquals("Forbidden", forbiddenProblemDetails.getTitle());
59+
Assertions.assertEquals(403, forbiddenProblemDetails.getStatus());
60+
Assertions.assertEquals("missing-permissions", forbiddenProblemDetails.getReasonCode());
61+
Assertions.assertEquals("Brak wymaganych uprawnień do wykonania operacji w bieżącym kontekście.", forbiddenProblemDetails.getDetail());
62+
Assertions.assertNotNull(forbiddenProblemDetails.getInstance());
63+
Assertions.assertNotNull(forbiddenProblemDetails.getTraceId());
64+
Map<String, Object> security = forbiddenProblemDetails.getSecurity();
65+
Assertions.assertNotNull(security);
66+
Assertions.assertTrue(security.get("requiredAnyOfPermissions").toString().contains("CredentialsManage"));
67+
Assertions.assertTrue(security.get("presentPermissions").toString().contains("InvoiceRead"));
68+
Assertions.assertTrue(security.get("presentPermissions").toString().contains("InvoiceWrite"));
69+
}
70+
71+
@Test
72+
void unauthorizedTest() {
73+
String subjectNip = IdentifierGeneratorUtils.generateRandomNIP();
74+
75+
ApiException apiException = assertThrows(ApiException.class, () ->
76+
grantPermission(subjectNip, "invalidToken"));
77+
Assertions.assertEquals(401, apiException.getCode());
78+
Assertions.assertEquals("POST", apiException.getMethod());
79+
Assertions.assertTrue(apiException.getUrl().contains(GRANT_INVOICE_SUBJECT_PERMISSION.getUrl()));
80+
UnauthorizedApiException unauthorizedApiException = (UnauthorizedApiException) apiException;
81+
Assertions.assertNotNull(unauthorizedApiException);
82+
UnauthorizedProblemDetails unauthorizedProblemDetails = unauthorizedApiException.getUnauthorizedProblemDetails();
83+
Assertions.assertNotNull(unauthorizedProblemDetails);
84+
Assertions.assertEquals("Unauthorized", unauthorizedProblemDetails.getTitle());
85+
Assertions.assertEquals(401, unauthorizedProblemDetails.getStatus());
86+
Assertions.assertEquals("Wymagane jest uwierzytelnienie.", unauthorizedProblemDetails.getDetail());
87+
Assertions.assertNotNull(unauthorizedProblemDetails.getInstance());
88+
Assertions.assertNotNull(unauthorizedProblemDetails.getTraceId());
89+
}
90+
91+
private Boolean isOperationFinish(String referenceNumber, String accessToken) throws ApiException {
92+
PermissionStatusInfo operations = ksefClient.permissionOperationStatus(referenceNumber, accessToken);
93+
return operations != null && operations.getStatus().getCode() == 200;
94+
}
95+
96+
private String grantPermission(String targetNip, String accessToken) throws ApiException {
97+
GrantEntityPermissionsRequest request = new GrantEntityPermissionsRequestBuilder()
98+
.withPermissions(List.of(
99+
new EntityPermission(EntityPermissionType.INVOICE_READ, true),
100+
new EntityPermission(EntityPermissionType.INVOICE_WRITE, false)))
101+
.withDescription("description")
102+
.withSubjectIdentifier(new SubjectIdentifier(SubjectIdentifier.IdentifierType.NIP, targetNip))
103+
.withSubjectDetails(
104+
new GrantEntityPermissionsRequest.PermissionsEntitySubjectDetails("Testowo")
105+
)
106+
.build();
107+
108+
OperationResponse response = ksefClient.grantsPermissionEntity(request, accessToken);
109+
Assertions.assertNotNull(response);
110+
111+
return response.getReferenceNumber();
112+
}
113+
}

demo-web-app/src/integrationTest/java/pl/akmf/ksef/sdk/KsefTokenIntegrationTest.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,13 @@ void checkGenerateTokenTest() throws IOException, ApiException, JAXBException {
6565
Assertions.assertNotNull(token.getToken());
6666
Assertions.assertNotNull(token.getReferenceNumber());
6767

68-
// step 2: wait for token to become ACTIVE
68+
// step 2: wait for tokens to become ACTIVE
6969
Awaitility.await().pollDelay(Duration.ZERO)
7070
.atMost(10, SECONDS)
7171
.pollInterval(1, SECONDS)
72-
.until(() -> {
73-
AuthenticationToken ksefToken = ksefClient.getKsefToken(token.getReferenceNumber(), accessToken);
74-
return ksefToken != null && ksefToken.getStatus() == AuthenticationTokenStatus.ACTIVE;
75-
});
72+
.until(() -> isActiveToken(token, accessToken)
73+
&& isActiveToken(token2, accessToken)
74+
&& isActiveToken(token3, accessToken));
7675

7776
AuthenticationToken ksefToken = ksefClient.getKsefToken(token.getReferenceNumber(), accessToken);
7877
Assertions.assertNotNull(ksefToken);
@@ -150,4 +149,9 @@ private Boolean isAuthStatusReady(String referenceNumber, String tempToken) thro
150149
AuthStatus authStatus = ksefClient.getAuthStatus(referenceNumber, tempToken);
151150
return authStatus != null && authStatus.getStatus().getCode() == 200;
152151
}
152+
153+
private Boolean isActiveToken(GenerateTokenResponse token, String accessToken) throws ApiException {
154+
AuthenticationToken ksefToken = ksefClient.getKsefToken(token.getReferenceNumber(), accessToken);
155+
return ksefToken != null && ksefToken.getStatus() == AuthenticationTokenStatus.ACTIVE;
156+
}
153157
}

demo-web-app/src/integrationTest/java/pl/akmf/ksef/sdk/QrCodeOnlineIntegrationTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public void qrCodeOnlineE2ETest() throws JAXBException, IOException, ApiExceptio
7878
.pollInterval(2, SECONDS)
7979
.until(() -> isInvoicesInSessionAdded(sessionReferenceNumber, accessToken));
8080

81-
checkOnlineSessionStatus(sessionReferenceNumber, 100, accessToken);
81+
Assertions.assertTrue(checkOnlineSessionStatus(sessionReferenceNumber, 100, accessToken));
8282

8383
//Zamknięcie sesji online
8484
closeOnlineSession(sessionReferenceNumber, accessToken);
@@ -186,8 +186,7 @@ private boolean isInvoicesInSessionAdded(String sessionReferenceNumber, String a
186186
private boolean checkOnlineSessionStatus(String sessionReferenceNumber, int expectedSessionStatus, String accessToken) throws ApiException {
187187
SessionStatusResponse statusResponse = getSessionStatusResponse(sessionReferenceNumber, accessToken);
188188
Assertions.assertNotNull(statusResponse);
189-
Assertions.assertEquals(expectedSessionStatus, (int) statusResponse.getStatus().getCode());
190-
return true;
189+
return expectedSessionStatus == statusResponse.getStatus().getCode();
191190
}
192191

193192
private SessionStatusResponse getSessionStatusResponse(String sessionReferenceNumber, String accessToken) throws ApiException {

demo-web-app/src/integrationTest/java/pl/akmf/ksef/sdk/RrInvoiceIntegrationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ void sendingFaRrInvoiceWithGrantPermission() throws JAXBException, IOException,
105105
encryptionData = defaultCryptographyService.getEncryptionData();
106106

107107
// Otwarcie sesji online z kodem systemu FA_RR
108-
String sessionReferenceNumber = openOnlineSession(encryptionData, SystemCode.FA_RR, SchemaVersion.VERSION_1_0E, SessionValue.RR, authorizedAccessToken);
108+
String sessionReferenceNumber = openOnlineSession(encryptionData, SystemCode.FA_RR, SchemaVersion.VERSION_1_1E, SessionValue.RR, authorizedAccessToken);
109109

110110
// Wysłanie faktury FA-RR
111111
sendRrInvoice(sessionReferenceNumber, encryptionData, grantorNip, authorizedNip, templateFileName, authorizedAccessToken);

demo-web-app/src/integrationTest/resources/xml/invoices/sample/invoice-template-fa-rr-1.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Faktura xmlns:etd="http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2022/01/05/eD/DefinicjeTypy/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3-
xmlns="http://crd.gov.pl/wzor/2026/02/17/14164/">
3+
xmlns="http://crd.gov.pl/wzor/2026/03/06/14189/">
44
<Naglowek>
5-
<KodFormularza kodSystemowy="FA_RR(1)" wersjaSchemy="1-0E">FA_RR</KodFormularza>
5+
<KodFormularza kodSystemowy="FA_RR (1)" wersjaSchemy="1-1E">FA_RR</KodFormularza>
66
<WariantFormularza>1</WariantFormularza>
77
<DataWytworzeniaFa>2026-02-23T10:37:00Z</DataWytworzeniaFa>
88
<SystemInfo>SamploFaktur</SystemInfo>

ksef-client/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44
}
55

66

7-
val appVersion = "3.0.19"
7+
val appVersion = "3.0.20"
88
val artifactName = "ksef-client"
99

1010
val githubRepositoryToken = "token"

0 commit comments

Comments
 (0)