Skip to content

Commit 0e789b3

Browse files
authored
Merge pull request #184 from CIRFMF/release/3.0.23
release 3.0.23
2 parents 093b5d3 + 7936c5f commit 0e789b3

9 files changed

Lines changed: 205 additions & 18 deletions

File tree

RELEASE_NOTES.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2012,7 +2012,7 @@
20122012
## 2. demo-web-app
20132013

20142014
### 2.1 integrationTest
2015-
- **QueryInvoiceIntegrationTest.java.java**: 🔧 dodanie testu z użyciem `onlyMetadata = true` w `InvoiceExportRequest`
2015+
- **QueryInvoiceIntegrationTest.java**: 🔧 dodanie testu z użyciem `onlyMetadata = true` w `InvoiceExportRequest`
20162016

20172017
---
20182018
## 3. Podsumowanie
@@ -2045,3 +2045,30 @@
20452045
| 🔧 zmienione | 2 |
20462046
| ➖ usunięte | 0 |
20472047

2048+
2049+
# Changelog zmian - `## 3.0.23 (2026-03-31)`- `API: 2.3.0`
2050+
2051+
## 1. ksef-client
2052+
2053+
### 1.1 api.client.model
2054+
- **permission/search/QueryPersonalGrantContextIdentifier.java**: 🔧 dodanie enuma `INTERNAL_ID("InternalId")`
2055+
2056+
## 2. demo-web-app
2057+
2058+
### 2.1 integrationTest
2059+
- **BaseIntegrationTest.java**: 🔧 poprawka w `authAsInternalId` przy generowaniu certyfikatu dla nipu i/lub peselu
2060+
- **PersonPermissionIntegrationTest.java**: 🔧 dodanie testu z filtrowaniem po InternalId
2061+
- **SearchInvoiceForSubject3IntegrationTest.java**: 🔧 aktualizacja po zmianie szablonu xml faktury `invoice-template-fa-3-with-custom-subject_3.xml`
2062+
- **SubUnitPermissionIntegrationTest.java**: 🔧 aktualizacja po zmianie szablonu xml faktury `invoice-template-fa-3-with-custom-subject_3.xml`
2063+
2064+
### 2.1.1 integrationTest.resources
2065+
- **xml/invoices/sample/invoice-template-fa-3-with-custom-subject_3.xml**: 🔧 dodanie placeholderów dla podmiotu 2 i podmiotu 3
2066+
2067+
---
2068+
## 3. Podsumowanie
2069+
2070+
| Typ zmiany | Liczba plików |
2071+
|-------------|---------------|
2072+
| ➕ dodane | 0 |
2073+
| 🔧 zmienione | 6 |
2074+
| ➖ usunięte | 0 |

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.22"
11+
version = "3.0.23"
1212

1313
java {
1414
toolchain {

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

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,18 @@
66
import org.junit.jupiter.params.ParameterizedTest;
77
import org.junit.jupiter.params.provider.Arguments;
88
import org.junit.jupiter.params.provider.MethodSource;
9+
import pl.akmf.ksef.sdk.api.builders.permission.entity.GrantEntityPermissionsRequestBuilder;
910
import pl.akmf.ksef.sdk.api.builders.permission.person.GrantPersonPermissionsRequestBuilder;
1011
import pl.akmf.ksef.sdk.api.builders.permission.person.PersonPermissionsQueryRequestBuilder;
1112
import pl.akmf.ksef.sdk.api.builders.permission.proxy.GrantAuthorizationPermissionsRequestBuilder;
13+
import pl.akmf.ksef.sdk.api.builders.permission.subunit.SubunitPermissionsGrantRequestBuilder;
1214
import pl.akmf.ksef.sdk.client.model.ApiException;
1315
import pl.akmf.ksef.sdk.client.model.certificate.SelfSignedCertificate;
1416
import pl.akmf.ksef.sdk.client.model.permission.OperationResponse;
1517
import pl.akmf.ksef.sdk.client.model.permission.PermissionStatusInfo;
18+
import pl.akmf.ksef.sdk.client.model.permission.entity.EntityPermission;
19+
import pl.akmf.ksef.sdk.client.model.permission.entity.EntityPermissionType;
20+
import pl.akmf.ksef.sdk.client.model.permission.entity.GrantEntityPermissionsRequest;
1621
import pl.akmf.ksef.sdk.client.model.permission.person.GrantPersonPermissionsRequest;
1722
import pl.akmf.ksef.sdk.client.model.permission.person.PersonPermissionPersonByFingerprintWithId;
1823
import pl.akmf.ksef.sdk.client.model.permission.person.PersonPermissionPersonById;
@@ -35,9 +40,17 @@
3540
import pl.akmf.ksef.sdk.client.model.permission.search.QueryPersonalGrantRequest;
3641
import pl.akmf.ksef.sdk.client.model.permission.search.QueryPersonalGrantResponse;
3742
import pl.akmf.ksef.sdk.client.model.permission.search.QueryPersonalGrantTargetIdentifier;
43+
import pl.akmf.ksef.sdk.client.model.permission.search.QueryPersonalPermissionTypes;
44+
import pl.akmf.ksef.sdk.client.model.permission.subunit.ContextIdentifier;
45+
import pl.akmf.ksef.sdk.client.model.permission.subunit.PermissionsSubunitPersonByIdentifier;
46+
import pl.akmf.ksef.sdk.client.model.permission.subunit.PermissionsSubunitSubjectDetailsType;
47+
import pl.akmf.ksef.sdk.client.model.permission.subunit.SubunitPermissionsGrantRequest;
48+
import pl.akmf.ksef.sdk.client.model.permission.subunit.SubunitSubjectDetails;
3849
import pl.akmf.ksef.sdk.client.model.testdata.SubjectTypeTestData;
50+
import pl.akmf.ksef.sdk.client.model.testdata.Subunit;
3951
import pl.akmf.ksef.sdk.client.model.testdata.TestDataPersonCreateRequest;
4052
import pl.akmf.ksef.sdk.client.model.testdata.TestDataSubjectCreateRequest;
53+
import pl.akmf.ksef.sdk.client.model.testdata.TestDataSubjectRemoveRequest;
4154
import pl.akmf.ksef.sdk.configuration.BaseIntegrationTest;
4255
import pl.akmf.ksef.sdk.util.IdentifierGeneratorUtils;
4356

@@ -420,6 +433,107 @@ void searchGrantedAsOwnerNipFilterByAuthorizedPeselShouldReturnMatch() throws JA
420433
);
421434
}
422435

