introduce hs_booking_debitor_rv for HsBookingDebitorEntity including full debitorNumber

This commit is contained in:
Michael Hoennig 2024-06-05 19:09:06 +02:00
parent 31cedf1261
commit 8343152382
22 changed files with 64 additions and 35 deletions

View File

@ -18,7 +18,7 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
// a partial HsOfficeDebitorEntity to reduce the number of SQL queries to load the entity
@Entity
@Table(name = "hs_office_debitor_rv") // TODO.impl: create a readonly view for this, which also joins the partner-number?
@Table(name = "hs_booking_debitor_rv")
@Getter
@Builder
@NoArgsConstructor
@ -37,8 +37,8 @@ public class HsBookingDebitorEntity implements Stringifyable {
@Id
private UUID uuid;
@Column(name = "debitornumbersuffix", length = 2)
private String debitorNumberSuffix;
@Column(name = "debitornumber")
private Integer debitorNumber;
@Column(name = "defaultprefix", columnDefinition = "char(3) not null")
private String defaultPrefix;
@ -50,6 +50,6 @@ public class HsBookingDebitorEntity implements Stringifyable {
@Override
public String toShortString() {
return DEBITOR_NUMBER_TAG + defaultPrefix;
return DEBITOR_NUMBER_TAG + debitorNumber;
}
}

View File

@ -10,7 +10,5 @@ public interface HsBookingDebitorRepository extends Repository<HsBookingDebitorE
Optional<HsBookingDebitorEntity> findByUuid(UUID id);
List<HsBookingDebitorEntity> findByDefaultPrefix(String defaultPrefix);
long count();
List<HsBookingDebitorEntity> findByDefaultPrefix(String defaultPrefix); // FIXME: change to findByDebitorNumber
}

View File

@ -202,6 +202,6 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject, Validatab
}
public static void main(String[] args) throws IOException {
rbac().generateWithBaseFileName("6-hs-booking/620-booking-item/6203-hs-booking-item-rbac");
rbac().generateWithBaseFileName("6-hs-booking/630-booking-item/6303-hs-booking-item-rbac");
}
}

View File

