Compare commits

..

No commits in common. "032ce6d16e1d72724017b9dc172bc188d80fbdc3" and "82b7a00dd2a8526f056a16fb8806f843973b17fe" have entirely different histories.

14 changed files with 254 additions and 304 deletions

View File

@ -3,8 +3,7 @@ package net.hostsharing.hsadminng.hs.office.debitor;
import lombok.*; import lombok.*;
import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
import net.hostsharing.hsadminng.persistence.HasUuid; import net.hostsharing.hsadminng.persistence.HasUuid;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringify;
@ -12,9 +11,9 @@ import net.hostsharing.hsadminng.stringify.Stringifyable;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
@Entity @Entity
@ -32,7 +31,7 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
private static Stringify<HsOfficeDebitorEntity> stringify = private static Stringify<HsOfficeDebitorEntity> stringify =
stringify(HsOfficeDebitorEntity.class, "debitor") stringify(HsOfficeDebitorEntity.class, "debitor")
.withIdProp(HsOfficeDebitorEntity::toShortString) .withIdProp(HsOfficeDebitorEntity::toShortString)
.withProp(e -> ofNullable(e.getDebitorRel()).map(HsOfficeRelationshipEntity::toShortString).orElse(null)) .withProp(HsOfficeDebitorEntity::getPartner)
.withProp(HsOfficeDebitorEntity::getDefaultPrefix) .withProp(HsOfficeDebitorEntity::getDefaultPrefix)
.quotedValues(false); .quotedValues(false);
@ -41,12 +40,16 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid; private UUID uuid;
@ManyToOne
@JoinColumn(name = "partneruuid")
private HsOfficePartnerEntity partner;
@Column(name = "debitornumbersuffix", columnDefinition = "numeric(2)") @Column(name = "debitornumbersuffix", columnDefinition = "numeric(2)")
private Byte debitorNumberSuffix; // TODO maybe rather as a formatted String? private Byte debitorNumberSuffix; // TODO maybe rather as a formatted String?
@ManyToOne(cascade = CascadeType.ALL) @ManyToOne
@JoinColumn(name = "debitorreluuid", nullable = false) @JoinColumn(name = "billingcontactuuid")
private HsOfficeRelationshipEntity debitorRel; private HsOfficeContactEntity billingContact; // TODO: migrate to billingPerson
@Column(name = "billable", nullable = false) @Column(name = "billable", nullable = false)
private Boolean billable; // not a primitive because otherwise the default would be false private Boolean billable; // not a primitive because otherwise the default would be false
@ -71,18 +74,14 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
private String defaultPrefix; private String defaultPrefix;
private String getDebitorNumberString() { private String getDebitorNumberString() {
return ofNullable(debitorRel) if (partner == null || partner.getPartnerNumber() == null || debitorNumberSuffix == null ) {
.filter(partnerNumber -> debitorNumberSuffix != null) return null;
.map(HsOfficeRelationshipEntity::getRelAnchor) }
.map(HsOfficePersonEntity::getOptionalPartner) return partner.getPartnerNumber() + String.format("%02d", debitorNumberSuffix);
.map(HsOfficePartnerEntity::getPartnerNumber)
.map(Object::toString)
.map(partnerNumber -> partnerNumber + String.format("%02d", debitorNumberSuffix))
.orElse(null);
} }
public Integer getDebitorNumber() { public Integer getDebitorNumber() {
return ofNullable(getDebitorNumberString()).map(Integer::parseInt).orElse(null); return Optional.ofNullable(getDebitorNumberString()).map(Integer::parseInt).orElse(null);
} }
@Override @Override

View File