436+
437+
// Scenariusz E2E weryfikujący:
438+
// - poprawkę w API zwracającą w liście uprawnień (POST /v2/permissions/query/personal/grants)
439+
// również uprawnienia podmiotowe InvoiceRead/InvoiceWrite nadane z canDelegate=false,
440+
// - filtrowanie wyników po InternalId,
441+
// - dopuszczalną długość identyfikatora InternalId (16 znaków).
442+
//
443+
// Kroki:
444+
// 1. Utworzenie podmiotu głównego (VatGroup) z jednostką podrzędną
445+
// 2. Nadanie dyrektorowi (PESEL) uprawnień administracyjnych do jednostki podrzędnej w kontekście InternalId
446+
// 3. Uwierzytelnienie dyrektora w kontekście InternalId
447+
// 4. Nadanie dyrektorowi uprawnień osobistych InvoiceRead/InvoiceWrite w kontekście InternalId
448+
// 5. Nadanie w tym samym kontekście uprawnień podmiotowych InvoiceRead/InvoiceWrite z canDelegate=false
449+
// 6. Weryfikacja listy uprawnień bez filtra (powinny zawierać InvoiceRead/InvoiceWrite z CanDelegate=false)
450+
// 7. Weryfikacja listy uprawnień z filtrem InternalId (powinny zawierać InvoiceRead/InvoiceWrite z CanDelegate=false)
451+
// 8. Sprzątanie danych testowych
452+
@Test
453+
void personalPermissionsWithInternalIdFilterShouldReturnPermissions() throws ApiException, JAXBException, IOException {
454+
// Przygotowanie danych
455+
String municipalOfficeNip = IdentifierGeneratorUtils.generateRandomNIP();
456+
String subunitNip = IdentifierGeneratorUtils.generateRandomNIP();
457+
String kindergartenId = IdentifierGeneratorUtils.generateInternalIdentifier(municipalOfficeNip);
458+
String directorPesel = IdentifierGeneratorUtils.getRandomPesel();
459+
460+
// Weryfikacja kontraktu: InternalId ma długość 16
461+
Assertions.assertEquals(16, kindergartenId.length());
462+
463+
// Utworzenie podmiotu głównego z jednostką podrzędną
464+
createVatGroupWithSubunit(municipalOfficeNip, subunitNip, "Przedszkole testowe", "Gmina testowa");
465+
466+
// 1) Uwierzytelnienie jako podmiot główny (właściciel kontekstu)
467+
String municipalOfficeAuthToken = authWithCustomNip(municipalOfficeNip, municipalOfficeNip).accessToken();
468+
469+
// 2) Nadanie dyrektorowi uprawnień administracyjnych do jednostki podrzędnej w kontekście InternalId
470+
String operationGrantNumber = grantPermissionSubunit(directorPesel, kindergartenId, "Przedszkole Testowe", "Sub-unit permission grant", municipalOfficeAuthToken);
471+
472+
await().pollDelay(Duration.ZERO)
473+
.atMost(15, SECONDS)
474+
.pollInterval(1, SECONDS)
475+
.until(() -> isOperationFinish(operationGrantNumber, municipalOfficeAuthToken));
476+
477+
// 3) Uwierzytelnienie dyrektora w kontekście InternalId
478+
String kindergartenAuthToken = authAsInternalId(kindergartenId, directorPesel).accessToken();
479+
480+
// 4) Nadanie uprawnień osobistych InvoiceRead/InvoiceWrite w kontekście InternalId
481+
String grantPersonReferenceNumber = grantPersonPermission(directorPesel, "Nadanie InvoiceRead i InvoiceWrite dyrektorowi w kontekście InternalId", kindergartenAuthToken);
482+
483+
await().pollDelay(Duration.ZERO)
484+
.atMost(15, SECONDS)
485+
.pollInterval(1, SECONDS)
486+
.until(() -> isOperationFinish(grantPersonReferenceNumber, kindergartenAuthToken));
487+
488+
// 5) Nadanie uprawnień podmiotowych (entity) InvoiceRead/InvoiceWrite z canDelegate=false
489+
String grantEntityReferenceNumber = grantPermissionEntity(municipalOfficeNip,
490+
"Uprawnienia podmiotowe InvoiceRead/InvoiceWrite bez delegowania",
491+
"Podmiot " + municipalOfficeNip,
492+
kindergartenAuthToken);
493+
494+
await().pollDelay(Duration.ZERO)
495+
.atMost(30, SECONDS)
496+
.pollInterval(2, SECONDS)
497+
.until(() -> isOperationFinish(grantEntityReferenceNumber, kindergartenAuthToken));
498+
499+
// 6) Weryfikacja listy uprawnień bez filtra
500+
QueryPersonalGrantRequest queryWithoutFilter = new QueryPersonalGrantRequest();
501+
QueryPersonalGrantResponse personalPermissions = ksefClient.searchPersonalGrantPermission(queryWithoutFilter, 0, 50, kindergartenAuthToken);
502+
503+
// Uprawnienia InvoiceRead/InvoiceWrite powinny być zwrócone również wtedy, gdy canDelegate=false
504+
Assertions.assertTrue(personalPermissions.getPermissions().stream()
505+
.anyMatch(p -> QueryPersonalPermissionTypes.INVOICE_READ.equals(p.getPermissionScope()) && p.getCanDelegate() == false)
506+
);
507+
Assertions.assertTrue(personalPermissions.getPermissions().stream()
508+
.anyMatch(p -> QueryPersonalPermissionTypes.INVOICE_WRITE.equals(p.getPermissionScope()) && p.getCanDelegate() == false)
509+
);
510+
511+
// 7) Weryfikacja listy uprawnień z filtrem ContextIdentifier=InternalId
512+
QueryPersonalGrantRequest request = new QueryPersonalGrantRequest();
513+
request.setContextIdentifier(new QueryPersonalGrantContextIdentifier(QueryPersonalGrantContextIdentifier.IdentifierType.INTERNAL_ID, kindergartenId));
514+
QueryPersonalGrantResponse permissionsWithInternalIdFilter = ksefClient.searchPersonalGrantPermission(request, 0, 50, kindergartenAuthToken);
515+
516+
Assertions.assertTrue(permissionsWithInternalIdFilter.getPermissions().stream()
517+
.anyMatch(p -> QueryPersonalPermissionTypes.INVOICE_READ.equals(p.getPermissionScope()) && p.getCanDelegate() == false)
518+
);
519+
Assertions.assertTrue(permissionsWithInternalIdFilter.getPermissions().stream()
520+
.anyMatch(p -> QueryPersonalPermissionTypes.INVOICE_WRITE.equals(p.getPermissionScope()) && p.getCanDelegate() == false)
521+
);
522+
523+
// 8) Sprzątanie danych testowych
524+
ksefClient.removeTestSubject(new TestDataSubjectRemoveRequest(municipalOfficeNip));
525+
}
526+
527+
private void createVatGroupWithSubunit(String vatGroupNip, String subunitNip, String subunitDescription, String description) throws ApiException {
528+
TestDataSubjectCreateRequest request = new TestDataSubjectCreateRequest();
529+
request.setSubjectNip(vatGroupNip);
530+
request.setSubjectType(SubjectTypeTestData.VAT_GROUP);
531+
request.setSubunits(List.of(new Subunit(subunitNip, subunitDescription)));
532+
request.setDescription(description);
533+
534+
ksefClient.createTestSubject(request);
535+
}
536+
423537
private void createEnforcementSubject(String nip, String description) throws ApiException {
424538
TestDataSubjectCreateRequest request = new TestDataSubjectCreateRequest();
425539
request.setSubjectNip(nip);
@@ -537,4 +651,46 @@ private Boolean isOperationFinish(String referenceNumber, String accessToken) th
537651
PermissionStatusInfo operations = ksefClient.permissionOperationStatus(referenceNumber, accessToken);
538652
return operations != null && operations.getStatus().getCode() == 200;
539653
}
654+
655+
private String grantPermissionSubunit(String pesel, String contextIdentifierValue, String subunitName, String subunitDescription, String accessToken) throws ApiException {
656+
SubunitPermissionsGrantRequest request = new SubunitPermissionsGrantRequestBuilder()
657+
.withSubjectIdentifier(new pl.akmf.ksef.sdk.client.model.permission.subunit.SubjectIdentifier(pl.akmf.ksef.sdk.client.model.permission.subunit.SubjectIdentifier.IdentifierType.PESEL, pesel))
658+
.withContextIdentifier(new ContextIdentifier(ContextIdentifier.IdentifierType.INTERNALID, contextIdentifierValue))
659+
.withDescription(subunitDescription)
660+
.withSubunitName(subunitName)
661+
.withSubjectDetails(
662+
new SubunitSubjectDetails(PermissionsSubunitSubjectDetailsType.PersonByIdentifier,
663+
new PermissionsSubunitPersonByIdentifier("Jan", "Kowalski"),
664+
null,
665+
null
666+
)
667+
)
668+
.build();
669+
670+
return grantPermissionSubunit(request, accessToken);
671+
}
672+
673+
private String grantPermissionSubunit(SubunitPermissionsGrantRequest request, String accessToken) throws ApiException {
674+
OperationResponse response = ksefClient.grantsPermissionSubUnit(request, accessToken);
675+
Assertions.assertNotNull(response);
676+
return response.getReferenceNumber();
677+
}
678+
679+
private String grantPermissionEntity(String targetNip, String description, String subjectDetailsFullName, String accessToken) throws ApiException {
680+
GrantEntityPermissionsRequest request = new GrantEntityPermissionsRequestBuilder()
681+
.withPermissions(List.of(
682+
new EntityPermission(EntityPermissionType.INVOICE_READ, false),
683+
new EntityPermission(EntityPermissionType.INVOICE_WRITE, false)))
684+
.withDescription(description)
685+
.withSubjectIdentifier(new pl.akmf.ksef.sdk.client.model.permission.entity.SubjectIdentifier(pl.akmf.ksef.sdk.client.model.permission.entity.SubjectIdentifier.IdentifierType.NIP, targetNip))
686+
.withSubjectDetails(
687+
new GrantEntityPermissionsRequest.PermissionsEntitySubjectDetails(subjectDetailsFullName)
688+
)
689+
.build();
690+
691+
OperationResponse response = ksefClient.grantsPermissionEntity(request, accessToken);
692+
Assertions.assertNotNull(response);
693+
694+
return response.getReferenceNumber();
695+
}
540696
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ void queryInvoiceE2EForSubject3Test() throws JAXBException, IOException, ApiExce
5959
//open Session as company && send invoice
6060
String sessionReferenceNumber = openOnlineSession(encryptionData, SystemCode.FA_3, SchemaVersion.VERSION_1_0E, SessionValue.FA, companyAccessToken);
6161