@ -1,6 +1,7 @@
package net.hostsharing.hsadminng.hs.booking.project;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorRepository;
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.api.HsBookingProjectsApi;
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingProjectInsertResource;
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingProjectPatchResource;
@ -12,8 +13,10 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import jakarta.persistence.EntityNotFoundException;
import java.util.List;
import java.util.UUID;
import java.util.function.BiConsumer;
@RestController
public class HsBookingProjectController implements HsBookingProjectsApi {
@ -27,6 +30,9 @@ public class HsBookingProjectController implements HsBookingProjectsApi {
@Autowired
private HsBookingProjectRepository bookingProjectRepo;
@Autowired
private HsBookingDebitorRepository debitorRepo;
@Override
@Transactional(readOnly = true)
public ResponseEntity<List<HsBookingProjectResource>> listBookingProjectsByDebitorUuid(
@ -50,7 +56,7 @@ public class HsBookingProjectController implements HsBookingProjectsApi {
context.define(currentUser, assumedRoles);
final var entityToSave = mapper.map(body, HsBookingProjectEntity.class);
final var entityToSave = mapper.map(body, HsBookingProjectEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER);
final var saved = bookingProjectRepo.save(entityToSave);
@ -111,4 +117,12 @@ public class HsBookingProjectController implements HsBookingProjectsApi {
final var mapped = mapper.map(saved, HsBookingProjectResource.class);
return ResponseEntity.ok(mapped);
}
final BiConsumer<HsBookingProjectInsertResource, HsBookingProjectEntity> RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> {
if (resource.getDebitorUuid() != null) {
entity.setDebitor(debitorRepo.findByUuid(resource.getDebitorUuid())
.orElseThrow(() -> new EntityNotFoundException("ERROR: [400] debitorUuid %s not found".formatted(
resource.getDebitorUuid()))));
}
};
}

View File

@ -109,6 +109,6 @@ public class HsBookingProjectEntity implements Stringifyable, RbacObject {
}
public static void main(String[] args) throws IOException {
rbac().generateWithBaseFileName("6-hs-booking/610-booking-project/6103-hs-booking-project-rbac");
rbac().generateWithBaseFileName("6-hs-booking/620-booking-project/6203-hs-booking-project-rbac");
}
}

View File

@ -0,0 +1,17 @@
--liquibase formatted sql
-- ============================================================================
--changeset hs-booking-debitor-RESTRICTED-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
create view hs_booking_debitor_rv as
select debitor.uuid,
debitor.version,
(partner.partnerNumber::varchar || debitor.debitorNumberSuffix)::numeric as debitorNumber,
debitor.defaultPrefix
from hs_office_debitor_rv debitor
-- RBAC for debitor is sufficient, for faster access we are bypassing RBAC for the join tables
join hs_office_relation debitorRel on debitor.debitorReluUid=debitorRel.uuid
join hs_office_relation partnerRel on partnerRel.holderUuid=debitorRel.anchorUuid
join hs_office_partner partner on partner.partnerReluUid=partnerRel.uuid;
--//

View File

@ -130,17 +130,19 @@ databaseChangeLog:
- include:
file: db/changelog/5-hs-office/512-coopassets/5128-hs-office-coopassets-test-data.sql
- include:
file: db/changelog/6-hs-booking/610-booking-project/6100-hs-booking-project.sql
file: db/changelog/6-hs-booking/610-booking-debitor/6100-hs-booking-debitor.sql
- include:
file: db/changelog/6-hs-booking/610-booking-project/6103-hs-booking-project-rbac.sql
file: db/changelog/6-hs-booking/620-booking-project/6200-hs-booking-project.sql
- include:
file: db/changelog/6-hs-booking/610-booking-project/6108-hs-booking-project-test-data.sql
file: db/changelog/6-hs-booking/620-booking-project/6203-hs-booking-project-rbac.sql
- include:
file: db/changelog/6-hs-booking/620-booking-item/6200-hs-booking-item.sql
file: db/changelog/6-hs-booking/620-booking-project/6208-hs-booking-project-test-data.sql
- include:
file: db/changelog/6-hs-booking/620-booking-item/6203-hs-booking-item-rbac.sql
file: db/changelog/6-hs-booking/630-booking-item/6200-hs-booking-item.sql
- include:
file: db/changelog/6-hs-booking/620-booking-item/6208-hs-booking-item-test-data.sql
file: db/changelog/6-hs-booking/630-booking-item/6203-hs-booking-item-rbac.sql
- include:
file: db/changelog/6-hs-booking/630-booking-item/6208-hs-booking-item-test-data.sql
- include:
file: db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql
- include:

View File

@ -9,25 +9,25 @@ class HsBookingDebitorEntityTest {
@Test
void toStringContainsDebitorNumberAndDefaultPrefix() {
final var given = HsBookingDebitorEntity.builder()
.debitorNumberSuffix("67")
.debitorNumber(1234567)
.defaultPrefix("som")
.build();
final var result = given.toString();
assertThat(result).isEqualTo("booking-debitor(D-som: som)"); // FIXME: I want "booking-debitor(D-1000167: som)"
assertThat(result).isEqualTo("booking-debitor(D-1234567: som)");
}
@Test
void toShortStringContainsDefaultPrefix() {
final var given = HsBookingDebitorEntity.builder()
.debitorNumberSuffix("67")
.debitorNumber(1234567)
.defaultPrefix("som")
.build();
final var result = given.toShortString();
assertThat(result).isEqualTo("D-som"); // FIXME: I want "booking-debitor(D-1000167: som)"
assertThat(result).isEqualTo("D-1234567");
}
}

View File

@ -6,10 +6,8 @@ import lombok.experimental.UtilityClass;
@UtilityClass
public class TestHsBookingDebitor {
public String DEFAULT_DEBITOR_SUFFIX = "00";
public static final HsBookingDebitorEntity TEST_BOOKING_DEBITOR = HsBookingDebitorEntity.builder()
.debitorNumberSuffix(DEFAULT_DEBITOR_SUFFIX)
.debitorNumber(1234500)
.defaultPrefix("abc")
.build();
}

View File

@ -311,7 +311,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
context.define("superuser-alex@hostsharing.net");
assertThat(bookingItemRepo.findByUuid(givenBookingItem.getUuid())).isPresent().get()
.matches(mandate -> {
assertThat(mandate.getProject().getDebitor().toString()).isEqualTo("booking-debitor(D-fir: fir)");
assertThat(mandate.getProject().getDebitor().toString()).isEqualTo("booking-debitor(D-1000111: fir)");
assertThat(mandate.getValidFrom()).isEqualTo("2022-11-01");
assertThat(mandate.getValidTo()).isEqualTo("2022-12-31");
return true;

View File

@ -29,14 +29,14 @@ class HsBookingItemEntityUnitTest {
void toStringContainsAllPropertiesAndResourcesSortedByKey() {
final var result = givenBookingItem.toString();
assertThat(result).isEqualTo("HsBookingItemEntity(D-abc:test project, CLOUD_SERVER, [2020-01-01,2031-01-01), some caption, { CPUs: 2, HDD-storage: 2048, SSD-storage: 512 })");
assertThat(result).isEqualTo("HsBookingItemEntity(D-1234500:test project, CLOUD_SERVER, [2020-01-01,2031-01-01), some caption, { CPUs: 2, HDD-storage: 2048, SSD-storage: 512 })");
}
@Test
void toShortStringContainsOnlyMemberNumberAndCaption() {
final var result = givenBookingItem.toShortString();
assertThat(result).isEqualTo("D-abc:test project:some caption");
assertThat(result).isEqualTo("D-1234500:test project:some caption");
}
@Test

View File

@ -174,9 +174,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
// then
allTheseBookingItemsAreReturned(
result,
"HsBookingItemEntity(D-sec:D-1000212 default project, MANAGED_WEBSPACE, [2022-10-01,), some ManagedWebspace, { Daemons: 2, Multi: 4, SDD: 512, Traffic: 12 })",
"HsBookingItemEntity(D-sec:D-1000212 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SDD: 512, Traffic: 42 })",
"HsBookingItemEntity(D-sec:D-1000212 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10240, SDD: 10240, Traffic: 42 })");
"HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_WEBSPACE, [2022-10-01,), some ManagedWebspace, { Daemons: 2, Multi: 4, SDD: 512, Traffic: 12 })",
"HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SDD: 512, Traffic: 42 })",
"HsBookingItemEntity(D-1000212:D-1000212 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10240, SDD: 10240, Traffic: 42 })");
}
@Test
@ -194,9 +194,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
// then:
exactlyTheseBookingItemsAreReturned(
result,
"HsBookingItemEntity(D-fir:D-1000111 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SDD: 512, Traffic: 42 })",
"HsBookingItemEntity(D-fir:D-1000111 default project, MANAGED_WEBSPACE, [2022-10-01,), some ManagedWebspace, { Daemons: 2, Multi: 4, SDD: 512, Traffic: 12 })",
"HsBookingItemEntity(D-fir:D-1000111 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10240, SDD: 10240, Traffic: 42 })");
"HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SDD: 512, Traffic: 42 })",
"HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_WEBSPACE, [2022-10-01,), some ManagedWebspace, { Daemons: 2, Multi: 4, SDD: 512, Traffic: 12 })",
"HsBookingItemEntity(D-1000111:D-1000111 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10240, SDD: 10240, Traffic: 42 })");
}
}