@ -1,8 +1,8 @@
package net.hostsharing.hsadminng.hs.office.debitor; package net.hostsharing.hsadminng.hs.office.debitor;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorPatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorPatchResource;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
import net.hostsharing.hsadminng.mapper.EntityPatcher; import net.hostsharing.hsadminng.mapper.EntityPatcher;
import net.hostsharing.hsadminng.mapper.OptionalFromJson; import net.hostsharing.hsadminng.mapper.OptionalFromJson;
@ -23,9 +23,9 @@ class HsOfficeDebitorEntityPatcher implements EntityPatcher<HsOfficeDebitorPatch
@Override @Override
public void apply(final HsOfficeDebitorPatchResource resource) { public void apply(final HsOfficeDebitorPatchResource resource) {
OptionalFromJson.of(resource.getDebitorRelUuid()).ifPresent(newValue -> { OptionalFromJson.of(resource.getBillingContactUuid()).ifPresent(newValue -> {
verifyNotNull(newValue, "debitorRel"); verifyNotNull(newValue, "billingContact");
entity.setDebitorRel(em.getReference(HsOfficeRelationshipEntity.class, newValue)); entity.setBillingContact(em.getReference(HsOfficeContactEntity.class, newValue));
}); });
Optional.ofNullable(resource.getBillable()).ifPresent(entity::setBillable); Optional.ofNullable(resource.getBillable()).ifPresent(entity::setBillable);
OptionalFromJson.of(resource.getVatId()).ifPresent(entity::setVatId); OptionalFromJson.of(resource.getVatId()).ifPresent(entity::setVatId);

View File

@ -3,7 +3,6 @@ package net.hostsharing.hsadminng.hs.office.person;
import lombok.*; import lombok.*;
import lombok.experimental.FieldNameConstants; import lombok.experimental.FieldNameConstants;
import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import net.hostsharing.hsadminng.persistence.HasUuid; import net.hostsharing.hsadminng.persistence.HasUuid;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.stringify.Stringifyable;
@ -47,14 +46,6 @@ public class HsOfficePersonEntity implements HasUuid, Stringifyable {
@Column(name = "givenname") @Column(name = "givenname")
private String givenName; private String givenName;
@OneToOne(cascade = CascadeType.ALL)
@JoinTable(name = "hs_office_relationship",
joinColumns =
{ @JoinColumn(name = "uuid", referencedColumnName = "relanchoruuid") },
inverseJoinColumns =
{ @JoinColumn(name = "relanchoruuid", referencedColumnName = "uuid") })
private HsOfficePartnerEntity optionalPartner;
@Override @Override
public String toString() { public String toString() {
return toString.apply(this); return toString.apply(this);

View File

@ -43,7 +43,7 @@ components:
HsOfficeDebitorPatch: HsOfficeDebitorPatch:
type: object type: object
properties: properties:
debitorRelUuid: billingContactUuid:
type: string type: string
format: uuid format: uuid
nullable: true nullable: true

View File

@ -7,9 +7,10 @@
create table hs_office_debitor create table hs_office_debitor
( (
uuid uuid unique references RbacObject (uuid) initially deferred, uuid uuid unique references RbacObject (uuid) initially deferred,
debitorNumberSuffix numeric(2) not null, partnerUuid uuid not null references hs_office_partner(uuid),
debitorRelUuid uuid not null references hs_office_relationship(uuid),
billable boolean not null default true, billable boolean not null default true,
debitorNumberSuffix numeric(2) not null,
billingContactUuid uuid not null references hs_office_contact(uuid),
vatId varchar(24), -- TODO.spec: here or in person? vatId varchar(24), -- TODO.spec: here or in person?
vatCountryCode varchar(2), vatCountryCode varchar(2),
vatBusiness boolean not null, vatBusiness boolean not null,

View File

@ -7,6 +7,13 @@ call generateRelatedRbacObject('hs_office_debitor');
--// --//
-- ============================================================================
--changeset hs-office-debitor-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRbacRoleDescriptors('hsOfficeDebitor', 'hs_office_debitor');
--//
-- ============================================================================ -- ============================================================================
--changeset hs-office-debitor-rbac-ROLES-CREATION:1 endDelimiter:--// --changeset hs-office-debitor-rbac-ROLES-CREATION:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
@ -20,103 +27,121 @@ create or replace function hsOfficeDebitorRbacRolesTrigger()
language plpgsql language plpgsql
strict as $$ strict as $$
declare declare
debitorUuid uuid; hsOfficeDebitorTenant RbacRoleDescriptor;
oldPartner hs_office_partner;
oldDebitorRel hs_office_relationship; newPartner hs_office_partner;
newDebitorRel hs_office_relationship; oldPartnerRel hs_office_relationship;
newPartnerRel hs_office_relationship; newPartnerRel hs_office_relationship;
oldContact hs_office_contact;
newContact hs_office_contact;
newBankAccount hs_office_bankaccount; newBankAccount hs_office_bankaccount;
oldBankAccount hs_office_bankaccount; oldBankAccount hs_office_bankaccount;
begin begin
call enterTriggerForObjectUuid(NEW.uuid); call enterTriggerForObjectUuid(NEW.uuid);
debitorUuid := NEW.uuid; hsOfficeDebitorTenant := hsOfficeDebitorTenant(NEW);
select * into newDebitorRel select * from hs_office_partner as p where p.uuid = NEW.partnerUuid into newPartner;
from hs_office_relationship as r where r.relType = 'DEBITOR' and r.relHolderUuid = NEW.debitorRelUuid; select * from hs_office_relationship as r where r.relType = 'PARTNER' and r.relHolderUuid = NEW.partnerUuid into newPartnerRel;
select * from hs_office_contact as c where c.uuid = NEW.billingContactUuid into newContact;
select * into newPartnerRel select * from hs_office_bankaccount as b where b.uuid = NEW.refundBankAccountUuid into newBankAccount;
from hs_office_relationship as r
join hs_office_partner as p on p.partnerRoleUuid = r.uuid
where r.relType = 'PARTNER' and r.relHolderUuid = newPartnerRel;
select * from hs_office_bankaccount as b where b.uuid = NEW.refundBankAccountUuid
into newBankAccount;
if TG_OP = 'INSERT' then if TG_OP = 'INSERT' then
-- Permissions and Grants for Debitor perform createRoleWithGrants(
hsOfficeDebitorOwner(NEW),
call grantPermissionsToRole( permissions => array['*'],
getRoleId(hsOfficeRelationshipOwner(newDebitorRel), 'fail'), incomingSuperRoles => array[globalAdmin()],
createPermissions(partnerUuid, array ['*']) userUuids => array[currentUserUuid()],
grantedByRole => globalAdmin()
); );
call grantPermissionsToRole( perform createRoleWithGrants(
getRoleId(hsOfficeRelationshipAdmin(newDebitorRel), 'fail'), hsOfficeDebitorAdmin(NEW),
createPermissions(partnerUuid, array ['edit']) permissions => array['edit'],
incomingSuperRoles => array[hsOfficeDebitorOwner(NEW)]
); );
call grantPermissionsToRole( perform createRoleWithGrants(
getRoleId(hsOfficeRelationshipTenant(newDebitorRel), 'fail'), hsOfficeDebitorAgent(NEW),
createPermissions(partnerUuid, array ['view']) incomingSuperRoles => array[
hsOfficeDebitorAdmin(NEW),
hsOfficeRelationshipAdmin(newPartnerRel),
hsOfficeContactAdmin(newContact)],
outgoingSubRoles => array[
hsOfficeBankAccountTenant(newBankaccount)]
); );
-- Grants to and from related Partner Relationship perform createRoleWithGrants(
hsOfficeDebitorTenant(NEW),
incomingSuperRoles => array[
hsOfficeDebitorAgent(NEW),
hsOfficeRelationshipAgent(newPartnerRel),
hsOfficeBankAccountAdmin(newBankaccount)],
outgoingSubRoles => array[
hsOfficeRelationshipTenant(newPartnerRel),
hsOfficeContactReferrer(newContact),
hsOfficeBankAccountGuest(newBankaccount)]
);
call grantRoleToRole(hsOfficeRelationshipAdmin(newDebitorRel), hsOfficeRelationshipAdmin(newPartnerRel), true); perform createRoleWithGrants(
call grantRoleToRole(hsOfficeRelationshipAgent(newPartnerRel), hsOfficeRelationshipAdmin(newDebitorRel), true); hsOfficeDebitorGuest(NEW),
permissions => array['view'],
call grantRoleToRole(hsOfficeRelationshipAgent(newDebitorRel), hsOfficeRelationshipAgent(newPartnerRel), true); incomingSuperRoles => array[
call grantRoleToRole(hsOfficeRelationshipTenant(newPartnerRel), hsOfficeRelationshipAgent(newDebitorRel), true); hsOfficeDebitorTenant(NEW)]
);
-- Grants to and from refundBankAccount
if newBankAccount is not null then
call grantRoleToRole(hsOfficeBankAccountReferrer(newBankAccount), hsOfficeRelationshipAgent(newDebitorRel), true);
call grantRoleToRole(hsOfficeRelationshipAgent(newDebitorRel), hsOfficeBankAccountAdmin(newBankAccount), true);
end if;
elsif TG_OP = 'UPDATE' then elsif TG_OP = 'UPDATE' then
if OLD.debitorRelUuid is distinct from NEW.debitorRelUuid then if OLD.partnerUuid <> NEW.partnerUuid then
select * from hs_office_partner as p where p.uuid = OLD.partnerUuid into oldPartner;
select * from hs_office_relationship as r where r.uuid = OLD.partnerUuid into oldPartnerRel;
select * into oldDebitorRel call revokeRoleFromRole(hsOfficeDebitorAgent(OLD), hsOfficeRelationshipAdmin(oldPartnerRel));
from hs_office_relationship as r where r.relType = 'DEBITOR' and r.relHolderUuid = NEW.debitorRelUuid; call grantRoleToRole(hsOfficeDebitorAgent(NEW), hsOfficeRelationshipAdmin(oldPartnerRel));
call grantPermissionsToRole( call revokeRoleFromRole(hsOfficeDebitorTenant(OLD), hsOfficeRelationshipAgent(oldPartnerRel));
getRoleId(hsOfficeRelationshipOwner(newDebitorRel), 'fail'), call grantRoleToRole(hsOfficeDebitorTenant(NEW), hsOfficeRelationshipAgent(newPartner));
createPermissions(partnerUuid, array ['*'])
);
call grantPermissionsToRole(
getRoleId(hsOfficeRelationshipAdmin(newDebitorRel), 'fail'),
createPermissions(partnerUuid, array ['edit'])
);
call grantPermissionsToRole(
getRoleId(hsOfficeRelationshipTenant(newDebitorRel), 'fail'),
createPermissions(partnerUuid, array ['view'])
);
call revokeRoleFromRole(hsOfficeRelationshipTenant(oldPartnerRel), hsOfficeDebitorTenant(OLD));
call grantRoleToRole(hsOfficeRelationshipTenant(newPartnerRel), hsOfficeDebitorTenant(NEW));
end if; end if;
if OLD.refundBankAccountUuid is distinct from NEW.refundBankAccountUuid then if OLD.billingContactUuid <> NEW.billingContactUuid then
select * from hs_office_contact as c where c.uuid = OLD.billingContactUuid into oldContact;
select * into oldBankAccount call revokeRoleFromRole(hsOfficeDebitorAgent(OLD), hsOfficeContactAdmin(oldContact));
from hs_office_bankaccount as b where b.uuid = OLD.refundBankAccountUuid; call grantRoleToRole(hsOfficeDebitorAgent(NEW), hsOfficeContactAdmin(newContact));
call revokeRoleFromRole(hsOfficeContactReferrer(oldContact), hsOfficeDebitorTenant(OLD));
call grantRoleToRole(hsOfficeContactReferrer(newContact), hsOfficeDebitorTenant(NEW));
end if;
if (OLD.refundBankAccountUuid is not null or NEW.refundBankAccountUuid is not null) and
( OLD.refundBankAccountUuid is null or NEW.refundBankAccountUuid is null or
OLD.refundBankAccountUuid <> NEW.refundBankAccountUuid ) then
select * from hs_office_bankaccount as b where b.uuid = OLD.refundBankAccountUuid into oldBankAccount;
if oldBankAccount is not null then if oldBankAccount is not null then
call revokeRoleFromRole(hsOfficeBankAccountReferrer(oldBankAccount), hsOfficeRelationshipAgent(oldDebitorRel), true); call revokeRoleFromRole(hsOfficeBankAccountTenant(oldBankaccount), hsOfficeDebitorAgent(OLD));
call revokeRoleFromRole(hsOfficeRelationshipAgent(oldDebitorRel), hsOfficeBankAccountAdmin(oldBankAccount), true); end if;
if newBankAccount is not null then
call grantRoleToRole(hsOfficeBankAccountTenant(newBankaccount), hsOfficeDebitorAgent(NEW));
end if; end if;
if oldBankAccount is not null then
call revokeRoleFromRole(hsOfficeDebitorTenant(OLD), hsOfficeBankAccountAdmin(oldBankaccount));
end if;
if newBankAccount is not null then if newBankAccount is not null then
call grantRoleToRole(hsOfficeBankAccountReferrer(newBankAccount), hsOfficeRelationshipAgent(newDebitorRel), true); call grantRoleToRole(hsOfficeDebitorTenant(NEW), hsOfficeBankAccountAdmin(newBankaccount));
call grantRoleToRole(hsOfficeRelationshipAgent(newDebitorRel), hsOfficeBankAccountAdmin(newBankAccount), true); end if;
if oldBankAccount is not null then
call revokeRoleFromRole(hsOfficeBankAccountGuest(oldBankaccount), hsOfficeDebitorTenant(OLD));
end if;
if newBankAccount is not null then
call grantRoleToRole(hsOfficeBankAccountGuest(newBankaccount), hsOfficeDebitorTenant(NEW));
end if; end if;
end if; end if;
else else
@ -147,37 +172,6 @@ execute procedure hsOfficeDebitorRbacRolesTrigger();
--// --//
/*
Creates and updates the roles and their assignments for debitor entities if partner rel changes.
*/
create or replace function hsOfficeDebitorPartnerRelRbacRolesTrigger()
returns trigger
language plpgsql
strict as $$
declare
begin
call enterTriggerForObjectUuid(NEW.uuid);
-- TODO
call leaveTriggerForObjectUuid(NEW.uuid);
return NEW;
end; $$;
--//
/*
An AFTER UPDATE TRIGGER which creates the role structure for debitors if partner relations change.
*/
create trigger updateRbacRolesForHsOfficeDebitor_Trigger
after update
on hs_office_partner
for each row
execute procedure hsOfficeDebitorPartnerRelRbacRolesTrigger();
--//
-- ============================================================================ -- ============================================================================
--changeset hs-office-debitor-rbac-IDENTITY-VIEW:1 endDelimiter:--// --changeset hs-office-debitor-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------

View File

@ -410,20 +410,19 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
.body("vatBusiness", is(true)) .body("vatBusiness", is(true))
.body("defaultPrefix", is("for")) .body("defaultPrefix", is("for"))
.body("billingContact.label", is(givenContact.getLabel())) .body("billingContact.label", is(givenContact.getLabel()))
// TODO .body("partner.partnerRole.relHolder.tradeName", is(givenDebitor.getPartner().getPartnerRole().getRelHolder().getTradeName())) .body("partner.partnerRole.relHolder.tradeName", is(givenDebitor.getPartner().getPartnerRole().getRelHolder().getTradeName()));
;
// @formatter:on // @formatter:on
// finally, the debitor is actually updated // finally, the debitor is actually updated
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent().get() assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent().get()
.matches(debitor -> { .matches(partner -> {
assertThat(debitor.getDebitorRel().getRelHolder().getTradeName()) assertThat(partner.getPartner().getPartnerRole().getRelHolder().getTradeName())
.isEqualTo(givenDebitor.getDebitorRel().getRelHolder().getTradeName()); .isEqualTo(givenDebitor.getPartner().getPartnerRole().getRelHolder().getTradeName());
assertThat(debitor.getDebitorRel().getContact().getLabel()).isEqualTo("fourth contact"); assertThat(partner.getBillingContact().getLabel()).isEqualTo("fourth contact");
assertThat(debitor.getVatId()).isEqualTo("VAT222222"); assertThat(partner.getVatId()).isEqualTo("VAT222222");
assertThat(debitor.getVatCountryCode()).isEqualTo("AA"); assertThat(partner.getVatCountryCode()).isEqualTo("AA");
assertThat(debitor.isVatBusiness()).isEqualTo(true); assertThat(partner.isVatBusiness()).isEqualTo(true);
return true; return true;
}); });
} }
@ -461,9 +460,9 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
// finally, the debitor is actually updated // finally, the debitor is actually updated
assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent().get() assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent().get()
.matches(partner -> { .matches(partner -> {
assertThat(partner.getDebitorRel().getRelHolder().getTradeName()) assertThat(partner.getPartner().getPartnerRole().getRelHolder().getTradeName())
.isEqualTo(givenDebitor.getDebitorRel().getRelHolder().getTradeName()); .isEqualTo(givenDebitor.getPartner().getPartnerRole().getRelHolder().getTradeName());
assertThat(partner.getDebitorRel().getContact().getLabel()).isEqualTo("sixth contact"); assertThat(partner.getBillingContact().getLabel()).isEqualTo("sixth contact");
assertThat(partner.getVatId()).isEqualTo("VAT999999"); assertThat(partner.getVatId()).isEqualTo("VAT999999");
assertThat(partner.getVatCountryCode()).isEqualTo(givenDebitor.getVatCountryCode()); assertThat(partner.getVatCountryCode()).isEqualTo(givenDebitor.getVatCountryCode());
assertThat(partner.isVatBusiness()).isEqualTo(givenDebitor.isVatBusiness()); assertThat(partner.isVatBusiness()).isEqualTo(givenDebitor.isVatBusiness());
@ -500,7 +499,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
void contactAdminUser_canNotDeleteRelatedDebitor() { void contactAdminUser_canNotDeleteRelatedDebitor() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenDebitor = givenSomeTemporaryDebitor(); final var givenDebitor = givenSomeTemporaryDebitor();
assertThat(givenDebitor.getDebitorRel().getContact().getLabel()).isEqualTo("fourth contact"); assertThat(givenDebitor.getBillingContact().getLabel()).isEqualTo("fourth contact");
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
@ -520,7 +519,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
void normalUser_canNotDeleteUnrelatedDebitor() { void normalUser_canNotDeleteUnrelatedDebitor() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenDebitor = givenSomeTemporaryDebitor(); final var givenDebitor = givenSomeTemporaryDebitor();
assertThat(givenDebitor.getDebitorRel().getContact().getLabel()).isEqualTo("fourth contact"); assertThat(givenDebitor.getBillingContact().getLabel()).isEqualTo("fourth contact");
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
@ -544,8 +543,8 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
final var newDebitor = HsOfficeDebitorEntity.builder() final var newDebitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix(++nextDebitorSuffix) .debitorNumberSuffix(++nextDebitorSuffix)
.billable(true) .billable(true)
// .partner(givenPartner) .partner(givenPartner)
// .billingContact(givenContact) .billingContact(givenContact)
.defaultPrefix("abc") .defaultPrefix("abc")
.vatReverseCharge(false) .vatReverseCharge(false)
.build(); .build();

View File

@ -1,8 +1,9 @@
package net.hostsharing.hsadminng.hs.office.debitor; package net.hostsharing.hsadminng.hs.office.debitor;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorPatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorPatchResource;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import net.hostsharing.test.PatchUnitTestBase; import net.hostsharing.test.PatchUnitTestBase;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance;
@ -27,8 +28,9 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
> { > {
private static final UUID INITIAL_DEBITOR_UUID = UUID.randomUUID(); private static final UUID INITIAL_DEBITOR_UUID = UUID.randomUUID();
private static final UUID INITIAL_DEBITOR_REL_UUID = UUID.randomUUID(); private static final UUID INITIAL_PARTNER_UUID = UUID.randomUUID();
private static final UUID PATCHED_DEBITOR_REL_UUID = UUID.randomUUID(); private static final UUID INITIAL_CONTACT_UUID = UUID.randomUUID();
private static final UUID PATCHED_CONTACT_UUID = UUID.randomUUID();
private static final String PATCHED_DEFAULT_PREFIX = "xyz"; private static final String PATCHED_DEFAULT_PREFIX = "xyz";
private static final String PATCHED_VAT_COUNTRY_CODE = "ZZ"; private static final String PATCHED_VAT_COUNTRY_CODE = "ZZ";
@ -44,8 +46,12 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
private static final UUID INITIAL_REFUND_BANK_ACCOUNT_UUID = UUID.randomUUID(); private static final UUID INITIAL_REFUND_BANK_ACCOUNT_UUID = UUID.randomUUID();
private static final UUID PATCHED_REFUND_BANK_ACCOUNT_UUID = UUID.randomUUID(); private static final UUID PATCHED_REFUND_BANK_ACCOUNT_UUID = UUID.randomUUID();
private final HsOfficeRelationshipEntity givenInitialDebitorRel = HsOfficeRelationshipEntity.builder() private final HsOfficePartnerEntity givenInitialPartner = HsOfficePartnerEntity.builder()
.uuid(INITIAL_DEBITOR_REL_UUID) .uuid(INITIAL_PARTNER_UUID)
.build();
private final HsOfficeContactEntity givenInitialContact = HsOfficeContactEntity.builder()
.uuid(INITIAL_CONTACT_UUID)
.build(); .build();
private final HsOfficeBankAccountEntity givenInitialBankAccount = HsOfficeBankAccountEntity.builder() private final HsOfficeBankAccountEntity givenInitialBankAccount = HsOfficeBankAccountEntity.builder()
@ -56,8 +62,8 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
@BeforeEach @BeforeEach
void initMocks() { void initMocks() {
lenient().when(em.getReference(eq(HsOfficeRelationshipEntity.class), any())).thenAnswer(invocation -> lenient().when(em.getReference(eq(HsOfficeContactEntity.class), any())).thenAnswer(invocation ->
HsOfficeRelationshipEntity.builder().uuid(invocation.getArgument(1)).build()); HsOfficeContactEntity.builder().uuid(invocation.getArgument(1)).build());
lenient().when(em.getReference(eq(HsOfficeBankAccountEntity.class), any())).thenAnswer(invocation -> lenient().when(em.getReference(eq(HsOfficeBankAccountEntity.class), any())).thenAnswer(invocation ->
HsOfficeBankAccountEntity.builder().uuid(invocation.getArgument(1)).build()); HsOfficeBankAccountEntity.builder().uuid(invocation.getArgument(1)).build());
} }
@ -66,7 +72,8 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
protected HsOfficeDebitorEntity newInitialEntity() { protected HsOfficeDebitorEntity newInitialEntity() {
final var entity = new HsOfficeDebitorEntity(); final var entity = new HsOfficeDebitorEntity();
entity.setUuid(INITIAL_DEBITOR_UUID); entity.setUuid(INITIAL_DEBITOR_UUID);
entity.setDebitorRel(givenInitialDebitorRel); entity.setPartner(givenInitialPartner);
entity.setBillingContact(givenInitialContact);
entity.setBillable(INITIAL_BILLABLE); entity.setBillable(INITIAL_BILLABLE);
entity.setVatId("initial VAT-ID"); entity.setVatId("initial VAT-ID");
entity.setVatCountryCode("AA"); entity.setVatCountryCode("AA");
@ -91,11 +98,11 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
protected Stream<Property> propertyTestDescriptors() { protected Stream<Property> propertyTestDescriptors() {
return Stream.of( return Stream.of(
new JsonNullableProperty<>( new JsonNullableProperty<>(
"debitorRel", "billingContact",
HsOfficeDebitorPatchResource::setDebitorRelUuid, HsOfficeDebitorPatchResource::setBillingContactUuid,
PATCHED_DEBITOR_REL_UUID, PATCHED_CONTACT_UUID,
HsOfficeDebitorEntity::setDebitorRel, HsOfficeDebitorEntity::setBillingContact,
newDebitorRel(PATCHED_DEBITOR_REL_UUID)) newBillingContact(PATCHED_CONTACT_UUID))
.notNullable(), .notNullable(),
new SimpleProperty<>( new SimpleProperty<>(
"billable", "billable",
@ -122,7 +129,7 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
new SimpleProperty<>( new SimpleProperty<>(
"vatReverseCharge", "vatReverseCharge",
HsOfficeDebitorPatchResource::setVatReverseCharge, HsOfficeDebitorPatchResource::setVatReverseCharge,
PATCHED_VAT_REVERSE_CHARGE, PATCHED_BILLABLE,
HsOfficeDebitorEntity::setVatReverseCharge) HsOfficeDebitorEntity::setVatReverseCharge)
.notNullable(), .notNullable(),
new JsonNullableProperty<>( new JsonNullableProperty<>(
@ -141,15 +148,15 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
); );
} }
private HsOfficeRelationshipEntity newDebitorRel(final UUID uuid) { private HsOfficeContactEntity newBillingContact(final UUID uuid) {
return HsOfficeRelationshipEntity.builder() final var newContact = new HsOfficeContactEntity();
.uuid(uuid) newContact.setUuid(uuid);
.build(); return newContact;
} }
private HsOfficeBankAccountEntity newBankAccount(final UUID uuid) { private HsOfficeBankAccountEntity newBankAccount(final UUID uuid) {
return HsOfficeBankAccountEntity.builder() final var newBankAccount = new HsOfficeBankAccountEntity();
.uuid(uuid) newBankAccount.setUuid(uuid);
.build(); return newBankAccount;
} }
} }

View File

@ -1,6 +1,7 @@
package net.hostsharing.hsadminng.hs.office.debitor; package net.hostsharing.hsadminng.hs.office.debitor;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerDetailsEntity;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType;
@ -11,38 +12,52 @@ import static org.assertj.core.api.Assertions.assertThat;
class HsOfficeDebitorEntityUnitTest { class HsOfficeDebitorEntityUnitTest {
private HsOfficeRelationshipEntity givenDebitorRel = HsOfficeRelationshipEntity.builder()
.relAnchor(HsOfficePersonEntity.builder()
.personType(HsOfficePersonType.LEGAL_PERSON)
.tradeName("some partner trade name")
.optionalPartner(HsOfficePartnerEntity.builder()
.partnerNumber(12345)
.build())
.build())
.relHolder(HsOfficePersonEntity.builder()
.personType(HsOfficePersonType.LEGAL_PERSON)
.tradeName("some billing trade name")
.build())
.contact(HsOfficeContactEntity.builder().label("some label").build())
.build();
@Test @Test
void toStringContainsPartnerAndContact() { void toStringContainsPartnerAndContact() {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix((byte)67) .debitorNumberSuffix((byte)67)
.debitorRel(givenDebitorRel) .partner(HsOfficePartnerEntity.builder()
.partnerRole(HsOfficeRelationshipEntity.builder()
.relHolder(HsOfficePersonEntity.builder()
.personType(HsOfficePersonType.LEGAL_PERSON)
.tradeName("some trade name")
.build())
.build())
.details(HsOfficePartnerDetailsEntity.builder().birthName("some birth name").build())
.partnerNumber(12345)
.build())
.billingContact(HsOfficeContactEntity.builder().label("some label").build())
.defaultPrefix("som") .defaultPrefix("som")
.build(); .build();
final var result = given.toString(); final var result = given.toString();
assertThat(result).isEqualTo("debitor(D-1234567: rel(relAnchor='LP some partner trade name', relHolder='LP some billing trade name'), som)"); assertThat(result).isEqualTo("debitor(D-1234567: P-12345, som)");
}
@Test
void toStringWithoutPersonContainsDebitorNumber() {
final var given = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix((byte)67)
.partner(HsOfficePartnerEntity.builder()
.partnerRole(null)
.details(HsOfficePartnerDetailsEntity.builder().birthName("some birth name").build())
.partnerNumber(12345)
.build())
.billingContact(HsOfficeContactEntity.builder().label("some label").build())
.build();
final var result = given.toString();
assertThat(result).isEqualTo("debitor(D-1234567: P-12345)");
} }
@Test @Test
void toShortStringContainsDebitorNumber() { void toShortStringContainsDebitorNumber() {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .partner(HsOfficePartnerEntity.builder()
.partnerNumber(12345)
.build())
.debitorNumberSuffix((byte)67) .debitorNumberSuffix((byte)67)
.build(); .build();
@ -54,7 +69,9 @@ class HsOfficeDebitorEntityUnitTest {
@Test @Test
void getDebitorNumberWithPartnerNumberAndDebitorNumberSuffix() { void getDebitorNumberWithPartnerNumberAndDebitorNumberSuffix() {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .partner(HsOfficePartnerEntity.builder()
.partnerNumber(12345)
.build())
.debitorNumberSuffix((byte)67) .debitorNumberSuffix((byte)67)
.build(); .build();
@ -65,9 +82,8 @@ class HsOfficeDebitorEntityUnitTest {
@Test @Test
void getDebitorNumberWithoutPartnerReturnsNull() { void getDebitorNumberWithoutPartnerReturnsNull() {
givenDebitorRel.getRelAnchor().setOptionalPartner(null);
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .partner(null)
.debitorNumberSuffix((byte)67) .debitorNumberSuffix((byte)67)
.build(); .build();
@ -78,9 +94,10 @@ class HsOfficeDebitorEntityUnitTest {
@Test @Test
void getDebitorNumberWithoutPartnerNumberReturnsNull() { void getDebitorNumberWithoutPartnerNumberReturnsNull() {
givenDebitorRel.getRelAnchor().getOptionalPartner().setPartnerNumber(null);
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .partner(HsOfficePartnerEntity.builder()
.partnerNumber(null)
.build())
.debitorNumberSuffix((byte)67) .debitorNumberSuffix((byte)67)
.build(); .build();
@ -92,7 +109,9 @@ class HsOfficeDebitorEntityUnitTest {
@Test @Test
void getDebitorNumberWithoutDebitorNumberSuffixReturnsNull() { void getDebitorNumberWithoutDebitorNumberSuffixReturnsNull() {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .partner(HsOfficePartnerEntity.builder()
.partnerNumber(12345)
.build())
.debitorNumberSuffix(null) .debitorNumberSuffix(null)
.build(); .build();

View File

@ -4,13 +4,8 @@ import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRepository;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipType;
import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantRepository; import net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantRepository;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsMermaidService;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsMermaidService.Include;
import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository; import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository;
import net.hostsharing.test.Array; import net.hostsharing.test.Array;
import net.hostsharing.test.JpaAttempt; import net.hostsharing.test.JpaAttempt;
@ -30,17 +25,15 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import java.util.Arrays; import java.util.Arrays;
import java.util.EnumSet;
import java.util.List; import java.util.List;
import static net.hostsharing.hsadminng.hs.office.test.EntityList.one;
import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.distinctGrantDisplaysOf; import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.distinctGrantDisplaysOf;
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.distinctRoleNamesOf; import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.distinctRoleNamesOf;
import static net.hostsharing.test.JpaAttempt.attempt; import static net.hostsharing.test.JpaAttempt.attempt;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest @DataJpaTest
@Import( { Context.class, JpaAttempt.class, RbacGrantsMermaidService.class }) @Import( { Context.class, JpaAttempt.class })
class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithCleanup { class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithCleanup {
@Autowired @Autowired
@ -52,9 +45,6 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
@Autowired @Autowired
HsOfficeContactRepository contactRepo; HsOfficeContactRepository contactRepo;
@Autowired
HsOfficePersonRepository personRepo;
@Autowired @Autowired
HsOfficeBankAccountRepository bankAccountRepo; HsOfficeBankAccountRepository bankAccountRepo;
@ -70,11 +60,9 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
@Autowired @Autowired
JpaAttempt jpaAttempt; JpaAttempt jpaAttempt;
@Autowired
RbacGrantsMermaidService mermaidService;
@MockBean @MockBean
HttpServletRequest request; HttpServletRequest request;
@Nested @Nested
class CreateDebitor { class CreateDebitor {
@ -83,19 +71,15 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var count = debitorRepo.count(); final var count = debitorRepo.count();
final var givenPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First GmbH")); final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First GmbH").get(0);
final var givenContact = one(contactRepo.findContactByOptionalLabelLike("first contact")); final var givenContact = contactRepo.findContactByOptionalLabelLike("first contact").get(0);
// when // when
final var result = attempt(em, () -> { final var result = attempt(em, () -> {
final var newDebitor = HsOfficeDebitorEntity.builder() final var newDebitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix((byte)21) .debitorNumberSuffix((byte)21)
.debitorRel(HsOfficeRelationshipEntity.builder() .partner(givenPartner)
.relType(HsOfficeRelationshipType.ACCOUNTING) .billingContact(givenContact)
.relAnchor(givenPartnerPerson)
.relHolder(givenPartnerPerson)
.contact(givenContact)
.build())
.defaultPrefix("abc") .defaultPrefix("abc")
.billable(false) .billable(false)
.build(); .build();
@ -115,19 +99,16 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
public void canNotCreateNewDebitorWithInvalidDefaultPrefix(final String givenPrefix) { public void canNotCreateNewDebitorWithInvalidDefaultPrefix(final String givenPrefix) {
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First GmbH")); final var count = debitorRepo.count();
final var givenContact = one(contactRepo.findContactByOptionalLabelLike("first contact")); final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First GmbH").get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike("first contact").get(0);
// when // when
final var result = attempt(em, () -> { final var result = attempt(em, () -> {
final var newDebitor = HsOfficeDebitorEntity.builder() final var newDebitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix((byte)21) .debitorNumberSuffix((byte)21)
.debitorRel(HsOfficeRelationshipEntity.builder() .partner(givenPartner)
.relType(HsOfficeRelationshipType.ACCOUNTING) .billingContact(givenContact)
.relAnchor(givenPartnerPerson)
.relHolder(givenPartnerPerson)
.contact(givenContact)
.build())
.billable(true) .billable(true)
.vatReverseCharge(false) .vatReverseCharge(false)
.vatBusiness(false) .vatBusiness(false)
@ -138,7 +119,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
// then // then
System.out.println("ok"); System.out.println("ok");
// TODO result.assertExceptionWithRootCauseMessage(org.hibernate.exception.ConstraintViolationException.class); // result.assertExceptionWithRootCauseMessage(org.hibernate.exception.ConstraintViolationException.class);
} }
@Test @Test
@ -157,16 +138,12 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
// when // when
attempt(em, () -> { attempt(em, () -> {
final var givenPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First GmbH")); final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Fourth").get(0);
final var givenContact = one(contactRepo.findContactByOptionalLabelLike("fourth contact")); final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth contact").get(0);
final var newDebitor = HsOfficeDebitorEntity.builder() final var newDebitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix((byte)22) .debitorNumberSuffix((byte)22)
.debitorRel(HsOfficeRelationshipEntity.builder() .partner(givenPartner)
.relType(HsOfficeRelationshipType.ACCOUNTING) .billingContact(givenContact)
.relAnchor(givenPartnerPerson)
.relHolder(givenPartnerPerson)
.contact(givenContact)
.build())
.defaultPrefix("abc") .defaultPrefix("abc")
.billable(false) .billable(false)
.build(); .build();
@ -201,14 +178,13 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
// agent // agent
"{ grant role debitor#1000422:FeG.agent to role debitor#1000422:FeG.admin by system and assume }", "{ grant role debitor#1000422:FeG.agent to role debitor#1000422:FeG.admin by system and assume }",
"{ grant role debitor#1000422:FeG.agent to role contact#4th.admin by system and assume }", "{ grant role debitor#1000422:FeG.agent to role contact#4th.admin by system and assume }",
// "{ grant role debitor#1000422:FeG.agent to role partner#10004:FeG.admin by system and assume }", "{ grant role debitor#1000422:FeG.agent to role partner#10004:FeG.admin by system and assume }",
// tenant // tenant
//"{ grant role contact#4th.guest to role debitor#1000422:FeG.tenant by system and assume }", "{ grant role contact#4th.guest to role debitor#1000422:FeG.tenant by system and assume }",
"{ grant role debitor#1000422:FeG.tenant to role debitor#1000422:FeG.agent by system and assume }", "{ grant role debitor#1000422:FeG.tenant to role debitor#1000422:FeG.agent by system and assume }",
//"{ grant role debitor#1000422:FeG.tenant to role partner#10004:FeG.agent by system and assume }", "{ grant role debitor#1000422:FeG.tenant to role partner#10004:FeG.agent by system and assume }",
//"{ grant role partner#10004:FeG.tenant to role debitor#1000422:FeG.tenant by system and assume }", "{ grant role partner#10004:FeG.tenant to role debitor#1000422:FeG.tenant by system and assume }",
"{ grant role contact#4th.referrer to role debitor#1000422:FeG.tenant by system and assume }",
// guest // guest
"{ grant perm view on debitor#1000422:FeG to role debitor#1000422:FeG.guest by system and assume }", "{ grant perm view on debitor#1000422:FeG to role debitor#1000422:FeG.guest by system and assume }",
@ -315,17 +291,13 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", "Fourth", "fif"); final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", "Fourth", "fif");
RbacGrantsMermaidService.writeToFile("initial partner: Fourth eG + fourth contact",
mermaidService.allGrantsFrom(givenDebitor.getUuid(), "view", EnumSet.of(Include.USERS, Include.DETAILS)),
"doc/all-grants-before-globalAdmin_canUpdateArbitraryDebitor.md");
assertThatDebitorIsVisibleForUserWithRole( assertThatDebitorIsVisibleForUserWithRole(
givenDebitor, givenDebitor,
"hs_office_debitor#1000420:FourtheG-fourthcontact.agent"); "hs_office_partner#10004:FourtheG-fourthcontact.admin");
final var givenNewPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First")); assertThatDebitorActuallyInDatabase(givenDebitor);
final var givenNewContact = one(contactRepo.findContactByOptionalLabelLike("sixth contact")); final var givenNewPartner = partnerRepo.findPartnerByOptionalNameLike("First").get(0);
final var givenNewBankAccount = one(bankAccountRepo.findByOptionalHolderLike("first")); final var givenNewContact = contactRepo.findContactByOptionalLabelLike("sixth contact").get(0);
final var givenNewBankAccount = bankAccountRepo.findByOptionalHolderLike("first").get(0);
final String givenNewVatId = "NEW-VAT-ID"; final String givenNewVatId = "NEW-VAT-ID";
final String givenNewVatCountryCode = "NC"; final String givenNewVatCountryCode = "NC";
final boolean givenNewVatBusiness = !givenDebitor.isVatBusiness(); final boolean givenNewVatBusiness = !givenDebitor.isVatBusiness();
@ -333,12 +305,8 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
// when // when
final var result = jpaAttempt.transacted(() -> { final var result = jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
givenDebitor.setDebitorRel(HsOfficeRelationshipEntity.builder() givenDebitor.setPartner(givenNewPartner);
.relType(HsOfficeRelationshipType.ACCOUNTING) givenDebitor.setBillingContact(givenNewContact);
.relAnchor(givenNewPartnerPerson)
.relHolder(givenNewPartnerPerson)
.contact(givenNewContact)
.build());
givenDebitor.setRefundBankAccount(givenNewBankAccount); givenDebitor.setRefundBankAccount(givenNewBankAccount);
givenDebitor.setVatId(givenNewVatId); givenDebitor.setVatId(givenNewVatId);
givenDebitor.setVatCountryCode(givenNewVatCountryCode); givenDebitor.setVatCountryCode(givenNewVatCountryCode);
@ -386,7 +354,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
givenDebitor, givenDebitor,
"hs_office_partner#10004:FourtheG-fourthcontact.admin"); "hs_office_partner#10004:FourtheG-fourthcontact.admin");
assertThatDebitorActuallyInDatabase(givenDebitor); assertThatDebitorActuallyInDatabase(givenDebitor);
final var givenNewBankAccount = one(bankAccountRepo.findByOptionalHolderLike("first")); final var givenNewBankAccount = bankAccountRepo.findByOptionalHolderLike("first").get(0);
// when // when
final var result = jpaAttempt.transacted(() -> { final var result = jpaAttempt.transacted(() -> {
@ -530,14 +498,14 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
} }
@Test @Test
public void debitorAgent_canViewButNotDeleteTheirRelatedDebitor() { public void relatedPerson_canNotDeleteTheirRelatedDebitor() {
// given // given
context("superuser-alex@hostsharing.net", null); context("superuser-alex@hostsharing.net", null);
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "eleventh", "Fourth", "ele"); final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "eleventh", "Fourth", "ele");
// when // when
final var result = jpaAttempt.transacted(() -> { final var result = jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net", "hs_office_debitor#1000420:FourtheG-fourthcontact.agent"); context("person-FourtheG@example.com");
assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent(); assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent();
debitorRepo.deleteByUuid(givenDebitor.getUuid()); debitorRepo.deleteByUuid(givenDebitor.getUuid());
@ -594,24 +562,20 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
} }
private HsOfficeDebitorEntity givenSomeTemporaryDebitor( private HsOfficeDebitorEntity givenSomeTemporaryDebitor(
final String partnerName, final String partner,
final String contactLabel, final String contact,
final String bankAccountHolder, final String bankAccount,
final String defaultPrefix) { final String defaultPrefix) {
return jpaAttempt.transacted(() -> { return jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenPartnerPerson = one(personRepo.findPersonByOptionalNameLike(partnerName)); final var givenPartner = partnerRepo.findPartnerByOptionalNameLike(partner).get(0);
final var givenContact = one(contactRepo.findContactByOptionalLabelLike(contactLabel)); final var givenContact = contactRepo.findContactByOptionalLabelLike(contact).get(0);
final var givenBankAccount = final var givenBankAccount =
bankAccountHolder != null ? one(bankAccountRepo.findByOptionalHolderLike(bankAccountHolder)) : null; bankAccount != null ? bankAccountRepo.findByOptionalHolderLike(bankAccount).get(0) : null;
final var newDebitor = HsOfficeDebitorEntity.builder() final var newDebitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix((byte)20) .debitorNumberSuffix((byte)20)
.debitorRel(HsOfficeRelationshipEntity.builder() .partner(givenPartner)
.relType(HsOfficeRelationshipType.ACCOUNTING) .billingContact(givenContact)
.relAnchor(givenPartnerPerson)
.relHolder(givenPartnerPerson)
.contact(givenContact)
.build())
.refundBankAccount(givenBankAccount) .refundBankAccount(givenBankAccount)
.defaultPrefix(defaultPrefix) .defaultPrefix(defaultPrefix)
.billable(true) .billable(true)

View File

@ -1,8 +1,7 @@
package net.hostsharing.hsadminng.hs.office.debitor; package net.hostsharing.hsadminng.hs.office.debitor;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
import static net.hostsharing.hsadminng.hs.office.contact.TestHsOfficeContact.TEST_CONTACT; import static net.hostsharing.hsadminng.hs.office.contact.TestHsOfficeContact.TEST_CONTACT;
import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER; import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER;
@ -14,12 +13,7 @@ public class TestHsOfficeDebitor {
public static final HsOfficeDebitorEntity TEST_DEBITOR = HsOfficeDebitorEntity.builder() public static final HsOfficeDebitorEntity TEST_DEBITOR = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix(DEFAULT_DEBITOR_SUFFIX) .debitorNumberSuffix(DEFAULT_DEBITOR_SUFFIX)
.debitorRel(HsOfficeRelationshipEntity.builder() .partner(TEST_PARTNER)
.relHolder(HsOfficePersonEntity.builder().build()) .billingContact(TEST_CONTACT)
.relAnchor(HsOfficePersonEntity.builder()
.optionalPartner(TEST_PARTNER)
.build())
.contact(TEST_CONTACT)
.build())
.build(); .build();
} }

View File

@ -445,7 +445,8 @@ public class ImportOfficeData extends ContextBasedTest {
final var idsToRemove = new HashSet<Integer>(); final var idsToRemove = new HashSet<Integer>();
debitors.forEach( (id, d) -> { debitors.forEach( (id, d) -> {
// such a record is in test data to test error messages // such a record is in test data to test error messages
if (false) { // TODO: how can I now empty debitors? if (d.getBillingContact() == null || d.getBillingContact().getLabel() == null ||
d.getPartner() == null || d.getPartner().getPartnerRole().getRelAnchor().getPersonType() == null ) {
idsToRemove.add(id); idsToRemove.add(id);
} }
}); });
@ -675,15 +676,10 @@ public class ImportOfficeData extends ContextBasedTest {
partners.put(rec.getInteger("bp_id"), partner); partners.put(rec.getInteger("bp_id"), partner);
final var debitor = HsOfficeDebitorEntity.builder() final var debitor = HsOfficeDebitorEntity.builder()
.partner(partner)
.debitorNumberSuffix((byte) 0) .debitorNumberSuffix((byte) 0)
.debitorRel(
HsOfficeRelationshipEntity.builder()
.relType(HsOfficeRelationshipType.ACCOUNTING)
.relAnchor(partnerRelationship.getRelHolder())
.relHolder(null) // gets set later
.build()
)
.defaultPrefix(rec.getString("member_code").replace("hsh00-", "")) .defaultPrefix(rec.getString("member_code").replace("hsh00-", ""))
.partner(partner)
.billable(rec.isEmpty("free") || rec.getString("free").equals("f")) .billable(rec.isEmpty("free") || rec.getString("free").equals("f"))
.vatReverseCharge(rec.getBoolean("exempt_vat")) .vatReverseCharge(rec.getBoolean("exempt_vat"))
.vatBusiness("GROSS".equals(rec.getString("indicator_vat"))) // TODO: remove .vatBusiness("GROSS".equals(rec.getString("indicator_vat"))) // TODO: remove
@ -850,8 +846,8 @@ public class ImportOfficeData extends ContextBasedTest {
partner.getPartnerRole().setContact(contact); partner.getPartnerRole().setContact(contact);
} }
if (containsRole(rec, "billing")) { if (containsRole(rec, "billing")) {
assertThat(debitor.getDebitorRel().getContact()).isNull(); assertThat(debitor.getBillingContact()).isNull();
debitor.getDebitorRel().setContact(contact); debitor.setBillingContact(contact);
} }
if (containsRole(rec, "operation")) { if (containsRole(rec, "operation")) {
addRelationship(partnerPerson, contactPerson, contact, HsOfficeRelationshipType.OPERATIONS); addRelationship(partnerPerson, contactPerson, contact, HsOfficeRelationshipType.OPERATIONS);

View File

@ -19,6 +19,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.EnumSet;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;

View File

@ -1,15 +0,0 @@
package net.hostsharing.hsadminng.hs.office.test;
import net.hostsharing.hsadminng.persistence.HasUuid;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class EntityList {
public static <E extends HasUuid> E one(final List<E> entities) {
assertThat(entities).hasSize(1);
return entities.stream().findFirst().orElseThrow();
}
}