All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.liferay.commerce.internal.order.engine.CommerceOrderEngineImpl Maven / Gradle / Ivy

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library 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 Lesser General Public License for more
 * details.
 */

package com.liferay.commerce.internal.order.engine;

import com.liferay.commerce.constants.CommerceOrderActionKeys;
import com.liferay.commerce.constants.CommerceOrderConstants;
import com.liferay.commerce.constants.CommercePaymentConstants;
import com.liferay.commerce.context.CommerceContext;
import com.liferay.commerce.context.CommerceContextFactory;
import com.liferay.commerce.exception.CommerceOrderBillingAddressException;
import com.liferay.commerce.exception.CommerceOrderShippingAddressException;
import com.liferay.commerce.exception.CommerceOrderShippingMethodException;
import com.liferay.commerce.exception.CommerceOrderStatusException;
import com.liferay.commerce.exception.CommerceOrderValidatorException;
import com.liferay.commerce.inventory.CPDefinitionInventoryEngine;
import com.liferay.commerce.inventory.CPDefinitionInventoryEngineRegistry;
import com.liferay.commerce.inventory.engine.CommerceInventoryEngine;
import com.liferay.commerce.inventory.model.CommerceInventoryBookedQuantity;
import com.liferay.commerce.inventory.service.CommerceInventoryBookedQuantityLocalService;
import com.liferay.commerce.model.CPDefinitionInventory;
import com.liferay.commerce.model.CommerceAddress;
import com.liferay.commerce.model.CommerceOrder;
import com.liferay.commerce.model.CommerceOrderItem;
import com.liferay.commerce.model.CommerceShippingMethod;
import com.liferay.commerce.notification.util.CommerceNotificationHelper;
import com.liferay.commerce.order.CommerceOrderValidatorRegistry;
import com.liferay.commerce.order.engine.CommerceOrderEngine;
import com.liferay.commerce.order.status.CommerceOrderStatus;
import com.liferay.commerce.order.status.CommerceOrderStatusRegistry;
import com.liferay.commerce.payment.method.CommercePaymentMethod;
import com.liferay.commerce.payment.method.CommercePaymentMethodRegistry;
import com.liferay.commerce.product.model.CPInstance;
import com.liferay.commerce.product.service.CPInstanceLocalService;
import com.liferay.commerce.service.CPDefinitionInventoryLocalService;
import com.liferay.commerce.service.CommerceAddressLocalService;
import com.liferay.commerce.service.CommerceOrderItemLocalService;
import com.liferay.commerce.service.CommerceOrderLocalServiceUtil;
import com.liferay.commerce.service.CommerceOrderService;
import com.liferay.commerce.service.CommerceShippingMethodLocalService;
import com.liferay.commerce.stock.activity.CommerceLowStockActivity;
import com.liferay.commerce.stock.activity.CommerceLowStockActivityRegistry;
import com.liferay.commerce.subscription.CommerceSubscriptionEntryHelperUtil;
import com.liferay.commerce.util.CommerceShippingHelper;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.security.permission.PermissionThreadLocal;
import com.liferay.portal.kernel.security.permission.resource.ModelResourcePermission;
import com.liferay.portal.kernel.service.ServiceContext;
import com.liferay.portal.kernel.transaction.Propagation;
import com.liferay.portal.kernel.transaction.TransactionCommitCallbackUtil;
import com.liferay.portal.kernel.transaction.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ReferencePolicyOption;

/**
 * @author Alec Sloan
 */
@Component(immediate = true, service = CommerceOrderEngine.class)
public class CommerceOrderEngineImpl implements CommerceOrderEngine {

