Newer
Older
use QUI\ERP\Discount\Handler as DiscountHandler;
*
* @var int
*/
protected $id;
/**
* Actual code
*
* @var string
*/
protected $code;
/**
/**
* IDs of all linked discounts
*
* @var int[]
*/
protected $discountIds = [];
*
* @var \DateTime
*/
protected $ValidUntilDate = null;
/**
protected $maxUsages = Handler::MAX_USAGE_ONCE_PER_USER;
try {
$result = QUI::getDataBase()->fetch([
'from' => Handler::getTable(),
'where' => [
'id' => $id
]
]);
} catch (QUI\DataBase\Exception $Exception) {
QUI\System\Log::addError($Exception->getMessage());
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.not_found',
[
'id' => $id
]
], 404);
}
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.not_found',
[
$this->id = (int)$data['id'];
$this->code = $data['code'];
$this->title = $data['title'];
$this->usages = \json_decode($data['usages'], true);
$this->userIds = \json_decode($data['userIds'], true);
$this->groupIds = \json_decode($data['groupIds'], true);
if (!empty($data['maxUsages'])) {
$this->maxUsages = $data['maxUsages'];
$this->discountIds = \json_decode($data['discountIds'], true);
$this->CreateDate = new \DateTime($data['createDate']);
if (!empty($data['validUntilDate'])) {
$this->ValidUntilDate = new \DateTime($data['validUntilDate']);
$this->ValidUntilDate->setTime(23, 59, 59);
{
return $this->id;
}
/**
* @return string
*/
{
return $this->code;
}
/**
* @return \DateTime
*/
{
return $this->ValidUntilDate;
}
/**
* @return string
*/
/**
* Get all discounts associated with this CouponCode
*
* @return QUI\ERP\Discount\Discount[]
*/
{
$discounts = [];
$DiscountHandler = DiscountHandler::getInstance();
foreach ($this->discountIds as $discountId) {
try {
$discounts[] = $DiscountHandler->getChild($discountId);
} catch (\Exception $Exception) {
QUI\System\Log::writeDebugException($Exception);
}
}
return $discounts;
}
/**
* @return int[]
*/
public function getUserIds(): array
{
return $this->userIds;
}
/**
* @return int[]
*/
public function getGroupIds(): array
{
return $this->groupIds;
}
* Redeems this CouponCode
*
* Hint: This may invalidate the code for future use
*
* @param QUI\Users\User $User - The user that redeems the CouponCode [if omitted use Session User]
* @param QUI\ERP\Order\Order $Order (optional) - Link redemption to a specific Order
public function redeem($User = null, $Order = null)
$User = QUI::getUserBySession();
}
$this->checkRedemption($User);
$Now = new \DateTime();
$usage = [
'userId' => $User->getId(),
'date' => $Now->format('Y-m-d H:i:s'),
'orderPrefixedId' => false
if (!\is_null($Order) && $Order instanceof QUI\ERP\Order\Order) {
$usage['orderPrefixedId'] = $Order->getPrefixedId();
}
$this->usages[] = $usage;
['usages' => \json_encode($this->usages)],
['id' => $this->id]
QUI::getEvents()->fireEvent(
'quiqqerCouponsRedeem',
[
'User' => $User,
'CouponCode' => $this
]
);
* @param QUI\Interfaces\Users\User $User - If omitted, use session user
* @throws CouponCodeException - Thrown if not redeemable by the given User
public function checkRedemption($User)
if (!$this->isValid()) {
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.no_longer_valid'
]);
}
$DiscountHandler = DiscountHandler::getInstance();
$discountsValid = false;
$discountError = false;
foreach ($this->discountIds as $discountId) {
try {
/** @var QUI\ERP\Discount\Discount $Discount */
$Discount = $DiscountHandler->getChild($discountId);
} catch (\Exception $Exception) {
$discountError = $Exception->getMessage();
continue;
}
if ($Discount->canUsedBy($User)) {
$discountsValid = true;
break;
}
}
if (!$discountsValid) {
if (\count($this->discountIds) === 1) {
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.discount_invalid',
[
'reason' => $discountError
]
]);
} else {
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.discounts_invalid'
]);
}
}
// Max usage restrictions
switch ($this->maxUsages) {
case Handler::MAX_USAGE_ONCE_PER_USER:
if ($this->hasUserRedeemed($User)) {
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.already_used'
]);
}
break;
case Handler::MAX_USAGE_ONCE:
if (!empty($this->usages)) {
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.already_used'
]);
}
break;
}
// Restriction to QUIQQER user(s)
if (\in_array($User->getId(), $this->userIds)) {
if ($this->maxUsages !== Handler::MAX_USAGE_UNLIMITED
&& $this->hasUserRedeemed($User)) {
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.already_used'
]);
}
} else {
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.user_not_allowed'
]);
}
// Restriction to QUIQQER group(s)
foreach ($this->groupIds as $groupId) {
if ($User->isInGroup($groupId)) {
$userInGroup = true;
break;
}
}
if ($this->maxUsages !== Handler::MAX_USAGE_UNLIMITED
&& $this->hasUserRedeemed($User)) {
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.already_used'
]);
}
} else {
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.user_not_allowed_group'
]);
}
}
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
/**
* Check if the given Order can redeem this CouponCode
*
* @param OrderInterface|null $Order
* @throws CouponCodeException
*/
public function checkOrderRedemption($Order)
{
if ($Order === null) {
return;
}
$DiscountHandler = DiscountHandler::getInstance();
$discountsValid = false;
$discountError = false;
foreach ($this->discountIds as $discountId) {
try {
/** @var QUI\ERP\Discount\Discount $Discount */
$Discount = $DiscountHandler->getChild($discountId);
} catch (\Exception $Exception) {
$discountError = $Exception->getMessage();
continue;
}
if ($Discount->canUsedInOrder($Order)) {
$discountsValid = true;
break;
}
}
if (!$discountsValid) {
if (\count($this->discountIds) === 1) {
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.discount_invalid',
[
'reason' => $discountError
]
]);
} else {
throw new CouponCodeException([
'quiqqer/coupons',
'exception.CouponCode.discounts_invalid'
]);
}
}
}
* @param QUI\Users\User $User - If omitted, use session user
public function isRedeemable($User = null, $Order = null): bool
try {
$this->checkRedemption($User);
} catch (CouponCodeException $Exception) {
return false;
}
if ($Order) {
try {
$this->checkOrderRedemption($Order);
} catch (CouponCodeException $Exception) {
$Order->addFrontendMessage($Exception->getMessage());
return false;
}
}
public function hasUserRedeemed(QUI\Interfaces\Users\User $User): bool
foreach ($this->usages as $usage) {
if ($usage['userId'] === $userId) {
return true;
}
*/
public function delete()
{
Permission::checkPermission(Handler::PERMISSION_DELETE);
try {
QUI::getDataBase()->delete(
Handler::getTable(),
['id' => $this->id]
);
} catch (QUI\DataBase\Exception $Exception) {
QUI\System\Log::addError($Exception->getMessage());
}

Patrick Müller
committed
// If hidden discount are connected to this coupon -> delete them aswell
foreach ($this->getDiscounts() as $Discount) {
if (!empty($Discount->getAttribute('hidden'))) {
try {
$Discount->delete();
} catch (\Exception $Exception) {
QUI\System\Log::writeException($Exception);
}
}
}
'userIds' => $this->userIds,
'groupIds' => $this->groupIds,
'createDate' => $this->getCreateDate()->format('Y-m-d H:i:s'),
'validUntilDate' => false,
'title' => $this->getTitle() ?: false,
$data['validUntilDate'] = $ValidUntilDate->format('Y-m-d');
/**
* Checks if this CouponCode is still valid
*
* @return void
*/
protected function checkValidity()
{
// Check if the expiration date has been reached
if (!empty($this->ValidUntilDate)) {
$Now = new \DateTime();
if ($Now > $this->ValidUntilDate) {
$this->valid = false;
if ($this->maxUsages === Handler::MAX_USAGE_UNLIMITED) {
return;
}
if ($this->maxUsages === Handler::MAX_USAGE_ONCE && !empty($this->usages)) {
$this->valid = false;
// If the CouponCode is restricted to certain users -> Check if all those
// users have already redeemed the code
if (!empty($this->userIds)) {
$usedByAllUsers = true;
foreach ($this->userIds as $userId) {
foreach ($this->usages as $usage) {
if ($userId == $usage['userId']) {
continue 2;
}
}
$usedByAllUsers = false;
break;
}
if ($usedByAllUsers) {
$this->valid = false;
}
}
}
/**
* @param QUI\ERP\Order\OrderInProcess $Order
* @throws QUI\Exception
*/
public function addToOrder(QUI\ERP\Order\OrderInProcess $Order)
{
$coupons = $Order->getDataEntry('quiqqer-coupons');
if (!$coupons) {
return;
}
$calculations = $Order->getArticles()->getCalculations();
$vatArray = $calculations['vatArray'];
$vat = false;
if (\count($vatArray) === 1) {
$vat = \array_key_first($vatArray);
}
foreach ($coupons as $coupon) {
/* @var $Coupon CouponCode */
try {
$Coupon = Handler::getCouponCodeByCode($coupon);
} catch (\Exception $Exception) {
continue;
}
// coupon check
if (!$Coupon->isRedeemable($Order->getCustomer(), $Order)) {
continue;
}
/* @var $Discount QUI\ERP\Discount\Discount */
$discounts = $Coupon->getDiscounts();
foreach ($discounts as $Discount) {
$PriceFactor = $Discount->toPriceFactor(null, $Order->getCustomer());
if ($vat !== false) {
$PriceFactor->setVat($vat);
}
$PriceFactor->setTitle(
QUI::getLocale()->get('quiqqer/coupons', 'coupon.discount.title', [
'code' => $Coupon->getCode()
])
);
$priceFactors[] = $PriceFactor;
// @todo wenn fest preis (zb 10$), dann eigener produkt typ hinzufügen
$articles[] = new QUI\ERP\Accounting\Articles\Text([
'id' => '-',
'articleNo' => $Coupon->getCode(),
'title' => $PriceFactor->getTitle(),
'description' => '',
'unitPrice' => 0,
'control' => '',
'quantity' => 1,
'customData' => [
'package' => 'quiqqer/coupon',
'code' => $Coupon->getCode()
]
]);
* @return boolean
*/
$isInArticles = function ($Article) use ($Order) {
$articles = $Order->getArticles();
$code = $Article->getCustomData()['code'];
foreach ($articles as $Entry) {
if (!\method_exists($Entry, 'getCustomData')) {
continue;
}
$customData = $Entry->getCustomData();
if (!$customData || !\is_array($customData)) {
continue;
}
if (!isset($customData['package']) || !isset($customData['code'])) {
continue;
}
return $customData['package'] === 'quiqqer/coupon'
&& $customData['code'] === $code;
}
return false;
};
foreach ($articles as $Article) {
/* @var $PriceFactor QUI\ERP\Accounting\Articles\Text */
if ($isInArticles($Article) === false) {
$Order->addArticle($Article);
}
}
$Order->update();
$Order->addPriceFactors($priceFactors);