Compare commits
7 Commits
2d81d3f6fd
...
2aeb8fef6f
Author | SHA1 | Date | |
---|---|---|---|
|
2aeb8fef6f | ||
|
3c2f607f0b | ||
|
8f4ac8b2bf | ||
|
17a73918f5 | ||
|
82573d1c9f | ||
|
53c3b04ba1 | ||
|
10cd4bd0e8 |
14
doc/hs-office-mailinglist-subscriptions.md
Normal file
14
doc/hs-office-mailinglist-subscriptions.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Sketch UI for mailinglist subscriptions
|
||||||
|
|
||||||
|
```PlantUML
|
||||||
|
@startsalt
|
||||||
|
{{^==Mailinglist-Subscriptions
|
||||||
|
Members-Announce: | [<color:#9a9a9a>X</color>] | ^frank.meiler@example.org^ | [Create New]
|
||||||
|
Members-Discussion: | [X] | ^frank.meiler@example.org^ | [Create New]
|
||||||
|
Customers-Announce: | [<color:#9a9a9a>X</color>] | ^frank.meiler@example.org^ | [Create New]
|
||||||
|
Operations-Announce: | [<color:#9a9a9a>X</color>] | ^Default Contact Data^ | [Create New]
|
||||||
|
Operations-Discussion: | [ ] | ^ ^ | [Create New]
|
||||||
|
|
||||||
|
}}
|
||||||
|
@endsalt
|
||||||
|
```
|
@ -26,6 +26,7 @@ public class HsOfficeRelationshipEntity implements HasUuid, Stringifyable {
|
|||||||
private static Stringify<HsOfficeRelationshipEntity> toString = stringify(HsOfficeRelationshipEntity.class, "rel")
|
private static Stringify<HsOfficeRelationshipEntity> toString = stringify(HsOfficeRelationshipEntity.class, "rel")
|
||||||
.withProp(Fields.relAnchor, HsOfficeRelationshipEntity::getRelAnchor)
|
.withProp(Fields.relAnchor, HsOfficeRelationshipEntity::getRelAnchor)
|
||||||
.withProp(Fields.relType, HsOfficeRelationshipEntity::getRelType)
|
.withProp(Fields.relType, HsOfficeRelationshipEntity::getRelType)
|
||||||
|
.withProp(Fields.relMark, HsOfficeRelationshipEntity::getRelMark)
|
||||||
.withProp(Fields.relHolder, HsOfficeRelationshipEntity::getRelHolder)
|
.withProp(Fields.relHolder, HsOfficeRelationshipEntity::getRelHolder)
|
||||||
.withProp(Fields.contact, HsOfficeRelationshipEntity::getContact);
|
.withProp(Fields.contact, HsOfficeRelationshipEntity::getContact);
|
||||||
|
|
||||||
@ -54,6 +55,9 @@ public class HsOfficeRelationshipEntity implements HasUuid, Stringifyable {
|
|||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private HsOfficeRelationshipType relType;
|
private HsOfficeRelationshipType relType;
|
||||||
|
|
||||||
|
@Column(name = "relmark")
|
||||||
|
private String relMark;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return toString.apply(this);
|
return toString.apply(this);
|
||||||
|
@ -7,5 +7,6 @@ public enum HsOfficeRelationshipType {
|
|||||||
REPRESENTATIVE,
|
REPRESENTATIVE,
|
||||||
VIP_CONTACT,
|
VIP_CONTACT,
|
||||||
ACCOUNTING,
|
ACCOUNTING,
|
||||||
OPERATIONS
|
OPERATIONS,
|
||||||
|
SUBSCRIBER
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ components:
|
|||||||
- VIP_CONTACT
|
- VIP_CONTACT
|
||||||
- ACCOUNTING,
|
- ACCOUNTING,
|
||||||
- OPERATIONS
|
- OPERATIONS
|
||||||
|
- SUBSCRIBER
|
||||||
|
|
||||||
HsOfficeRelationship:
|
HsOfficeRelationship:
|
||||||
type: object
|
type: object
|
||||||
@ -25,6 +26,9 @@ components:
|
|||||||
$ref: './hs-office-person-schemas.yaml#/components/schemas/HsOfficePerson'
|
$ref: './hs-office-person-schemas.yaml#/components/schemas/HsOfficePerson'
|
||||||
relType:
|
relType:
|
||||||
type: string
|
type: string
|
||||||
|
relMark:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
contact:
|
contact:
|
||||||
$ref: './hs-office-contact-schemas.yaml#/components/schemas/HsOfficeContact'
|
$ref: './hs-office-contact-schemas.yaml#/components/schemas/HsOfficeContact'
|
||||||
|
|
||||||
@ -48,6 +52,8 @@ components:
|
|||||||
relType:
|
relType:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
|
relMark:
|
||||||
|
type: string
|
||||||
contactUuid:
|
contactUuid:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
@ -53,6 +53,19 @@ create table tx_journal
|
|||||||
create index on tx_journal (targetTable, targetUuid);
|
create index on tx_journal (targetTable, targetUuid);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset audit-TX-JOURNAL-VIEW:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
A view combining tx_journal with tx_context.
|
||||||
|
*/
|
||||||
|
create view tx_journal_v as
|
||||||
|
select txc.*, txj.targettable, txj.targetop, txj.targetuuid, txj.targetdelta
|
||||||
|
from tx_journal txj
|
||||||
|
left join tx_context txc using (contextid)
|
||||||
|
order by txc.txtimestamp;
|
||||||
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset audit-TX-JOURNAL-TRIGGER:1 endDelimiter:--//
|
--changeset audit-TX-JOURNAL-TRIGGER:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
@ -11,7 +11,8 @@ CREATE TYPE HsOfficeRelationshipType AS ENUM (
|
|||||||
'REPRESENTATIVE',
|
'REPRESENTATIVE',
|
||||||
'VIP_CONTACT',
|
'VIP_CONTACT',
|
||||||
'ACCOUNTING',
|
'ACCOUNTING',
|
||||||
'OPERATIONS');
|
'OPERATIONS',
|
||||||
|
'SUBSCRIBER');
|
||||||
|
|
||||||
CREATE CAST (character varying as HsOfficeRelationshipType) WITH INOUT AS IMPLICIT;
|
CREATE CAST (character varying as HsOfficeRelationshipType) WITH INOUT AS IMPLICIT;
|
||||||
|
|
||||||
@ -21,7 +22,8 @@ create table if not exists hs_office_relationship
|
|||||||
relAnchorUuid uuid not null references hs_office_person(uuid),
|
relAnchorUuid uuid not null references hs_office_person(uuid),
|
||||||
relHolderUuid uuid not null references hs_office_person(uuid),
|
relHolderUuid uuid not null references hs_office_person(uuid),
|
||||||
contactUuid uuid references hs_office_contact(uuid),
|
contactUuid uuid references hs_office_contact(uuid),
|
||||||
relType HsOfficeRelationshipType not null
|
relType HsOfficeRelationshipType not null,
|
||||||
|
relMark varchar(24)
|
||||||
);
|
);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
@ -12,7 +12,8 @@ create or replace procedure createHsOfficeRelationshipTestData(
|
|||||||
holderPersonName varchar,
|
holderPersonName varchar,
|
||||||
relationshipType HsOfficeRelationshipType,
|
relationshipType HsOfficeRelationshipType,
|
||||||
anchorPersonTradeName varchar,
|
anchorPersonTradeName varchar,
|
||||||
contactLabel varchar)
|
contactLabel varchar,
|
||||||
|
mark varchar default null)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
declare
|
declare
|
||||||
currentTask varchar;
|
currentTask varchar;
|
||||||
@ -49,8 +50,8 @@ begin
|
|||||||
raise notice '- using holder person (%): %', holderPerson.uuid, holderPerson;
|
raise notice '- using holder person (%): %', holderPerson.uuid, holderPerson;
|
||||||
raise notice '- using contact (%): %', contact.uuid, contact;
|
raise notice '- using contact (%): %', contact.uuid, contact;
|
||||||
insert
|
insert
|
||||||
into hs_office_relationship (uuid, relanchoruuid, relholderuuid, reltype, contactUuid)
|
into hs_office_relationship (uuid, relanchoruuid, relholderuuid, reltype, relmark, contactUuid)
|
||||||
values (uuid_generate_v4(), anchorPerson.uuid, holderPerson.uuid, relationshipType, contact.uuid);
|
values (uuid_generate_v4(), anchorPerson.uuid, holderPerson.uuid, relationshipType, mark, contact.uuid);
|
||||||
end; $$;
|
end; $$;
|
||||||
--//
|
--//
|
||||||
|
|
||||||
@ -97,7 +98,7 @@ do language plpgsql $$
|
|||||||
call createHsOfficeRelationshipTestData('Fouler', 'REPRESENTATIVE', 'Third OHG', 'third contact');
|
call createHsOfficeRelationshipTestData('Fouler', 'REPRESENTATIVE', 'Third OHG', 'third contact');
|
||||||
|
|
||||||
call createHsOfficeRelationshipTestData('Smith', 'PARTNER', 'Hostsharing eG', 'sixth contact');
|
call createHsOfficeRelationshipTestData('Smith', 'PARTNER', 'Hostsharing eG', 'sixth contact');
|
||||||
|
call createHsOfficeRelationshipTestData('Smith', 'SUBSCRIBER', 'Third OHG', 'third contact', 'members-announce');
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
--//
|
--//
|
||||||
|
@ -33,7 +33,7 @@ create table hs_office_partner
|
|||||||
(
|
(
|
||||||
uuid uuid unique references RbacObject (uuid) initially deferred,
|
uuid uuid unique references RbacObject (uuid) initially deferred,
|
||||||
partnerNumber numeric(5),
|
partnerNumber numeric(5),
|
||||||
partnerRoleUuid uuid not null references hs_office_relationship(uuid),
|
partnerRoleUuid uuid not null references hs_office_relationship(uuid) on delete cascade,
|
||||||
personUuid uuid not null references hs_office_person(uuid), -- TODO: remove, replaced by partnerRoleUuid
|
personUuid uuid not null references hs_office_person(uuid), -- TODO: remove, replaced by partnerRoleUuid
|
||||||
contactUuid uuid not null references hs_office_contact(uuid), -- TODO: remove, replaced by partnerRoleUuid
|
contactUuid uuid not null references hs_office_contact(uuid), -- TODO: remove, replaced by partnerRoleUuid
|
||||||
detailsUuid uuid not null references hs_office_partner_details(uuid) on delete cascade
|
detailsUuid uuid not null references hs_office_partner_details(uuid) on delete cascade
|
||||||
|
@ -27,12 +27,17 @@ create or replace function hsOfficePartnerRbacRolesTrigger()
|
|||||||
language plpgsql
|
language plpgsql
|
||||||
strict as $$
|
strict as $$
|
||||||
declare
|
declare
|
||||||
|
oldPartnerRole hs_office_relationship;
|
||||||
|
newPartnerRole hs_office_relationship;
|
||||||
|
|
||||||
oldPerson hs_office_person;
|
oldPerson hs_office_person;
|
||||||
newPerson hs_office_person;
|
newPerson hs_office_person;
|
||||||
|
|
||||||
oldContact hs_office_contact;
|
oldContact hs_office_contact;
|
||||||
newContact hs_office_contact;
|
newContact hs_office_contact;
|
||||||
begin
|
begin
|
||||||
|
|
||||||
|
select * from hs_office_relationship as r where r.uuid = NEW.partnerroleuuid into newPartnerRole;
|
||||||
select * from hs_office_person as p where p.uuid = NEW.personUuid into newPerson;
|
select * from hs_office_person as p where p.uuid = NEW.personUuid into newPerson;
|
||||||
select * from hs_office_contact as c where c.uuid = NEW.contactUuid into newContact;
|
select * from hs_office_contact as c where c.uuid = NEW.contactUuid into newContact;
|
||||||
|
|
||||||
@ -52,6 +57,7 @@ begin
|
|||||||
incomingSuperRoles => array[
|
incomingSuperRoles => array[
|
||||||
hsOfficePartnerOwner(NEW)],
|
hsOfficePartnerOwner(NEW)],
|
||||||
outgoingSubRoles => array[
|
outgoingSubRoles => array[
|
||||||
|
hsOfficeRelationshipTenant(newPartnerRole),
|
||||||
hsOfficePersonTenant(newPerson),
|
hsOfficePersonTenant(newPerson),
|
||||||
hsOfficeContactTenant(newContact)]
|
hsOfficeContactTenant(newContact)]
|
||||||
);
|
);
|
||||||
@ -60,6 +66,7 @@ begin
|
|||||||
hsOfficePartnerAgent(NEW),
|
hsOfficePartnerAgent(NEW),
|
||||||
incomingSuperRoles => array[
|
incomingSuperRoles => array[
|
||||||
hsOfficePartnerAdmin(NEW),
|
hsOfficePartnerAdmin(NEW),
|
||||||
|
hsOfficeRelationshipAdmin(newPartnerRole),
|
||||||
hsOfficePersonAdmin(newPerson),
|
hsOfficePersonAdmin(newPerson),
|
||||||
hsOfficeContactAdmin(newContact)]
|
hsOfficeContactAdmin(newContact)]
|
||||||
);
|
);
|
||||||
@ -69,6 +76,7 @@ begin
|
|||||||
incomingSuperRoles => array[
|
incomingSuperRoles => array[
|
||||||
hsOfficePartnerAgent(NEW)],
|
hsOfficePartnerAgent(NEW)],
|
||||||
outgoingSubRoles => array[
|
outgoingSubRoles => array[
|
||||||
|
hsOfficeRelationshipTenant(newPartnerRole),
|
||||||
hsOfficePersonGuest(newPerson),
|
hsOfficePersonGuest(newPerson),
|
||||||
hsOfficeContactGuest(newContact)]
|
hsOfficeContactGuest(newContact)]
|
||||||
);
|
);
|
||||||
@ -109,6 +117,19 @@ begin
|
|||||||
|
|
||||||
elsif TG_OP = 'UPDATE' then
|
elsif TG_OP = 'UPDATE' then
|
||||||
|
|
||||||
|
if OLD.partnerRoleUuid <> NEW.partnerRoleUuid then
|
||||||
|
select * from hs_office_relationship as r where r.uuid = OLD.partnerRoleUuid into oldPartnerRole;
|
||||||
|
|
||||||
|
call revokeRoleFromRole(hsOfficeRelationshipTenant(oldPerson), hsOfficePartnerAdmin(OLD));
|
||||||
|
call grantRoleToRole(hsOfficeRelationshipTenant(newPerson), hsOfficePartnerAdmin(NEW));
|
||||||
|
|
||||||
|
call revokeRoleFromRole(hsOfficePartnerAgent(OLD), hsOfficeRelationshipAdmin(oldPerson));
|
||||||
|
call grantRoleToRole(hsOfficePartnerAgent(NEW), hsOfficeRelationshipAdmin(newPerson));
|
||||||
|
|
||||||
|
call revokeRoleFromRole(hsOfficeRelationshipGuest(oldPerson), hsOfficePartnerTenant(OLD));
|
||||||
|
call grantRoleToRole(hsOfficeRelationshipGuest(newPerson), hsOfficePartnerTenant(NEW));
|
||||||
|
end if;
|
||||||
|
|
||||||
if OLD.personUuid <> NEW.personUuid then
|
if OLD.personUuid <> NEW.personUuid then
|
||||||
select * from hs_office_person as p where p.uuid = OLD.personUuid into oldPerson;
|
select * from hs_office_person as p where p.uuid = OLD.personUuid into oldPerson;
|
||||||
|
|
||||||
@ -179,7 +200,7 @@ call generateRbacIdentityView('hs_office_partner', $idName$
|
|||||||
call generateRbacRestrictedView('hs_office_partner',
|
call generateRbacRestrictedView('hs_office_partner',
|
||||||
'(select idName from hs_office_person_iv p where p.uuid = target.personUuid)',
|
'(select idName from hs_office_person_iv p where p.uuid = target.personUuid)',
|
||||||
$updates$
|
$updates$
|
||||||
partherRoleUuid = new.partnerRoleUuid,
|
partnerRoleUuid = new.partnerRoleUuid,
|
||||||
personUuid = new.personUuid,
|
personUuid = new.personUuid,
|
||||||
contactUuid = new.contactUuid
|
contactUuid = new.contactUuid
|
||||||
$updates$);
|
$updates$);
|
||||||
@ -191,7 +212,7 @@ call generateRbacRestrictedView('hs_office_partner',
|
|||||||
--changeset hs-office-partner-rbac-NEW-PARTNER:1 endDelimiter:--//
|
--changeset hs-office-partner-rbac-NEW-PARTNER:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
/*
|
/*
|
||||||
Creates a global permission for new-partner and assigns it to the hostsharing admins role.
|
Creates a global permission for new-partner and assigns it to the Hostsharing admins role.
|
||||||
*/
|
*/
|
||||||
do language plpgsql $$
|
do language plpgsql $$
|
||||||
declare
|
declare
|
||||||
|
@ -279,9 +279,8 @@ class HsOfficeBankAccountRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
public void auditJournalLogIsAvailable() {
|
public void auditJournalLogIsAvailable() {
|
||||||
// given
|
// given
|
||||||
final var query = em.createNativeQuery("""
|
final var query = em.createNativeQuery("""
|
||||||
select c.currenttask, j.targettable, j.targetop
|
select currentTask, targetTable, targetOp
|
||||||
from tx_journal j
|
from tx_journal_v
|
||||||
join tx_context c on j.contextId = c.contextId
|
|
||||||
where targettable = 'hs_office_bankaccount';
|
where targettable = 'hs_office_bankaccount';
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
@ -259,9 +259,8 @@ class HsOfficeContactRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
public void auditJournalLogIsAvailable() {
|
public void auditJournalLogIsAvailable() {
|
||||||
// given
|
// given
|
||||||
final var query = em.createNativeQuery("""
|
final var query = em.createNativeQuery("""
|
||||||
select c.currenttask, j.targettable, j.targetop
|
select currentTask, targetTable, targetOp
|
||||||
from tx_journal j
|
from tx_journal_v
|
||||||
join tx_context c on j.contextId = c.contextId
|
|
||||||
where targettable = 'hs_office_contact';
|
where targettable = 'hs_office_contact';
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
@ -216,9 +216,8 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
|
|||||||
public void auditJournalLogIsAvailable() {
|
public void auditJournalLogIsAvailable() {
|
||||||
// given
|
// given
|
||||||
final var query = em.createNativeQuery("""
|
final var query = em.createNativeQuery("""
|
||||||
select c.currenttask, j.targettable, j.targetop
|
select currentTask, targetTable, targetOp
|
||||||
from tx_journal j
|
from tx_journal_v
|
||||||
join tx_context c on j.contextId = c.contextId
|
|
||||||
where targettable = 'hs_office_coopassetstransaction';
|
where targettable = 'hs_office_coopassetstransaction';
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
@ -215,9 +215,8 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
|
|||||||
public void auditJournalLogIsAvailable() {
|
public void auditJournalLogIsAvailable() {
|
||||||
// given
|
// given
|
||||||
final var query = em.createNativeQuery("""
|
final var query = em.createNativeQuery("""
|
||||||
select c.currenttask, j.targettable, j.targetop
|
select currentTask, targetTable, targetOp
|
||||||
from tx_journal j
|
from tx_journal_v
|
||||||
join tx_context c on j.contextId = c.contextId
|
|
||||||
where targettable = 'hs_office_coopsharestransaction';
|
where targettable = 'hs_office_coopsharestransaction';
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
@ -548,10 +548,9 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
public void auditJournalLogIsAvailable() {
|
public void auditJournalLogIsAvailable() {
|
||||||
// given
|
// given
|
||||||
final var query = em.createNativeQuery("""
|
final var query = em.createNativeQuery("""
|
||||||
select c.currenttask, j.targettable, j.targetop
|
select currentTask, targetTable, targetOp
|
||||||
from tx_journal j
|
from tx_journal_v
|
||||||
join tx_context c on j.contextId = c.contextId
|
where targettable = 'hs_office_coopsharestransaction';
|
||||||
where targettable = 'hs_office_debitor';
|
|
||||||
""");
|
""");
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
@ -376,9 +376,8 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
public void auditJournalLogIsAvailable() {
|
public void auditJournalLogIsAvailable() {
|
||||||
// given
|
// given
|
||||||
final var query = em.createNativeQuery("""
|
final var query = em.createNativeQuery("""
|
||||||
select c.currenttask, j.targettable, j.targetop
|
select currentTask, targetTable, targetOp
|
||||||
from tx_journal j
|
from tx_journal_v
|
||||||
join tx_context c on j.contextId = c.contextId
|
|
||||||
where targettable = 'hs_office_membership';
|
where targettable = 'hs_office_membership';
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEnti
|
|||||||
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipType;
|
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipType;
|
||||||
import net.hostsharing.hsadminng.hs.office.sepamandate.HsOfficeSepaMandateEntity;
|
import net.hostsharing.hsadminng.hs.office.sepamandate.HsOfficeSepaMandateEntity;
|
||||||
import net.hostsharing.test.JpaAttempt;
|
import net.hostsharing.test.JpaAttempt;
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.junit.jupiter.api.*;
|
import org.junit.jupiter.api.*;
|
||||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||||
@ -113,6 +114,17 @@ import static org.assertj.core.api.Fail.fail;
|
|||||||
@ExtendWith(OrderedDependedTestsExtension.class)
|
@ExtendWith(OrderedDependedTestsExtension.class)
|
||||||
public class ImportOfficeData extends ContextBasedTest {
|
public class ImportOfficeData extends ContextBasedTest {
|
||||||
|
|
||||||
|
private static final String[] SUBSCRIBER_ROLES = new String[] {
|
||||||
|
"subscriber:operations-discussion",
|
||||||
|
"subscriber:operations-announce",
|
||||||
|
"subscriber:members-announce",
|
||||||
|
"subscriber:members-discussion",
|
||||||
|
"subscriber:customers-announce"
|
||||||
|
};
|
||||||
|
private static final String[] KNOWN_ROLES = ArrayUtils.addAll(
|
||||||
|
new String[]{"partner", "vip-contact", "ex-partner", "billing", "contractual", "operation"},
|
||||||
|
SUBSCRIBER_ROLES);
|
||||||
|
|
||||||
static int relationshipId = 2000000;
|
static int relationshipId = 2000000;
|
||||||
|
|
||||||
@Value("${spring.datasource.url}")
|
@Value("${spring.datasource.url}")
|
||||||
@ -257,10 +269,13 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
2000004=rel(relAnchor='LP JM GmbH', relType='EX_PARTNER', relHolder='LP JM e.K.', contact='JM e.K.'),
|
2000004=rel(relAnchor='LP JM GmbH', relType='EX_PARTNER', relHolder='LP JM e.K.', contact='JM e.K.'),
|
||||||
2000005=rel(relAnchor='LP JM GmbH', relType='OPERATIONS', relHolder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
2000005=rel(relAnchor='LP JM GmbH', relType='OPERATIONS', relHolder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||||
2000006=rel(relAnchor='LP JM GmbH', relType='VIP_CONTACT', relHolder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
2000006=rel(relAnchor='LP JM GmbH', relType='VIP_CONTACT', relHolder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||||
2000007=rel(relAnchor='LP JM GmbH', relType='REPRESENTATIVE', relHolder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
2000007=rel(relAnchor='LP JM GmbH', relType='SUBSCRIBER', relMark='operations-announce', relHolder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||||
2000008=rel(relAnchor='?? Test PS', relType='OPERATIONS', relHolder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
2000008=rel(relAnchor='LP JM GmbH', relType='REPRESENTATIVE', relHolder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||||
2000009=rel(relAnchor='?? Test PS', relType='REPRESENTATIVE', relHolder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
2000009=rel(relAnchor='LP JM GmbH', relType='SUBSCRIBER', relMark='members-announce', relHolder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||||
2000010=rel(relAnchor='NP Mellies, Michael', relType='REPRESENTATIVE', relHolder='NP Mellies, Michael', contact='Herr Michael Mellies ')
|
2000010=rel(relAnchor='LP JM GmbH', relType='SUBSCRIBER', relMark='customers-announce', relHolder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||||
|
2000011=rel(relAnchor='?? Test PS', relType='OPERATIONS', relHolder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||||
|
2000012=rel(relAnchor='?? Test PS', relType='REPRESENTATIVE', relHolder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||||
|
2000013=rel(relAnchor='NP Mellies, Michael', relType='REPRESENTATIVE', relHolder='NP Mellies, Michael', contact='Herr Michael Mellies ')
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
@ -763,7 +778,14 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
if (containsRole(rec, "vip-contact")) {
|
if (containsRole(rec, "vip-contact")) {
|
||||||
addRelationship(partnerPerson, contactPerson, contact, HsOfficeRelationshipType.VIP_CONTACT);
|
addRelationship(partnerPerson, contactPerson, contact, HsOfficeRelationshipType.VIP_CONTACT);
|
||||||
}
|
}
|
||||||
verifyContainsOnly(rec.getString("roles"), "partner", "vip-contact", "ex-partner", "billing", "contractual", "operation");
|
for (String subscriberRole: SUBSCRIBER_ROLES) {
|
||||||
|
if (containsRole(rec, subscriberRole)) {
|
||||||
|
addRelationship(partnerPerson, contactPerson, contact, HsOfficeRelationshipType.SUBSCRIBER)
|
||||||
|
.setRelMark(subscriberRole.split(":")[1])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
verifyContainsOnlyKnownRoles(rec.getString("roles"));
|
||||||
});
|
});
|
||||||
|
|
||||||
optionallyAddMissingContractualRelationships();
|
optionallyAddMissingContractualRelationships();
|
||||||
@ -787,7 +809,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
return containsRole(rec, "partner");
|
return containsRole(rec, "partner");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addRelationship(
|
private static HsOfficeRelationshipEntity addRelationship(
|
||||||
final HsOfficePersonEntity partnerPerson,
|
final HsOfficePersonEntity partnerPerson,
|
||||||
final HsOfficePersonEntity contactPerson,
|
final HsOfficePersonEntity contactPerson,
|
||||||
final HsOfficeContactEntity contact,
|
final HsOfficeContactEntity contact,
|
||||||
@ -799,6 +821,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
.relType(representative)
|
.relType(representative)
|
||||||
.build();
|
.build();
|
||||||
relationships.put(relationshipId++, rel);
|
relationships.put(relationshipId++, rel);
|
||||||
|
return rel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HsOfficePersonEntity initPerson(final HsOfficePersonEntity person, final Record contactRecord) {
|
private HsOfficePersonEntity initPerson(final HsOfficePersonEntity person, final Record contactRecord) {
|
||||||
@ -843,9 +866,9 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyContainsOnly(final String roles, final String... allowedRoles) {
|
private void verifyContainsOnlyKnownRoles(final String roles) {
|
||||||
|
final var allowedRolesSet = stream(KNOWN_ROLES).collect(Collectors.toSet());
|
||||||
final var givenRolesSet = stream(roles.replace(" ", "").split(",")).collect(Collectors.toSet());
|
final var givenRolesSet = stream(roles.replace(" ", "").split(",")).collect(Collectors.toSet());
|
||||||
final var allowedRolesSet = stream(allowedRoles).collect(Collectors.toSet());
|
|
||||||
final var unexpectedRolesSet = new HashSet<>(givenRolesSet);
|
final var unexpectedRolesSet = new HashSet<>(givenRolesSet);
|
||||||
unexpectedRolesSet.removeAll(allowedRolesSet);
|
unexpectedRolesSet.removeAll(allowedRolesSet);
|
||||||
assertThat(unexpectedRolesSet).isEmpty();
|
assertThat(unexpectedRolesSet).isEmpty();
|
||||||
|
@ -122,7 +122,7 @@ class HsOfficePartnerControllerAcceptanceTest {
|
|||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenPerson = personRepo.findPersonByOptionalNameLike("Third").get(0);
|
final var givenPerson = personRepo.findPersonByOptionalNameLike("Third").get(0);
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth").get(0);
|
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth").get(0);
|
||||||
|
|
||||||
final var location = RestAssured // @formatter:off
|
final var location = RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -191,8 +191,9 @@ class HsOfficePartnerControllerAcceptanceTest {
|
|||||||
void globalAdmin_canNotAddPartner_ifPersonDoesNotExist() {
|
void globalAdmin_canNotAddPartner_ifPersonDoesNotExist() {
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
|
final var mandantPerson = personRepo.findPersonByOptionalNameLike("Hostsharing eG").get(0);
|
||||||
final var givenPersonUuid = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6");
|
final var givenPersonUuid = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6");
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth").get(0);
|
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth").get(0);
|
||||||
|
|
||||||
final var location = RestAssured // @formatter:off
|
final var location = RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -201,11 +202,22 @@ class HsOfficePartnerControllerAcceptanceTest {
|
|||||||
.body("""
|
.body("""
|
||||||
{
|
{
|
||||||
"partnerNumber": "12345",
|
"partnerNumber": "12345",
|
||||||
"contactUuid": "%s",
|
"partnerRole": {
|
||||||
|
"relAnchorUuid": "%s",
|
||||||
|
"relType": "PARTNER",
|
||||||
|
"relHolder": "%s",
|
||||||
|
"contact": "%s",
|
||||||
|
},
|
||||||
"personUuid": "%s",
|
"personUuid": "%s",
|
||||||
|
"contactUuid": "%s",
|
||||||
"details": {}
|
"details": {}
|
||||||
}
|
}
|
||||||
""".formatted(givenContact.getUuid(), givenPersonUuid))
|
""".formatted(
|
||||||
|
mandantPerson.getUuid(),
|
||||||
|
givenPersonUuid,
|
||||||
|
givenContact.getUuid(),
|
||||||
|
givenPersonUuid,
|
||||||
|
givenContact.getUuid()))
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.post("http://localhost/api/hs/office/partners")
|
.post("http://localhost/api/hs/office/partners")
|
||||||
|
@ -74,13 +74,23 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var count = partnerRepo.count();
|
final var count = partnerRepo.count();
|
||||||
final var givenPerson = personRepo.findPersonByOptionalNameLike("First GmbH").get(0);
|
final var givenMandantorPerson = personRepo.findPersonByOptionalNameLike("Hostsharing eG").get(0);
|
||||||
|
final var givenPartnerPerson = personRepo.findPersonByOptionalNameLike("First GmbH").get(0);
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("first contact").get(0);
|
final var givenContact = contactRepo.findContactByOptionalLabelLike("first contact").get(0);
|
||||||
|
|
||||||
|
final var partnerRole = HsOfficeRelationshipEntity.builder()
|
||||||
|
.relHolder(givenPartnerPerson)
|
||||||
|
.relType(HsOfficeRelationshipType.PARTNER)
|
||||||
|
.relAnchor(givenMandantorPerson)
|
||||||
|
.contact(givenContact)
|
||||||
|
.build();
|
||||||
|
relationshipRepo.save(partnerRole);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = attempt(em, () -> {
|
final var result = attempt(em, () -> {
|
||||||
final var newPartner = toCleanup(HsOfficePartnerEntity.builder()
|
final var newPartner = toCleanup(HsOfficePartnerEntity.builder()
|
||||||
.person(givenPerson)
|
.partnerRole(partnerRole)
|
||||||
|
.person(givenPartnerPerson)
|
||||||
.contact(givenContact)
|
.contact(givenContact)
|
||||||
.details(HsOfficePartnerDetailsEntity.builder()
|
.details(HsOfficePartnerDetailsEntity.builder()
|
||||||
.build())
|
.build())
|
||||||
@ -148,11 +158,12 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
.containsExactlyInAnyOrder(Array.fromFormatted(
|
.containsExactlyInAnyOrder(Array.fromFormatted(
|
||||||
initialGrantNames,
|
initialGrantNames,
|
||||||
// relationship - TODO: check and cleanup
|
// relationship - TODO: check and cleanup
|
||||||
|
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role partner#22222:EBess-4th.admin by system and assume }",
|
||||||
|
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role partner#22222:EBess-4th.tenant by system and assume }",
|
||||||
|
"{ grant role partner#22222:EBess-4th.agent to role relationship#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
|
||||||
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.owner to role global#global.admin by system and assume }",
|
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.owner to role global#global.admin by system and assume }",
|
||||||
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role contact#4th.admin by system and assume }",
|
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role contact#4th.admin by system and assume }",
|
||||||
"{ grant role person#HostsharingeG.tenant to role person#EBess.admin by system and assume }",
|
|
||||||
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role person#EBess.admin by system and assume }",
|
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role person#EBess.admin by system and assume }",
|
||||||
"{ grant role person#EBess.tenant to role person#HostsharingeG.admin by system and assume }",
|
|
||||||
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.owner to role person#HostsharingeG.admin by system and assume }",
|
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.owner to role person#HostsharingeG.admin by system and assume }",
|
||||||
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role person#HostsharingeG.admin by system and assume }",
|
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role person#HostsharingeG.admin by system and assume }",
|
||||||
"{ grant perm edit on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
|
"{ grant perm edit on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
|
||||||
@ -311,6 +322,10 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenPartner = givenSomeTemporaryPartnerBessler(22222, "Erben Bessler", "ninth");
|
final var givenPartner = givenSomeTemporaryPartnerBessler(22222, "Erben Bessler", "ninth");
|
||||||
|
final var newPartnerRole = em.createNativeQuery(
|
||||||
|
"select uuid from hs_office_relationship where uuid=:partnerRoleUuid")
|
||||||
|
.setParameter("partnerRoleUuid", givenPartner.getPartnerRole().getUuid())
|
||||||
|
.getSingleResult();
|
||||||
assertThatPartnerIsVisibleForUserWithRole(
|
assertThatPartnerIsVisibleForUserWithRole(
|
||||||
givenPartner,
|
givenPartner,
|
||||||
"hs_office_partner#22222:ErbenBesslerMelBessler-ninthcontact.agent");
|
"hs_office_partner#22222:ErbenBesslerMelBessler-ninthcontact.agent");
|
||||||
@ -412,7 +427,8 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
// when
|
// when
|
||||||
final var result = jpaAttempt.transacted(() -> {
|
final var result = jpaAttempt.transacted(() -> {
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
return partnerRepo.deleteByUuid(givenPartner.getUuid());
|
return relationshipRepo.deleteByUuid(givenPartner.getPartnerRole().getUuid());
|
||||||
|
// return partnerRepo.deleteByUuid(givenPartner.getUuid());
|
||||||
});
|
});
|
||||||
|
|
||||||
// then
|
// then
|
||||||
@ -427,9 +443,8 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
public void auditJournalLogIsAvailable() {
|
public void auditJournalLogIsAvailable() {
|
||||||
// given
|
// given
|
||||||
final var query = em.createNativeQuery("""
|
final var query = em.createNativeQuery("""
|
||||||
select c.currenttask, j.targettable, j.targetop
|
select currentTask, targetTable, targetOp
|
||||||
from tx_journal j
|
from tx_journal_v
|
||||||
join tx_context c on j.contextId = c.contextId
|
|
||||||
where targettable = 'hs_office_partner';
|
where targettable = 'hs_office_partner';
|
||||||
""");
|
""");
|
||||||
|
|
||||||
@ -455,11 +470,23 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
final Integer partnerNumber, final String person, final String contact) {
|
final Integer partnerNumber, final String person, final String contact) {
|
||||||
return jpaAttempt.transacted(() -> {
|
return jpaAttempt.transacted(() -> {
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenPerson = personRepo.findPersonByOptionalNameLike(person).get(0);
|
final var givenMandantorPerson = personRepo.findPersonByOptionalNameLike("Hostsharing eG").get(0);
|
||||||
|
final var givenPartnerPerson = personRepo.findPersonByOptionalNameLike(person).get(0);
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike(contact).get(0);
|
final var givenContact = contactRepo.findContactByOptionalLabelLike(contact).get(0);
|
||||||
|
|
||||||
|
final var partnerRole = HsOfficeRelationshipEntity.builder()
|
||||||
|
.relHolder(givenPartnerPerson)
|
||||||
|
.relType(HsOfficeRelationshipType.PARTNER)
|
||||||
|
.relAnchor(givenMandantorPerson)
|
||||||
|
.contact(givenContact)
|
||||||
|
.build();
|
||||||
|
relationshipRepo.save(partnerRole);
|
||||||
|
em.flush(); // TODO: why is that necessary?
|
||||||
|
|
||||||
final var newPartner = HsOfficePartnerEntity.builder()
|
final var newPartner = HsOfficePartnerEntity.builder()
|
||||||
.partnerNumber(partnerNumber)
|
.partnerNumber(partnerNumber)
|
||||||
.person(givenPerson)
|
.partnerRole(partnerRole)
|
||||||
|
.person(givenPartnerPerson)
|
||||||
.contact(givenContact)
|
.contact(givenContact)
|
||||||
.details(HsOfficePartnerDetailsEntity.builder().build())
|
.details(HsOfficePartnerDetailsEntity.builder().build())
|
||||||
.build();
|
.build();
|
||||||
|
@ -262,9 +262,8 @@ class HsOfficePersonRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
public void auditJournalLogIsAvailable() {
|
public void auditJournalLogIsAvailable() {
|
||||||
// given
|
// given
|
||||||
final var query = em.createNativeQuery("""
|
final var query = em.createNativeQuery("""
|
||||||
select c.currenttask, j.targettable, j.targetop
|
select currentTask, targetTable, targetOp
|
||||||
from tx_journal j
|
from tx_journal_v
|
||||||
join tx_context c on j.contextId = c.contextId
|
|
||||||
where targettable = 'hs_office_person';
|
where targettable = 'hs_office_person';
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
@ -19,6 +19,18 @@ class HsOfficeRelationshipEntityUnitTest {
|
|||||||
.givenName("Mellie")
|
.givenName("Mellie")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toStringReturnsAllProperties() {
|
||||||
|
final var given = HsOfficeRelationshipEntity.builder()
|
||||||
|
.relType(HsOfficeRelationshipType.SUBSCRIBER)
|
||||||
|
.relMark("members-announce")
|
||||||
|
.relAnchor(anchor)
|
||||||
|
.relHolder(holder)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(given.toString()).isEqualTo("rel(relAnchor='LP some trade name', relType='SUBSCRIBER', relMark='members-announce', relHolder='NP Meier, Mellie')");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void toShortString() {
|
void toShortString() {
|
||||||
final var given = HsOfficeRelationshipEntity.builder()
|
final var given = HsOfficeRelationshipEntity.builder()
|
||||||
|
@ -370,9 +370,8 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
public void auditJournalLogIsAvailable() {
|
public void auditJournalLogIsAvailable() {
|
||||||
// given
|
// given
|
||||||
final var query = em.createNativeQuery("""
|
final var query = em.createNativeQuery("""
|
||||||
select c.currenttask, j.targettable, j.targetop
|
select currentTask, targetTable, targetOp
|
||||||
from tx_journal j
|
from tx_journal_v
|
||||||
join tx_context c on j.contextId = c.contextId
|
|
||||||
where targettable = 'hs_office_relationship';
|
where targettable = 'hs_office_relationship';
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
@ -390,9 +390,8 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
|
|||||||
public void auditJournalLogIsAvailable() {
|
public void auditJournalLogIsAvailable() {
|
||||||
// given
|
// given
|
||||||
final var query = em.createNativeQuery("""
|
final var query = em.createNativeQuery("""
|
||||||
select c.currenttask, j.targettable, j.targetop
|
select currentTask, targetTable, targetOp
|
||||||
from tx_journal j
|
from tx_journal_v
|
||||||
join tx_context c on j.contextId = c.contextId
|
|
||||||
where targettable = 'hs_office_sepamandate';
|
where targettable = 'hs_office_sepamandate';
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@ contact_id; bp_id; salut; first_name; last_name; title; firma; co; street; zip
|
|||||||
# eine juristische Person mit drei separaten Ansprechpartnern, vip-contact und ex-partner
|
# eine juristische Person mit drei separaten Ansprechpartnern, vip-contact und ex-partner
|
||||||
1200; 20;; ; ; ; JM e.K.;; Wiesenweg 15; 12335; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; jm-ex-partner@example.org; ex-partner
|
1200; 20;; ; ; ; JM e.K.;; Wiesenweg 15; 12335; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; jm-ex-partner@example.org; ex-partner
|
||||||
1201; 20; Frau; Jenny; Meyer-Billing; Dr.; JM GmbH;; Waldweg 5; 11001; Berlin; DE; +49 30 7777777; +49 30 1111111; ; +49 30 2222222; jm-billing@example.org; billing
|
1201; 20; Frau; Jenny; Meyer-Billing; Dr.; JM GmbH;; Waldweg 5; 11001; Berlin; DE; +49 30 7777777; +49 30 1111111; ; +49 30 2222222; jm-billing@example.org; billing
|
||||||
1202; 20; Herr; Andrew; Meyer-Operation; ; JM GmbH;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 3333333; ; +49 30 4444444; am-operation@example.org; operation,vip-contact
|
1202; 20; Herr; Andrew; Meyer-Operation; ; JM GmbH;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 3333333; ; +49 30 4444444; am-operation@example.org; operation,vip-contact,subscriber:operations-announce
|
||||||
1203; 20; Herr; Philip; Meyer-Contract; ; JM GmbH;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; pm-partner@example.org; partner,contractual
|
1203; 20; Herr; Philip; Meyer-Contract; ; JM GmbH;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; pm-partner@example.org; partner,contractual,subscriber:members-announce,subscriber:customers-announce
|
||||||
|
|
||||||
# eine juristische Person mit nur einem Ansprechpartner und explizitem contractual
|
# eine juristische Person mit nur einem Ansprechpartner und explizitem contractual
|
||||||
1301; 22; ; Petra; Schmidt; ; Test PS;; ; ; ; ; ; ; ; ; ps@example.com; partner,billing,contractual,operation
|
1301; 22; ; Petra; Schmidt; ; Test PS;; ; ; ; ; ; ; ; ; ps@example.com; partner,billing,contractual,operation
|
||||||
|
|
Loading…
Reference in New Issue
Block a user