import-cancelled-memberships-if-booking-exist #36
@ -19,13 +19,7 @@ import org.hibernate.annotations.JoinFormula;
|
||||
import org.hibernate.annotations.NotFound;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
@ -2,7 +2,11 @@ package net.hostsharing.hsadminng.hs.office.membership;
|
||||
|
||||
import io.hypersistence.utils.hibernate.type.range.PostgreSQLRangeType;
|
||||
import io.hypersistence.utils.hibernate.type.range.Range;
|
||||
import lombok.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
||||
@ -13,17 +17,32 @@ import net.hostsharing.hsadminng.stringify.Stringify;
|
||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.PrePersist;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Version;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.*;
|
||||
import static io.hypersistence.utils.hibernate.type.range.Range.emptyRange;
|
||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.lowerInclusiveFromPostgresDateRange;
|
||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange;
|
||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.upperInclusiveFromPostgresDateRange;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.DELETE;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.UPDATE;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.ADMIN;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.AGENT;
|
||||
@ -50,7 +69,7 @@ public class HsOfficeMembershipEntity implements RbacObject, Stringifyable {
|
||||
.withProp(e -> MEMBER_NUMBER_TAG + e.getMemberNumber())
|
||||
.withProp(e -> e.getPartner().toShortString())
|
||||
.withProp(e -> e.getValidity().asString())
|
||||
.withProp(HsOfficeMembershipEntity::getReasonForTermination)
|
||||
.withProp(HsOfficeMembershipEntity::getStatus)
|
||||
.quotedValues(false);
|
||||
|
||||
@Id
|
||||
@ -75,9 +94,9 @@ public class HsOfficeMembershipEntity implements RbacObject, Stringifyable {
|
||||
@Column(name = "membershipfeebillable", nullable = false)
|
||||
private Boolean membershipFeeBillable; // not primitive to force setting the value
|
||||
|
||||
@Column(name = "reasonfortermination")
|
||||
@Column(name = "status")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private HsOfficeReasonForTermination reasonForTermination;
|
||||
private HsOfficeMembershipStatus status;
|
||||
|
||||
public void setValidFrom(final LocalDate validFrom) {
|
||||
setValidity(toPostgresDateRange(validFrom, getValidTo()));
|
||||
@ -97,7 +116,7 @@ public class HsOfficeMembershipEntity implements RbacObject, Stringifyable {
|
||||
|
||||
public Range<LocalDate> getValidity() {
|
||||
if (validity == null) {
|
||||
validity = Range.infinite(LocalDate.class);
|
||||
validity = emptyRange(LocalDate.class);
|
||||
}
|
||||
return validity;
|
||||
}
|
||||
@ -121,8 +140,8 @@ public class HsOfficeMembershipEntity implements RbacObject, Stringifyable {
|
||||
|
||||
@PrePersist
|
||||
void init() {
|
||||
if (getReasonForTermination() == null) {
|
||||
setReasonForTermination(HsOfficeReasonForTermination.NONE);
|
||||
if (getStatus() == null) {
|
||||
setStatus(HsOfficeMembershipStatus.INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,7 +154,7 @@ public class HsOfficeMembershipEntity implements RbacObject, Stringifyable {
|
||||
JOIN hs_office_partner AS p ON p.uuid = m.partnerUuid
|
||||
"""))
|
||||
.withRestrictedViewOrderBy(SQL.projection("validity"))
|
||||
.withUpdatableColumns("validity", "membershipFeeBillable", "reasonForTermination")
|
||||
.withUpdatableColumns("validity", "membershipFeeBillable", "status")
|
||||
|
||||
.importEntityAlias("partnerRel", HsOfficeRelationEntity.class,
|
||||
dependsOnColumn("partnerUuid"),
|
||||
|
@ -23,9 +23,9 @@ public class HsOfficeMembershipEntityPatcher implements EntityPatcher<HsOfficeMe
|
||||
public void apply(final HsOfficeMembershipPatchResource resource) {
|
||||
OptionalFromJson.of(resource.getValidTo()).ifPresent(
|
||||
entity::setValidTo);
|
||||
Optional.ofNullable(resource.getReasonForTermination())
|
||||
.map(v -> mapper.map(v, HsOfficeReasonForTermination.class))
|
||||
.ifPresent(entity::setReasonForTermination);
|
||||
Optional.ofNullable(resource.getStatus())
|
||||
.map(v -> mapper.map(v, HsOfficeMembershipStatus.class))
|
||||
.ifPresent(entity::setStatus);
|
||||
OptionalFromJson.of(resource.getMembershipFeeBillable()).ifPresent(
|
||||
entity::setMembershipFeeBillable);
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
package net.hostsharing.hsadminng.hs.office.membership;
|
||||
|
||||
public enum HsOfficeMembershipStatus {
|
||||
INVALID, ACTIVE, CANCELLED, TRANSFERRED, DECEASED, LIQUIDATED, EXPULSED, UNKNOWN;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package net.hostsharing.hsadminng.hs.office.membership;
|
||||
|
||||
public enum HsOfficeReasonForTermination {
|
||||
NONE, CANCELLATION, TRANSFER, DEATH, LIQUIDATION, EXPULSION, UNKNOWN;
|
||||
}
|
@ -3,15 +3,17 @@ components:
|
||||
|
||||
schemas:
|
||||
|
||||
HsOfficeReasonForTermination:
|
||||
HsOfficeMembershipStatus:
|
||||
type: string
|
||||
enum:
|
||||
- NONE
|
||||
- CANCELLATION
|
||||
- TRANSFER
|
||||
- DEATH
|
||||
- LIQUIDATION
|
||||
- EXPULSION
|
||||
- INVALID
|
||||
- ACTIVE
|
||||
- CANCELLED
|
||||
- TRANSFERRED
|
||||
- DECEASED
|
||||
- LIQUIDATED
|
||||
- EXPULSED
|
||||
- UNKNOWN
|
||||
|
||||
HsOfficeMembership:
|
||||
type: object
|
||||
@ -38,8 +40,8 @@ components:
|
||||
validTo:
|
||||
type: string
|
||||
format: date
|
||||
reasonForTermination:
|
||||
$ref: '#/components/schemas/HsOfficeReasonForTermination'
|
||||
status:
|
||||
$ref: '#/components/schemas/HsOfficeMembershipStatus'
|
||||
membershipFeeBillable:
|
||||
type: boolean
|
||||
|
||||
@ -50,9 +52,8 @@ components:
|
||||
type: string
|
||||
format: date
|
||||
nullable: true
|
||||
reasonForTermination:
|
||||
nullable: true
|
||||
$ref: '#/components/schemas/HsOfficeReasonForTermination'
|
||||
status:
|
||||
$ref: '#/components/schemas/HsOfficeMembershipStatus'
|
||||
membershipFeeBillable:
|
||||
nullable: true
|
||||
type: boolean
|
||||
@ -79,8 +80,8 @@ components:
|
||||
type: string
|
||||
format: date
|
||||
nullable: true
|
||||
reasonForTermination:
|
||||
$ref: '#/components/schemas/HsOfficeReasonForTermination'
|
||||
status:
|
||||
$ref: '#/components/schemas/HsOfficeMembershipStatus'
|
||||
membershipFeeBillable:
|
||||
nullable: false
|
||||
type: boolean
|
||||
|
@ -1,4 +1,4 @@
|
||||
openapi: 3.0.1
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Hostsharing hsadmin-ng API
|
||||
version: v0
|
||||
|
@ -4,9 +4,18 @@
|
||||
--changeset hs-office-membership-MAIN-TABLE:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
|
||||
CREATE TYPE HsOfficeReasonForTermination AS ENUM ('NONE', 'CANCELLATION', 'TRANSFER', 'DEATH', 'LIQUIDATION', 'EXPULSION', 'UNKNOWN');
|
||||
CREATE TYPE HsOfficeMembershipStatus AS ENUM (
|
||||
'INVALID',
|
||||
'ACTIVE',
|
||||
'CANCELLED',
|
||||
'TRANSFERRED',
|
||||
'DECEASED',
|
||||
'LIQUIDATED',
|
||||
'EXPULSED',
|
||||
'UNKNOWN'
|
||||
);
|
||||
|
||||
CREATE CAST (character varying as HsOfficeReasonForTermination) WITH INOUT AS IMPLICIT;
|
||||
CREATE CAST (character varying as HsOfficeMembershipStatus) WITH INOUT AS IMPLICIT;
|
||||
|
||||
create table if not exists hs_office_membership
|
||||
(
|
||||
@ -15,7 +24,7 @@ create table if not exists hs_office_membership
|
||||
partnerUuid uuid not null references hs_office_partner(uuid),
|
||||
memberNumberSuffix char(2) not null check (memberNumberSuffix::text ~ '^[0-9][0-9]$'),
|
||||
validity daterange not null,
|
||||
reasonForTermination HsOfficeReasonForTermination not null default 'NONE',
|
||||
status HsOfficeMembershipStatus not null default 'ACTIVE',
|
||||
membershipFeeBillable boolean not null default true,
|
||||
|
||||
UNIQUE(partnerUuid, memberNumberSuffix)
|
||||
|
@ -172,7 +172,7 @@ call generateRbacRestrictedView('hs_office_membership',
|
||||
$updates$
|
||||
validity = new.validity,
|
||||
membershipFeeBillable = new.membershipFeeBillable,
|
||||
reasonForTermination = new.reasonForTermination
|
||||
status = new.status
|
||||
$updates$);
|
||||
--//
|
||||
|
||||
|
@ -28,8 +28,8 @@ begin
|
||||
raise notice 'creating test Membership: M-% %', forPartnerNumber, newMemberNumberSuffix;
|
||||
raise notice '- using partner (%): %', relatedPartner.uuid, relatedPartner;
|
||||
insert
|
||||
into hs_office_membership (uuid, partneruuid, memberNumberSuffix, validity, reasonfortermination)
|
||||
values (uuid_generate_v4(), relatedPartner.uuid, newMemberNumberSuffix, daterange('20221001' , null, '[]'), 'NONE');
|
||||
into hs_office_membership (uuid, partneruuid, memberNumberSuffix, validity, status)
|
||||
values (uuid_generate_v4(), relatedPartner.uuid, newMemberNumberSuffix, daterange('20221001' , null, '[]'), 'ACTIVE');
|
||||
end; $$;
|
||||
--//
|
||||
|
||||
|
@ -23,8 +23,8 @@ import jakarta.persistence.PersistenceContext;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.office.membership.HsOfficeReasonForTermination.CANCELLATION;
|
||||
import static net.hostsharing.hsadminng.hs.office.membership.HsOfficeReasonForTermination.NONE;
|
||||
import static net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipStatus.ACTIVE;
|
||||
import static net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipStatus.CANCELLED;
|
||||
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
||||
import static net.hostsharing.test.JsonMatcher.lenientlyEquals;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -84,7 +84,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
"memberNumberSuffix": "01",
|
||||
"validFrom": "2022-10-01",
|
||||
"validTo": null,
|
||||
"reasonForTermination": "NONE"
|
||||
"status": "ACTIVE"
|
||||
},
|
||||
{
|
||||
"partner": { "partnerNumber": 10002 },
|
||||
@ -92,7 +92,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
"memberNumberSuffix": "02",
|
||||
"validFrom": "2022-10-01",
|
||||
"validTo": null,
|
||||
"reasonForTermination": "NONE"
|
||||
"status": "ACTIVE"
|
||||
},
|
||||
{
|
||||
"partner": { "partnerNumber": 10003 },
|
||||
@ -100,7 +100,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
"memberNumberSuffix": "03",
|
||||
"validFrom": "2022-10-01",
|
||||
"validTo": null,
|
||||
"reasonForTermination": "NONE"
|
||||
"status": "ACTIVE"
|
||||
}
|
||||
]
|
||||
"""));
|
||||
@ -131,7 +131,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
"memberNumberSuffix": "01",
|
||||
"validFrom": "2022-10-01",
|
||||
"validTo": null,
|
||||
"reasonForTermination": "NONE"
|
||||
"status": "ACTIVE"
|
||||
}
|
||||
]
|
||||
"""));
|
||||
@ -159,7 +159,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
"memberNumberSuffix": "02",
|
||||
"validFrom": "2022-10-01",
|
||||
"validTo": null,
|
||||
"reasonForTermination": "NONE"
|
||||
"status": "ACTIVE"
|
||||
}
|
||||
]
|
||||
"""));
|
||||
@ -239,7 +239,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
"memberNumberSuffix": "01",
|
||||
"validFrom": "2022-10-01",
|
||||
"validTo": null,
|
||||
"reasonForTermination": "NONE"
|
||||
"status": "ACTIVE"
|
||||
}
|
||||
""")); // @formatter:on
|
||||
}
|
||||
@ -283,7 +283,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
"memberNumberSuffix": "03",
|
||||
"validFrom": "2022-10-01",
|
||||
"validTo": null,
|
||||
"reasonForTermination": "NONE"
|
||||
"status": "ACTIVE"
|
||||
}
|
||||
""")); // @formatter:on
|
||||
}
|
||||
@ -306,7 +306,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
.body("""
|
||||
{
|
||||
"validTo": "2023-12-31",
|
||||
"reasonForTermination": "CANCELLATION"
|
||||
"status": "CANCELLED"
|
||||
}
|
||||
""")
|
||||
.port(port)
|
||||
@ -320,7 +320,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
.body("memberNumberSuffix", is(givenMembership.getMemberNumberSuffix()))
|
||||
.body("validFrom", is("2022-11-01"))
|
||||
.body("validTo", is("2023-12-31"))
|
||||
.body("reasonForTermination", is("CANCELLATION"));
|
||||
.body("status", is("CANCELLED"));
|
||||
// @formatter:on
|
||||
|
||||
// finally, the Membership is actually updated
|
||||
@ -329,7 +329,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
assertThat(mandate.getPartner().toShortString()).isEqualTo("P-10001");
|
||||
assertThat(mandate.getMemberNumberSuffix()).isEqualTo(givenMembership.getMemberNumberSuffix());
|
||||
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2024-01-01)");
|
||||
assertThat(mandate.getReasonForTermination()).isEqualTo(CANCELLATION);
|
||||
assertThat(mandate.getStatus()).isEqualTo(CANCELLED);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -351,7 +351,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
.body("""
|
||||
{
|
||||
"validTo": "2024-01-01",
|
||||
"reasonForTermination": "CANCELLATION"
|
||||
"status": "CANCELLED"
|
||||
}
|
||||
""")
|
||||
.port(port)
|
||||
@ -364,7 +364,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
assertThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent().get()
|
||||
.matches(mandate -> {
|
||||
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2024-01-02)");
|
||||
assertThat(mandate.getReasonForTermination()).isEqualTo(CANCELLATION);
|
||||
assertThat(mandate.getStatus()).isEqualTo(CANCELLED);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -441,7 +441,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
||||
.partner(givenPartner)
|
||||
.memberNumberSuffix(TEMP_MEMBER_NUMBER_SUFFIX)
|
||||
.validity(Range.closedInfinite(LocalDate.parse("2022-11-01")))
|
||||
.reasonForTermination(NONE)
|
||||
.status(ACTIVE)
|
||||
.membershipFeeBillable(true)
|
||||
.build();
|
||||
|
||||
|
@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.office.membership;
|
||||
import io.hypersistence.utils.hibernate.type.range.Range;
|
||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeReasonForTerminationResource;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipStatusResource;
|
||||
import net.hostsharing.hsadminng.mapper.Mapper;
|
||||
import net.hostsharing.test.PatchUnitTestBase;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@ -79,11 +79,11 @@ class HsOfficeMembershipEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
PATCHED_VALID_TO,
|
||||
HsOfficeMembershipEntity::setValidTo),
|
||||
new SimpleProperty<>(
|
||||
"reasonForTermination",
|
||||
HsOfficeMembershipPatchResource::setReasonForTermination,
|
||||
HsOfficeReasonForTerminationResource.CANCELLATION,
|
||||
HsOfficeMembershipEntity::setReasonForTermination,
|
||||
HsOfficeReasonForTermination.CANCELLATION)
|
||||
"status",
|
||||
HsOfficeMembershipPatchResource::setStatus,
|
||||
HsOfficeMembershipStatusResource.CANCELLED,
|
||||
HsOfficeMembershipEntity::setStatus,
|
||||
HsOfficeMembershipStatus.CANCELLED)
|
||||
.notNullable(),
|
||||
new JsonNullableProperty<>(
|
||||
"membershipFeeBillable",
|
||||
|
@ -62,27 +62,27 @@ class HsOfficeMembershipEntityUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void getValidtyIfNull() {
|
||||
void getEmptyValidtyIfNull() {
|
||||
givenMembership.setValidity(null);
|
||||
final var result = givenMembership.getValidity();
|
||||
assertThat(result).isEqualTo(Range.infinite(LocalDate.class));
|
||||
assertThat(result.isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void initializesReasonForTerminationInPrePersistIfNull() throws Exception {
|
||||
void initializesStatusInPrePersistIfNull() throws Exception {
|
||||
final var givenUninitializedMembership = new HsOfficeMembershipEntity();
|
||||
assertThat(givenUninitializedMembership.getReasonForTermination()).as("precondition failed").isNull();
|
||||
assertThat(givenUninitializedMembership.getStatus()).as("precondition failed").isNull();
|
||||
|
||||
invokePrePersist(givenUninitializedMembership);
|
||||
assertThat(givenUninitializedMembership.getReasonForTermination()).isEqualTo(HsOfficeReasonForTermination.NONE);
|
||||
assertThat(givenUninitializedMembership.getStatus()).isEqualTo(HsOfficeMembershipStatus.INVALID);
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotOverwriteReasonForTerminationInPrePersistIfNotNull() throws Exception {
|
||||
givenMembership.setReasonForTermination(HsOfficeReasonForTermination.CANCELLATION);
|
||||
void doesNotOverwriteStatusInPrePersistIfNotNull() throws Exception {
|
||||
givenMembership.setStatus(HsOfficeMembershipStatus.CANCELLED);
|
||||
|
||||
invokePrePersist(givenMembership);
|
||||
assertThat(givenMembership.getReasonForTermination()).isEqualTo(HsOfficeReasonForTermination.CANCELLATION);
|
||||
assertThat(givenMembership.getStatus()).isEqualTo(HsOfficeMembershipStatus.CANCELLED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -161,9 +161,9 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
||||
// then
|
||||
exactlyTheseMembershipsAreReturned(
|
||||
result,
|
||||
"Membership(M-1000101, P-10001, [2022-10-01,), NONE)",
|
||||
"Membership(M-1000202, P-10002, [2022-10-01,), NONE)",
|
||||
"Membership(M-1000303, P-10003, [2022-10-01,), NONE)");
|
||||
"Membership(M-1000101, P-10001, [2022-10-01,), ACTIVE)",
|
||||
"Membership(M-1000202, P-10002, [2022-10-01,), ACTIVE)",
|
||||
"Membership(M-1000303, P-10003, [2022-10-01,), ACTIVE)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -177,7 +177,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
||||
|
||||
// then
|
||||
exactlyTheseMembershipsAreReturned(result,
|
||||
"Membership(M-1000101, P-10001, [2022-10-01,), NONE)");
|
||||
"Membership(M-1000101, P-10001, [2022-10-01,), ACTIVE)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -192,7 +192,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
||||
assertThat(result)
|
||||
.isNotNull()
|
||||
.extracting(Object::toString)
|
||||
.isEqualTo("Membership(M-1000202, P-10002, [2022-10-01,), NONE)");
|
||||
.isEqualTo("Membership(M-1000202, P-10002, [2022-10-01,), ACTIVE)");
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,7 +213,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
||||
context("superuser-alex@hostsharing.net");
|
||||
givenMembership.setValidity(Range.closedOpen(
|
||||
givenMembership.getValidity().lower(), newValidityEnd));
|
||||
givenMembership.setReasonForTermination(HsOfficeReasonForTermination.CANCELLATION);
|
||||
givenMembership.setStatus(HsOfficeMembershipStatus.CANCELLED);
|
||||
return toCleanup(membershipRepo.save(givenMembership));
|
||||
});
|
||||
|
||||
|
@ -13,7 +13,7 @@ import net.hostsharing.hsadminng.hs.office.coopshares.HsOfficeCoopSharesTransact
|
||||
import net.hostsharing.hsadminng.hs.office.coopshares.HsOfficeCoopSharesTransactionType;
|
||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeReasonForTermination;
|
||||
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipStatus;
|
||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerDetailsEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
|
||||
@ -54,6 +54,7 @@ import java.util.stream.Collectors;
|
||||
import static java.lang.Boolean.parseBoolean;
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
@ -185,6 +186,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
17=partner(P-10017: null null, null),
|
||||
20=partner(P-10020: null null, null),
|
||||
22=partner(P-11022: null null, null),
|
||||
90=partner(P-19090: null null, null),
|
||||
99=partner(P-19999: null null, null)
|
||||
}
|
||||
""");
|
||||
@ -194,14 +196,15 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
17=debitor(D-1001700: rel(anchor='null null, null', type='DEBITOR'), mih),
|
||||
20=debitor(D-1002000: rel(anchor='null null, null', type='DEBITOR'), xyz),
|
||||
22=debitor(D-1102200: rel(anchor='null null, null', type='DEBITOR'), xxx),
|
||||
90=debitor(D-1909000: rel(anchor='null null, null', type='DEBITOR'), yyy),
|
||||
99=debitor(D-1999900: rel(anchor='null null, null', type='DEBITOR'), zzz)
|
||||
}
|
||||
""");
|
||||
assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
17=Membership(M-1001700, P-10017, [2000-12-06,), NONE),
|
||||
17=Membership(M-1001700, P-10017, [2000-12-06,), ACTIVE),
|
||||
20=Membership(M-1002000, P-10020, [2000-12-06,2016-01-01), UNKNOWN),
|
||||
22=Membership(M-1102200, P-11022, [2021-04-01,), NONE)
|
||||
22=Membership(M-1102200, P-11022, [2021-04-01,), ACTIVE)
|
||||
}
|
||||
""");
|
||||
}
|
||||
@ -228,6 +231,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
17=partner(P-10017: NP Mellies, Michael, Herr Michael Mellies ),
|
||||
20=partner(P-10020: LP JM GmbH, Herr Philip Meyer-Contract , JM GmbH),
|
||||
22=partner(P-11022: ?? Test PS, Petra Schmidt , Test PS),
|
||||
90=partner(P-19090: NP Camus, Cecilia, Frau Cecilia Camus ),
|
||||
99=partner(P-19999: null null, null)
|
||||
}
|
||||
""");
|
||||
@ -240,7 +244,8 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
1203=contact(label='Herr Philip Meyer-Contract , JM GmbH', emailAddresses='pm-partner@example.org'),
|
||||
1204=contact(label='Frau Tammy Meyer-VIP , JM GmbH', emailAddresses='tm-vip@example.org'),
|
||||
1301=contact(label='Petra Schmidt , Test PS', emailAddresses='ps@example.com'),
|
||||
1401=contact(label='Frau Frauke Fanninga ', emailAddresses='ff@example.org')
|
||||
1401=contact(label='Frau Frauke Fanninga ', emailAddresses='ff@example.org'),
|
||||
1501=contact(label='Frau Cecilia Camus ', emailAddresses='cc@example.org')
|
||||
}
|
||||
""");
|
||||
assertThat(toFormattedString(persons)).isEqualToIgnoringWhitespace("""
|
||||
@ -253,7 +258,8 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
1203=person(personType='LP', tradeName='JM GmbH', familyName='Meyer-Contract', givenName='Philip'),
|
||||
1204=person(personType='LP', tradeName='JM GmbH', familyName='Meyer-VIP', givenName='Tammy'),
|
||||
1301=person(personType='??', tradeName='Test PS', familyName='Schmidt', givenName='Petra'),
|
||||
1401=person(personType='NP', tradeName='', familyName='Fanninga', givenName='Frauke')
|
||||
1401=person(personType='NP', tradeName='', familyName='Fanninga', givenName='Frauke'),
|
||||
1501=person(personType='NP', tradeName='', familyName='Camus', givenName='Cecilia')
|
||||
}
|
||||
""");
|
||||
assertThat(toFormattedString(debitors)).isEqualToIgnoringWhitespace("""
|
||||
@ -261,14 +267,15 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
17=debitor(D-1001700: rel(anchor='NP Mellies, Michael', type='DEBITOR', holder='NP Mellies, Michael'), mih),
|
||||
20=debitor(D-1002000: rel(anchor='LP JM GmbH', type='DEBITOR', holder='LP JM GmbH'), xyz),
|
||||
22=debitor(D-1102200: rel(anchor='?? Test PS', type='DEBITOR', holder='?? Test PS'), xxx),
|
||||
90=debitor(D-1909000: rel(anchor='NP Camus, Cecilia', type='DEBITOR', holder='NP Camus, Cecilia'), yyy),
|
||||
99=debitor(D-1999900: rel(anchor='null null, null', type='DEBITOR'), zzz)
|
||||
}
|
||||
""");
|
||||
assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
17=Membership(M-1001700, P-10017, [2000-12-06,), NONE),
|
||||
17=Membership(M-1001700, P-10017, [2000-12-06,), ACTIVE),
|
||||
20=Membership(M-1002000, P-10020, [2000-12-06,2016-01-01), UNKNOWN),
|
||||
22=Membership(M-1102200, P-11022, [2021-04-01,), NONE)
|
||||
22=Membership(M-1102200, P-11022, [2021-04-01,), ACTIVE)
|
||||
}
|
||||
""");
|
||||
assertThat(toFormattedString(relations)).isEqualToIgnoringWhitespace("""
|
||||
@ -279,21 +286,25 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
2000003=rel(anchor='LP JM GmbH', type='DEBITOR', holder='LP JM GmbH', contact='Frau Dr. Jenny Meyer-Billing , JM GmbH'),
|
||||
2000004=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000005=rel(anchor='?? Test PS', type='DEBITOR', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000006=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='null null, null'),
|
||||
2000007=rel(anchor='null null, null', type='DEBITOR'),
|
||||
2000008=rel(anchor='NP Mellies, Michael', type='OPERATIONS', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
||||
2000009=rel(anchor='NP Mellies, Michael', type='REPRESENTATIVE', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
||||
2000010=rel(anchor='LP JM GmbH', type='EX_PARTNER', holder='LP JM e.K.', contact='JM e.K.'),
|
||||
2000011=rel(anchor='LP JM GmbH', type='OPERATIONS', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||
2000012=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||
2000013=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='operations-announce', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||
2000014=rel(anchor='LP JM GmbH', type='REPRESENTATIVE', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000015=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='members-announce', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000016=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='customers-announce', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000017=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='Frau Tammy Meyer-VIP , JM GmbH'),
|
||||
2000018=rel(anchor='?? Test PS', type='OPERATIONS', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000019=rel(anchor='?? Test PS', type='REPRESENTATIVE', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000020=rel(anchor='NP Mellies, Michael', type='SUBSCRIBER', mark='operations-announce', holder='NP Fanninga, Frauke', contact='Frau Frauke Fanninga ')
|
||||
2000006=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus '),
|
||||
2000007=rel(anchor='NP Camus, Cecilia', type='DEBITOR', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus '),
|
||||
2000008=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='null null, null'),
|
||||
2000009=rel(anchor='null null, null', type='DEBITOR'),
|
||||
2000010=rel(anchor='NP Mellies, Michael', type='OPERATIONS', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
||||
2000011=rel(anchor='NP Mellies, Michael', type='REPRESENTATIVE', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
||||
2000012=rel(anchor='LP JM GmbH', type='EX_PARTNER', holder='LP JM e.K.', contact='JM e.K.'),
|
||||
2000013=rel(anchor='LP JM GmbH', type='OPERATIONS', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||
2000014=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||
2000015=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='operations-announce', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||
2000016=rel(anchor='LP JM GmbH', type='REPRESENTATIVE', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000017=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='members-announce', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000018=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='customers-announce', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000019=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='Frau Tammy Meyer-VIP , JM GmbH'),
|
||||
2000020=rel(anchor='?? Test PS', type='OPERATIONS', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000021=rel(anchor='?? Test PS', type='REPRESENTATIVE', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000022=rel(anchor='NP Mellies, Michael', type='SUBSCRIBER', mark='operations-announce', holder='NP Fanninga, Frauke', contact='Frau Frauke Fanninga '),
|
||||
2000023=rel(anchor='NP Camus, Cecilia', type='OPERATIONS', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus '),
|
||||
2000024=rel(anchor='NP Camus, Cecilia', type='REPRESENTATIVE', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus ')
|
||||
}
|
||||
""");
|
||||
}
|
||||
@ -383,7 +394,23 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
33002=CoopAssetsTransaction(M-1002000: 2005-01-10, ADOPTION, 512.00, for transfer from 7),
|
||||
34001=CoopAssetsTransaction(M-1002000: 2016-12-31, CLEARING, -8.00, for cancellation D),
|
||||
34002=CoopAssetsTransaction(M-1002000: 2016-12-31, DISBURSAL, -100.00, for cancellation D),
|
||||
34003=CoopAssetsTransaction(M-1002000: 2016-12-31, LOSS, -20.00, for cancellation D)
|
||||
34003=CoopAssetsTransaction(M-1002000: 2016-12-31, LOSS, -20.00, for cancellation D),
|
||||
35001=CoopAssetsTransaction(M-1909000: 2024-01-15, DEPOSIT, 128.00, for subscription E),
|
||||
35002=CoopAssetsTransaction(M-1909000: 2024-01-20, ADJUSTMENT, -128.00, chargeback for subscription E)
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1099)
|
||||
void verifyMemberships() {
|
||||
assumeThatWeAreImportingControlledTestData();
|
||||
assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
17=Membership(M-1001700, P-10017, [2000-12-06,), ACTIVE),
|
||||
20=Membership(M-1002000, P-10020, [2000-12-06,2016-01-01), UNKNOWN),
|
||||
22=Membership(M-1102200, P-11022, [2021-04-01,), ACTIVE),
|
||||
90=Membership(M-1909000, P-19090, empty, INVALID)
|
||||
}
|
||||
""");
|
||||
}
|
||||
@ -742,10 +769,10 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
rec.getLocalDate("member_since"),
|
||||
rec.getLocalDate("member_until")))
|
||||
.membershipFeeBillable(rec.isEmpty("member_role"))
|
||||
.reasonForTermination(
|
||||
.status(
|
||||
isBlank(rec.getString("member_until"))
|
||||
? HsOfficeReasonForTermination.NONE
|
||||
: HsOfficeReasonForTermination.UNKNOWN)
|
||||
? HsOfficeMembershipStatus.ACTIVE
|
||||
: HsOfficeMembershipStatus.UNKNOWN)
|
||||
.build();
|
||||
memberships.put(rec.getInteger("bp_id"), membership);
|
||||
}
|
||||
@ -760,7 +787,9 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
.map(this::trimAll)
|
||||
.map(row -> new Record(columns, row))
|
||||
.forEach(rec -> {
|
||||
final var member = memberships.get(rec.getInteger("bp_id"));
|
||||
final var bpId = rec.getInteger("bp_id");
|
||||
final var member = ofNullable(memberships.get(bpId))
|
||||
.orElseGet(() -> createOnDemandMembership(bpId));
|
||||
|
||||
final var shareTransaction = HsOfficeCoopSharesTransactionEntity.builder()
|
||||
.membership(member)
|
||||
@ -788,11 +817,14 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
.map(this::trimAll)
|
||||
.map(row -> new Record(columns, row))
|
||||
.forEach(rec -> {
|
||||
final var member = memberships.get(rec.getInteger("bp_id"));
|
||||
final var bpId = rec.getInteger("bp_id");
|
||||
final var member = ofNullable(memberships.get(bpId))
|
||||
.orElseGet(() -> createOnDemandMembership(bpId));
|
||||
|
||||
final var assetTypeMapping = new HashMap<String, HsOfficeCoopAssetsTransactionType>() {
|
||||
|
||||
{
|
||||
put("ADJUSTMENT", HsOfficeCoopAssetsTransactionType.ADJUSTMENT);
|
||||
put("HANDOVER", HsOfficeCoopAssetsTransactionType.TRANSFER);
|
||||
put("ADOPTION", HsOfficeCoopAssetsTransactionType.ADOPTION);
|
||||
put("LOSS", HsOfficeCoopAssetsTransactionType.LOSS);
|
||||
@ -823,6 +855,17 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
});
|
||||
}
|
||||
|
||||
private static HsOfficeMembershipEntity createOnDemandMembership(final Integer bpId) {
|
||||
final var onDemandMembership = HsOfficeMembershipEntity.builder()
|
||||
.memberNumberSuffix("00")
|
||||
.membershipFeeBillable(false)
|
||||
.partner(partners.get(bpId))
|
||||
.status(HsOfficeMembershipStatus.INVALID)
|
||||
.build();
|
||||
memberships.put(bpId, onDemandMembership);
|
||||
return onDemandMembership;
|
||||
}
|
||||
|
||||
private void importSepaMandates(final String[] header, final List<String[]> records) {
|
||||
|
||||
final var columns = new Columns(header);
|
||||
|
@ -86,7 +86,7 @@ class HsOfficePersonEntityUnitTest {
|
||||
|
||||
final var actualDisplay = givenPersonEntity.toShortString();
|
||||
|
||||
assertThat(actualDisplay).isEqualTo("NP Frau some family name, some given name");
|
||||
assertThat(actualDisplay).isEqualTo("NP some family name, some given name");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -7,3 +7,5 @@ member_asset_id; bp_id; date; action; amount; comment
|
||||
34001; 20; 2016-12-31; CLEARING; -8.00; for cancellation D
|
||||
34002; 20; 2016-12-31; PAYBACK; -100.00; for cancellation D
|
||||
34003; 20; 2016-12-31; LOSS; -20.00; for cancellation D
|
||||
35001; 90; 2024-01-15; PAYMENT; 128.00; for subscription E
|
||||
35002; 90; 2024-01-20; ADJUSTMENT;-128.00; chargeback for subscription E
|
||||
|
|
@ -2,4 +2,5 @@ bp_id;member_id;member_code;member_since;member_until;member_role;author_contrac
|
||||
17;10017;hsh00-mih;2000-12-06;;Aufsichtsrat;2006-10-15;2001-10-15;false;false;NET;DE-VAT-007
|
||||
20;10020;hsh00-xyz;2000-12-06;2015-12-31;;;;false;false;GROSS;
|
||||
22;11022;hsh00-xxx;2021-04-01;;;;;true;true;GROSS;
|
||||
90;19090;hsh00-yyy;;;;;;true;true;GROSS;
|
||||
99;19999;hsh00-zzz;;;;;;false;false;GROSS;
|
||||
|
|
@ -15,3 +15,6 @@ contact_id; bp_id; salut; first_name; last_name; title; firma; co; street; zip
|
||||
|
||||
# eine natürliche Person, die nur Subscriber ist
|
||||
1401; 17; Frau; Frauke; Fanninga; ; ; ; Am Walde 1; 29456; Hitzacker; DE; ; ; ;; ff@example.org; subscriber:operations-announce
|
||||
|
||||
# eine natürliche Person als Partner
|
||||
1501; 90; Frau; Cecilia; Camus; ; ; ; Rue d'Avignion 60; 45000; Orléans; FR; ; ; ;; cc@example.org; partner,contractual,billing,operation
|
||||
|
|
Loading…
Reference in New Issue
Block a user