package eu.reply.lea.tenants.westwing.wm.entities;

import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import eu.reply.lea.tenants.westwing.wm.enums.ComparisonOperation;
import eu.reply.lea.tenants.westwing.wm.request.DropOffPointRequestHeader;
import eu.reply.sce.backend.core.entity.StandardEntity;

@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(
uniqueConstraints = {
@UniqueConstraint(columnNames = {"sequence", "siteCode"})
}
)
@NamedQuery(name = DropOffPoint.FIND_BY_SITE_CODE, query = DropOffPoint.BY_SITE_CODE_QUERY)
public class DropOffPoint extends StandardEntity {


public static final String FIND_BY_SITE_CODE = "findBySiteCode";
public static final String P_SITE_CODE = "siteCode";
public static final String BY_SITE_CODE_QUERY = "select d from DropOffPoint d"
                                                + " where d.enabled = true and d.siteCode = :"
                                                + P_SITE_CODE;


private static final long serialVersionUID = -4241558462200818070L;
private static final Map<String, Integer> handlingTypeOrder = new HashMap<>();

static {
    handlingTypeOrder.put("Small", 1);
    handlingTypeOrder.put("Bulky", 2);
    handlingTypeOrder.put("2MH", 3);
    handlingTypeOrder.put("Big", 4);
}

@ManyToOne(optional = false)
private DropOffPointHeader dropOffPointHeader;

@Builder.Default
private boolean enabled = true;
private int sequence;

@NotNull
private String name;

@NotNull
private String siteCode;
private String description;
private String orderType;

@Builder.Default
private Boolean consolidation = false;
private String handlingType;

private BigDecimal fragilityIndex;
@Builder.Default
@Enumerated(EnumType.STRING)
private ComparisonOperation fragilityIndexOperation = ComparisonOperation.EQUAL;

private BigDecimal minWeight;
private BigDecimal maxWeight;
@Builder.Default
@Enumerated(EnumType.STRING)
private ComparisonOperation weightOperation = ComparisonOperation.EQUAL;

private BigDecimal minVolume;
private BigDecimal maxVolume;
@Builder.Default
@Enumerated(EnumType.STRING)
private ComparisonOperation volumeOperation = ComparisonOperation.EQUAL;

private BigDecimal maxSize;
@Builder.Default
@Enumerated(EnumType.STRING)
private ComparisonOperation maxSizeOperation = ComparisonOperation.EQUAL;

private BigDecimal minSize;
@Builder.Default
@Enumerated(EnumType.STRING)
private ComparisonOperation minSizeOperation = ComparisonOperation.EQUAL;

private BigDecimal pickingListCount;
@Builder.Default
@Enumerated(EnumType.STRING)
private ComparisonOperation pickingListCountOperation = ComparisonOperation.EQUAL;

@ElementCollection(fetch = FetchType.EAGER)
private Set<BigDecimal> fragilityIndexes;
private BigDecimal fragilityIndexItemCount;
@Builder.Default
@Enumerated(EnumType.STRING)
private ComparisonOperation fragilityIndexItemCountOperation = ComparisonOperation.EQUAL;


private static int compareHandlingTypes(final String handlingType1, final String handlingType2) {
    return Integer.compare(
        handlingTypeOrder.getOrDefault(handlingType1, Integer.MAX_VALUE),
        handlingTypeOrder.getOrDefault(handlingType2, Integer.MAX_VALUE)
    );
}

public static List<DropOffPoint> findBySiteCode(final EntityManager em, final String siteCode) {
    return em.createNamedQuery(FIND_BY_SITE_CODE, DropOffPoint.class)
        .setParameter(P_SITE_CODE, siteCode)
        .getResultList();
}

public boolean matches(final DropOffPointRequestHeader request) {

    if (orderType != null && !orderType.equals(request.getOrderType())) {
        return false;
    }

    if (consolidation != null && !consolidation.equals(request.getConsolidation())) {
        return false;
    }

    if (handlingType != null && request.getMinHandlingType() != null && !handlingType.equals(request.getMinHandlingType())) {
        return false;
    }

    if (request.getFragilityIndexList() != null) {
        for (BigDecimal fragilityIndexValue : request.getFragilityIndexList()) {
            if (!compareValue(fragilityIndexValue, fragilityIndex, fragilityIndexOperation)) {
                return false;
            }
        }
    }

    if (fragilityIndexes != null && request.getFragilityIndexList() != null && !fragilityIndexes.isEmpty()
        && !compareValue(
        BigDecimal.valueOf(request.getFragilityIndexList().stream().filter(fragilityIndexes::contains).count()),
        fragilityIndexItemCount, fragilityIndexItemCountOperation)) {
        return false;
    }

    if (pickingListCount != null && !compareValue(request.getPickingListCount(), pickingListCount,
                                                  pickingListCountOperation)) {
        return false;
    }

    if (!compareRange(request.getWeight(), minWeight, maxWeight, weightOperation)) {
        return false;
    }

    if (!compareRange(request.getVolume(), minVolume, maxVolume, volumeOperation)) {
        return false;
    }

    if (!compareValue(request.getMaxSize(), maxSize, maxSizeOperation)) {
        return false;
    }

    if (!compareValue(request.getMinSize(), minSize, minSizeOperation)) {
        return false;
    }

    return true;
}

private boolean compareValue(final BigDecimal requestValue, final BigDecimal criteriaValue,
                             final ComparisonOperation operation) {
    if (criteriaValue == null || requestValue == null) {
        return true;
    }
    int comparison = requestValue.compareTo(criteriaValue);
    return switch (operation) {
        case LESS_THAN -> comparison < 0;
        case LESS_THAN_EQUAL -> comparison <= 0;
        case GREATER_THAN -> comparison > 0;
        case GREATER_THAN_EQUAL -> comparison >= 0;
        case EQUAL -> comparison == 0;
        default -> false;
    };
}

private boolean compareRange(final BigDecimal requestValue, final BigDecimal minValue, final BigDecimal maxValue,
                             final ComparisonOperation operation) {
    if (requestValue == null) {
        return true;
    }
    boolean minValid = minValue == null || compareValue(requestValue, minValue, operation == ComparisonOperation.BETWEEN
                                                                                ? ComparisonOperation.GREATER_THAN_EQUAL
                                                                                : ComparisonOperation.GREATER_THAN);
    boolean maxValid = maxValue == null || compareValue(requestValue, maxValue, operation == ComparisonOperation.BETWEEN
                                                                                ? ComparisonOperation.LESS_THAN_EQUAL
                                                                                : ComparisonOperation.LESS_THAN);
    return minValid && maxValid;
}
}
package eu.reply.lea.tenants.westwing.wm.entities;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import java.util.HashSet;
import java.util.Set;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import eu.reply.sce.backend.core.entity.StandardEntity;