62-
String invoiceReferenceNumber = sendInvoiceOnlineSession(contextNip, recipientNip, sessionReferenceNumber,
62+
String invoiceReferenceNumber = sendInvoiceOnlineSession(contextNip, recipientNip, recipientNip, sessionReferenceNumber,
6363
encryptionData, "/xml/invoices/sample/invoice-template-fa-3-with-custom-subject_3.xml", companyAccessToken);
6464

6565
//check if invoice has been processed correctly
@@ -131,11 +131,12 @@ private String openOnlineSession(EncryptionData encryptionData, SystemCode syste
131131
return openOnlineSessionResponse.getReferenceNumber();
132132
}
133133

134-
private String sendInvoiceOnlineSession(String nip, String recipientNip, String sessionReferenceNumber,
134+
private String sendInvoiceOnlineSession(String nip, String recipientNip, String thirdSubject, String sessionReferenceNumber,
135135
EncryptionData encryptionData, String path, String accessToken) throws IOException, ApiException {
136136
String invoiceTemplate = new String(readBytesFromPath(path), StandardCharsets.UTF_8)
137137
.replace("#nip#", nip)
138-
.replace("#subject3nip#", recipientNip)
138+
.replace("#subject2nip#", recipientNip)
139+
.replace("#subject3IdentifierValue#", thirdSubject.length() == 10 ? (("<NIP>" + thirdSubject + "</NIP>")) : ("<IDWew>" + thirdSubject + "</IDWew>"))
139140
.replace("#invoicing_date#",
140141
LocalDate.of(2025, 9, 15).format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")))
141142
.replace("#invoice_number#", UUID.randomUUID().toString());

0 commit comments

Comments
 (0)