http-get endpoints for partner, debitor and memberhip-number #135

Merged
9 changed files with 116 additions and 90 deletions
Showing only changes of commit 65f48160f8 - Show all commits

View File

@ -57,12 +57,15 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
final String currentSubject, final String currentSubject,
final String assumedRoles, final String assumedRoles,
final String name, final String name,
final UUID partnerUuid,
final String partnerNumber) { final String partnerNumber) {
context.define(currentSubject, assumedRoles); context.define(currentSubject, assumedRoles);
final var entities = partnerNumber != null final var entities = partnerNumber != null
? debitorRepo.findDebitorByPartnerNumber(cropTag("P-", partnerNumber)) ? debitorRepo.findDebitorsByPartnerNumber(cropTag("P-", partnerNumber))
: debitorRepo.findDebitorByOptionalNameLike(name); : partnerUuid != null
? debitorRepo.findDebitorsByPartnerUuid(partnerUuid)
: debitorRepo.findDebitorsByOptionalNameLike(name);
final var resources = mapper.mapList(entities, HsOfficeDebitorResource.class, ENTITY_TO_RESOURCE_POSTMAPPER); final var resources = mapper.mapList(entities, HsOfficeDebitorResource.class, ENTITY_TO_RESOURCE_POSTMAPPER);
return ResponseEntity.ok(resources); return ResponseEntity.ok(resources);

View File

@ -14,6 +14,9 @@ public interface HsOfficeDebitorRepository extends Repository<HsOfficeDebitorEnt
@Timed("app.office.debitors.repo.findByUuid") @Timed("app.office.debitors.repo.findByUuid")
Optional<HsOfficeDebitorEntity> findByUuid(UUID id); Optional<HsOfficeDebitorEntity> findByUuid(UUID id);
@Timed("app.office.debitors.repo.findDebitorByPartnerUuid")
List<HsOfficeDebitorEntity> findDebitorsByPartnerUuid(UUID partnerUuid);
@Query(""" @Query("""
SELECT debitor FROM HsOfficeDebitorEntity debitor SELECT debitor FROM HsOfficeDebitorEntity debitor
JOIN HsOfficePartnerEntity partner JOIN HsOfficePartnerEntity partner
@ -32,7 +35,7 @@ public interface HsOfficeDebitorRepository extends Repository<HsOfficeDebitorEnt
return result.stream().reduce(Reducer::toSingleElement); return result.stream().reduce(Reducer::toSingleElement);
} }
default List<HsOfficeDebitorEntity> findDebitorByPartnerNumber(int partnerNumber) { default List<HsOfficeDebitorEntity> findDebitorsByPartnerNumber(int partnerNumber) {
final var result = findDebitorByPartnerNumberAndOptionalDebitorNumberSuffix(partnerNumber, null); final var result = findDebitorByPartnerNumberAndOptionalDebitorNumberSuffix(partnerNumber, null);
return result; return result;
} }
@ -56,7 +59,7 @@ public interface HsOfficeDebitorRepository extends Repository<HsOfficeDebitorEnt
OR contact.caption like concat(cast(:name as text), '%') OR contact.caption like concat(cast(:name as text), '%')
""") """)
@Timed("app.office.debitors.repo.findDebitorByOptionalNameLike") @Timed("app.office.debitors.repo.findDebitorByOptionalNameLike")
List<HsOfficeDebitorEntity> findDebitorByOptionalNameLike(String name); List<HsOfficeDebitorEntity> findDebitorsByOptionalNameLike(String name);
@Timed("app.office.debitors.repo.save") @Timed("app.office.debitors.repo.save")
HsOfficeDebitorEntity save(final HsOfficeDebitorEntity entity); HsOfficeDebitorEntity save(final HsOfficeDebitorEntity entity);

View File

@ -12,8 +12,8 @@ get:
schema: schema:
type: number type: number
format: integer format: integer
minimum: 1000000 # minimum: 1000000
hsh-michaelhoennig marked this conversation as resolved Outdated

wieder rein

wieder rein
maximum: 9999999 # maximum: 9999999
description: debitor-number of the debitor to fetch. description: debitor-number of the debitor to fetch.
responses: responses:
"200": "200":