	@Override
	@Transactional(
		propagation = Propagation.REQUIRED, rollbackFor = Exception.class
	)
	public CommerceOrder checkoutCommerceOrder(
			CommerceOrder commerceOrder, long userId)
		throws PortalException {

		_commerceOrderModelResourcePermission.check(
			PermissionThreadLocal.getPermissionChecker(), commerceOrder,
			CommerceOrderActionKeys.CHECKOUT_COMMERCE_ORDER);

		CommerceOrderStatus currentCommerceOrderStatus =
			_commerceOrderStatusRegistry.getCommerceOrderStatus(
				commerceOrder.getOrderStatus());

		if ((currentCommerceOrderStatus == null) ||
			(currentCommerceOrderStatus.getKey() !=
				CommerceOrderConstants.ORDER_STATUS_OPEN)) {

			throw new CommerceOrderStatusException();
		}

		_validateCheckout(commerceOrder);

		ServiceContext serviceContext = new ServiceContext();

		serviceContext.setScopeGroupId(commerceOrder.getGroupId());
		serviceContext.setUserId(userId);

		long commerceOrderId = commerceOrder.getCommerceOrderId();

		CommerceContext commerceContext = _commerceContextFactory.create(
			commerceOrder.getCompanyId(), commerceOrder.getGroupId(), userId,
			commerceOrderId, commerceOrder.getCommerceAccountId());

		_bookQuantities(commerceOrder);

		commerceOrder = CommerceOrderLocalServiceUtil.recalculatePrice(
			commerceOrderId, commerceContext);

		// Commerce addresses

		if (commerceOrder.getBillingAddressId() > 0) {
			CommerceAddress commerceAddress =
				_commerceAddressLocalService.copyCommerceAddress(
					commerceOrder.getBillingAddressId(),
					commerceOrder.getModelClassName(), commerceOrderId,
					serviceContext);

			commerceOrder.setBillingAddressId(
				commerceAddress.getCommerceAddressId());
		}

		if (commerceOrder.getShippingAddressId() > 0) {
			CommerceAddress commerceAddress =
				_commerceAddressLocalService.copyCommerceAddress(
					commerceOrder.getShippingAddressId(),
					commerceOrder.getModelClassName(), commerceOrderId,
					serviceContext);

			commerceOrder.setShippingAddressId(
				commerceAddress.getCommerceAddressId());
		}

		// Set Order Status

		commerceOrder.setOrderDate(new Date());
		commerceOrder.setOrderStatus(
			CommerceOrderConstants.ORDER_STATUS_IN_PROGRESS);

		CommercePaymentMethod commercePaymentMethod =
			_commercePaymentMethodRegistry.getCommercePaymentMethod(
				commerceOrder.getCommercePaymentMethodKey());

		if ((commerceOrder.getPaymentStatus() ==
				CommerceOrderConstants.PAYMENT_STATUS_PAID) ||
			((commercePaymentMethod != null) &&
			 (commercePaymentMethod.getPaymentType() ==
				 CommercePaymentConstants.
					 COMMERCE_PAYMENT_METHOD_TYPE_OFFLINE) &&
			 (commerceOrder.getPaymentStatus() ==
				 CommerceOrderConstants.PAYMENT_STATUS_PENDING))) {

			commerceOrder = transitionCommerceOrder(
				commerceOrder, CommerceOrderConstants.ORDER_STATUS_PENDING,
				userId);
		}

		return _commerceOrderService.updateCommerceOrder(commerceOrder);
	}

	@Override
	@Transactional(
		propagation = Propagation.REQUIRED, rollbackFor = Exception.class
	)
	public CommerceOrderStatus getCurrentCommerceOrderStatus(
		CommerceOrder commerceOrder) {

		return _commerceOrderStatusRegistry.getCommerceOrderStatus(
			commerceOrder.getOrderStatus());
	}

	@Override
	@Transactional(
		propagation = Propagation.REQUIRED, rollbackFor = Exception.class
	)
	public List getNextCommerceOrderStatuses(
			CommerceOrder commerceOrder)
		throws PortalException {

		CommerceOrderStatus currentCommerceOrderStatus =
			_commerceOrderStatusRegistry.getCommerceOrderStatus(
				commerceOrder.getOrderStatus());

		List nextCommerceOrderStatuses = new ArrayList<>();

		if (currentCommerceOrderStatus == null) {
			return nextCommerceOrderStatuses;
		}
		else if (currentCommerceOrderStatus.getKey() ==
					CommerceOrderConstants.ORDER_STATUS_ON_HOLD) {

			nextCommerceOrderStatuses.add(
				_commerceOrderStatusRegistry.getCommerceOrderStatus(
					CommerceOrderConstants.ORDER_STATUS_ON_HOLD));

			return nextCommerceOrderStatuses;
		}

		List commerceOrderStatuses =
			_commerceOrderStatusRegistry.getCommerceOrderStatuses();

		int currentOrderStatusIndex = commerceOrderStatuses.indexOf(
			currentCommerceOrderStatus);

		if (currentOrderStatusIndex != (commerceOrderStatuses.size() - 1)) {
			CommerceOrderStatus nextCommerceOrderStatus =
				commerceOrderStatuses.get(currentOrderStatusIndex + 1);

			for (CommerceOrderStatus commerceOrderStatus :
					commerceOrderStatuses) {

				if (commerceOrderStatus.isTransitionCriteriaMet(
						commerceOrder) &&
					(((commerceOrderStatus.getPriority() ==
						CommerceOrderConstants.ORDER_STATUS_ANY) &&
					  (currentCommerceOrderStatus.getKey() !=
						  CommerceOrderConstants.ORDER_STATUS_OPEN)) ||
					 (commerceOrderStatus.getPriority() ==
						 nextCommerceOrderStatus.getPriority()))) {

					nextCommerceOrderStatuses.add(commerceOrderStatus);
				}
			}
		}

		return nextCommerceOrderStatuses;
	}

