feature/split-up-postalAddress (#118)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: #118
Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
Michael Hoennig 2024-11-06 12:24:37 +01:00
parent 63af33d003
commit 6191bf16e0
19 changed files with 207 additions and 89 deletions

View File

@ -54,8 +54,14 @@ public class HsOfficeContact implements Stringifyable, BaseEntity<HsOfficeContac
@Column(name = "caption") @Column(name = "caption")
private String caption; private String caption;
@Builder.Default
@Setter(AccessLevel.NONE)
@Type(JsonType.class)
@Column(name = "postaladdress") @Column(name = "postaladdress")
private String postalAddress; // multiline free-format text private Map<String, String> postalAddress = new HashMap<>();
@Transient
private PatchableMapWrapper<String> postalAddressWrapper;
@Builder.Default @Builder.Default
@Setter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
@ -75,6 +81,17 @@ public class HsOfficeContact implements Stringifyable, BaseEntity<HsOfficeContac
@Transient @Transient
private PatchableMapWrapper<String> phoneNumbersWrapper; private PatchableMapWrapper<String> phoneNumbersWrapper;
public PatchableMapWrapper<String> getPostalAddress() {
return PatchableMapWrapper.of(
postalAddressWrapper,
(newWrapper) -> {postalAddressWrapper = newWrapper;},
postalAddress);
}
public void putPostalAddress(Map<String, String> newPostalAddress) {
getPostalAddress().assign(newPostalAddress);
}
public PatchableMapWrapper<String> getEmailAddresses() { public PatchableMapWrapper<String> getEmailAddresses() {
return PatchableMapWrapper.of( return PatchableMapWrapper.of(
emailAddressesWrapper, emailAddressesWrapper,

View File

@ -18,7 +18,8 @@ class HsOfficeContactEntityPatcher implements EntityPatcher<HsOfficeContactPatch
@Override @Override
public void apply(final HsOfficeContactPatchResource resource) { public void apply(final HsOfficeContactPatchResource resource) {
OptionalFromJson.of(resource.getCaption()).ifPresent(entity::setCaption); OptionalFromJson.of(resource.getCaption()).ifPresent(entity::setCaption);
OptionalFromJson.of(resource.getPostalAddress()).ifPresent(entity::setPostalAddress); Optional.ofNullable(resource.getPostalAddress())
.ifPresent(r -> entity.getPostalAddress().patch(KeyValueMap.from(resource.getPostalAddress())));
Optional.ofNullable(resource.getEmailAddresses()) Optional.ofNullable(resource.getEmailAddresses())
.ifPresent(r -> entity.getEmailAddresses().patch(KeyValueMap.from(resource.getEmailAddresses()))); .ifPresent(r -> entity.getEmailAddresses().patch(KeyValueMap.from(resource.getEmailAddresses())));
Optional.ofNullable(resource.getPhoneNumbers()) Optional.ofNullable(resource.getPhoneNumbers())

View File

@ -47,7 +47,7 @@ public interface HsOfficeRelationRbacRepository extends Repository<HsOfficeRelat
OR lower(rel.anchor.givenName) LIKE :personData OR lower(rel.holder.givenName) LIKE :personData ) OR lower(rel.anchor.givenName) LIKE :personData OR lower(rel.holder.givenName) LIKE :personData )
AND ( :contactData IS NULL AND ( :contactData IS NULL
OR lower(rel.contact.caption) LIKE :contactData OR lower(rel.contact.caption) LIKE :contactData
OR lower(rel.contact.postalAddress) LIKE :contactData OR lower(CAST(rel.contact.postalAddress AS String)) LIKE :contactData
OR lower(CAST(rel.contact.emailAddresses AS String)) LIKE :contactData OR lower(CAST(rel.contact.emailAddresses AS String)) LIKE :contactData
OR lower(CAST(rel.contact.phoneNumbers AS String)) LIKE :contactData ) OR lower(CAST(rel.contact.phoneNumbers AS String)) LIKE :contactData )
""") """)

View File

@ -12,7 +12,7 @@ components:
caption: caption:
type: string type: string
postalAddress: postalAddress:
type: string $ref: '#/components/schemas/HsOfficeContactPostalAddress'
emailAddresses: emailAddresses:
$ref: '#/components/schemas/HsOfficeContactEmailAddresses' $ref: '#/components/schemas/HsOfficeContactEmailAddresses'
phoneNumbers: phoneNumbers:
@ -24,7 +24,7 @@ components:
caption: caption:
type: string type: string
postalAddress: postalAddress:
type: string $ref: '#/components/schemas/HsOfficeContactPostalAddress'
emailAddresses: emailAddresses:
$ref: '#/components/schemas/HsOfficeContactEmailAddresses' $ref: '#/components/schemas/HsOfficeContactEmailAddresses'
phoneNumbers: phoneNumbers:
@ -39,21 +39,48 @@ components:
type: string type: string
nullable: true nullable: true
postalAddress: postalAddress:
type: string $ref: '#/components/schemas/HsOfficeContactPostalAddress'
nullable: true
emailAddresses: emailAddresses:
$ref: '#/components/schemas/HsOfficeContactEmailAddresses' $ref: '#/components/schemas/HsOfficeContactEmailAddresses'
phoneNumbers: phoneNumbers:
$ref: '#/components/schemas/HsOfficeContactPhoneNumbers' $ref: '#/components/schemas/HsOfficeContactPhoneNumbers'
HsOfficeContactPostalAddress:
# forces generating a java.lang.Object containing a Map, instead of a class with fixed properties
anyOf:
- type: object
properties:
firm:
type: string
nullable: true
name:
type: string
nullable: true
co:
type: string
nullable: true
street:
type: string
nullable: true
zipcode:
type: string
nullable: true
city:
type: string
nullable: true
country:
type: string
nullable: true
additionalProperties: true
HsOfficeContactEmailAddresses: HsOfficeContactEmailAddresses:
# forces generating a java.lang.Object containing a Map, instead of class HsOfficeContactEmailAddresses # forces generating a java.lang.Object containing a Map, instead of a class with fixed properties
anyOf: anyOf:
- type: object - type: object
additionalProperties: true additionalProperties: true
HsOfficeContactPhoneNumbers: HsOfficeContactPhoneNumbers:
# forces generating a java.lang.Object containing a Map, instead of class HsOfficeContactEmailAddresses # forces generating a java.lang.Object containing a Map, instead of a class with fixed properties
anyOf: anyOf:
- type: object - type: object
properties: properties:

View File

@ -9,7 +9,7 @@ create table if not exists hs_office.contact
uuid uuid unique references rbac.object (uuid) initially deferred, uuid uuid unique references rbac.object (uuid) initially deferred,
version int not null default 0, version int not null default 0,
caption varchar(128) not null, caption varchar(128) not null,
postalAddress text, postalAddress jsonb not null,
emailAddresses jsonb not null, emailAddresses jsonb not null,
phoneNumbers jsonb not null phoneNumbers jsonb not null
); );

View File

@ -11,7 +11,6 @@
create or replace procedure hs_office.contact_create_test_data(contCaption varchar) create or replace procedure hs_office.contact_create_test_data(contCaption varchar)
language plpgsql as $$ language plpgsql as $$
declare declare
postalAddr varchar;
emailAddr varchar; emailAddr varchar;
begin begin
emailAddr = 'contact-admin@' || base.cleanIdentifier(contCaption) || '.example.com'; emailAddr = 'contact-admin@' || base.cleanIdentifier(contCaption) || '.example.com';
@ -19,14 +18,18 @@ begin
perform rbac.create_subject(emailAddr); perform rbac.create_subject(emailAddr);
call base.defineContext('creating contact test-data', null, emailAddr); call base.defineContext('creating contact test-data', null, emailAddr);
postalAddr := E'Vorname Nachname\nStraße Hnr\nPLZ Stadt';
raise notice 'creating test contact: %', contCaption; raise notice 'creating test contact: %', contCaption;
insert insert
into hs_office.contact (caption, postaladdress, emailaddresses, phonenumbers) into hs_office.contact (caption, postaladdress, emailaddresses, phonenumbers)
values ( values (
contCaption, contCaption,
postalAddr, ( '{ ' ||
-- '"name": "' || contCaption || '",' ||
-- '"street": "Somewhere 1",' ||
-- '"zipcode": "12345",' ||
-- '"city": "Where-Ever",' ||
'"country": "Germany"' ||
'}')::jsonb,
('{ "main": "' || emailAddr || '" }')::jsonb, ('{ "main": "' || emailAddr || '" }')::jsonb,
('{ "phone_office": "+49 123 1234567" }')::jsonb ('{ "phone_office": "+49 123 1234567" }')::jsonb
); );

View File

@ -110,7 +110,6 @@ public class HsHostingAssetControllerRestTest {
"caption": "some fake cloud-server", "caption": "some fake cloud-server",
"alarmContact": { "alarmContact": {
"caption": "some contact", "caption": "some contact",
"postalAddress": "address of some contact",
"emailAddresses": { "emailAddresses": {
"main": "some-contact@example.com" "main": "some-contact@example.com"
} }
@ -141,7 +140,6 @@ public class HsHostingAssetControllerRestTest {
"caption": "some fake managed-server", "caption": "some fake managed-server",
"alarmContact": { "alarmContact": {
"caption": "some contact", "caption": "some contact",
"postalAddress": "address of some contact",
"emailAddresses": { "emailAddresses": {
"main": "some-contact@example.com" "main": "some-contact@example.com"
} }

View File

@ -1111,7 +1111,7 @@ public abstract class BaseOfficeDataImport extends CsvDataImport {
contactRecord.getString("last_name"), contactRecord.getString("last_name"),
contactRecord.getString("firma"))); contactRecord.getString("firma")));
contact.putEmailAddresses(Map.of("main", contactRecord.getString("email"))); contact.putEmailAddresses(Map.of("main", contactRecord.getString("email")));
contact.setPostalAddress(toAddress(contactRecord)); contact.putPostalAddress(toAddress(contactRecord));
contact.putPhoneNumbers(toPhoneNumbers(contactRecord)); contact.putPhoneNumbers(toPhoneNumbers(contactRecord));
contacts.put(contactRecord.getInteger("contact_id"), contact); contacts.put(contactRecord.getInteger("contact_id"), contact);
@ -1131,36 +1131,23 @@ public abstract class BaseOfficeDataImport extends CsvDataImport {
return phoneNumbers; return phoneNumbers;
} }
private String toAddress(final Record rec) { private Map<String, String> toAddress(final Record rec) {
final var result = new StringBuilder(); final var result = new LinkedHashMap<String, String>();
final var name = toName( final var name = toName(
rec.getString("salut"), rec.getString("salut"),
rec.getString("title"), rec.getString("title"),
rec.getString("first_name"), rec.getString("first_name"),
rec.getString("last_name")); rec.getString("last_name"));
if (isNotBlank(name)) if (isNotBlank(name))
result.append(name + "\n"); result.put("name", name);
if (isNotBlank(rec.getString("firma"))) if (isNotBlank(rec.getString("firma")))
result.append(rec.getString("firma") + "\n"); result.put("firm", name);
if (isNotBlank(rec.getString("co")))
result.append("c/o " + rec.getString("co") + "\n");
if (isNotBlank(rec.getString("street")))
result.append(rec.getString("street") + "\n");
final var zipcodeAndCity = toZipcodeAndCity(rec);
if (isNotBlank(zipcodeAndCity))
result.append(zipcodeAndCity + "\n");
return result.toString();
}
private String toZipcodeAndCity(final Record rec) { List.of("co", "street", "zipcode", "city", "country").forEach(key -> {
final var result = new StringBuilder(); if (isNotBlank(rec.getString(key)))
if (isNotBlank(rec.getString("country"))) result.put(key, rec.getString(key));
result.append(rec.getString("country") + " "); });
if (isNotBlank(rec.getString("zipcode"))) return result;
result.append(rec.getString("zipcode") + " ");
if (isNotBlank(rec.getString("city")))
result.append(rec.getString("city"));
return result.toString();
} }
private String toCaption( private String toCaption(

View File

@ -21,10 +21,13 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import static java.util.Map.entry;
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.hasEntry;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.startsWith;
@ -214,7 +217,11 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
"emailAddresses": { "emailAddresses": {
"main": "patched@example.org" "main": "patched@example.org"
}, },
"postalAddress": "Patched Address", "postalAddress": {
"extra": "Extra Property",
"co": "P. Patcher",
"street": "Patchstraße 5"
},
"phoneNumbers": { "phoneNumbers": {
"phone_office": "+01 100 123456" "phone_office": "+01 100 123456"
} }
@ -229,7 +236,10 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
.body("uuid", isUuidValid()) .body("uuid", isUuidValid())
.body("caption", is("Temp patched contact")) .body("caption", is("Temp patched contact"))
.body("emailAddresses", is(Map.of("main", "patched@example.org"))) .body("emailAddresses", is(Map.of("main", "patched@example.org")))
.body("postalAddress", is("Patched Address")) .body("postalAddress", hasEntry("name", givenContact.getPostalAddress().get("name"))) // unchanged
.body("postalAddress", hasEntry("extra", "Extra Property")) // unchanged
.body("postalAddress", hasEntry("co", "P. Patcher")) // patched
.body("postalAddress", hasEntry("street", "Patchstraße 5")) // patched
.body("phoneNumbers", is(Map.of("phone_office", "+01 100 123456"))); .body("phoneNumbers", is(Map.of("phone_office", "+01 100 123456")));
// @formatter:on // @formatter:on
@ -239,7 +249,11 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
.matches(person -> { .matches(person -> {
assertThat(person.getCaption()).isEqualTo("Temp patched contact"); assertThat(person.getCaption()).isEqualTo("Temp patched contact");
assertThat(person.getEmailAddresses()).containsExactlyEntriesOf(Map.of("main", "patched@example.org")); assertThat(person.getEmailAddresses()).containsExactlyEntriesOf(Map.of("main", "patched@example.org"));
assertThat(person.getPostalAddress()).isEqualTo("Patched Address"); assertThat(person.getPostalAddress()).containsAllEntriesOf(Map.ofEntries(
entry("name", givenContact.getPostalAddress().get("name")),
entry("co", "P. Patcher"),
entry("street", "Patchstraße 5")
));
assertThat(person.getPhoneNumbers()).containsExactlyEntriesOf(Map.of("phone_office", "+01 100 123456")); assertThat(person.getPhoneNumbers()).containsExactlyEntriesOf(Map.of("phone_office", "+01 100 123456"));
return true; return true;
}); });
@ -274,7 +288,6 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
.body("uuid", isUuidValid()) .body("uuid", isUuidValid())
.body("caption", is(givenContact.getCaption())) .body("caption", is(givenContact.getCaption()))
.body("emailAddresses", is(Map.of("main", "patched@example.org"))) .body("emailAddresses", is(Map.of("main", "patched@example.org")))
.body("postalAddress", is(givenContact.getPostalAddress()))
.body("phoneNumbers", is(Map.of("phone_office", "+01 100 123456"))); .body("phoneNumbers", is(Map.of("phone_office", "+01 100 123456")));
// @formatter:on // @formatter:on
@ -283,12 +296,11 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
.matches(person -> { .matches(person -> {
assertThat(person.getCaption()).isEqualTo(givenContact.getCaption()); assertThat(person.getCaption()).isEqualTo(givenContact.getCaption());
assertThat(person.getEmailAddresses()).containsExactlyEntriesOf(Map.of("main", "patched@example.org")); assertThat(person.getEmailAddresses()).containsExactlyEntriesOf(Map.of("main", "patched@example.org"));
assertThat(person.getPostalAddress()).isEqualTo(givenContact.getPostalAddress()); assertThat(person.getPostalAddress()).containsExactlyInAnyOrderEntriesOf(givenContact.getPostalAddress());
assertThat(person.getPhoneNumbers()).containsExactlyEntriesOf(Map.of("phone_office", "+01 100 123456")); assertThat(person.getPhoneNumbers()).containsExactlyEntriesOf(Map.of("phone_office", "+01 100 123456"));
return true; return true;
}); });
} }
} }
@Nested @Nested
@ -361,8 +373,13 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
final var newContact = HsOfficeContactRbacEntity.builder() final var newContact = HsOfficeContactRbacEntity.builder()
.uuid(UUID.randomUUID()) .uuid(UUID.randomUUID())
.caption("Temp from " + Context.getCallerMethodNameFromStackFrame(1) ) .caption("Temp from " + Context.getCallerMethodNameFromStackFrame(1) )
.postalAddress(Map.ofEntries(
entry("name", RandomStringUtils.randomAlphabetic(6) + " " + RandomStringUtils.randomAlphabetic(10)),
entry("street", RandomStringUtils.randomAlphabetic(10) + randomInt(1, 99)),
entry("zipcode", "D-" + randomInt(10000, 99999)),
entry("city", RandomStringUtils.randomAlphabetic(10))
))
.emailAddresses(Map.of("main", RandomStringUtils.randomAlphabetic(10) + "@example.org")) .emailAddresses(Map.of("main", RandomStringUtils.randomAlphabetic(10) + "@example.org"))
.postalAddress("Postal Address " + RandomStringUtils.randomAlphabetic(10))
.phoneNumbers(Map.of("phone_office", "+01 200 " + RandomStringUtils.randomNumeric(8))) .phoneNumbers(Map.of("phone_office", "+01 200 " + RandomStringUtils.randomNumeric(8)))
.build(); .build();
@ -378,4 +395,8 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
em.createQuery("DELETE FROM HsOfficeContactRbacEntity c WHERE c.caption LIKE 'Temp %'").executeUpdate(); em.createQuery("DELETE FROM HsOfficeContactRbacEntity c WHERE c.caption LIKE 'Temp %'").executeUpdate();
}).assertSuccessful(); }).assertSuccessful();
} }
private int randomInt(final int min, final int max) {
return ThreadLocalRandom.current().nextInt(min, max);
}
} }

