diff --git a/src/main/java/de/metas/ui/web/order/purchase/process/WEBUI_SalesOrder_CreatePurchaseOLCands_Launcher.java b/src/main/java/de/metas/ui/web/order/purchase/process/WEBUI_SalesOrder_CreatePurchaseOLCands_Launcher.java new file mode 100644 index 000000000..30874af6f --- /dev/null +++ b/src/main/java/de/metas/ui/web/order/purchase/process/WEBUI_SalesOrder_CreatePurchaseOLCands_Launcher.java @@ -0,0 +1,90 @@ +package de.metas.ui.web.order.purchase.process; + +import java.util.Set; + +import org.adempiere.exceptions.AdempiereException; +import org.adempiere.util.lang.impl.TableRecordReference; +import org.compiere.model.I_C_OrderLine; + +import com.google.common.collect.ImmutableSet; + +import de.metas.adempiere.model.I_C_Order; +import de.metas.process.IProcessPrecondition; +import de.metas.process.IProcessPreconditionsContext; +import de.metas.process.JavaProcess; +import de.metas.process.ProcessPreconditionsResolution; +import de.metas.ui.web.order.purchase.view.SalesOrderToOLCandViewFactory; + +/* + * #%L + * metasfresh-webui-api + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +public class WEBUI_SalesOrder_CreatePurchaseOLCands_Launcher extends JavaProcess implements IProcessPrecondition +{ + @Override + public ProcessPreconditionsResolution checkPreconditionsApplicable(final IProcessPreconditionsContext context) + { + if (!context.isSingleSelection()) + { + return ProcessPreconditionsResolution.rejectWithInternalReason("one and only one order shall be selected"); + } + + // Only draft orders + final I_C_Order order = context.getSelectedModel(I_C_Order.class); + if (order.isProcessed()) + { + return ProcessPreconditionsResolution.rejectWithInternalReason("only draft orders are allowed"); + } + + // Only sales orders + if (!order.isSOTrx()) + { + return ProcessPreconditionsResolution.rejectWithInternalReason("only sales orders are allowed"); + } + + // At least one sales order line shall be selected + final Set selectedOrderLineRefs = context.getSelectedIncludedRecords(); + if (selectedOrderLineRefs.isEmpty()) + { + return ProcessPreconditionsResolution.rejectBecauseNoSelection(); + } + + return ProcessPreconditionsResolution.accept(); + } + + @Override + protected String doIt() + { + final Set salesOrderLineRefs = getSelectedIncludedRecordIds(I_C_OrderLine.class) + .stream() + .map(recordId -> TableRecordReference.of(I_C_OrderLine.Table_Name, recordId)) + .collect(ImmutableSet.toImmutableSet()); + if (salesOrderLineRefs.isEmpty()) + { + throw new AdempiereException("@NoSelection@"); + } + + getResult().setRecordsToOpen(salesOrderLineRefs, SalesOrderToOLCandViewFactory.WINDOW_ID_STRING); + + return MSG_OK; + } + +} diff --git a/src/main/java/de/metas/ui/web/order/purchase/view/OLCandRow.java b/src/main/java/de/metas/ui/web/order/purchase/view/OLCandRow.java new file mode 100644 index 000000000..3de0b91a6 --- /dev/null +++ b/src/main/java/de/metas/ui/web/order/purchase/view/OLCandRow.java @@ -0,0 +1,142 @@ +package de.metas.ui.web.order.purchase.view; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import de.metas.ui.web.view.IViewRow; +import de.metas.ui.web.view.IViewRowType; +import de.metas.ui.web.view.ViewRow.DefaultRowType; +import de.metas.ui.web.view.descriptor.annotation.ViewColumn; +import de.metas.ui.web.view.descriptor.annotation.ViewColumn.ViewColumnLayout; +import de.metas.ui.web.view.descriptor.annotation.ViewColumnHelper; +import de.metas.ui.web.view.json.JSONViewDataType; +import de.metas.ui.web.window.datatypes.DocumentId; +import de.metas.ui.web.window.datatypes.DocumentPath; +import de.metas.ui.web.window.datatypes.json.JSONLookupValue; +import de.metas.ui.web.window.descriptor.DocumentFieldWidgetType; +import de.metas.ui.web.window.descriptor.ViewEditorRenderMode; +import lombok.Builder; +import lombok.NonNull; +import lombok.ToString; + +/* + * #%L + * metasfresh-webui-api + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +@ToString(exclude = "_fieldNameAndJsonValues") +public class OLCandRow implements IViewRow +{ + private final DocumentId rowId; + + @ViewColumn(captionKey = "M_Product_ID", widgetType = DocumentFieldWidgetType.Lookup, layouts = { + @ViewColumnLayout(when = JSONViewDataType.grid, seqNo = 10), + @ViewColumnLayout(when = JSONViewDataType.includedView, seqNo = 10) + }) + private final JSONLookupValue product; + @ViewColumn(captionKey = "Vendor_ID", widgetType = DocumentFieldWidgetType.Lookup, layouts = { + @ViewColumnLayout(when = JSONViewDataType.grid, seqNo = 20), + @ViewColumnLayout(when = JSONViewDataType.includedView, seqNo = 20) + }) + private final JSONLookupValue vendorBPartner; + + @ViewColumn(captionKey = "QtyToDeliver", widgetType = DocumentFieldWidgetType.Quantity, layouts = { + @ViewColumnLayout(when = JSONViewDataType.grid, seqNo = 30), + @ViewColumnLayout(when = JSONViewDataType.includedView, seqNo = 30) + }) + private final BigDecimal qtyToDeliver; + + @ViewColumn(captionKey = "QtyToPurchase", widgetType = DocumentFieldWidgetType.Quantity, editor = ViewEditorRenderMode.ALWAYS, layouts = { + @ViewColumnLayout(when = JSONViewDataType.grid, seqNo = 40), + @ViewColumnLayout(when = JSONViewDataType.includedView, seqNo = 40) + }) + private final BigDecimal qtyToPurchase; + + @ViewColumn(captionKey = "DatePromised", widgetType = DocumentFieldWidgetType.DateTime, editor = ViewEditorRenderMode.ALWAYS, layouts = { + @ViewColumnLayout(when = JSONViewDataType.grid, seqNo = 50), + @ViewColumnLayout(when = JSONViewDataType.includedView, seqNo = 50) + }) + private final Date datePromised; + + private transient ImmutableMap _fieldNameAndJsonValues; + + @Builder + public OLCandRow( + @NonNull final DocumentId rowId, + @NonNull final JSONLookupValue product, + @NonNull final JSONLookupValue vendorBPartner, + @NonNull final BigDecimal qtyToDeliver, + @NonNull final BigDecimal qtyToPurchase, + @NonNull final Date datePromised) + { + this.rowId = rowId; + this.product = product; + this.vendorBPartner = vendorBPartner; + this.qtyToDeliver = qtyToDeliver; + this.qtyToPurchase = qtyToPurchase; + this.datePromised = datePromised; + } + + @Override + public DocumentId getId() + { + return rowId; + } + + @Override + public IViewRowType getType() + { + return DefaultRowType.Row; + } + + @Override + public boolean isProcessed() + { + return false; + } + + @Override + public DocumentPath getDocumentPath() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map getFieldNameAndJsonValues() + { + if (_fieldNameAndJsonValues == null) + { + _fieldNameAndJsonValues = ViewColumnHelper.extractJsonMap(this); + } + return _fieldNameAndJsonValues; + } + + @Override + public List getIncludedRows() + { + return ImmutableList.of(); + } +} diff --git a/src/main/java/de/metas/ui/web/order/purchase/view/OLCandRowsCollection.java b/src/main/java/de/metas/ui/web/order/purchase/view/OLCandRowsCollection.java new file mode 100644 index 000000000..45cd68e48 --- /dev/null +++ b/src/main/java/de/metas/ui/web/order/purchase/view/OLCandRowsCollection.java @@ -0,0 +1,130 @@ +package de.metas.ui.web.order.purchase.view; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +import org.adempiere.util.lang.ExtendedMemorizingSupplier; +import org.adempiere.util.lang.impl.TableRecordReference; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; + +import de.metas.handlingunits.model.I_C_OLCand; +import de.metas.ui.web.exceptions.EntityNotFoundException; +import de.metas.ui.web.view.IViewRow; +import de.metas.ui.web.window.datatypes.DocumentId; +import de.metas.ui.web.window.datatypes.DocumentIdsSelection; +import lombok.NonNull; + +/* + * #%L + * metasfresh-webui-api + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +class OLCandRowsCollection +{ + private static final int DEFAULT_PAGE_LENGTH = 30; + + public static final OLCandRowsCollection ofSupplier(final OLCandRowsSupplier rowsSupplier) + { + return new OLCandRowsCollection(rowsSupplier); + } + + private final ExtendedMemorizingSupplier> rowsSupplier; + + private OLCandRowsCollection(@NonNull final OLCandRowsSupplier rowsSupplier) + { + this.rowsSupplier = ExtendedMemorizingSupplier.of(() -> Maps.uniqueIndex(rowsSupplier.retrieveRows(), OLCandRow::getId)); + } + + @Override + public String toString() + { + return MoreObjects.toStringHelper(this).addValue(rowsSupplier).toString(); + } + + public void invalidateAll() + { + rowsSupplier.forget(); + } + + private final Map getRowsMap() + { + return rowsSupplier.get(); + } + + public long size() + { + return getRowsMap().size(); + } + + public List getPage(final int firstRow, final int pageLength) + { + return getRowsMap().values().stream() + .skip(firstRow >= 0 ? firstRow : 0) + .limit(pageLength > 0 ? pageLength : DEFAULT_PAGE_LENGTH) + .collect(ImmutableList.toImmutableList()); + } + + public OLCandRow getById(@NonNull final DocumentId rowId) throws EntityNotFoundException + { + final OLCandRow row = getRowsMap().get(rowId); + if (row == null) + { + throw new EntityNotFoundException("Row not found").setParameter("rowId", rowId); + } + return row; + } + + public Stream streamByIds(final DocumentIdsSelection rowIds) + { + if (rowIds.isAll()) + { + return getRowsMap().values().stream(); + } + else + { + return rowIds.stream().map(this::getById); + } + } + + public boolean notifyRecordsChanged(Set recordRefs) + { + final Set rowIds = getRowsMap().keySet(); + + final boolean matches = recordRefs.stream() + .filter(record -> I_C_OLCand.Table_Name.equals(record.getTableName())) + .map(record -> DocumentId.of(record.getRecord_ID())) + .anyMatch(rowIds::contains); + + if(matches) + { + invalidateAll(); + return true; + } + else + { + return false; + } + } +} diff --git a/src/main/java/de/metas/ui/web/order/purchase/view/OLCandRowsSupplier.java b/src/main/java/de/metas/ui/web/order/purchase/view/OLCandRowsSupplier.java new file mode 100644 index 000000000..5098e5b89 --- /dev/null +++ b/src/main/java/de/metas/ui/web/order/purchase/view/OLCandRowsSupplier.java @@ -0,0 +1,31 @@ +package de.metas.ui.web.order.purchase.view; + +import java.util.List; + +/* + * #%L + * metasfresh-webui-api + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +@FunctionalInterface +public interface OLCandRowsSupplier +{ + List retrieveRows(); +} diff --git a/src/main/java/de/metas/ui/web/order/purchase/view/OLCandView.java b/src/main/java/de/metas/ui/web/order/purchase/view/OLCandView.java new file mode 100644 index 000000000..0839a655a --- /dev/null +++ b/src/main/java/de/metas/ui/web/order/purchase/view/OLCandView.java @@ -0,0 +1,215 @@ +package de.metas.ui.web.order.purchase.view; + +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +import org.adempiere.exceptions.AdempiereException; +import org.adempiere.util.lang.impl.TableRecordReference; +import org.compiere.util.Evaluatee; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + +import de.metas.ordercandidate.model.I_C_OLCand; +import de.metas.ui.web.document.filter.DocumentFilter; +import de.metas.ui.web.exceptions.EntityNotFoundException; +import de.metas.ui.web.view.IView; +import de.metas.ui.web.view.IViewRow; +import de.metas.ui.web.view.ViewId; +import de.metas.ui.web.view.ViewResult; +import de.metas.ui.web.view.event.ViewChangesCollector; +import de.metas.ui.web.view.json.JSONViewDataType; +import de.metas.ui.web.window.datatypes.DocumentId; +import de.metas.ui.web.window.datatypes.DocumentIdsSelection; +import de.metas.ui.web.window.datatypes.DocumentPath; +import de.metas.ui.web.window.datatypes.LookupValuesList; +import de.metas.ui.web.window.model.DocumentQueryOrderBy; +import de.metas.ui.web.window.model.sql.SqlOptions; +import lombok.Builder; +import lombok.NonNull; + +/* + * #%L + * metasfresh-webui-api + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +public class OLCandView implements IView +{ + public static OLCandView cast(IView view) + { + return (OLCandView)view; + } + + private final ViewId viewId; + private final OLCandRowsCollection rows; + + @Builder + private OLCandView( + @NonNull final ViewId viewId, + @NonNull final OLCandRowsSupplier rowsSupplier) + { + this.viewId = viewId; + rows = OLCandRowsCollection.ofSupplier(rowsSupplier); + } + + @Override + public ViewId getViewId() + { + return viewId; + } + + @Override + public JSONViewDataType getViewType() + { + return JSONViewDataType.grid; + } + + @Override + public Set getReferencingDocumentPaths() + { + return ImmutableSet.of(); + } + + @Override + public String getTableNameOrNull(final DocumentId documentId) + { + return I_C_OLCand.Table_Name; + } + + @Override + public ViewId getParentViewId() + { + return null; + } + + @Override + public DocumentId getParentRowId() + { + return null; + } + + @Override + public long size() + { + return rows.size(); + } + + @Override + public void close() + { + } + + @Override + public int getQueryLimit() + { + return -1; + } + + @Override + public boolean isQueryLimitHit() + { + return false; + } + + @Override + public void invalidateAll() + { + rows.invalidateAll(); + ViewChangesCollector.getCurrentOrAutoflush().collectFullyChanged(this); + } + + @Override + public ViewResult getPage(final int firstRow, final int pageLength, final List orderBys) + { + if (!orderBys.isEmpty()) + { + throw new AdempiereException("orderBys is not supported"); + } + final List pageRows = rows.getPage(firstRow, pageLength); + return ViewResult.ofViewAndPage(this, firstRow, pageLength, orderBys, pageRows); + } + + @Override + public IViewRow getById(final DocumentId rowId) throws EntityNotFoundException + { + return rows.getById(rowId); + } + + @Override + public LookupValuesList getFilterParameterDropdown(final String filterId, final String filterParameterName, final Evaluatee ctx) + { + throw new UnsupportedOperationException(); + } + + @Override + public LookupValuesList getFilterParameterTypeahead(final String filterId, final String filterParameterName, final String query, final Evaluatee ctx) + { + throw new UnsupportedOperationException(); + } + + @Override + public List getStickyFilters() + { + return ImmutableList.of(); + } + + @Override + public List getFilters() + { + return ImmutableList.of(); + } + + @Override + public List getDefaultOrderBys() + { + return ImmutableList.of(); + } + + @Override + public String getSqlWhereClause(final DocumentIdsSelection rowIds, final SqlOptions sqlOpts) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public List retrieveModelsByIds(final DocumentIdsSelection rowIds, final Class modelClass) + { + throw new UnsupportedOperationException(); + } + + @Override + public Stream streamByIds(final DocumentIdsSelection rowIds) + { + return rows.streamByIds(rowIds); + } + + @Override + public void notifyRecordsChanged(final Set recordRefs) + { + if (rows.notifyRecordsChanged(recordRefs)) + { + // Collect event + // TODO: check which rowIds are contained in this view and fire events only for those + ViewChangesCollector.getCurrentOrAutoflush().collectFullyChanged(this); + } + } +} diff --git a/src/main/java/de/metas/ui/web/order/purchase/view/OLCandViewCreateRequest.java b/src/main/java/de/metas/ui/web/order/purchase/view/OLCandViewCreateRequest.java new file mode 100644 index 000000000..16bb58f88 --- /dev/null +++ b/src/main/java/de/metas/ui/web/order/purchase/view/OLCandViewCreateRequest.java @@ -0,0 +1,48 @@ +package de.metas.ui.web.order.purchase.view; + +import java.util.Set; + +import org.adempiere.util.Check; + +import com.google.common.collect.ImmutableSet; + +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; + +/* + * #%L + * metasfresh-webui-api + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +@Value +public class OLCandViewCreateRequest +{ + private final Set salesOrderLineIds; + + @Builder + public OLCandViewCreateRequest( + @NonNull final Set salesOrderLineIds) + { + Check.assumeNotEmpty(salesOrderLineIds, "salesOrderLineIds is not empty"); + this.salesOrderLineIds = ImmutableSet.copyOf(salesOrderLineIds); + } + +} diff --git a/src/main/java/de/metas/ui/web/order/purchase/view/SalesOrderToOLCandViewFactory.java b/src/main/java/de/metas/ui/web/order/purchase/view/SalesOrderToOLCandViewFactory.java new file mode 100644 index 000000000..886b79929 --- /dev/null +++ b/src/main/java/de/metas/ui/web/order/purchase/view/SalesOrderToOLCandViewFactory.java @@ -0,0 +1,205 @@ +package de.metas.ui.web.order.purchase.view; + +import java.math.BigDecimal; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; + +import org.adempiere.ad.dao.IQueryBL; +import org.adempiere.util.Services; +import org.compiere.model.I_C_BPartner; +import org.compiere.model.I_C_OrderLine; +import org.compiere.model.I_M_Product; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.collect.ImmutableList; + +import de.metas.interfaces.I_C_BPartner_Product; +import de.metas.purchasing.api.IBPartnerProductDAO; +import de.metas.ui.web.exceptions.EntityNotFoundException; +import de.metas.ui.web.view.CreateViewRequest; +import de.metas.ui.web.view.IView; +import de.metas.ui.web.view.IViewFactory; +import de.metas.ui.web.view.IViewsIndexStorage; +import de.metas.ui.web.view.ViewFactory; +import de.metas.ui.web.view.ViewId; +import de.metas.ui.web.view.descriptor.ViewLayout; +import de.metas.ui.web.view.json.JSONViewDataType; +import de.metas.ui.web.window.datatypes.DocumentId; +import de.metas.ui.web.window.datatypes.WindowId; +import de.metas.ui.web.window.datatypes.json.JSONLookupValue; + +/* + * #%L + * metasfresh-webui-api + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +@ViewFactory(windowId = SalesOrderToOLCandViewFactory.WINDOW_ID_STRING) +public class SalesOrderToOLCandViewFactory implements IViewFactory, IViewsIndexStorage +{ + public static final String WINDOW_ID_STRING = "SO2OLCand"; + public static final WindowId WINDOW_ID = WindowId.fromJson(WINDOW_ID_STRING); + + private final Cache views = CacheBuilder.newBuilder() + .expireAfterAccess(1, TimeUnit.HOURS) + .build(); + + @Override + public WindowId getWindowId() + { + return WINDOW_ID; + } + + @Override + public ViewLayout getViewLayout(final WindowId windowId, final JSONViewDataType viewDataType) + { + return ViewLayout.builder() + .setWindowId(windowId) + // + .setHasAttributesSupport(false) + .setHasTreeSupport(false) + // + .addElementsFromViewRowClass(OLCandRow.class, viewDataType) + // + .build(); + } + + @Override + public void put(final IView view) + { + views.put(view.getViewId(), OLCandView.cast(view)); + } + + @Override + public IView getByIdOrNull(final ViewId viewId) + { + return views.getIfPresent(viewId); + } + + public IView getById(final ViewId viewId) + { + final IView view = getByIdOrNull(viewId); + if (view == null) + { + throw new EntityNotFoundException("View " + viewId + " was not found"); + } + return view; + } + + @Override + public void removeById(final ViewId viewId) + { + views.invalidate(viewId); + views.cleanUp(); // also cleanup to prevent views cache to grow. + } + + @Override + public Stream streamAllViews() + { + return Stream.empty(); + } + + @Override + public void invalidateView(final ViewId viewId) + { + final IView view = getByIdOrNull(viewId); + if (view == null) + { + return; + } + + view.invalidateAll(); + } + + @Override + @Deprecated // shall not be called directly + public IView createView(final CreateViewRequest request) + { + return createView(OLCandViewCreateRequest.builder() + .salesOrderLineIds(request.getFilterOnlyIds()) + .build()); + } + + private IView createView(final OLCandViewCreateRequest request) + { + final OLCandView view = OLCandView.builder() + .viewId(ViewId.random(WINDOW_ID)) + .rowsSupplier(() -> retrieveRows(request)) + .build(); + + return view; + } + + private List retrieveRows(final OLCandViewCreateRequest request) + { + return Services.get(IQueryBL.class) + .createQueryBuilder(I_C_OrderLine.class) + .addInArrayFilter(I_C_OrderLine.COLUMNNAME_C_OrderLine_ID, request.getSalesOrderLineIds()) + .create() + .stream(I_C_OrderLine.class) + .flatMap(this::createOLCandRows) + .collect(ImmutableList.toImmutableList()); + } + + private Stream createOLCandRows(final I_C_OrderLine salesOrderLine) + { + return Services.get(IBPartnerProductDAO.class) + .retrieveAllVendors(salesOrderLine.getM_Product_ID(), salesOrderLine.getAD_Org_ID()) + .stream() + .map(vendorProductInfo -> createOLCandRow(salesOrderLine, vendorProductInfo)); + } + + private OLCandRow createOLCandRow(final I_C_OrderLine salesOrderLine, final I_C_BPartner_Product vendorProductInfo) + { + return OLCandRow.builder() + .rowId(DocumentId.ofString(UUID.randomUUID().toString())) + .product(createProductLookupValue(salesOrderLine.getM_Product())) + .qtyToDeliver(salesOrderLine.getQtyOrdered().subtract(salesOrderLine.getQtyDelivered())) + .datePromised(salesOrderLine.getDatePromised()) + .qtyToPurchase(BigDecimal.ZERO) + .vendorBPartner(createBPartnerLookupValue(vendorProductInfo.getC_BPartner())) + .build(); + } + + private static JSONLookupValue createProductLookupValue(final I_M_Product product) + { + if (product == null) + { + return null; + } + + final String displayName = product.getValue() + "_" + product.getName(); + return JSONLookupValue.of(product.getM_Product_ID(), displayName); + } + + private static JSONLookupValue createBPartnerLookupValue(final I_C_BPartner bpartner) + { + if (bpartner == null) + { + return null; + } + + final String displayName = bpartner.getValue() + "_" + bpartner.getName(); + return JSONLookupValue.of(bpartner.getC_BPartner_ID(), displayName); + } + +}