View File

@ -220,7 +220,7 @@ class HsBookingProjectControllerAcceptanceTest extends ContextBasedTestWithClean
context.define("superuser-alex@hostsharing.net");
assertThat(bookingProjectRepo.findByUuid(givenBookingProject.getUuid())).isPresent().get()
.matches(mandate -> {
assertThat(mandate.getDebitor().toString()).isEqualTo("debitor(D-1000111: rel(anchor='LP First GmbH', type='DEBITOR', holder='LP First GmbH'), fir)");
assertThat(mandate.getDebitor().toString()).isEqualTo("booking-debitor(D-1000111: fir)");
return true;
});
}

View File

@ -15,13 +15,13 @@ class HsBookingProjectEntityUnitTest {
void toStringContainsAllPropertiesAndResourcesSortedByKey() {
final var result = givenBookingProject.toString();
assertThat(result).isEqualTo("HsBookingProjectEntity(D-1000100, some caption)");
assertThat(result).isEqualTo("HsBookingProjectEntity(D-1234500, some caption)");
}
@Test
void toShortStringContainsOnlyMemberNumberAndCaption() {
final var result = givenBookingProject.toShortString();
assertThat(result).isEqualTo("D-1000100:some caption");
assertThat(result).isEqualTo("D-1234500:some caption");
}
}