@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(
uniqueConstraints = {
@UniqueConstraint(columnNames = {"name", "siteCode"})
}
)
public class DropOffPointHeader extends StandardEntity {


private static final long serialVersionUID = -5499697325844422439L;

@OneToMany(mappedBy = "dropOffPointHeader", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH},
    orphanRemoval = true)
private Set<DropOffPoint> dropOffPoints = new HashSet<>();

private String name;
private String siteCode;
}

Considering the entity above, i want to create a fe page (similar to the one i have shown you, using YUI.
which has a button to insert a new dropoffpoint and a button to insert a new parameter in the dropoffpoint.
For esample to insert a new parameter for the dropoffpoint you would have a picker where you select "volume" then it would appear in the same row a form where you insert the min value , a form where you insert the max value and a form where you insert the operator.
But it should be flexible, in fact for esample for the fragility index, you have are requiring that you have a number of frafility indexes contained in the list equal, bigger or less thant the specified fragilityindexitemcount

take inspiration by this page
/* global SCE */
SCE.add('sce-task-standard-execution', Y => {
'use strict'


const CLASS_NAME = 'sceTaskStandardExecution'

const _MAIN_TEMPLATE = Y.Handlebars.compile(Y.SCE.Commons.getTemplate(CLASS_NAME, 'sce-task-standard-execution.html'))
const _PROGRESS_TEMPLATE = Y.Handlebars.compile(Y.SCE.Commons.getTemplate(CLASS_NAME, 'sce-task-standard-execution-progress.html'))

const ERROR_MESSAGE = function (key, params) {
    return new Y.SCE.Error(key, params, null, null, Y.SCE.Intl.getComponentBundlePath(CLASS_NAME, key));
};
const ERRORS = {
    MISSING_TABLE_CLASS: 'error.missingTableClass',
    MISSING_HEADER_CLASS: 'error.missingHeaderClass',
};
const MESSAGES = {
    TASK_DONE: 'message.taskDone',
    TASK_COMPLETE: 'question.taskComplete',
    TASK_NOT_EXECUTABLE: 'message.taskNotExecutable',
};

const SELECTORS = {
    TABLE_CONTAINER: '.sce-task-standard-execution-table-container',
    HEADER_CONTAINER: '.sce-task-standard-execution-header-container',
    SIDEBAR_CONTAINER: '.sce-task-standard-execution-sidebar-container',
    PROGRESS_CONTAINER: '#sce-task-standard-execution-progress-container',
    SWITCH_MODE_BUTTON: '[data-id="btn.switch"]',
    CLOSE_TASK_BUTTON: '[data-id="btn.close"]',
    REFRESH_TASK_BUTTON: '[data-id="btn.refresh"]',
    CUSTOM_TOOLBAR_LINK: '.sce-task-standard-execution-link',
};

const TASK_ATTRIBUTES = {
    NAME: 'name',
    STATUS: 'status',
    PERCENTAGE: 'percentage',
    SITE_CODE: 'positionInfo.siteCode',
};

Y.namespace('SCE.task').StandardExecution = Y.Base.create(CLASS_NAME, Y.View, [], {
    template: _MAIN_TEMPLATE,
    progressTemplate: _PROGRESS_TEMPLATE,

    events: {
        [SELECTORS.SWITCH_MODE_BUTTON]: {
            click: '_onSwitch'
        },
        [SELECTORS.CLOSE_TASK_BUTTON]: {
            click: '_onTaskClose'
        },
        [SELECTORS.REFRESH_TASK_BUTTON]: {
            click: '_onTaskRefresh'
        },
        [SELECTORS.CUSTOM_TOOLBAR_LINK]: {
            click: '_onToolbarButtonClick'
        }
    },

    initializer(viewParams) {
        this._eventHandles = [];
        this._tableView = null;
        this._headerView = null;
        this._sidebarView = null;

        this._resourceConfig = viewParams.resource;
        this._dataModel = viewParams.dataModel;
        this._parent = viewParams.parent;
        this._executionConfig = viewParams.params;
        this._executionConfig.taskAttributes = Y.merge({
            siteCode: TASK_ATTRIBUTES.SITE_CODE
        }, this._executionConfig.taskAttributes || {});
        this._configModes = viewParams.configModes;

        this._detailModel = null;
        this._selectedActivityPositionInfo = null;
        this._selectedActivityId = null;
        this._selectedActivityConfirmPayload = null;
        this._additionalData = null;
        this._sourcePositionInfo = null;
        this._destinationPositionInfo = null;
        this._targetAdditionalData = null;
        this._targetSourcePositionInfo = null;
        this._targetDestinationPositionInfo = null;

        this.traceabilityReaderClass = this._parent.traceabilityReaderClass;
        this.serialsReaderClass = this._parent.serialsReaderClass;
    },

    render() {
        this.container = this.get('container')

        const fullName = this._dataModel.get('entityReference.businessKey');

        this.container.setHTML(this.template({
            fullName: fullName,
            className: CLASS_NAME,
            hasSidebar: !!this._executionConfig.sidebarClass,
            modes: this._configModes,
            links: this._getLinkButtons(),
            actions: this._getActionButtons(),
        }));

        Y.SCE.Intl.intlDomNodes(this.container);

        this._renderPercentage();

        this._renderTable()
            .then(this._renderHeader.bind(this))
            .then(this._renderSidebar.bind(this))
            .catch(function (err) {
                console.error(err);
                Y.SCE.Error.notify(err);
            });
    },

    _getLinkButtons() {
        const links = this._executionConfig.links || [];

        return links.map(function (link) {
            const bundlePath = link.bundlePath || Y.SCE.Intl.getResourceBundlePath(
                this._resourceConfig.get('bundleInfo'),
                link.name,
            );
            return Y.merge({bundlePath: bundlePath}, link);
        }.bind(this));
    },

    _getActionButtons() {
        const actions = this._executionConfig.actions || [];

        return actions.map(function (action) {
            const bundlePath = action.name ? Y.SCE.Intl.getResourceBundlePath(
                this._resourceConfig.get('bundleInfo'),
                `action.${action.name}`,
            ) : null;
            return Y.merge({
                bundlePath: bundlePath,
                action: action.action || action.name,
                reload: true,
            }, action);
        }.bind(this));
    },

    _renderPercentage() {
        const progressionNode = this.container.one(SELECTORS.PROGRESS_CONTAINER);
        if (progressionNode) {
            const percentage = ((this._dataModel.get(TASK_ATTRIBUTES.PERCENTAGE) || 0) * 100).toFixed(1);
            progressionNode.setHTML(this.progressTemplate({
                percentage: percentage,
            }));
        }
    },

    _renderSidebar() {
        if (!this._executionConfig.sidebarClass) {
            return Y.Promise.resolve();
        }
        const baseConfirmActionFn = function () {
            if (this._headerView) {
                return this._headerView.getBaseConfirmActionPayload();
            }
            return {};
        }.bind(this);
        return this._parent.renderSubView(
            this,
            SELECTORS.SIDEBAR_CONTAINER,
            this._executionConfig.sidebarClass,
            {
                sidebarConfiguration: this._executionConfig.sidebarConfiguration,
                resource: this._resourceConfig,
                dataModel: this._dataModel,
                parent: this,
                baseConfirmActionFn,
            }, function (subView) {
                this._sidebarView = subView
            }.bind(this),
        )
    },

    _renderTable() {
        if (!this._executionConfig.tableClass) {
            throw ERROR_MESSAGE(ERRORS.MISSING_TABLE_CLASS);
        }
        return this._parent.renderSubView(
            this,
            SELECTORS.TABLE_CONTAINER,
            this._executionConfig.tableClass,
            {
                fetchConfiguration: this._executionConfig.fetchConfiguration,
                resource: this._resourceConfig,
                dataModel: this._dataModel,
                parent: this,
            },
            function (subView) {
                this._tableView = subView;
                this._executionConfig.fetchConfiguration = subView.getFetchConfiguration();
                this._executionConfig.headerClass = this._executionConfig.headerClass || subView.getHeaderCompanionClassName();
            }.bind(this),
        );
    },

    _renderHeader() {
        if (!this._executionConfig.headerClass) {
            throw ERROR_MESSAGE(ERRORS.MISSING_HEADER_CLASS);
        }
        return this._parent.renderSubView(
            this,
            SELECTORS.HEADER_CONTAINER,
            this._executionConfig.headerClass,
            {
                fetchConfiguration: this._executionConfig.fetchConfiguration,
                resource: this._resourceConfig,
                dataModel: this._dataModel,
                parent: this,
            },
            function (subView) {
                this._headerView = subView;
            }.bind(this),
        );
    },

    destructor() {
        if (this._tableView) {
            this._tableView.destroy({remove: true});
            this._tableView = null;
        }
        if (this._headerView) {
            this._headerView.destroy({remove: true});
            this._headerView = null;
        }
        if (this._sidebarView) {
            this._sidebarView.destroy({remove: true});
            this._sidebarView = null;
        }
        Y.each(this._eventHandles, function (handle) {
            handle.detach();
        });
    },

    sync() {
        this._tableView && this._tableView.sync();
        this._headerView && this._headerView.sync();
        this._sidebarView && this._sidebarView.sync();
    },

    updateFilteringData(additionalData, sourcePositionInfo, destinationPositionInfo) {
        let changed = !Y.SCE.Commons.deepEqual(additionalData, this._additionalData);
        changed |= !Y.SCE.Commons.deepEqual(sourcePositionInfo, this._sourcePositionInfo);
        changed |= !Y.SCE.Commons.deepEqual(destinationPositionInfo, this._destinationPositionInfo);
        this._additionalData = additionalData;
        this._sourcePositionInfo = sourcePositionInfo;
        this._destinationPositionInfo = destinationPositionInfo;
        if (changed) {
            this.reloadData(false, true, false);
        }
    },

    updateTargetData(additionalData, sourcePositionInfo, destinationPositionInfo) {
        this._targetAdditionalData = additionalData;
        this._targetSourcePositionInfo = sourcePositionInfo;
        this._targetDestinationPositionInfo = destinationPositionInfo;
    },

    getFilteringAdditionalData() {
        return this._additionalData;
    },

    getFilteringPositionInfo() {
        return this._sourcePositionInfo;
    },

    getTargetAdditionalData() {
        return this._additionalData || this._targetAdditionalData;
    },

    getTargetSourcePositionInfo() {
        return this._selectedActivityPositionInfo || this._sourcePositionInfo || this._targetSourcePositionInfo;
    },

    getTargetDestinationPositionInfo() {
        return Y.merge({
            siteCode: this._dataModel.get(this._executionConfig.taskAttributes.siteCode),
        }, this._destinationPositionInfo || this._targetDestinationPositionInfo || {});
    },

    getTargetBaseConfirmAction() {
        return this._selectedActivityConfirmPayload;
    },

    _exit() {
        this._parent.exit();
    },

    _onSwitch(ev) {
        if (ev) {
            ev.preventDefault();
            ev.stopPropagation();
        }

        const targetMode = ev.currentTarget.getData("task-mode");
        this._parent.switchMode(targetMode);
    },

    _onTaskRefresh(ev) {
        ev.preventDefault();
        ev.stopPropagation();

        this.refresh();
    },

    refresh() {
        this.reloadData(true, true, true);
    },

    _onTaskClose(ev, skipConfirmation) {
        if (ev) {
            ev.preventDefault();
            ev.stopPropagation();
        }

        this._parent.closeTask(skipConfirmation);
    },

    _onToolbarButtonClick(ev) {
        if (ev) {
            ev.preventDefault();
            ev.stopPropagation();
        }

        const rawUrl = ev.currentTarget.getData("href");
        const action = ev.currentTarget.getData("action");
        const reload = ev.currentTarget.getData("reload");

        if (rawUrl) {
            const url = Y.SCE.Commons.sub(rawUrl, this._dataModel.toJSON());
            this.fire(Y.SCE.Commons.EVENT_OPEN_LINK, {
                url: url
            });
        } else {
            const callback = Y.bind(function (data, actionConfiguration, error) {
                if (!error && reload) {
                    this.refresh();
                }

                Y.SCE.Actionhandler.defaultCallback(data, actionConfiguration, error);
            }, this);
            this._parent.startAction(action, callback);
        }
    },

    _askClosingTask() {
        let type = null;
        let bundleKey = null;
        let buttons = 1;
        let callback = this._exit.bind(this);
        let buttonBundle = 'components/sce-dialog:button.ok';
        if (this._sidebarView && !this._sidebarView.canCloseTask()) {
            return;
        }
        if (this._dataModel.get(TASK_ATTRIBUTES.STATUS) === 'DONE') {
            type = Y.SCE.Dialog.SUCCESS;
            bundleKey = MESSAGES.TASK_DONE;
        } else if (this._dataModel.get(TASK_ATTRIBUTES.STATUS) !== 'TODO') {
            type = Y.SCE.Dialog.WARN;
            bundleKey = MESSAGES.TASK_NOT_EXECUTABLE;
        } else if (this._dataModel.get(TASK_ATTRIBUTES.PERCENTAGE) === 1) {
            type = Y.SCE.Dialog.QUESTION;
            bundleKey = MESSAGES.TASK_COMPLETE;
            buttons = 2;
            callback = this._onTaskClose.bind(this, null, true);
            buttonBundle = 'components/sce-dialog:button.yes';
        }
        if (type && bundleKey) {
            new Y.SCE.Dialog({
                message: Y.SCE.Intl.getComponentLabel(CLASS_NAME, bundleKey, this._dataModel.toJSON()),
                type: type,
                callback: callback,
                buttons: buttons,
                positiveButtonBundlePath: buttonBundle,
            }).render();
        }
    },

    reloadData(reloadTask, reloadTable, reloadSidebar) {
        let reloadPromises = [];
        if (reloadTable && this._tableView) {
            reloadPromises.push(this._tableView.reloadActivities(this._selectedActivityId));
        }
        if (reloadSidebar && this._sidebarView) {
            reloadPromises.push(this._sidebarView.reloadSidebar());
        }
        if (reloadTask) {
            reloadPromises.push(this._dataModel.loadAsPromise());
        }
        if (reloadPromises.length > 0) {
            return Y.Promise.all(reloadPromises)
                .then(this._renderPercentage.bind(this))
                .then(this._askClosingTask.bind(this));
        }
        return Y.Promise.resolve();
    },

    getEntityReferenceKey(entityReference) {
        return this._parent.getEntityReferenceKey(entityReference);
    },

    getLoadedEntityReferences(references) {
        return this._parent.getLoadedEntityReferences(references);
    },

    getLoadedItemReadSettings(itemId, traceabilityMode) {
        const siteCode = this._dataModel.get(this._executionConfig.taskAttributes.siteCode);
        return this._parent.getLoadedItemReadSettings(itemId, siteCode, traceabilityMode);
    },

    getLoadedSnRequest(snRequest) {
        return this._parent.getLoadedSnRequest(snRequest);
    },

    searchModel(searchKey) {
        this._tableView && this._tableView.searchModel(searchKey);
    },

    selectModel(selectedModel, modelConfig, baseConfirmPayload, positionInfo, id) {
        const modelChanged = this._selectedActivityId !== id;

        this._selectedActivityPositionInfo = positionInfo;
        this._selectedActivityId = id;
        this._selectedActivityConfirmPayload = baseConfirmPayload;
        this._detailModel = selectedModel;

        this._headerView && this._headerView.showDetailModel(selectedModel, modelConfig);
        // if model is different, update the sidebar (it does not look at inside the model)
        if (this._sidebarView && modelChanged) {
            this._sidebarView.updateDetailModel(selectedModel);
        }
    },

    clearModelSelection() {
        this._selectedActivityPositionInfo = null;
        this._selectedActivityId = null;
        this._selectedActivityConfirmPayload = null;
        this._detailModel = null;
        this._headerView && this._headerView.clearDetailModel();
        this._sidebarView && this._sidebarView.updateDetailModel();
    },

}, {
    ATTRS: {}
})
}, '0.0.1', {
requires: [
'view',
'handlebars',
'sce-foundation',
'sce-commons',
'sce-intl',
'sce-error',
'sce-task-standard-execution-table',
'sce-task-standard-execution-header',
'sce-task-standard-execution-sidebar',
]
})

you should also use stuff like sce.add and everything, i'm using the same framework