View File

@ -13,13 +13,20 @@ get:
schema: schema:
type: string type: string
description: Prefix of name properties from person or contact to filter the results. description: Prefix of name properties from person or contact to filter the results.
- name: partnerUuid
in: query
required: false
schema:
type: string
format: uuid
description: UUID of the business partner, exclusive to `memberNumber`.
- name: partnerNumber - name: partnerNumber
in: query in: query
required: false required: false
schema: schema:
type: string type: string
minLength: 9 minLength: 7
maxLength: 9 maxLength: 7
pattern: 'P-[0-9]{5}' pattern: 'P-[0-9]{5}'
description: Partner number of the requested debitor. description: Partner number of the requested debitor.
responses: responses:

View File

@ -120,7 +120,7 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var count = rbacBookingItemRepo.count(); final var count = rbacBookingItemRepo.count();
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0); final var givenDebitor = debitorRepo.findDebitorsByOptionalNameLike("First").get(0);
final var givenProject = realProjectRepo.findAllByDebitorUuid(givenDebitor.getUuid()).get(0); final var givenProject = realProjectRepo.findAllByDebitorUuid(givenDebitor.getUuid()).get(0);
// when // when
@ -151,7 +151,7 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
// when // when
attempt(em, () -> { attempt(em, () -> {
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0); final var givenDebitor = debitorRepo.findDebitorsByOptionalNameLike("First").get(0);
final var givenProject = realProjectRepo.findAllByDebitorUuid(givenDebitor.getUuid()).get(0); final var givenProject = realProjectRepo.findAllByDebitorUuid(givenDebitor.getUuid()).get(0);
final var newBookingItem = HsBookingItemRbacEntity.builder() final var newBookingItem = HsBookingItemRbacEntity.builder()
.project(givenProject) .project(givenProject)

View File

@ -31,7 +31,10 @@ import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.
import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.hsadminng.rbac.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.rbac.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
@ -74,6 +77,69 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
@PersistenceContext @PersistenceContext
EntityManager em; EntityManager em;
@Nested
class GetSingleDebitor {
@Test
void globalAdmin_withoutAssumedRoles_canGetDebitorByDebitorUuid() {
final var givenDebitor = jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net");
return debitorRepo.findDebitorByDebitorNumber(1000212).orElseThrow();
}).assertSuccessful().returnedValue();
RestAssured // @formatter:off
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.port(port)
.when()
.get("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid())
.then().log().all().assertThat()
.statusCode(200)
.contentType("application/json")
.body("", lenientlyEquals("""
{
"debitorNumber": "D-1000212",
"partner": { "partnerNumber": "P-10002" },
"debitorRel": {
"contact": { "caption": "second contact" }
},
"vatId": null,
"vatCountryCode": null,
"vatBusiness": true
}
"""));
// @formatter:on
}
@Test
void globalAdmin_withoutAssumedRoles_canGetDebitorByDebitorNumber() {
RestAssured // @formatter:off
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.port(port)
.when()
.get("http://localhost/api/hs/office/debitors/D-1000212")
.then().log().all().assertThat()
.statusCode(200)
.contentType("application/json")
.body("", lenientlyEquals("""
{
"debitorNumber": "D-1000212",
"partner": { "partnerNumber": "P-10002" },
"debitorRel": {
"contact": { "caption": "second contact" }
},
"vatId": null,
"vatCountryCode": null,
"vatBusiness": true
}
"""));
// @formatter:on
}
}
@Nested @Nested
class GetListOfDebitors { class GetListOfDebitors {
@ -232,80 +298,27 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
// @formatter:on // @formatter:on
} }
@Test
void globalAdmin_withoutAssumedRoles_canGetDebitorByDebitorNumber() {
RestAssured // @formatter:off
.given()
.header("current-subject", "superuser-alex@hostsharing.net")
.port(port)
.when()
.get("http://localhost/api/hs/office/debitors/P-10002")
.then().log().all().assertThat()
.statusCode(200)
.contentType("application/json")
.body("", lenientlyEquals("""
[
{
"debitorNumber": "D-1000211",
"partner": { "partnerNumber": "P-10002" },
"debitorRel": {
"contact": { "caption": "second contact" }
},
"vatId": null,
"vatCountryCode": null,
"vatBusiness": true
},
{
"debitorNumber": "D-1000212",
"partner": { "partnerNumber": "P-10002" },
"debitorRel": {
"contact": { "caption": "second contact" }
},
"vatId": null,
"vatCountryCode": null,
"vatBusiness": true
},
{
"debitorNumber": "D-1000213",
"partner": { "partnerNumber": "P-10002" },
"debitorRel": {
"contact": { "caption": "second contact" }
},
"vatId": null,
"vatCountryCode": null,
"vatBusiness": true
}
]
"""));
// @formatter:on
}
@Test @Test
void globalAdmin_withoutAssumedRoles_canFindDebitorsByPartnerNumber() { void globalAdmin_withoutAssumedRoles_canFindDebitorsByPartnerNumber() {
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("current-subject", "superuser-alex@hostsharing.net") .header("current-subject", "superuser-alex@hostsharing.net")
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/debitors?debitorNumber=D-1000212") .get("http://localhost/api/hs/office/debitors?partnerNumber=P-10002")
.then().log().all().assertThat() .then().log().all().assertThat()
.statusCode(200) .statusCode(200)
.contentType("application/json") .contentType("application/json")
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
[ [
{ {
"debitorNumber": "D-1000212", "debitorNumber": "D-1000212",
"partner": { "partnerNumber": "P-10002" }, "partner": {
"debitorRel": { "partnerNumber": "P-10002"
"contact": { "caption": "second contact" } }
}, }
"vatId": null, ]
"vatCountryCode": null,
"vatBusiness": true
}
]
""")); """));
// @formatter:on // @formatter:on
} }
@ -493,7 +506,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
@Test @Test
void globalAdmin_withoutAssumedRole_canGetArbitraryDebitor() { void globalAdmin_withoutAssumedRole_canGetArbitraryDebitor() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenDebitorUuid = debitorRepo.findDebitorByOptionalNameLike("First").get(0).getUuid(); final var givenDebitorUuid = debitorRepo.findDebitorsByOptionalNameLike("First").get(0).getUuid();
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
@ -558,7 +571,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
@Test @Test
void normalUser_canNotGetUnrelatedDebitor() { void normalUser_canNotGetUnrelatedDebitor() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenDebitorUuid = debitorRepo.findDebitorByOptionalNameLike("First").get(0).getUuid(); final var givenDebitorUuid = debitorRepo.findDebitorsByOptionalNameLike("First").get(0).getUuid();
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
@ -573,7 +586,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
@Test @Test
void contactAdminUser_canGetRelatedDebitorExceptRefundBankAccount() { void contactAdminUser_canGetRelatedDebitorExceptRefundBankAccount() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenDebitorUuid = debitorRepo.findDebitorByOptionalNameLike("first contact").get(0).getUuid(); final var givenDebitorUuid = debitorRepo.findDebitorsByOptionalNameLike("first contact").get(0).getUuid();
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()

View File

@ -234,7 +234,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
// when // when
final var result = debitorRepo.findDebitorByOptionalNameLike(null); final var result = debitorRepo.findDebitorsByOptionalNameLike(null);
// then // then
allTheseDebitorsAreReturned( allTheseDebitorsAreReturned(
@ -256,7 +256,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
context("superuser-alex@hostsharing.net", assumedRole); context("superuser-alex@hostsharing.net", assumedRole);
// when: // when:
final var result = debitorRepo.findDebitorByOptionalNameLike(""); final var result = debitorRepo.findDebitorsByOptionalNameLike("");
// then: // then:
exactlyTheseDebitorsAreReturned(result, exactlyTheseDebitorsAreReturned(result,
@ -270,7 +270,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
context("selfregistered-test-user@hostsharing.org"); context("selfregistered-test-user@hostsharing.org");
// when: // when:
final var result = debitorRepo.findDebitorByOptionalNameLike(null); final var result = debitorRepo.findDebitorsByOptionalNameLike(null);
// then: // then:
assertThat(result).isEmpty(); assertThat(result).isEmpty();
@ -303,7 +303,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
// when // when
final var result = debitorRepo.findDebitorByPartnerNumber(10003); final var result = debitorRepo.findDebitorsByPartnerNumber(10003);
// then // then
exactlyTheseDebitorsAreReturned(result, exactlyTheseDebitorsAreReturned(result,
@ -320,7 +320,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
// when // when
final var result = debitorRepo.findDebitorByOptionalNameLike("third contact"); final var result = debitorRepo.findDebitorsByOptionalNameLike("third contact");
// then // then
exactlyTheseDebitorsAreReturned(result, "debitor(D-1000313: rel(anchor='IF Third OHG', type='DEBITOR', holder='IF Third OHG'), thi)"); exactlyTheseDebitorsAreReturned(result, "debitor(D-1000313: rel(anchor='IF Third OHG', type='DEBITOR', holder='IF Third OHG'), thi)");

View File

@ -138,7 +138,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
void globalAdmin_canPostNewSepaMandate() { void globalAdmin_canPostNewSepaMandate() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("Third").get(0); final var givenDebitor = debitorRepo.findDebitorsByOptionalNameLike("Third").get(0);
final var givenBankAccount = bankAccountRepo.findByIbanOrderByIbanAsc("DE02200505501015871393").get(0); final var givenBankAccount = bankAccountRepo.findByIbanOrderByIbanAsc("DE02200505501015871393").get(0);
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
@ -180,7 +180,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
void globalAdmin_canNotPostNewSepaMandateWhenDebitorUuidIsMissing() { void globalAdmin_canNotPostNewSepaMandateWhenDebitorUuidIsMissing() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("Third").get(0); final var givenDebitor = debitorRepo.findDebitorsByOptionalNameLike("Third").get(0);
final var givenBankAccount = bankAccountRepo.findByIbanOrderByIbanAsc("DE02200505501015871393").get(0); final var givenBankAccount = bankAccountRepo.findByIbanOrderByIbanAsc("DE02200505501015871393").get(0);
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
@ -205,7 +205,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
void globalAdmin_canNotPostNewSepaMandate_ifBankAccountDoesNotExist() { void globalAdmin_canNotPostNewSepaMandate_ifBankAccountDoesNotExist() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("Third").get(0); final var givenDebitor = debitorRepo.findDebitorsByOptionalNameLike("Third").get(0);
final var givenBankAccountUuid = UUID.fromString("00000000-0000-0000-0000-000000000000"); final var givenBankAccountUuid = UUID.fromString("00000000-0000-0000-0000-000000000000");
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off

View File

@ -66,7 +66,7 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTestWithC
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var count = sepaMandateRepo.count(); final var count = sepaMandateRepo.count();
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0); final var givenDebitor = debitorRepo.findDebitorsByOptionalNameLike("First").get(0);
final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike("Paul Winkler").get(0); final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike("Paul Winkler").get(0);
// when // when
@ -100,7 +100,7 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTestWithC
// when // when
attempt(em, () -> { attempt(em, () -> {
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0); final var givenDebitor = debitorRepo.findDebitorsByOptionalNameLike("First").get(0);
final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike("Paul Winkler").get(0); final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike("Paul Winkler").get(0);
final var newSepaMandate = HsOfficeSepaMandateEntity.builder() final var newSepaMandate = HsOfficeSepaMandateEntity.builder()
.debitor(givenDebitor) .debitor(givenDebitor)
@ -397,7 +397,7 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTestWithC
private HsOfficeSepaMandateEntity givenSomeTemporarySepaMandate(final String iban) { private HsOfficeSepaMandateEntity givenSomeTemporarySepaMandate(final String iban) {
return jpaAttempt.transacted(() -> { return jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0); final var givenDebitor = debitorRepo.findDebitorsByOptionalNameLike("First").get(0);
final var givenBankAccount = bankAccountRepo.findByIbanOrderByIbanAsc(iban).get(0); final var givenBankAccount = bankAccountRepo.findByIbanOrderByIbanAsc(iban).get(0);
final var newSepaMandate = HsOfficeSepaMandateEntity.builder() final var newSepaMandate = HsOfficeSepaMandateEntity.builder()
.debitor(givenDebitor) .debitor(givenDebitor)