<?php
namespace Twigel\BonusProgram\Subscriber;
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
use Shopware\Core\Checkout\Order\OrderEntity;
use Shopware\Core\Checkout\Order\OrderEvents;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\Framework\Uuid\Uuid;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Twigel\BonusProgram\Service\TwigelCustomerOrderService;
class OnOrderWritten implements EventSubscriberInterface
{
/** @var EntityRepository */
private $orderRepository;
/** @var SystemConfigService */
private $config;
/** @var EntityRepository */
private $twigelOrderStatusRepository;
/** @var EntityRepository */
private $orderCustomerRepository;
/** @var EntityRepository */
private $customerRepository;
/** @var EntityRepository */
private $twigelCustomerAccountRepository;
/** @var EntityRepository */
private $twigelStatusRepository;
public function __construct(
EntityRepository $orderRepository,
SystemConfigService $config,
EntityRepository $twigelOrderStatusRepository,
EntityRepository $orderCustomerRepository,
EntityRepository $customerRepository,
EntityRepository $twigelCustomerAccountRepository,
EntityRepository $twigelStatusRepository
)
{
$this->orderRepository = $orderRepository;
$this->config = $config;
$this->twigelOrderStatusRepository = $twigelOrderStatusRepository;
$this->orderCustomerRepository = $orderCustomerRepository;
$this->customerRepository = $customerRepository;
$this->twigelCustomerAccountRepository = $twigelCustomerAccountRepository;
$this->twigelStatusRepository = $twigelStatusRepository;
}
/**
* @inheritDoc
*/
public static function getSubscribedEvents()
{
return [
OrderEvents::ORDER_WRITTEN_EVENT => 'onOrderWritten'
];
}
public function onOrderWritten(EntityWrittenEvent $event)
{
if ($event->getName() !== OrderEvents::ORDER_WRITTEN_EVENT) {
return;
}
if (!$this->config->get("TwigelBonusProgram")) {
return;
}
$results = $event->getWriteResults();
$customerId = '';
$orderUpdate = [];
foreach ($results as $result) {
$criteria = new Criteria([$result->getPrimaryKey()]);
$criteria->addAssociations(['lineItems']);
/** @var OrderEntity $order */
$order = $this->orderRepository->search($criteria, $event->getContext())->first();
$customerId = $order->getOrderCustomer()->getCustomerId();
$customer = self::getCustomer($customerId, $event->getContext());
$bonusAmount = 0;
$bonusSell = 0;
/** @var OrderLineItemEntity $lineItem */
foreach ($order->getLineItems() as $lineItem){
if ($lineItem->getType() !== "promotion"){
$bonusAmount += round($lineItem->getTotalPrice() * $this->config->get("TwigelBonusProgram.config.bonusToEuro"));
}
if (array_key_exists('productBonusSell', $lineItem->getPayload())){
$bonusSell += $lineItem->getPayload()['productBonusSell'];
}elseif(array_key_exists("promotionId", $lineItem->getPayload()) && $lineItem->getPayload()["promotionId"] == $this->config->get("TwigelBonusProgram")["config"]["discountByBonus"]){
$bonusSell += +($lineItem->getPayload()["value"]) * $this->config->get("TwigelBonusProgram")["config"]["euroToBonus"];
}
}
if($bonusSell){
$orderUpdate[] = [
'id' => $order->getId(),
'customFields' => [
'bonusOrder' => $bonusAmount,
'bonusSell' => $bonusSell
]
];
}else{
$orderUpdate[] = [
'id' => $order->getId(),
'customFields' => [
'bonusOrder' => $bonusAmount
]
];
}
$bonusAmount = $bonusAmount - $bonusSell;
$orderStatus = [
'id' => Uuid::randomHex(),
'orderId' => $order->getId(),
'customerId' => $order->getOrderCustomer()->getCustomerId(),
'bonusAmount' => (int)$bonusAmount
];
$criteria = new Criteria();
$criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_AND, [
new EqualsFilter('orderId', $order->getId()),
new EqualsFilter('customerId', $order->getOrderCustomer()->getCustomerId())
]));
$orderStatusDb = $this->twigelOrderStatusRepository->search($criteria, $event->getContext())->first();
if ($orderStatusDb) {
$this->twigelOrderStatusRepository->update([[
'id' => $orderStatusDb->getId(),
'bonusAmount' => (int)$bonusAmount,
]], $event->getContext());
} else {
$this->twigelOrderStatusRepository->create([$orderStatus], $event->getContext());
}
$customerAccountCriteria = new Criteria();
$customerAccountCriteria->addFilter(new EqualsFilter('customerId', $customerId));
$customerAccount = $this->twigelCustomerAccountRepository->search($customerAccountCriteria, $event->getContext())->first();
if (!$customerAccount) {
$status = self::getCustomerStatusId($customerId, $event->getContext());
$customerAccount = [
'id' => Uuid::randomHex(),
'customerId' => $customerId,
'bonusAmount' => (int)$bonusAmount
];
if ($status){
$customerAccount['statusId'] = $status->getId();
}
$this->twigelCustomerAccountRepository->create([$customerAccount], $event->getContext());
} else {
$status = self::getCustomerStatusId($customerId, $event->getContext());
if ($status && $customerAccount->getStatusId() !== $status->getId()){
$this->twigelCustomerAccountRepository->update([
[
'id' => $customerAccount->getId(),
'statusId' => $status->getId(),
'bonusAmount' => $customerAccount->getBonusAmount() + (int)$bonusAmount
]
], $event->getContext());
}else{
$this->twigelCustomerAccountRepository->update([
[
'id' => $customerAccount->getId(),
'bonusAmount' => $customerAccount->getBonusAmount() + (int)$bonusAmount
]
], $event->getContext());
}
}
if (!$order->getCustomFields()){
self::orderUpdate($orderUpdate, $event->getContext());
}
}
self::getCustomerTurnOver($customerId, $event->getContext());
}
private function orderUpdate(array $update, Context $context){
if (!$update){
return;
}
$this->orderRepository->update($update, $context);
}
private function getCustomerStatusId($customerId, Context $context){
$status = self::getCustomerStatus($customerId);
if ($status['turnOver']){
$customerGroupId = $this->config->get('TwigelBonusProgram')['config'][TwigelCustomerOrderService::CONFIG_CUSTOMER_GROUPS[$status['turnOver']]];
$statusCriteria = new Criteria();
$statusCriteria->addFilter(new EqualsFilter('customerGroupId', $customerGroupId));
return $this->twigelStatusRepository->search($statusCriteria, $context)->first();
}else{
return null;
}
}
private function getCustomerStatus($customerId){
$service = new TwigelCustomerOrderService($this->orderCustomerRepository);
return [
'turnOver' => $service->countTurnOver($customerId),
'amountOfOrders' => $service->countOrdersOfCustomer($customerId)
];
}
private function getCustomerTurnOver($customerId, Context $context)
{
$status = self::getCustomerStatus($customerId);
if (($status['turnOver'] !== 0 || $status['amountOfOrders'] !== 0) && $status['turnOver'] !== $status['amountOfOrders']) {
self::setCustomerStatus($status['turnOver'], $customerId, $context);
} elseif (($status['turnOver'] !== 0 || $status['amountOfOrders'] !== 0) && $status['turnOver'] === $status['amountOfOrders']) {
self::setCustomerStatus($status['amountOfOrders'], $customerId, $context);
}
}
private function setCustomerStatus($status, $customerId, Context $context)
{
if ($status === "0") {
return;
}
$customerGroupId = $this->config->get('TwigelBonusProgram')['config'][TwigelCustomerOrderService::CONFIG_CUSTOMER_GROUPS[$status]];
$criteria = new Criteria([$customerId]);
$criteria->addFilter(new EqualsFilter('groupId', $customerGroupId));
$customer = $this->customerRepository->search($criteria, $context)->first();
if (!$customer) {
$this->customerRepository->update([
[
'id' => $customerId,
'groupId' => $customerGroupId
]
], $context);
}
}
private function getCustomer($customerId, Context $context)
{
if (!$customerId){
return null;
}
$criteria = new Criteria([$customerId]);
return $this->customerRepository->search($criteria, $context)->first();
}
}