View File

@ -19,6 +19,19 @@ class HsOfficeContactPatcherUnitTest extends PatchUnitTestBase<
> { > {
private static final UUID INITIAL_CONTACT_UUID = UUID.randomUUID(); private static final UUID INITIAL_CONTACT_UUID = UUID.randomUUID();
private static final Map<String, String> PATCH_POSTAL_ADDRESS = patchMap(
entry("name", "Patty Patch"),
entry("street", "Patchstreet 10"),
entry("zipcode", null),
entry("city", "Hamburg")
);
private static final Map<String, String> PATCHED_POSTAL_ADDRESS = patchMap(
entry("name", "Patty Patch"),
entry("street", "Patchstreet 10"),
entry("city", "Hamburg")
);
private static final Map<String, String> PATCH_EMAIL_ADDRESSES = patchMap( private static final Map<String, String> PATCH_EMAIL_ADDRESSES = patchMap(
entry("main", "patched@example.com"), entry("main", "patched@example.com"),
entry("paul", null), entry("paul", null),
@ -46,6 +59,11 @@ class HsOfficeContactPatcherUnitTest extends PatchUnitTestBase<
final var entity = new HsOfficeContactRbacEntity(); final var entity = new HsOfficeContactRbacEntity();
entity.setUuid(INITIAL_CONTACT_UUID); entity.setUuid(INITIAL_CONTACT_UUID);
entity.setCaption("initial caption"); entity.setCaption("initial caption");
entity.putPostalAddress(Map.ofEntries(
entry("name", "Ina Initial"),
entry("street", "Initialstraße 50"),
entry("zipcode", "20000"),
entry("city", "Hamburg")));
entity.putEmailAddresses(Map.ofEntries( entity.putEmailAddresses(Map.ofEntries(
entry("main", "initial@example.org"), entry("main", "initial@example.org"),
entry("paul", "paul@example.com"), entry("paul", "paul@example.com"),
@ -54,7 +72,6 @@ class HsOfficeContactPatcherUnitTest extends PatchUnitTestBase<
entry("phone_office", "+49 40 12345-00"), entry("phone_office", "+49 40 12345-00"),
entry("phone_mobile", "+49 1555 1234567"), entry("phone_mobile", "+49 1555 1234567"),
entry("fax", "+49 40 12345-90"))); entry("fax", "+49 40 12345-90")));
entity.setPostalAddress("Initialstraße 50\n20000 Hamburg");
return entity; return entity;
} }
@ -77,24 +94,26 @@ class HsOfficeContactPatcherUnitTest extends PatchUnitTestBase<
"patched caption", "patched caption",
HsOfficeContactRbacEntity::setCaption), HsOfficeContactRbacEntity::setCaption),
new SimpleProperty<>( new SimpleProperty<>(
"resources", "postalAddress",
HsOfficeContactPatchResource::setPostalAddress,
PATCH_POSTAL_ADDRESS,
HsOfficeContactRbacEntity::putPostalAddress,
PATCHED_POSTAL_ADDRESS)
.notNullable(),
new SimpleProperty<>(
"emailAddresses",
HsOfficeContactPatchResource::setEmailAddresses, HsOfficeContactPatchResource::setEmailAddresses,
PATCH_EMAIL_ADDRESSES, PATCH_EMAIL_ADDRESSES,
HsOfficeContactRbacEntity::putEmailAddresses, HsOfficeContactRbacEntity::putEmailAddresses,
PATCHED_EMAIL_ADDRESSES) PATCHED_EMAIL_ADDRESSES)
.notNullable(), .notNullable(),
new SimpleProperty<>( new SimpleProperty<>(
"resources", "phoneNumbers",
HsOfficeContactPatchResource::setPhoneNumbers, HsOfficeContactPatchResource::setPhoneNumbers,
PATCH_PHONE_NUMBERS, PATCH_PHONE_NUMBERS,
HsOfficeContactRbacEntity::putPhoneNumbers, HsOfficeContactRbacEntity::putPhoneNumbers,
PATCHED_PHONE_NUMBERS) PATCHED_PHONE_NUMBERS)
.notNullable(), .notNullable()
new JsonNullableProperty<>(
"patched given name",
HsOfficeContactPatchResource::setPostalAddress,
"patched given name",
HsOfficeContactRbacEntity::setPostalAddress)
); );
} }
} }