	@Override
	@Transactional(
		propagation = Propagation.REQUIRED, rollbackFor = Exception.class
	)
	public CommerceOrder transitionCommerceOrder(
			CommerceOrder commerceOrder, int orderStatus, long userId)
		throws PortalException {

		CommerceOrderStatus commerceOrderStatus =
			_commerceOrderStatusRegistry.getCommerceOrderStatus(orderStatus);

		if (commerceOrderStatus == null) {
			throw new CommerceOrderStatusException();
		}

		CommerceOrderStatus currentCommerceOrderStatus =
			_commerceOrderStatusRegistry.getCommerceOrderStatus(
				commerceOrder.getOrderStatus());

		if (!currentCommerceOrderStatus.isComplete(commerceOrder) ||
			!commerceOrderStatus.isTransitionCriteriaMet(commerceOrder) ||
			((currentCommerceOrderStatus.getKey() ==
				CommerceOrderConstants.ORDER_STATUS_ON_HOLD) &&
			 (commerceOrderStatus.getKey() !=
				 CommerceOrderConstants.ORDER_STATUS_ON_HOLD) &&
			 (commerceOrderStatus.getKey() !=
				 CommerceOrderConstants.ORDER_STATUS_PROCESSING))) {

			throw new CommerceOrderStatusException();
		}

		_sendOrderStatusMessage(commerceOrder, commerceOrderStatus.getKey());

		return commerceOrderStatus.doTransition(commerceOrder, userId);
	}

	private void _bookQuantities(CommerceOrder commerceOrder)
		throws PortalException {

		List commerceOrderItems =
			commerceOrder.getCommerceOrderItems();

		for (CommerceOrderItem commerceOrderItem : commerceOrderItems) {
			Map context = new HashMap<>();

			context.put(
				"OrderId ",
				String.valueOf(commerceOrderItem.getCommerceOrderId()));
			context.put(
				"OrderItemId ",
				String.valueOf(commerceOrderItem.getCommerceOrderItemId()));

			CommerceInventoryBookedQuantity commerceInventoryBookedQuantity =
				_commerceInventoryBookedQuantityLocalService.
					addCommerceBookedQuantity(
						commerceOrderItem.getUserId(),
						commerceOrderItem.getSku(),
						commerceOrderItem.getQuantity(), null, context);

			_commerceOrderItemLocalService.updateCommerceOrderItem(
				commerceOrderItem.getCommerceOrderItemId(),
				commerceInventoryBookedQuantity.
					getCommerceInventoryBookedQuantityId());
		}

		// Low stock action

		long companyId = commerceOrder.getCompanyId();

		for (CommerceOrderItem commerceOrderItem :
				commerceOrder.getCommerceOrderItems()) {

			CPInstance cpInstance = _cpInstanceLocalService.getCPInstance(
				commerceOrderItem.getCPInstanceId());

			CPDefinitionInventory cpDefinitionInventory =
				_cpDefinitionInventoryLocalService.
					fetchCPDefinitionInventoryByCPDefinitionId(
						cpInstance.getCPDefinitionId());

			CommerceLowStockActivity commerceLowStockActivity =
				_commerceLowStockActivityRegistry.getCommerceLowStockActivity(
					cpDefinitionInventory);

			if (commerceLowStockActivity == null) {
				return;
			}

			int stockQuantity = _commerceInventoryEngine.getStockQuantity(
				companyId, commerceOrderItem.getSku());

			CPDefinitionInventoryEngine cpDefinitionInventoryEngine =
				_cpDefinitionInventoryEngineRegistry.
					getCPDefinitionInventoryEngine(cpDefinitionInventory);

			if (stockQuantity <=
					cpDefinitionInventoryEngine.getMinStockQuantity(
						cpInstance)) {

				commerceLowStockActivity.execute(cpInstance);
			}
		}
	}

