merging current DTO during deserialization
This commit is contained in:
		@@ -80,7 +80,6 @@ public final class SecurityUtils {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Role getLoginUserRoleFor(final Class<?> onDtoClass, final Long onId) {
 | 
			
		||||
 | 
			
		||||
        final Role highestRole = userRoleAssignments.stream().
 | 
			
		||||
            map(ura ->
 | 
			
		||||
                matches(onDtoClass, onId, ura)
 | 
			
		||||
@@ -91,7 +90,7 @@ public final class SecurityUtils {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static boolean matches(Class<?> onDtoClass, Long onId, UserRoleAssignment ura) {
 | 
			
		||||
        final boolean matches =  (ura.onClass == null || onDtoClass == ura.onClass) && (ura.onId == null || onId.equals(ura.onId) );
 | 
			
		||||
        final boolean matches =  (ura.onClass == null || onDtoClass == ura.onClass) && (ura.onId == null || ura.onId.equals(onId));
 | 
			
		||||
        return matches;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,5 +3,5 @@ package org.hostsharing.hsadminng.service;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
public interface IdToDtoResolver<T> {
 | 
			
		||||
    Optional<? extends T> findOne(Long id);
 | 
			
		||||
    Optional<T> findOne(Long id);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ import java.util.Optional;
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
@Transactional
 | 
			
		||||
public class ShareService {
 | 
			
		||||
public class ShareService implements IdToDtoResolver<ShareDTO> {
 | 
			
		||||
 | 
			
		||||
    private final Logger log = LoggerFactory.getLogger(ShareService.class);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,17 @@ import org.hostsharing.hsadminng.security.SecurityUtils;
 | 
			
		||||
import org.hostsharing.hsadminng.service.IdToDtoResolver;
 | 
			
		||||
import org.hostsharing.hsadminng.service.dto.MembershipDTO;
 | 
			
		||||
import org.hostsharing.hsadminng.service.util.ReflectionUtil;
 | 
			
		||||
import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException;
 | 
			
		||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.EntityNotFoundException;
 | 
			
		||||
import java.lang.annotation.Annotation;
 | 
			
		||||
import java.lang.reflect.Field;
 | 
			
		||||
import java.lang.reflect.ParameterizedType;
 | 
			
		||||
import java.lang.reflect.Type;
 | 
			
		||||
 | 
			
		||||
import static com.google.common.base.Verify.verify;
 | 
			
		||||
 | 
			
		||||
abstract class JSonAccessFilter<T> {
 | 
			
		||||
    private final ApplicationContext ctx;
 | 
			
		||||
    final T dto;
 | 
			
		||||
@@ -72,7 +75,7 @@ abstract class JSonAccessFilter<T> {
 | 
			
		||||
        final Long parentId = (Long) ReflectionUtil.getValue(dto, parentIdField);
 | 
			
		||||
        final Role roleOnParent = SecurityUtils.getLoginUserRoleFor(parentDtoClass, parentId);
 | 
			
		||||
 | 
			
		||||
        final Object parentEntity = findParentDto(parentDtoLoader, parentId);
 | 
			
		||||
        final Object parentEntity = loadDto(parentDtoLoader, parentId);
 | 
			
		||||
        return Role.broadest(baseRole, getLoginUserRoleOnAncestorOfDtoClassIfHigher(roleOnParent, parentEntity));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -91,9 +94,16 @@ abstract class JSonAccessFilter<T> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    private Object findParentDto(final Class<? extends IdToDtoResolver> parentDtoLoader, final Long parentId) {
 | 
			
		||||
        final IdToDtoResolver<MembershipDTO> idToDtoResolver = ctx.getAutowireCapableBeanFactory().createBean(parentDtoLoader);
 | 
			
		||||
        return idToDtoResolver.findOne(parentId).orElseThrow(() -> new EntityNotFoundException("Can't resolve parent entity ID " + parentId + " via " + parentDtoLoader));
 | 
			
		||||
    protected Object loadDto(final Class<? extends IdToDtoResolver> resolverClass, final Long id) {
 | 
			
		||||
        verify(id != null, "id must not be null");
 | 
			
		||||
 | 
			
		||||
        final AutowireCapableBeanFactory beanFactory = ctx.getAutowireCapableBeanFactory();
 | 
			
		||||
        verify(beanFactory != null, "no bean factory found, probably missing mock configuration for ApplicationContext, e.g. given(...)");
 | 
			
		||||
 | 
			
		||||
        final IdToDtoResolver<MembershipDTO> resolverBean = beanFactory.createBean(resolverClass);
 | 
			
		||||
        verify(resolverBean != null, "no " + resolverClass.getSimpleName() + " bean created, probably missing mock configuration for AutowireCapableBeanFactory, e.g. given(...)");
 | 
			
		||||
 | 
			
		||||
        return resolverBean.findOne(id).orElseThrow(() -> new BadRequestAlertException("Can't resolve entity ID " + id + " via " + resolverClass, resolverClass.getSimpleName(), "isNotFound"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static Field determineFieldWithAnnotation(final Class<?> dtoClass, final Class<? extends Annotation> idAnnotationClass) {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,15 +3,18 @@ package org.hostsharing.hsadminng.service.accessfilter;
 | 
			
		||||
import com.fasterxml.jackson.core.JsonParser;
 | 
			
		||||
import com.fasterxml.jackson.core.TreeNode;
 | 
			
		||||
import com.fasterxml.jackson.databind.DeserializationContext;
 | 
			
		||||
import com.fasterxml.jackson.databind.node.ArrayNode;
 | 
			
		||||
import com.fasterxml.jackson.databind.node.IntNode;
 | 
			
		||||
import com.fasterxml.jackson.databind.node.LongNode;
 | 
			
		||||
import com.fasterxml.jackson.databind.node.TextNode;
 | 
			
		||||
import org.apache.commons.lang3.NotImplementedException;
 | 
			
		||||
import org.apache.commons.lang3.ObjectUtils;
 | 
			
		||||
import org.hostsharing.hsadminng.service.util.ReflectionUtil;
 | 
			
		||||
import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Field;
 | 
			
		||||
import java.time.LocalDate;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
@@ -20,7 +23,7 @@ import static org.hostsharing.hsadminng.service.util.ReflectionUtil.unchecked;
 | 
			
		||||
public class JSonDeserializerWithAccessFilter<T> extends JSonAccessFilter<T> {
 | 
			
		||||
 | 
			
		||||
    private final TreeNode treeNode;
 | 
			
		||||
    private final Set<Field> modifiedFields = new HashSet<>();
 | 
			
		||||
    private final Set<Field> writtenFields = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
    public JSonDeserializerWithAccessFilter(final ApplicationContext ctx, final JsonParser jsonParser, final DeserializationContext deserializationContext, Class<T> dtoClass) {
 | 
			
		||||
        super(ctx, unchecked(dtoClass::newInstance));
 | 
			
		||||
@@ -30,7 +33,9 @@ public class JSonDeserializerWithAccessFilter<T> extends JSonAccessFilter<T> {
 | 
			
		||||
    // Jackson deserializes from the JsonParser, thus no input parameter needed.
 | 
			
		||||
    public T deserialize() {
 | 
			
		||||
        deserializeValues();
 | 
			
		||||
        checkAccessToModifiedFields();
 | 
			
		||||
        final T currentDto = loadCurrentDto(getId());
 | 
			
		||||
        overwriteUnmodifiedFieldsWithCurrentValues(currentDto);
 | 
			
		||||
        checkAccessToWrittenFields(currentDto);
 | 
			
		||||
        return dto;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -38,25 +43,52 @@ public class JSonDeserializerWithAccessFilter<T> extends JSonAccessFilter<T> {
 | 
			
		||||
        treeNode.fieldNames().forEachRemaining(fieldName -> {
 | 
			
		||||
            try {
 | 
			
		||||
                final Field field = dto.getClass().getDeclaredField(fieldName);
 | 
			
		||||
                final Object value = readValue(treeNode, field);
 | 
			
		||||
                writeValue(dto, field, value);
 | 
			
		||||
                markAsModified(field);
 | 
			
		||||
                final Object newValue = readValue(treeNode, field);
 | 
			
		||||
                writeValue(dto, field, newValue);
 | 
			
		||||
            } catch (NoSuchFieldException e) {
 | 
			
		||||
                throw new RuntimeException("setting field " + fieldName + " failed", e);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    private T loadCurrentDto(final Long id) {
 | 
			
		||||
        if (id != null) {
 | 
			
		||||
            return (T) loadDto(selfIdField.getAnnotation(SelfId.class).resolver(), id);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void overwriteUnmodifiedFieldsWithCurrentValues(final Object currentDto) {
 | 
			
		||||
        if ( currentDto == null ) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        for (Field field : currentDto.getClass().getDeclaredFields()) {
 | 
			
		||||
            if (field.isAnnotationPresent(AccessFor.class) && !writtenFields.contains(field)) {
 | 
			
		||||
                final Object value = ReflectionUtil.getValue(currentDto, field);
 | 
			
		||||
                ReflectionUtil.setValue(dto, field, value);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Object readValue(final TreeNode treeNode, final Field field) {
 | 
			
		||||
        final TreeNode fieldNode = treeNode.get(field.getName());
 | 
			
		||||
        return readValue(treeNode, field.getName(), field.getType());
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Object readValue(final TreeNode treeNode, final String fieldName, final Class<?> fieldClass) {
 | 
			
		||||
        final TreeNode fieldNode = treeNode.get(fieldName);
 | 
			
		||||
        if (fieldNode instanceof TextNode) {
 | 
			
		||||
            return ((TextNode) fieldNode).asText();
 | 
			
		||||
        } else if (fieldNode instanceof IntNode) {
 | 
			
		||||
            return ((IntNode) fieldNode).asInt();
 | 
			
		||||
        } else if (fieldNode instanceof LongNode) {
 | 
			
		||||
            return ((LongNode) fieldNode).asLong();
 | 
			
		||||
        } else if (fieldNode instanceof ArrayNode && LocalDate.class.isAssignableFrom(fieldClass)) {
 | 
			
		||||
            return LocalDate.of(((ArrayNode) fieldNode).get(0).asInt(), ((ArrayNode) fieldNode).get(1).asInt(), ((ArrayNode) fieldNode).get(2).asInt());
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new NotImplementedException("property type not yet implemented: " + field);
 | 
			
		||||
            throw new NotImplementedException("property type not yet implemented: " + fieldNode + " -> " + fieldName + ": " + fieldClass);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -67,30 +99,36 @@ public class JSonDeserializerWithAccessFilter<T> extends JSonAccessFilter<T> {
 | 
			
		||||
            ReflectionUtil.setValue(dto, field, ((Number) value).intValue());
 | 
			
		||||
        } else if (Long.class.isAssignableFrom(field.getType()) || long.class.isAssignableFrom(field.getType())) {
 | 
			
		||||
            ReflectionUtil.setValue(dto, field, ((Number) value).longValue());
 | 
			
		||||
        } else if (field.getType().isEnum()) {
 | 
			
		||||
            ReflectionUtil.setValue(dto, field, Enum.valueOf((Class<Enum>) field.getType(), value.toString()));
 | 
			
		||||
        } else if (LocalDate.class.isAssignableFrom(field.getType())) {
 | 
			
		||||
            ReflectionUtil.setValue(dto, field, LocalDate.parse(value.toString()));
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new NotImplementedException("property type not yet implemented: " + field);
 | 
			
		||||
        }
 | 
			
		||||
        writtenFields.add(field);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void markAsModified(final Field field) {
 | 
			
		||||
        modifiedFields.add(field);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void checkAccessToModifiedFields() {
 | 
			
		||||
        modifiedFields.forEach(field -> {
 | 
			
		||||
            if ( !field.equals(selfIdField) ) {
 | 
			
		||||
    private void checkAccessToWrittenFields(final T currentDto) {
 | 
			
		||||
        writtenFields.forEach(field -> {
 | 
			
		||||
            if (!field.equals(selfIdField)) {
 | 
			
		||||
                final Role role = getLoginUserRole();
 | 
			
		||||
                if (getId() == null) {
 | 
			
		||||
                    if (!getLoginUserRole().isAllowedToInit(field)) {
 | 
			
		||||
                        if ( !field.equals(parentIdField)) {
 | 
			
		||||
                            throw new BadRequestAlertException("Initialization of field prohibited for current user", toDisplay(field), "initializationProhibited");
 | 
			
		||||
                    if (!role.isAllowedToInit(field)) {
 | 
			
		||||
                        if (!field.equals(parentIdField)) {
 | 
			
		||||
                            throw new BadRequestAlertException("Initialization of field " + toDisplay(field) + " prohibited for current user role " + role, toDisplay(field), "initializationProhibited");
 | 
			
		||||
                        } else {
 | 
			
		||||
                            throw new BadRequestAlertException("Referencing field prohibited for current user", toDisplay(field), "referencingProhibited");
 | 
			
		||||
                            throw new BadRequestAlertException("Referencing field " + toDisplay(field) + " prohibited for current user role " + role, toDisplay(field), "referencingProhibited");
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } else if (!getLoginUserRole().isAllowedToUpdate(field)) {
 | 
			
		||||
                        throw new BadRequestAlertException("Update of field prohibited for current user", toDisplay(field), "updateProhibited");
 | 
			
		||||
                } else if (isUpdate(field, dto, currentDto) && !getLoginUserRole().isAllowedToUpdate(field)){
 | 
			
		||||
                    throw new BadRequestAlertException("Update of field " + toDisplay(field) + " prohibited for current user role " + role, toDisplay(field), "updateProhibited");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean isUpdate(final Field field, final T dto, T currentDto) {
 | 
			
		||||
        return ObjectUtils.notEqual(ReflectionUtil.getValue(dto, field), ReflectionUtil.getValue(currentDto, field));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ import java.io.IOException;
 | 
			
		||||
import java.lang.reflect.Field;
 | 
			
		||||
import java.time.LocalDate;
 | 
			
		||||
 | 
			
		||||
public class JSonSerializerWithAccessFilter <T> extends JSonAccessFilter<T> {
 | 
			
		||||
public class JSonSerializerWithAccessFilter<T> extends JSonAccessFilter<T> {
 | 
			
		||||
    private final JsonGenerator jsonGenerator;
 | 
			
		||||
    private final SerializerProvider serializerProvider;
 | 
			
		||||
 | 
			
		||||
@@ -27,32 +27,35 @@ public class JSonSerializerWithAccessFilter <T> extends JSonAccessFilter<T> {
 | 
			
		||||
    public void serialize() throws IOException {
 | 
			
		||||
 | 
			
		||||
        jsonGenerator.writeStartObject();
 | 
			
		||||
        for (Field prop : dto.getClass().getDeclaredFields()) {
 | 
			
		||||
            toJSon(dto, jsonGenerator, prop);
 | 
			
		||||
        for (Field field : dto.getClass().getDeclaredFields()) {
 | 
			
		||||
            toJSon(dto, jsonGenerator, field);
 | 
			
		||||
        }
 | 
			
		||||
        jsonGenerator.writeEndObject();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void toJSon(final Object dto, final JsonGenerator jsonGenerator, final Field prop) throws IOException {
 | 
			
		||||
        if (getLoginUserRole().isAllowedToRead(prop)) {
 | 
			
		||||
            final String fieldName = prop.getName();
 | 
			
		||||
    private void toJSon(final Object dto, final JsonGenerator jsonGenerator, final Field field) throws IOException {
 | 
			
		||||
        if (getLoginUserRole().isAllowedToRead(field)) {
 | 
			
		||||
            final String fieldName = field.getName();
 | 
			
		||||
            // TODO: maybe replace by serializerProvider.defaultSerialize...()?
 | 
			
		||||
            //  But that makes it difficult for parallel structure with the deserializer (clumsy API).
 | 
			
		||||
            //  Alternatively extract the supported types to subclasses of some abstract class and
 | 
			
		||||
            //  here as well as in the deserializer just access the matching implementation through a map.
 | 
			
		||||
            //  Or even completely switch from Jackson to GSON?
 | 
			
		||||
            if (Integer.class.isAssignableFrom(prop.getType()) || int.class.isAssignableFrom(prop.getType())) {
 | 
			
		||||
                jsonGenerator.writeNumberField(fieldName, (int) get(dto, prop));
 | 
			
		||||
            } else if (Long.class.isAssignableFrom(prop.getType()) || long.class.isAssignableFrom(prop.getType())) {
 | 
			
		||||
                jsonGenerator.writeNumberField(fieldName, (long) get(dto, prop));
 | 
			
		||||
            } else if (LocalDate.class.isAssignableFrom(prop.getType())) {
 | 
			
		||||
                jsonGenerator.writeStringField(fieldName, get(dto, prop).toString()); // TODO proper format
 | 
			
		||||
            } else if (Enum.class.isAssignableFrom(prop.getType())) {
 | 
			
		||||
                jsonGenerator.writeStringField(fieldName, get(dto, prop).toString()); // TODO proper representation
 | 
			
		||||
            } else if (String.class.isAssignableFrom(prop.getType())) {
 | 
			
		||||
                jsonGenerator.writeStringField(fieldName, (String) get(dto, prop));
 | 
			
		||||
            final Object fieldValue = get(dto, field);
 | 
			
		||||
            if (fieldValue == null) {
 | 
			
		||||
                jsonGenerator.writeNullField(fieldName);
 | 
			
		||||
            } else if (Integer.class.isAssignableFrom(field.getType()) || int.class.isAssignableFrom(field.getType())) {
 | 
			
		||||
                jsonGenerator.writeNumberField(fieldName, (int) fieldValue);
 | 
			
		||||
            } else if (Long.class.isAssignableFrom(field.getType()) || long.class.isAssignableFrom(field.getType())) {
 | 
			
		||||
                jsonGenerator.writeNumberField(fieldName, (long) fieldValue);
 | 
			
		||||
            } else if (LocalDate.class.isAssignableFrom(field.getType())) {
 | 
			
		||||
                jsonGenerator.writeStringField(fieldName, fieldValue.toString()); // TODO proper format
 | 
			
		||||
            } else if (Enum.class.isAssignableFrom(field.getType())) {
 | 
			
		||||
                jsonGenerator.writeStringField(fieldName, fieldValue.toString()); // TODO proper representation
 | 
			
		||||
            } else if (String.class.isAssignableFrom(field.getType())) {
 | 
			
		||||
                jsonGenerator.writeStringField(fieldName, (String) fieldValue);
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new NotImplementedException("property type not yet implemented: " + prop);
 | 
			
		||||
                throw new NotImplementedException("property type not yet implemented: " + field);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -33,17 +33,12 @@ public enum Role {
 | 
			
		||||
     */
 | 
			
		||||
    SUPPORTER(3),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This meta-role is to specify that any kind of customer contact can get access to the resource.
 | 
			
		||||
     */
 | 
			
		||||
    ANY_CUSTOMER_CONTACT(20),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This role is for contractual contacts of a customer, like a director of the company.
 | 
			
		||||
     * Who has this role, has the broadest access to all resources which belong to this customer.
 | 
			
		||||
     * Everything which relates to the contract with the customer, needs this role.
 | 
			
		||||
     */
 | 
			
		||||
    CONTRACTUAL_CONTACT(21),
 | 
			
		||||
    CONTRACTUAL_CONTACT(20),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This role is for financial contacts of a customer, e.g. for accessing billing data.
 | 
			
		||||
@@ -64,6 +59,11 @@ public enum Role {
 | 
			
		||||
    TECHNICAL_CONTACT(22),
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This meta-role is to specify that any kind of customer contact can get access to the resource.
 | 
			
		||||
     */
 | 
			
		||||
    ANY_CUSTOMER_CONTACT(29),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Any user which belongs to a customer has at least this role.
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
package org.hostsharing.hsadminng.service.accessfilter;
 | 
			
		||||
 | 
			
		||||
import org.hostsharing.hsadminng.service.IdToDtoResolver;
 | 
			
		||||
 | 
			
		||||
import java.lang.annotation.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -14,4 +16,6 @@ import java.lang.annotation.*;
 | 
			
		||||
@Target({ElementType.FIELD})
 | 
			
		||||
@Retention(RetentionPolicy.RUNTIME)
 | 
			
		||||
public @interface SelfId {
 | 
			
		||||
    /// The service which can load the referenced DTO.
 | 
			
		||||
    Class<? extends IdToDtoResolver<?>> resolver();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ public class AssetDTO implements Serializable {
 | 
			
		||||
 | 
			
		||||
    private Long membershipId;
 | 
			
		||||
 | 
			
		||||
    private String membershipAdmissionDocumentDate;
 | 
			
		||||
    private String membershipDisplayReference;
 | 
			
		||||
 | 
			
		||||
    public Long getId() {
 | 
			
		||||
        return id;
 | 
			
		||||
@@ -92,12 +92,12 @@ public class AssetDTO implements Serializable {
 | 
			
		||||
        this.membershipId = membershipId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getMembershipAdmissionDocumentDate() {
 | 
			
		||||
        return membershipAdmissionDocumentDate;
 | 
			
		||||
    public String getMembershipDisplayReference() {
 | 
			
		||||
        return membershipDisplayReference;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setMembershipAdmissionDocumentDate(String membershipAdmissionDocumentDate) {
 | 
			
		||||
        this.membershipAdmissionDocumentDate = membershipAdmissionDocumentDate;
 | 
			
		||||
    public void setMembershipDisplayReference(String membershipDisplayReference) {
 | 
			
		||||
        this.membershipDisplayReference = membershipDisplayReference;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -131,7 +131,7 @@ public class AssetDTO implements Serializable {
 | 
			
		||||
            ", amount=" + getAmount() +
 | 
			
		||||
            ", remark='" + getRemark() + "'" +
 | 
			
		||||
            ", membership=" + getMembershipId() +
 | 
			
		||||
            ", membership='" + getMembershipAdmissionDocumentDate() + "'" +
 | 
			
		||||
            ", membership='" + getMembershipDisplayReference() + "'" +
 | 
			
		||||
            "}";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.JsonSerializer;
 | 
			
		||||
import com.fasterxml.jackson.databind.SerializerProvider;
 | 
			
		||||
import org.hostsharing.hsadminng.domain.enumeration.CustomerKind;
 | 
			
		||||
import org.hostsharing.hsadminng.domain.enumeration.VatRegion;
 | 
			
		||||
import org.hostsharing.hsadminng.service.CustomerService;
 | 
			
		||||
import org.hostsharing.hsadminng.service.accessfilter.*;
 | 
			
		||||
import org.springframework.boot.jackson.JsonComponent;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
@@ -21,9 +22,9 @@ import java.util.Objects;
 | 
			
		||||
/**
 | 
			
		||||
 * A DTO for the Customer entity.
 | 
			
		||||
 */
 | 
			
		||||
public class CustomerDTO implements Serializable {
 | 
			
		||||
public class CustomerDTO extends FluentBuilder<CustomerDTO> implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @SelfId
 | 
			
		||||
    @SelfId(resolver = CustomerService.class)
 | 
			
		||||
    @AccessFor(read = Role.ANY_CUSTOMER_USER)
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
@@ -41,31 +42,38 @@ public class CustomerDTO implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @Size(max = 80)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, read = Role.ANY_CUSTOMER_USER)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.ANY_CUSTOMER_USER)
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.CONTRACTUAL_CONTACT)
 | 
			
		||||
    private CustomerKind kind;
 | 
			
		||||
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private LocalDate birthDate;
 | 
			
		||||
 | 
			
		||||
    @Size(max = 80)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private String birthPlace;
 | 
			
		||||
 | 
			
		||||
    @Size(max = 80)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private String registrationCourt;
 | 
			
		||||
 | 
			
		||||
    @Size(max = 80)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private String registrationNumber;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private VatRegion vatRegion;
 | 
			
		||||
 | 
			
		||||
    @Size(max = 40)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private String vatNumber;
 | 
			
		||||
 | 
			
		||||
    @Size(max = 80)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.CONTRACTUAL_CONTACT, read = Role.ANY_CUSTOMER_CONTACT)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.CONTRACTUAL_CONTACT, read = Role.CONTRACTUAL_CONTACT)
 | 
			
		||||
    private String contractualSalutation;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
@@ -78,7 +86,7 @@ public class CustomerDTO implements Serializable {
 | 
			
		||||
    private String billingSalutation;
 | 
			
		||||
 | 
			
		||||
    @Size(max = 400)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.CONTRACTUAL_CONTACT)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private String billingAddress;
 | 
			
		||||
 | 
			
		||||
    @Size(max = 160)
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
package org.hostsharing.hsadminng.service.dto;
 | 
			
		||||
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
 | 
			
		||||
public class FluentBuilder<T> {
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    public T with(
 | 
			
		||||
        Consumer<T> builderFunction) {
 | 
			
		||||
        builderFunction.accept((T) this);
 | 
			
		||||
        return (T) this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package org.hostsharing.hsadminng.service.dto;
 | 
			
		||||
 | 
			
		||||
import org.hostsharing.hsadminng.service.CustomerService;
 | 
			
		||||
import org.hostsharing.hsadminng.service.MembershipService;
 | 
			
		||||
import org.hostsharing.hsadminng.service.accessfilter.AccessFor;
 | 
			
		||||
import org.hostsharing.hsadminng.service.accessfilter.ParentId;
 | 
			
		||||
import org.hostsharing.hsadminng.service.accessfilter.Role;
 | 
			
		||||
@@ -11,14 +12,13 @@ import javax.validation.constraints.Size;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.time.LocalDate;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A DTO for the Membership entity.
 | 
			
		||||
 */
 | 
			
		||||
public class MembershipDTO implements Serializable {
 | 
			
		||||
public class MembershipDTO extends FluentBuilder<MembershipDTO> implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @SelfId
 | 
			
		||||
    @SelfId(resolver = MembershipService.class)
 | 
			
		||||
    @AccessFor(read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
@@ -47,12 +47,6 @@ public class MembershipDTO implements Serializable {
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private String customerPrefix;
 | 
			
		||||
 | 
			
		||||
    public MembershipDTO with(
 | 
			
		||||
        Consumer<MembershipDTO> builderFunction) {
 | 
			
		||||
        builderFunction.accept(this);
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Long getId() {
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,13 @@
 | 
			
		||||
package org.hostsharing.hsadminng.service.dto;
 | 
			
		||||
 | 
			
		||||
import org.hostsharing.hsadminng.domain.enumeration.ShareAction;
 | 
			
		||||
import org.hostsharing.hsadminng.service.MembershipService;
 | 
			
		||||
import org.hostsharing.hsadminng.service.ShareService;
 | 
			
		||||
import org.hostsharing.hsadminng.service.accessfilter.AccessFor;
 | 
			
		||||
import org.hostsharing.hsadminng.service.accessfilter.ParentId;
 | 
			
		||||
import org.hostsharing.hsadminng.service.accessfilter.Role;
 | 
			
		||||
import org.hostsharing.hsadminng.service.accessfilter.SelfId;
 | 
			
		||||
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
import javax.validation.constraints.Size;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
@@ -11,18 +19,16 @@ import java.util.Objects;
 | 
			
		||||
 */
 | 
			
		||||
public class ShareDTO implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @SelfId
 | 
			
		||||
    @SelfId(resolver = ShareService.class)
 | 
			
		||||
    @AccessFor(read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private LocalDate documentDate;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private LocalDate valueDate;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
@@ -41,8 +47,8 @@ public class ShareDTO implements Serializable {
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private Long membershipId;
 | 
			
		||||
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, read = Role.SUPPORTER)
 | 
			
		||||
    private String membershipAdmissionDocumentDate;
 | 
			
		||||
    @AccessFor(read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
 | 
			
		||||
    private String membershipDisplayReference;
 | 
			
		||||
 | 
			
		||||
    public Long getId() {
 | 
			
		||||
        return id;
 | 
			
		||||
@@ -100,12 +106,12 @@ public class ShareDTO implements Serializable {
 | 
			
		||||
        this.membershipId = membershipId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getMembershipAdmissionDocumentDate() {
 | 
			
		||||
        return membershipAdmissionDocumentDate;
 | 
			
		||||
    public String getMembershipDisplayReference() {
 | 
			
		||||
        return membershipDisplayReference;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setMembershipAdmissionDocumentDate(String membershipAdmissionDocumentDate) {
 | 
			
		||||
        this.membershipAdmissionDocumentDate = membershipAdmissionDocumentDate;
 | 
			
		||||
    public void setMembershipDisplayReference(String membershipDisplayReference) {
 | 
			
		||||
        this.membershipDisplayReference = membershipDisplayReference;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -139,7 +145,7 @@ public class ShareDTO implements Serializable {
 | 
			
		||||
            ", quantity=" + getQuantity() +
 | 
			
		||||
            ", remark='" + getRemark() + "'" +
 | 
			
		||||
            ", membership=" + getMembershipId() +
 | 
			
		||||
            ", membership='" + getMembershipAdmissionDocumentDate() + "'" +
 | 
			
		||||
            ", membership='" + getMembershipDisplayReference() + "'" +
 | 
			
		||||
            "}";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ import org.mapstruct.Mapping;
 | 
			
		||||
public interface AssetMapper extends EntityMapper<AssetDTO, Asset> {
 | 
			
		||||
 | 
			
		||||
    @Mapping(source = "membership.id", target = "membershipId")
 | 
			
		||||
    @Mapping(source = "membership.admissionDocumentDate", target = "membershipAdmissionDocumentDate")
 | 
			
		||||
    @Mapping(source = "membership.admissionDocumentDate", target = "membershipDisplayReference")
 | 
			
		||||
    AssetDTO toDto(Asset asset);
 | 
			
		||||
 | 
			
		||||
    @Mapping(source = "membershipId", target = "membership")
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ import org.mapstruct.Mapping;
 | 
			
		||||
public interface ShareMapper extends EntityMapper<ShareDTO, Share> {
 | 
			
		||||
 | 
			
		||||
    @Mapping(source = "membership.id", target = "membershipId")
 | 
			
		||||
    @Mapping(source = "membership.admissionDocumentDate", target = "membershipAdmissionDocumentDate")
 | 
			
		||||
    @Mapping(source = "membership.admissionDocumentDate", target = "membershipDisplayReference")
 | 
			
		||||
    ShareDTO toDto(Share share);
 | 
			
		||||
 | 
			
		||||
    @Mapping(source = "membershipId", target = "membership")
 | 
			
		||||
 
 | 
			
		||||
@@ -1,25 +1,24 @@
 | 
			
		||||
package org.hostsharing.hsadminng.web.rest;
 | 
			
		||||
 | 
			
		||||
import io.github.jhipster.web.util.ResponseUtil;
 | 
			
		||||
import org.hostsharing.hsadminng.service.CustomerQueryService;
 | 
			
		||||
import org.hostsharing.hsadminng.service.CustomerService;
 | 
			
		||||
import org.hostsharing.hsadminng.service.dto.CustomerCriteria;
 | 
			
		||||
import org.hostsharing.hsadminng.service.dto.CustomerDTO;
 | 
			
		||||
import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException;
 | 
			
		||||
import org.hostsharing.hsadminng.web.rest.util.HeaderUtil;
 | 
			
		||||
import org.hostsharing.hsadminng.web.rest.util.PaginationUtil;
 | 
			
		||||
import org.hostsharing.hsadminng.service.dto.CustomerDTO;
 | 
			
		||||
import org.hostsharing.hsadminng.service.dto.CustomerCriteria;
 | 
			
		||||
import org.hostsharing.hsadminng.service.CustomerQueryService;
 | 
			
		||||
import io.github.jhipster.web.util.ResponseUtil;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.springframework.data.domain.Page;
 | 
			
		||||
import org.springframework.data.domain.Pageable;
 | 
			
		||||
import org.springframework.http.HttpHeaders;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import javax.validation.Valid;
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
import java.net.URISyntaxException;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@@ -72,7 +71,7 @@ public class CustomerResource {
 | 
			
		||||
     * @throws URISyntaxException if the Location URI syntax is incorrect
 | 
			
		||||
     */
 | 
			
		||||
    @PutMapping("/customers")
 | 
			
		||||
    public ResponseEntity<CustomerDTO> updateCustomer(@Valid @RequestBody CustomerDTO customerDTO) throws URISyntaxException {
 | 
			
		||||
    public ResponseEntity<CustomerDTO> updateCustomer(@RequestBody CustomerDTO customerDTO) {
 | 
			
		||||
        log.debug("REST request to update Customer : {}", customerDTO);
 | 
			
		||||
        if (customerDTO.getId() == null) {
 | 
			
		||||
            throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull");
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
                <dt><span jhiTranslate="hsadminNgApp.asset.membership">Membership</span></dt>
 | 
			
		||||
                <dd>
 | 
			
		||||
                    <div *ngIf="asset.membershipId">
 | 
			
		||||
                        <a [routerLink]="['/membership', asset.membershipId, 'view']">{{asset.membershipAdmissionDocumentDate}}</a>
 | 
			
		||||
                        <a [routerLink]="['/membership', asset.membershipId, 'view']">{{asset.membershipDisplayReference}}</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </dd>
 | 
			
		||||
            </dl>
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
            <th jhiSortBy="action"><span jhiTranslate="hsadminNgApp.asset.action">Action</span> <fa-icon [icon]="'sort'"></fa-icon></th>
 | 
			
		||||
            <th jhiSortBy="amount"><span jhiTranslate="hsadminNgApp.asset.amount">Amount</span> <fa-icon [icon]="'sort'"></fa-icon></th>
 | 
			
		||||
            <th jhiSortBy="remark"><span jhiTranslate="hsadminNgApp.asset.remark">Remark</span> <fa-icon [icon]="'sort'"></fa-icon></th>
 | 
			
		||||
            <th jhiSortBy="membershipAdmissionDocumentDate"><span jhiTranslate="hsadminNgApp.asset.membership">Membership</span> <fa-icon [icon]="'sort'"></fa-icon></th>
 | 
			
		||||
            <th jhiSortBy="membershipDisplayReference"><span jhiTranslate="hsadminNgApp.asset.membership">Membership</span> <fa-icon [icon]="'sort'"></fa-icon></th>
 | 
			
		||||
            <th></th>
 | 
			
		||||
            </tr>
 | 
			
		||||
            </thead>
 | 
			
		||||
@@ -34,7 +34,7 @@
 | 
			
		||||
                <td>{{asset.remark}}</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <div *ngIf="asset.membershipId">
 | 
			
		||||
                        <a [routerLink]="['../membership', asset.membershipId , 'view' ]" >{{asset.membershipAdmissionDocumentDate}}</a>
 | 
			
		||||
                        <a [routerLink]="['../membership', asset.membershipId , 'view' ]" >{{asset.membershipDisplayReference}}</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </td>
 | 
			
		||||
                <td class="text-right">
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
                <dt><span jhiTranslate="hsadminNgApp.share.membership">Membership</span></dt>
 | 
			
		||||
                <dd>
 | 
			
		||||
                    <div *ngIf="share.membershipId">
 | 
			
		||||
                        <a [routerLink]="['/membership', share.membershipId, 'view']">{{share.membershipAdmissionDocumentDate}}</a>
 | 
			
		||||
                        <a [routerLink]="['/membership', share.membershipId, 'view']">{{share.membershipDisplayReference}}</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </dd>
 | 
			
		||||
            </dl>
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
            <th jhiSortBy="action"><span jhiTranslate="hsadminNgApp.share.action">Action</span> <fa-icon [icon]="'sort'"></fa-icon></th>
 | 
			
		||||
            <th jhiSortBy="quantity"><span jhiTranslate="hsadminNgApp.share.quantity">Quantity</span> <fa-icon [icon]="'sort'"></fa-icon></th>
 | 
			
		||||
            <th jhiSortBy="remark"><span jhiTranslate="hsadminNgApp.share.remark">Remark</span> <fa-icon [icon]="'sort'"></fa-icon></th>
 | 
			
		||||
            <th jhiSortBy="membershipAdmissionDocumentDate"><span jhiTranslate="hsadminNgApp.share.membership">Membership</span> <fa-icon [icon]="'sort'"></fa-icon></th>
 | 
			
		||||
            <th jhiSortBy="membershipDisplayReference"><span jhiTranslate="hsadminNgApp.share.membership">Membership</span> <fa-icon [icon]="'sort'"></fa-icon></th>
 | 
			
		||||
            <th></th>
 | 
			
		||||
            </tr>
 | 
			
		||||
            </thead>
 | 
			
		||||
@@ -34,7 +34,7 @@
 | 
			
		||||
                <td>{{share.remark}}</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <div *ngIf="share.membershipId">
 | 
			
		||||
                        <a [routerLink]="['../membership', share.membershipId , 'view' ]" >{{share.membershipAdmissionDocumentDate}}</a>
 | 
			
		||||
                        <a [routerLink]="['../membership', share.membershipId , 'view' ]" >{{share.membershipDisplayReference}}</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </td>
 | 
			
		||||
                <td class="text-right">
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ export interface IAsset {
 | 
			
		||||
    action?: AssetAction;
 | 
			
		||||
    amount?: number;
 | 
			
		||||
    remark?: string;
 | 
			
		||||
    membershipAdmissionDocumentDate?: string;
 | 
			
		||||
    membershipDisplayReference?: string;
 | 
			
		||||
    membershipId?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -28,7 +28,7 @@ export class Asset implements IAsset {
 | 
			
		||||
        public action?: AssetAction,
 | 
			
		||||
        public amount?: number,
 | 
			
		||||
        public remark?: string,
 | 
			
		||||
        public membershipAdmissionDocumentDate?: string,
 | 
			
		||||
        public membershipDisplayReference?: string,
 | 
			
		||||
        public membershipId?: number
 | 
			
		||||
    ) {}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ export interface IShare {
 | 
			
		||||
    action?: ShareAction;
 | 
			
		||||
    quantity?: number;
 | 
			
		||||
    remark?: string;
 | 
			
		||||
    membershipAdmissionDocumentDate?: string;
 | 
			
		||||
    membershipDisplayReference?: string;
 | 
			
		||||
    membershipId?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -24,7 +24,7 @@ export class Share implements IShare {
 | 
			
		||||
        public action?: ShareAction,
 | 
			
		||||
        public quantity?: number,
 | 
			
		||||
        public remark?: string,
 | 
			
		||||
        public membershipAdmissionDocumentDate?: string,
 | 
			
		||||
        public membershipDisplayReference?: string,
 | 
			
		||||
        public membershipId?: number
 | 
			
		||||
    ) {}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "error": {
 | 
			
		||||
        "idNotFound": "Technische Datensatz-ID nicht gefunden",
 | 
			
		||||
        "shareSubscriptionPositiveQuantity": "Zeichnungen von Geschäftsanteilen erfordern eine positive Stückzahl",
 | 
			
		||||
        "shareCancellationNegativeQuantity": "Kündigungen von Geschäftsanteilen erfordern eine negative Stückzahl",
 | 
			
		||||
        "shareTransactionImmutable": "Transaktionen mit Geschäftsanteilen sind unveränderlich",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "error": {
 | 
			
		||||
        "idNotFound": "Technical record-ID not found",
 | 
			
		||||
        "shareSubscriptionPositiveQuantity": "Share subscriptions require a positive quantity",
 | 
			
		||||
        "shareCancellationNegativeQuantity": "Share cancellations require a negative quantity",
 | 
			
		||||
        "shareTransactionImmutable": "Share transactions are immutable",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user