View File

@ -2,6 +2,8 @@ package net.hostsharing.hsadminng.hs.office.contact;
import java.util.Map; import java.util.Map;
import static java.util.Map.entry;
public class HsOfficeContactRbacTestEntity { public class HsOfficeContactRbacTestEntity {
public static final HsOfficeContactRbacEntity TEST_RBAC_CONTACT = hsOfficeContact("some contact", "some-contact@example.com"); public static final HsOfficeContactRbacEntity TEST_RBAC_CONTACT = hsOfficeContact("some contact", "some-contact@example.com");
@ -9,7 +11,12 @@ public class HsOfficeContactRbacTestEntity {
static public HsOfficeContactRbacEntity hsOfficeContact(final String caption, final String emailAddr) { static public HsOfficeContactRbacEntity hsOfficeContact(final String caption, final String emailAddr) {
return HsOfficeContactRbacEntity.builder() return HsOfficeContactRbacEntity.builder()
.caption(caption) .caption(caption)
.postalAddress("address of " + caption) .postalAddress(Map.ofEntries(
entry("name", "M. Meyer"),
entry("street", "Teststraße 11"),
entry("zipcode", "D-12345"),
entry("city", "Berlin")
))
.emailAddresses(Map.of("main", emailAddr)) .emailAddresses(Map.of("main", emailAddr))
.build(); .build();
} }

View File

@ -2,6 +2,8 @@ package net.hostsharing.hsadminng.hs.office.contact;
import java.util.Map; import java.util.Map;
import static java.util.Map.entry;
public class HsOfficeContactRealTestEntity { public class HsOfficeContactRealTestEntity {
public static final HsOfficeContactRealEntity TEST_REAL_CONTACT = hsOfficeContact("some contact", "some-contact@example.com"); public static final HsOfficeContactRealEntity TEST_REAL_CONTACT = hsOfficeContact("some contact", "some-contact@example.com");
@ -9,7 +11,12 @@ public class HsOfficeContactRealTestEntity {
static public HsOfficeContactRealEntity hsOfficeContact(final String caption, final String emailAddr) { static public HsOfficeContactRealEntity hsOfficeContact(final String caption, final String emailAddr) {
return HsOfficeContactRealEntity.builder() return HsOfficeContactRealEntity.builder()
.caption(caption) .caption(caption)
.postalAddress("address of " + caption) .postalAddress(Map.ofEntries(
entry("name", "M. Meyer"),
entry("street", "Teststraße 11"),
entry("zipcode", "D-12345"),
entry("city", "Berlin")
))
.emailAddresses(Map.of("main", emailAddr)) .emailAddresses(Map.of("main", emailAddr))
.build(); .build();
} }

View File

@ -460,10 +460,13 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
"type": "DEBITOR", "type": "DEBITOR",
"contact": { "contact": {
"caption": "first contact", "caption": "first contact",
"postalAddress": "Vorname Nachname\\nStraße Hnr\\nPLZ Stadt", "postalAddress": {
"country": "Germany"
},
"emailAddresses": { "main": "contact-admin@firstcontact.example.com" }, "emailAddresses": { "main": "contact-admin@firstcontact.example.com" },
"phoneNumbers": { "phone_office": "+49 123 1234567" } "phoneNumbers": { "phone_office": "+49 123 1234567" }
} }
}
}, },
"debitorNumber": 1000111, "debitorNumber": 1000111,
"debitorNumberSuffix": "11", "debitorNumberSuffix": "11",
@ -476,10 +479,11 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
"mark": null, "mark": null,
"contact": { "contact": {
"caption": "first contact", "caption": "first contact",
"postalAddress": "Vorname Nachname\\nStraße Hnr\\nPLZ Stadt", "postalAddress": {
"country": "Germany"
},
"emailAddresses": { "main": "contact-admin@firstcontact.example.com" }, "emailAddresses": { "main": "contact-admin@firstcontact.example.com" },
"phoneNumbers": { "phone_office": "+49 123 1234567" } "phoneNumbers": { "phone_office": "+49 123 1234567" }
}
}, },
"details": { "details": {
"registrationOffice": "Hamburg", "registrationOffice": "Hamburg",

View File

@ -199,7 +199,9 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
"type": "REPRESENTATIVE", "type": "REPRESENTATIVE",
"contact": { "contact": {
"caption": "first contact", "caption": "first contact",
"postalAddress": "Vorname Nachname\\nStraße Hnr\\nPLZ Stadt", "postalAddress": {
"country": "Germany"
},
"emailAddresses": { "emailAddresses": {
"main": "contact-admin@firstcontact.example.com" "main": "contact-admin@firstcontact.example.com"
}, },

View File

@ -55,8 +55,11 @@ class HsOfficeScenarioTests extends ScenarioTest {
.given("tradeName", "Test AG") .given("tradeName", "Test AG")
.given("contactCaption", "Test AG - Hamburg") .given("contactCaption", "Test AG - Hamburg")
.given("postalAddress", """ .given("postalAddress", """
Shanghai-Allee 1 "firm": "Test AG",
20123 Hamburg "street": "Shanghai-Allee 1",
"zipcode": "20123",
"city": "Hamburg",
"country": "Germany"
""") """)
.given("officePhoneNumber", "+49 40 654321-0") .given("officePhoneNumber", "+49 40 654321-0")
.given("emailAddress", "hamburg@test-ag.example.org") .given("emailAddress", "hamburg@test-ag.example.org")
@ -75,8 +78,11 @@ class HsOfficeScenarioTests extends ScenarioTest {
.given("familyName", "Matthieu") .given("familyName", "Matthieu")
.given("contactCaption", "Michelle Matthieu") .given("contactCaption", "Michelle Matthieu")
.given("postalAddress", """ .given("postalAddress", """
An der Wandse 34 "name": "Michelle Matthieu",
22123 Hamburg "street": "An der Wandse 34",
"zipcode": "22123",
"city": "Hamburg",
"country": "Germany"
""") """)
.given("officePhoneNumber", "+49 40 123456") .given("officePhoneNumber", "+49 40 123456")
.given("emailAddress", "michelle.matthieu@example.org") .given("emailAddress", "michelle.matthieu@example.org")
@ -94,8 +100,11 @@ class HsOfficeScenarioTests extends ScenarioTest {
.given("representativeFamilyName", "Trust") .given("representativeFamilyName", "Trust")
.given("representativeGivenName", "Tracy") .given("representativeGivenName", "Tracy")
.given("representativePostalAddress", """ .given("representativePostalAddress", """
An der Alster 100 "name": "Michelle Matthieu",
20000 Hamburg "street": "An der Alster 100",
"zipcode": "20000",
"city": "Hamburg",
"country": "Germany"
""") """)
.given("representativePhoneNumber", "+49 40 123456") .given("representativePhoneNumber", "+49 40 123456")
.given("representativeEMailAddress", "tracy.trust@example.org") .given("representativeEMailAddress", "tracy.trust@example.org")
@ -172,12 +181,18 @@ class HsOfficeScenarioTests extends ScenarioTest {
void shouldReplaceContactData() { void shouldReplaceContactData() {
new ReplaceContactData(this) new ReplaceContactData(this)
.given("partnerName", "Test AG") .given("partnerName", "Test AG")
.given("newContactCaption", "Test AG - Norden") .given("newContactCaption", "Test AG - China")
.given("newPostalAddress", """ .given("newPostalAddress", """
Am Hafen 11 "firm": "Test AG",
26506 Norden "name": "Fi Zhong-Kha",
"building": "Thi Chi Koh Building",
"street": "No.2 Commercial Second Street",
"district": "Niushan Wei Wu",
"city": "Dongguan City",
"province": "Guangdong Province",
"country": "China"
""") """)
.given("newOfficePhoneNumber", "+49 4931 654321-0") .given("newOfficePhoneNumber", "++15 999 654321" )
.given("newEmailAddress", "norden@test-ag.example.org") .given("newEmailAddress", "norden@test-ag.example.org")
.doRun(); .doRun();
} }

View File

@ -27,7 +27,9 @@ public class AmendContactData extends UseCase<AmendContactData> {
httpPatch("/api/hs/office/contacts/%{partnerContactUuid}", usingJsonBody(""" httpPatch("/api/hs/office/contacts/%{partnerContactUuid}", usingJsonBody("""
{ {
"caption": ${newContactCaption???}, "caption": ${newContactCaption???},
"postalAddress": ${newPostalAddress???}, "postalAddress": {
%{newPostalAddress???}
},
"phoneNumbers": { "phoneNumbers": {
"office": ${newOfficePhoneNumber???} "office": ${newOfficePhoneNumber???}
}, },

View File

@ -27,7 +27,9 @@ public class ReplaceContactData extends UseCase<ReplaceContactData> {
httpPost("/api/hs/office/contacts", usingJsonBody(""" httpPost("/api/hs/office/contacts", usingJsonBody("""
{ {
"caption": ${newContactCaption}, "caption": ${newContactCaption},
"postalAddress": ${newPostalAddress???}, "postalAddress": {
%{newPostalAddress???}
},
"phoneNumbers": { "phoneNumbers": {
"phone": ${newOfficePhoneNumber???} "phone": ${newOfficePhoneNumber???}
}, },
@ -37,8 +39,10 @@ public class ReplaceContactData extends UseCase<ReplaceContactData> {
} }
""")) """))
.expecting(CREATED).expecting(JSON), .expecting(CREATED).expecting(JSON),
"Please check first if that contact already exists, if so, use it's UUID below." "Please check first if that contact already exists, if so, use it's UUID below.",
); "If any `postalAddress` sub-properties besides those specified in the API " +
"(currently `firm`, `name`, `co`, `street`, `zipcode`, `city`, `country`) " +
"its values might not appear in external systems.");
withTitle("Replace the Contact-Reference in the Partner-Relation", () -> withTitle("Replace the Contact-Reference in the Partner-Relation", () ->
httpPatch("/api/hs/office/relations/%{partnerRelationUuid}", usingJsonBody(""" httpPatch("/api/hs/office/relations/%{partnerRelationUuid}", usingJsonBody("""

View File

@ -42,7 +42,9 @@ public class AddRepresentativeToPartner extends UseCase<AddRepresentativeToPartn
httpPost("/api/hs/office/contacts", usingJsonBody(""" httpPost("/api/hs/office/contacts", usingJsonBody("""
{ {
"caption": "%{representativeGivenName} %{representativeFamilyName}", "caption": "%{representativeGivenName} %{representativeFamilyName}",
"postalAddress": ${representativePostalAddress}, "postalAddress": {
%{representativePostalAddress}
},
"phoneNumbers": { "phoneNumbers": {
"main": ${representativePhoneNumber} "main": ${representativePhoneNumber}
}, },

View File

@ -44,7 +44,9 @@ public class CreatePartner extends UseCase<CreatePartner> {
httpPost("/api/hs/office/contacts", usingJsonBody(""" httpPost("/api/hs/office/contacts", usingJsonBody("""
{ {
"caption": ${contactCaption}, "caption": ${contactCaption},
"postalAddress": ${postalAddress???}, "postalAddress": {
%{postalAddress???}
},
"phoneNumbers": { "phoneNumbers": {
"office": ${officePhoneNumber???} "office": ${officePhoneNumber???}
}, },