Skip to content

Commit

Permalink
Merge pull request #521 from metasfresh/gh518-webui
Browse files Browse the repository at this point in the history
Picking prototype (v6) #518
  • Loading branch information
metas-ts authored Jul 27, 2017
2 parents d6c8600 + 4838ef7 commit 29960be
Show file tree
Hide file tree
Showing 20 changed files with 449 additions and 253 deletions.
29 changes: 25 additions & 4 deletions src/main/java/de/metas/ui/web/picking/PickingCandidateCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -255,15 +255,36 @@ public int setCandidatesProcessed(@NonNull final List<Integer> huIds)
}
final IQueryBL queryBL = Services.get(IQueryBL.class);

final IQuery<I_M_Picking_Candidate> query = queryBL.createQueryBuilder(I_M_Picking_Candidate.class)
.addOnlyActiveRecordsFilter()
.addEqualsFilter(I_M_Picking_Candidate.COLUMNNAME_Status, X_M_Picking_Candidate.STATUS_IP)
.addInArrayFilter(I_M_Picking_Candidate.COLUMNNAME_M_HU_ID, huIds)
.create();

final ICompositeQueryUpdater<I_M_Picking_Candidate> updater = queryBL.createCompositeQueryUpdater(I_M_Picking_Candidate.class)
.addSetColumnValue(I_M_Picking_Candidate.COLUMNNAME_Status, X_M_Picking_Candidate.STATUS_PR);

return queryBL.createQueryBuilder(I_M_Picking_Candidate.class)
return query.updateDirectly(updater);
}

public int setCandidatesInProgress(@NonNull final List<Integer> huIds)
{
if (huIds.isEmpty())
{
return 0;
}
final IQueryBL queryBL = Services.get(IQueryBL.class);

final IQuery<I_M_Picking_Candidate> query = queryBL.createQueryBuilder(I_M_Picking_Candidate.class)
.addOnlyActiveRecordsFilter()
.addEqualsFilter(I_M_Picking_Candidate.COLUMNNAME_Status, X_M_Picking_Candidate.STATUS_IP)
.addEqualsFilter(I_M_Picking_Candidate.COLUMNNAME_Status, X_M_Picking_Candidate.STATUS_PR)
.addInArrayFilter(I_M_Picking_Candidate.COLUMNNAME_M_HU_ID, huIds)
.create()
.updateDirectly(updater);
.create();

final ICompositeQueryUpdater<I_M_Picking_Candidate> updater = queryBL.createCompositeQueryUpdater(I_M_Picking_Candidate.class)
.addSetColumnValue(I_M_Picking_Candidate.COLUMNNAME_Status, X_M_Picking_Candidate.STATUS_IP);

return query.updateDirectly(updater);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,10 @@ public PickingHUsRepository()

/**
*
* @param pickingSlotRowQuery determines which shipment schedule ID this is about, and also (optionally) if the returned rows shall have picking candidates with a certain status.
* @param pickingSlotRowQuery determines which {@code M_ShipmentSchedule_ID}s this is about,<br>
* and also (optionally) if the returned rows shall have picking candidates with a certain status.
*
* @return a multi-map where the keys are {@code M_PickingSlot_ID}s and the value is a list of HUEditorRows with the respective picking candidates' processed status values.
* @return a multi-map where the keys are {@code M_PickingSlot_ID}s and the value is a list of HUEditorRows which also contain with the respective {@code M_Picking_Candidate}s' {@code processed} states.
*/
public ListMultimap<Integer, PickingSlotHUEditorRow> retrieveHUsIndexedByPickingSlotId(@NonNull final PickingSlotRepoQuery pickingSlotRowQuery)
{
Expand All @@ -80,7 +81,7 @@ public ListMultimap<Integer, PickingSlotHUEditorRow> retrieveHUsIndexedByPicking
final IQueryBuilder<I_M_Picking_Candidate> queryBuilder = queryBL
.createQueryBuilder(I_M_Picking_Candidate.class)
.addOnlyActiveRecordsFilter()
.addEqualsFilter(I_M_Picking_Candidate.COLUMN_M_ShipmentSchedule_ID, pickingSlotRowQuery.getShipmentScheduleId());
.addInArrayFilter(I_M_Picking_Candidate.COLUMN_M_ShipmentSchedule_ID, pickingSlotRowQuery.getShipmentScheduleIds());

switch (pickingSlotRowQuery.getPickingCandidates())
{
Expand Down
14 changes: 11 additions & 3 deletions src/main/java/de/metas/ui/web/picking/PickingRow.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,26 @@ public final class PickingRow implements IViewRow
@ViewColumnLayout(when = JSONViewDataType.grid, seqNo = 50)
})
private final java.util.Date preparationDate;

private final int shipmentScheduleId;

private final ViewId includedViewId;

private transient ImmutableMap<String, Object> _fieldNameAndJsonValues;

public static PickingRow cast(final IViewRow row)
{
return (PickingRow)row;
}

@Builder
private PickingRow(
@NonNull final DocumentId id,
@NonNull final ViewId viewId,
final IViewRowType type,
final boolean processed,
@NonNull final DocumentPath documentPath,
//

final LookupValue warehouse,
final LookupValue product,
final BigDecimal qtyToDeliver,
Expand All @@ -123,6 +128,9 @@ private PickingRow(
this.preparationDate = preparationDate;
this.shipmentScheduleId = shipmentScheduleId;

// create the included view's ID
// note that despite all our packageable-rows have the same picking slots, the IDs still need to be individual per-row,
// because we need to notify the picking slot view of this packageable-rows is selected at a given point in time
this.includedViewId = PickingSlotViewsIndexStorage.createViewId(viewId, id);
}

Expand Down
15 changes: 12 additions & 3 deletions src/main/java/de/metas/ui/web/picking/PickingSlotRepoQuery.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@
* #L%
*/

import de.metas.handlingunits.model.I_M_Picking_Candidate;
import de.metas.picking.model.I_M_PickingSlot;
import java.util.List;

import com.google.common.collect.ImmutableList;

import lombok.Builder;
import lombok.Builder.Default;
import lombok.Data;
import lombok.NonNull;
import lombok.Singular;

/**
* Used in the repo services, to specify which data we want to be retrieved.
Expand All @@ -43,8 +46,14 @@ public static PickingSlotRepoQuery of(final int shipmentScheduleId)
return builder().shipmentScheduleId(shipmentScheduleId).build();
}

public static PickingSlotRepoQuery of(final List<Integer> shipmentScheduleIds)
{
return builder().shipmentScheduleIds(shipmentScheduleIds).build();
}

@NonNull
final Integer shipmentScheduleId;
@Singular
final ImmutableList<Integer> shipmentScheduleIds;

public enum PickingCandidate
{
Expand Down
1 change: 1 addition & 0 deletions src/main/java/de/metas/ui/web/picking/PickingSlotView.java
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ public int getShipmentScheduleId()
}

/**
* Convenience method.
*
* @return never returns {@code null} (see constructor code).
*/
Expand Down
55 changes: 47 additions & 8 deletions src/main/java/de/metas/ui/web/picking/PickingSlotViewFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,22 @@
import java.util.Properties;
import java.util.function.Supplier;

import javax.annotation.Nullable;

import org.adempiere.util.Services;
import org.compiere.util.Env;
import org.springframework.beans.factory.annotation.Autowired;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;

import de.metas.printing.esb.base.util.Check;
import de.metas.process.IADProcessDAO;
import de.metas.process.RelatedProcessDescriptor;
import de.metas.ui.web.document.filter.DocumentFilterDescriptor;
import de.metas.ui.web.picking.process.WEBUI_Picking_AddHUToPickingSlot;
import de.metas.ui.web.picking.process.WEBUI_Picking_M_Picking_Candidate_Processed;
import de.metas.ui.web.picking.process.WEBUI_Picking_M_Picking_Candidate_Process;
import de.metas.ui.web.picking.process.WEBUI_Picking_M_Picking_Candidate_Unprocess;
import de.metas.ui.web.picking.process.WEBUI_Picking_OpenHUsToPick;
import de.metas.ui.web.picking.process.WEBUI_Picking_PickToExistingHU;
import de.metas.ui.web.picking.process.WEBUI_Picking_PickToNewHU;
Expand Down Expand Up @@ -52,7 +57,8 @@
* #L%
*/

@ViewFactory(windowId = PickingConstants.WINDOWID_PickingSlotView_String, viewTypes = { JSONViewDataType.grid, JSONViewDataType.includedView })
@ViewFactory(windowId = PickingConstants.WINDOWID_PickingSlotView_String, viewTypes =
{ JSONViewDataType.grid, JSONViewDataType.includedView })
public class PickingSlotViewFactory implements IViewFactory
{
@Autowired
Expand All @@ -78,22 +84,49 @@ public Collection<DocumentFilterDescriptor> getViewFilterDescriptors(final Windo
}

/**
* This method is called once for each shipment schedule (left-hand side) and creates the respective picking view (right-hand side)
* This method is called once for each shipment schedule (left-hand side) and creates the respective picking view (right-hand side).
*/
@Override
public PickingSlotView createView(@NonNull final CreateViewRequest request)
{
return createView(request, null);
}

/**
* This method is called once for each shipment schedule (left-hand side) and creates the respective picking view (right-hand side)
*
* @param request
* @param allShipmentScheduleIds the shipment schedule IDs to display picking slots for; <br>
* may be {@code null} or empty, in this case we assume that only the given {@code request}'s {@code shipmentScheduleId} is available.
* @return
*/
/* package */ PickingSlotView createView(
@NonNull final CreateViewRequest request,
@Nullable final List<Integer> allShipmentScheduleIds)
{
final ViewId pickingViewId = request.getParentViewId();
final DocumentId pickingRowId = request.getParentRowId();
final ViewId pickingSlotViewId = PickingSlotViewsIndexStorage.createViewId(pickingViewId, pickingRowId);

final int shipmentScheduleId = pickingRowId.toInt(); // TODO make it more obvious/explicit

final PickingSlotRepoQuery query = PickingSlotRepoQuery.of(shipmentScheduleId);

//
// setup the picking slot query and the rowsSupplier which uses the query to retrieve the PickingSlotView's rows.
final PickingSlotRepoQuery query;
if (allShipmentScheduleIds == null || allShipmentScheduleIds.isEmpty())
{
query = PickingSlotRepoQuery.of(shipmentScheduleId);
}
else
{
Check.errorUnless(allShipmentScheduleIds.contains(shipmentScheduleId),
"The given allShipmentScheduleIds has to include the given request's shipmentScheduleId; shipmentScheduleId={}; allShipmentScheduleIds={}; request={}",
shipmentScheduleId, allShipmentScheduleIds, request);

query = PickingSlotRepoQuery.of(allShipmentScheduleIds);
}
// notice for noobs such as me: this is executed each time the view is revalidated. and it's not executed when this createView method runs
final Supplier<List<PickingSlotRow>> rowsSupplier =
() -> pickingSlotRepo.retrieveRowsByShipmentScheduleId(query);
final Supplier<List<PickingSlotRow>> rowsSupplier = () -> pickingSlotRepo.retrieveRowsByShipmentScheduleId(query);

return PickingSlotView.builder()
.viewId(pickingSlotViewId)
Expand Down Expand Up @@ -144,7 +177,13 @@ private List<RelatedProcessDescriptor> createAdditionalRelatedProcessDescriptors
.build(),

RelatedProcessDescriptor.builder()
.processId(adProcessDAO.retriveProcessIdByClass(ctx, WEBUI_Picking_M_Picking_Candidate_Processed.class))
.processId(adProcessDAO.retriveProcessIdByClass(ctx, WEBUI_Picking_M_Picking_Candidate_Process.class))
.anyTable().anyWindow()
.webuiQuickAction(true)
.build(),

RelatedProcessDescriptor.builder()
.processId(adProcessDAO.retriveProcessIdByClass(ctx, WEBUI_Picking_M_Picking_Candidate_Unprocess.class))
.anyTable().anyWindow()
.webuiQuickAction(true)
.build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import de.metas.logging.LogManager;
import de.metas.picking.api.IPickingSlotDAO;
import de.metas.picking.model.I_M_PickingSlot;
import de.metas.printing.esb.base.util.Check;
import de.metas.ui.web.handlingunits.HUEditorRow;
import de.metas.ui.web.picking.PickingHUsRepository.PickingSlotHUEditorRow;
import de.metas.ui.web.picking.PickingSlotRepoQuery.PickingCandidate;
Expand Down Expand Up @@ -130,8 +131,11 @@ public PickingSlotViewRepository(@NonNull final PickingHUsRepository pickingHUsR
// ..ad least for checkPreconditionsApplicable()
public List<PickingSlotRow> retrieveRowsByShipmentScheduleId(@NonNull final PickingSlotRepoQuery query)
{
// retrieve the M_PickingSlots that are available for the given shipmentSchedule's partner and location.
final I_M_ShipmentSchedule shipmentSchedule = loadOutOfTrx(query.getShipmentScheduleId(), I_M_ShipmentSchedule.class);
Check.errorIf(query.getShipmentScheduleIds().isEmpty(), "Given query has no shipmentScheduleIds; query={}", query);

// retrieve the M_PickingSlots that are available for the given shipmentSchedules' partner and location.
// assume that all shipment schedules have the same partner and location (needs to be made sure) before starting all this stuff
final I_M_ShipmentSchedule shipmentSchedule = loadOutOfTrx(query.getShipmentScheduleIds().get(0), I_M_ShipmentSchedule.class);
final IShipmentScheduleEffectiveBL shipmentScheduleEffectiveBL = Services.get(IShipmentScheduleEffectiveBL.class);

final int bpartnerId = shipmentScheduleEffectiveBL.getC_BPartner_ID(shipmentSchedule);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package de.metas.ui.web.picking;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.adempiere.exceptions.AdempiereException;
Expand All @@ -14,6 +16,7 @@
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.WindowId;
import lombok.NonNull;

Expand Down Expand Up @@ -50,13 +53,13 @@
@Component
public class PickingSlotViewsIndexStorage implements IViewsIndexStorage
{
@Autowired
private PickingSlotViewFactory pickingSlotViewFactory;

// NOTE: avoid using @Autowired because might introduce cyclic dependency.
// We have a setter which will be called when this instance will be registered.
private IViewsRepository viewsRepository;

@Autowired
private PickingSlotViewFactory pickingSlotViewFactory;

@Override
public void setViewsRepository(@NonNull final IViewsRepository viewsRepository)
{
Expand Down Expand Up @@ -130,14 +133,21 @@ private PickingSlotView getOrCreatePickingSlotView(final ViewId pickingSlotViewI

if (create)
{
return pickingView.computePickingSlotViewIfAbsent(pickingSlotRowId, () -> {
final PickingRow pickingRow = pickingView.getById(pickingSlotRowId);
return pickingSlotViewFactory.createView(CreateViewRequest.builder(PickingConstants.WINDOWID_PickingSlotView, JSONViewDataType.includedView)
.setParentViewId(pickingView.getViewId())
.setParentRowId(pickingRow.getId())
.build());

});
return pickingView.computePickingSlotViewIfAbsent(
pickingSlotRowId,
() -> {
final PickingRow pickingRow = pickingView.getById(pickingSlotRowId);
final CreateViewRequest createViewRequest = CreateViewRequest
.builder(PickingConstants.WINDOWID_PickingSlotView, JSONViewDataType.includedView)
.setParentViewId(pickingView.getViewId())
.setParentRowId(pickingRow.getId())
.build();

// provide all pickingView's M_ShipmentSchedule_IDs to the factory, because we want to show the same picking slots and picked HU-rows for all of them.
final List<Integer> allShipmentScheduleIds = pickingView.streamByIds(DocumentIdsSelection.ALL).map(PickingRow::cast).map(PickingRow::getShipmentScheduleId).collect(Collectors.toList());

return pickingSlotViewFactory.createView(createViewRequest, allShipmentScheduleIds);
});
}
else
{
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/de/metas/ui/web/picking/PickingView.java
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,16 @@ public <T> List<T> retrieveModelsByIds(final DocumentIdsSelection rowIds, final
return InterfaceWrapperHelper.createList(packables, modelClass);
}

/**
* Also supports {@link DocumentIdsSelection#ALL}, because there won't be too many packageable lines at one time.
*/
@Override
public Stream<? extends IViewRow> streamByIds(final DocumentIdsSelection rowIds)
{
if(rowIds.isAll())
{
return getRows().values().stream();
}
return rowIds.stream().map(this::getById);
}

Expand Down
Loading

0 comments on commit 29960be

Please sign in to comment.