File: D:/HostingSpaces/SBogers10/shop.komma.nl/app/Discounts/DiscountService.php
<?php declare(strict_types=1);
namespace App\Discounts;
use App\Discounts\Conditions\AbstractDiscountConditionHandler;
use App\Vat\VatService;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
class DiscountService
{
private DiscountConditionService $discountConditionService;
private DiscountActionService $discountActionService;
private DiscountTranslationService $discountTranslationService;
private Collection $discounts;
private VatService $vatService;
/**
* DiscountService constructor.
*/
public function __construct()
{
$this->discounts = $this->baseQuery()->get();
$this->discountConditionService = new DiscountConditionService();
$this->discountActionService = new DiscountActionService();
$this->discountActionService = new DiscountActionService();
$this->discountTranslationService = new DiscountTranslationService();
$this->vatService = new VatService();
}
/**
* Determines which discounts should be applied to the given discountable.
*
* @param DiscountableInterface $discountable
* @return Collection
*/
public function applyDiscountsTo(DiscountableInterface $discountable) {
$discountable->clearDiscounts();
$applicableDiscounts = $this->getApplicableDiscounts($discountable, $this->discounts);
$this->applyDiscountActionsTo($applicableDiscounts, $discountable);
return $applicableDiscounts;
}
/**
* @param Discount[]|Collection $applicableDiscounts
* @param DiscountableInterface $discountable\
*/
private function applyDiscountActionsTo(Collection $applicableDiscounts, DiscountableInterface $discountable) {
foreach($applicableDiscounts as $applicableDiscount) {
foreach($applicableDiscount->actions as $discountAction) {
$handler = $this->discountActionService->makeHandler($discountAction->type);
$handler->apply($discountable, $this->vatService, $applicableDiscount->translation->title, $discountAction->params);
}
}
}
private function getApplicableDiscounts(DiscountableInterface $discountable, Collection $discounts): Collection {
/** @var Collection|Discount[] $discounts */
/** @var AbstractDiscountConditionHandler[]|Collection $discountConditionHandlers */
$stoppedProcessing = false;
$applicableDiscounts = $discounts->filter(function (Discount $discount) use($discountable, &$stoppedProcessing) {
//Check if we may must process this discount
if($stoppedProcessing) return false;
//Get the conditions of the discount which are applicable
$applicableConditions = $discount->conditions->filter(function(DiscountCondition $discountCondition) use($discountable) {
$handler = $this->discountConditionService->makeHandler($discountCondition->type);
return $handler->canBeApplied($discountable, $discountCondition->operator, $discountCondition->params);
});
//Filter out discounts of which not all conditions are met.
$allConditionsAreMet = $applicableConditions->count() === $discount->conditions->count();
//Check if we need to stop processing next discounts if all conditions where met.
if($allConditionsAreMet && $discount->stop_processing) {
$stoppedProcessing = true;
}
return $allConditionsAreMet;
});
return $applicableDiscounts;
}
public function saveFromJsonArray(array $data) {
if(!array_key_exists('state', $data)) return new Discount();
$discount = null;
switch ($data['state']) {
case Discount::NEW:
$discount = new Discount();
$discount->fill($data);
$discount->save();
if(array_key_exists('actions', $data)) $this->discountActionService->saveFromJsonArray($discount, $data['actions']);
if(array_key_exists('conditions', $data)) $this->discountConditionService->saveFromJsonArray($discount, $data['conditions']);
if(array_key_exists('translations', $data)) $this->discountTranslationService->saveFromJsonArray($discount, $data['translations']);
break;
case Discount::PRISTINE:
case Discount::DIRTY:
/** @var Discount $discount */
$discount = Discount::with('translations', 'conditions', 'actions')->find($data['id']);
$discount->fill($data);
$discount->save();
if(array_key_exists('actions', $data)) $this->discountActionService->saveFromJsonArray($discount, $data['actions']);
if(array_key_exists('conditions', $data)) $this->discountConditionService->saveFromJsonArray($discount, $data['conditions']);
if(array_key_exists('translations', $data)) $this->discountTranslationService->saveFromJsonArray($discount, $data['translations']);
break;
case Discount::DELETED:
$discount = Discount::find($data['id']);
if(!$discount) throw new \InvalidArgumentException('Data refers to a discount that does not exist anymore. Cannot delete discount');
$this->deleteDiscount($discount);
break;
}
return $discount;
}
private function deleteDiscount(Discount $discount) {
$discount->translations()->delete();
$discount->actions()->delete();
$discount->conditions()->delete();
$discount->delete();
}
/**
* @param $sortOrderData
* @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
*/
public function updateSortOrder($sortOrderData)
{
if(!is_array($sortOrderData)) abort(400, 'Expected the request to have a property of type array with name "sortOrderData", but did not get that');
$discounts = $this->baseQuery()->get();
foreach ($sortOrderData as $orderId => $sortOrder) {
$discount = $discounts->where('id', '=', $orderId)->first();
$discount->sort_order = $sortOrder;
$discount->save();
}
return $this->baseQuery()->get();
}
/**
* @return \Illuminate\Database\Eloquent\Builder
*/
public function baseQuery()
{
return Discount::with('translations.language', 'translation.language', 'conditions', 'actions')->orderBy('sort_order', 'asc');
}
/**
* @return array|mixed
*/
public function weatherInfo()
{
try {
$data = Cache::remember('buienradarWeerData', 3600, function () {
return file_get_contents('https://data.buienradar.nl/2.0/feed/json');
});
$data = json_decode($data, true);
if($data === null) return null;
return $data;
} catch (\Exception $exception) {
return [];
}
}
}