OrderRequestItemServiceImpl.java
/*
* Copyright 2020 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gringlobal.service.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.gringlobal.api.exception.InvalidApiUsageException;
import org.gringlobal.custom.elasticsearch.SearchException;
import org.gringlobal.model.OrderRequest;
import org.gringlobal.model.OrderRequestItem;
import org.gringlobal.model.OrderRequestItemAction;
import org.gringlobal.model.QAccession;
import org.gringlobal.model.QInventory;
import org.gringlobal.model.QOrderRequestItem;
import org.gringlobal.model.QOrderRequestItemAction;
import org.gringlobal.model.community.CommunityCodeValues;
import org.gringlobal.model.workflow.WorkflowActionStep;
import org.gringlobal.persistence.OrderRequestItemActionRepository;
import org.gringlobal.persistence.OrderRequestItemRepository;
import org.gringlobal.persistence.OrderRequestRepository;
import org.gringlobal.service.InventoryService;
import org.gringlobal.service.OrderRequestItemActionService;
import org.gringlobal.service.OrderRequestItemActionService.OrderRequestItemActionRequest;
import org.gringlobal.service.OrderRequestItemActionService.OrderRequestItemActionScheduleFilter;
import org.gringlobal.service.OrderRequestItemService;
import org.gringlobal.service.filter.OrderRequestItemActionFilter;
import org.gringlobal.service.filter.OrderRequestItemFilter;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.querydsl.core.types.EntityPath;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.NumberPath;
import com.querydsl.jpa.impl.JPAQuery;
/**
* The OrderRequestItemServiceImpl.
*/
@Transactional(readOnly = true)
@Service
@Slf4j
public class OrderRequestItemServiceImpl extends FilteredCRUDService2Impl<OrderRequestItem, OrderRequestItemFilter, OrderRequestItemRepository> implements OrderRequestItemService {
@Autowired
private InventoryService inventoryService;
@Component
protected static class ActionSupport extends BaseActionSupport<OrderRequestItem, OrderRequestItemAction, OrderRequestItemActionFilter, OrderRequestItemActionRepository, OrderRequestItemActionRequest, OrderRequestItemActionScheduleFilter>
implements OrderRequestItemActionService {
@Autowired
private OrderRequestRepository orderRequestRepository;
@Autowired
private OrderRequestItemRepository orderRequestItemRepository;
@Override
protected EntityPath<OrderRequestItem> getOwningEntityPath() {
return QOrderRequestItemAction.orderRequestItemAction.orderRequestItem();
}
@Override
protected void initializeActionDetails(List<OrderRequestItemAction> actions) {
actions.forEach(action -> {
Hibernate.initialize(action.getOrderRequestItem().getInventory());
Hibernate.initialize(action.getOrderRequestItem().getInventory().getAccession());
});
}
@Override
protected void applyOwningEntityFilter(OrderRequestItemActionScheduleFilter filter, String owningEntityAlias, List<Predicate> predicates) {
QOrderRequestItem qOrderRequestItem = new QOrderRequestItem(owningEntityAlias);
if (predicates != null && filter.orderRequestItem != null) {
predicates.addAll(filter.orderRequestItem.collectPredicates(qOrderRequestItem));
}
}
@Override
protected OrderRequestItemAction createAction(OrderRequestItem owningEntity) {
OrderRequestItemAction action = new OrderRequestItemAction();
action.setOrderRequestItem(owningEntity);
return action;
}
@Override
protected void updateAction(OrderRequestItemAction action, OrderRequestItemActionRequest request) {
action.setActionCost(request.actionCost);
action.setActionInformation(request.actionInformation);
}
@Override
protected OrderRequestItemAction prepareNextWorkflowStepAction(WorkflowActionStep nextStep, OrderRequestItemAction completedAction) {
OrderRequestItemAction nextAction = new OrderRequestItemAction();
nextAction.setOrderRequestItem(new OrderRequestItem(completedAction.getOrderRequestItem().getId()));
return createFast(nextAction);
}
@Override
@Transactional
public OrderRequestItemAction create(OrderRequestItemAction source) {
log.debug("Create OrderRequestItemAction. Input data {}", source);
OrderRequestItemAction entity = new OrderRequestItemAction();
entity.apply(source);
OrderRequestItemAction saved = get(repository.save(entity));
saved.lazyLoad();
return saved;
}
@Override
protected Iterable<OrderRequestItem> findOwningEntities(Set<Long> id) {
return orderRequestItemRepository.findAll(QOrderRequestItem.orderRequestItem.id.in(id));
}
/**
* Start an action for all items of the order request
*/
@Override
@Transactional
public List<OrderRequestItemAction> startActions(OrderRequest orderRequest, String actionCode) {
OrderRequestItemActionRequest request = new OrderRequestItemActionRequest();
orderRequest = orderRequestRepository.getReferenceById(orderRequest.getId());
request.id = orderRequest.getOrderRequestItems().stream()
// filter for allowed codes
.filter((ori) -> CommunityCodeValues.ORDER_REQUEST_ITEM_STATUS_PENDING.is(ori.getStatusCode()))
// to ID
.map(OrderRequestItem::getId).collect(Collectors.toSet());
request.actionNameCode = actionCode;
if (CollectionUtils.isEmpty(request.id)) {
return new ArrayList<>();
}
return super.startAction(request);
}
@Override
public Page<OrderRequestItemAction> listByOrderRequest(OrderRequest orderRequest, Pageable page) {
assert(orderRequest != null);
assert(orderRequest.isNew() == false);
final var orderRequestItemAction = new QOrderRequestItemAction("oria");
final var orderRequestItem = new QOrderRequestItem("ori");
var query = jpaQueryFactory.selectFrom(orderRequestItemAction)
.join(orderRequestItemAction.orderRequestItem(), orderRequestItem).fetchJoin()
.join(orderRequestItem.inventory()).fetchJoin()
.leftJoin(orderRequestItemAction.cooperator()).fetchJoin()
.where(orderRequestItem.orderRequest().eq(orderRequest));
var totalElements = query.fetchCount();
// apply sorting
for (Sort.Order o : page.getSort()) {
query.orderBy(new OrderSpecifier<>(o.isAscending() ? Order.ASC : Order.DESC, ExpressionUtils.path(String.class, orderRequestItemAction, o.getProperty())));
}
// apply pagination
if (page.isPaged()) {
query.offset(page.getOffset()).limit(page.getPageSize());
}
return new PageImpl<>(query.fetch(), page, totalElements);
}
}
@Override
protected NumberPath<Long> entityIdPredicate() {
return QOrderRequestItem.orderRequestItem.id;
}
@Override
public Page<OrderRequestItem> list(OrderRequestItemFilter filter, Pageable page) throws SearchException {
return super.list(OrderRequestItem.class, filter, page);
}
@Override
protected JPAQuery<OrderRequestItem> entityListQuery() {
QInventory inventory = QInventory.inventory;
QAccession accession = QAccession.accession;
return jpaQueryFactory.selectFrom(QOrderRequestItem.orderRequestItem)
//
.leftJoin(QOrderRequestItem.orderRequestItem.sourceCooperator()).fetchJoin()
.leftJoin(QOrderRequestItem.orderRequestItem.webOrderRequestItem()).fetchJoin()
.leftJoin(QOrderRequestItem.orderRequestItem.inventory(), inventory).fetchJoin()
.leftJoin(inventory.site()).fetchJoin()
// owner
.leftJoin(inventory.accession(), accession).fetchJoin()
.leftJoin(accession.taxonomySpecies()).fetchJoin();
}
@Override
@Transactional
@PreAuthorize("@ggceSec.actionAllowed('Request', 'ADMINISTRATION')")
public OrderRequestItem createFast(OrderRequestItem source) {
return super.createFast(source);
}
@Override
@Transactional
@PreAuthorize("@ggceSec.actionAllowed('Request', 'ADMINISTRATION')")
public OrderRequestItem create(OrderRequestItem source) {
log.debug("Create order request item. Input data {}", source);
var orderRequestItem = new OrderRequestItem();
orderRequestItem.apply(source);
var saved = repository.save(orderRequestItem);
// TODO Permission check
return _lazyLoad(saved);
}
@Override
@Transactional
@PreAuthorize("@ggceSec.actionAllowed('Request', 'ADMINISTRATION')")
public OrderRequestItem updateFast(@NotNull @Valid OrderRequestItem updated, OrderRequestItem target) {
if (Objects.isNull(updated.getInventory())) {
throw new InvalidApiUsageException("OrderRequestItem does not specify inventory");
}
updated.setInventory(inventoryService.get(updated.getInventory().getId()));
if (updated.getWithdrawnInventory() != null) {
updated.setWithdrawnInventory(inventoryService.get(updated.getWithdrawnInventory().getId()));
}
// save order request
updated.setOrderRequest(target.getOrderRequest());
target.apply(updated);
assert(target.getInventory().equals(updated.getInventory()));
var saved = repository.save(target);
return saved;
}
@Override
@Transactional
@PreAuthorize("@ggceSec.actionAllowed('Request', 'ADMINISTRATION')")
public OrderRequestItem update(OrderRequestItem input, OrderRequestItem target) {
log.debug("Update OrderRequestItem. Input data {}", input);
if (Objects.isNull(input.getInventory())) {
throw new InvalidApiUsageException("OrderRequestItem does not specify inventory");
}
input.setInventory(inventoryService.get(input.getInventory().getId()));
if (input.getWithdrawnInventory() != null) {
input.setWithdrawnInventory(inventoryService.get(input.getWithdrawnInventory().getId()));
}
// save order request
input.setOrderRequest(target.getOrderRequest());
target.apply(input);
var saved = repository.save(target);
return _lazyLoad(saved);
}
@Override
@Transactional
@PreAuthorize("@ggceSec.actionAllowed('Request', 'ADMINISTRATION')")
public List<OrderRequestItem> updateAll(Collection<OrderRequestItem> items) {
if (CollectionUtils.isEmpty(items))
return Collections.emptyList();
List<OrderRequestItem> result = new ArrayList<>(items.size());
for (OrderRequestItem item : items) {
if (item.isNew())
throw new InvalidApiUsageException("Unable to update non-existing OrderRequestItem.");
OrderRequestItem target = reload(item);
result.add(update(item, target));
}
return result;
}
@Override
protected void prepareLabelContext(Map<String, Object> context, OrderRequestItem entity) {
context.put("orderRequestItem", entity);
context.put("orderRequest", entity.getOrderRequest());
context.put("inventory", entity.getInventory());
context.put("withdrawnInventory", entity.getWithdrawnInventory());
}
}