	@Transactional(
		propagation = Propagation.REQUIRED, rollbackFor = Exception.class
	)
	private void _sendOrderStatusMessage(
		CommerceOrder commerceOrder, int orderStatus) {

		TransactionCommitCallbackUtil.registerCallback(
			new Callable() {

				@Override
				public Void call() throws Exception {
					if ((orderStatus ==
							CommerceOrderConstants.ORDER_STATUS_PENDING) &&
						(commerceOrder.getPaymentStatus() ==
							CommerceOrderConstants.PAYMENT_STATUS_PAID)) {

						CommerceSubscriptionEntryHelperUtil.
							checkCommerceSubscriptions(commerceOrder);
					}

					_commerceNotificationHelper.sendNotifications(
						commerceOrder.getScopeGroupId(),
						commerceOrder.getUserId(),
						CommerceOrderConstants.getNotificationKey(orderStatus),
						commerceOrder);

					return null;
				}

			});
	}

	private void _validateCheckout(CommerceOrder commerceOrder)
		throws PortalException {

		if (!_commerceOrderValidatorRegistry.isValid(null, commerceOrder)) {
			throw new CommerceOrderValidatorException();
		}

		if (commerceOrder.isB2B() &&
			(commerceOrder.getBillingAddressId() <= 0)) {

			throw new CommerceOrderBillingAddressException();
		}

		CommerceShippingMethod commerceShippingMethod = null;

		long commerceShippingMethodId =
			commerceOrder.getCommerceShippingMethodId();

		if (commerceShippingMethodId > 0) {
			commerceShippingMethod =
				_commerceShippingMethodLocalService.getCommerceShippingMethod(
					commerceShippingMethodId);

			if (!commerceShippingMethod.isActive()) {
				commerceShippingMethod = null;
			}
			else if (commerceOrder.getShippingAddressId() <= 0) {
				throw new CommerceOrderShippingAddressException();
			}
		}

		if ((commerceShippingMethod == null) &&
			(_commerceShippingMethodLocalService.
				getCommerceShippingMethodsCount(
					commerceOrder.getGroupId(), true) > 0) &&
			_commerceShippingHelper.isShippable(commerceOrder)) {

			throw new CommerceOrderShippingMethodException();
		}
	}

	@Reference
	private CommerceAddressLocalService _commerceAddressLocalService;

	@Reference
	private CommerceContextFactory _commerceContextFactory;

	@Reference
	private CommerceInventoryBookedQuantityLocalService
		_commerceInventoryBookedQuantityLocalService;

	@Reference
	private CommerceInventoryEngine _commerceInventoryEngine;

	@Reference
	private CommerceLowStockActivityRegistry _commerceLowStockActivityRegistry;

	@Reference
	private CommerceNotificationHelper _commerceNotificationHelper;

	@Reference
	private CommerceOrderItemLocalService _commerceOrderItemLocalService;

	@Reference(
		target = "(model.class.name=com.liferay.commerce.model.CommerceOrder)"
	)
	private ModelResourcePermission
		_commerceOrderModelResourcePermission;

	@Reference(
		policy = ReferencePolicy.DYNAMIC,
		policyOption = ReferencePolicyOption.GREEDY
	)
	private volatile CommerceOrderService _commerceOrderService;

	@Reference
	private CommerceOrderStatusRegistry _commerceOrderStatusRegistry;

	@Reference
	private CommerceOrderValidatorRegistry _commerceOrderValidatorRegistry;

	@Reference
	private CommercePaymentMethodRegistry _commercePaymentMethodRegistry;

	@Reference
	private CommerceShippingHelper _commerceShippingHelper;

	@Reference
	private CommerceShippingMethodLocalService
		_commerceShippingMethodLocalService;

	@Reference
	private CPDefinitionInventoryEngineRegistry
		_cpDefinitionInventoryEngineRegistry;

	@Reference
	private CPDefinitionInventoryLocalService
		_cpDefinitionInventoryLocalService;

	@Reference
	private CPInstanceLocalService _cpInstanceLocalService;

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy