Skip to content
Code-Schnipsel Gruppen Projekte
CouponCode.php 20,7 KiB
Newer Older
  • Learn to ignore specific revisions
  • Patrick Müller's avatar
    Patrick Müller committed
    <?php
    
    namespace QUI\ERP\Coupons;
    
    
    Henning Leutz's avatar
    Henning Leutz committed
    use DateTime;
    use Exception;
    
    Patrick Müller's avatar
    Patrick Müller committed
    use QUI;
    
    use QUI\ERP\Discount\Handler as DiscountHandler;
    
    use QUI\ERP\Order\AbstractOrder;
    use QUI\ERP\Order\Order;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use QUI\ERP\Order\OrderInterface;
    
    use QUI\ExceptionStack;
    use QUI\Interfaces\Users\User;
    
    Patrick Müller's avatar
    Patrick Müller committed
    use QUI\Permissions\Permission;
    
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function array_key_first;
    use function count;
    use function current;
    use function in_array;
    use function is_array;
    use function is_null;
    
    use function is_numeric;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function json_decode;
    
    use function json_encode;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function method_exists;
    
    
    Patrick Müller's avatar
    Patrick Müller committed
    /**
    
    Patrick Müller's avatar
    Patrick Müller committed
     * Class CouponCode
    
    Patrick Müller's avatar
    Patrick Müller committed
     */
    class CouponCode
    {
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * CouponCode ID
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
         * @var int
         */
    
        protected int $id;
    
    Patrick Müller's avatar
    Patrick Müller committed
    
        /**
         * Actual code
         *
         * @var string
         */
    
    Patrick Müller's avatar
    Patrick Müller committed
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * IDs of users that this CouponCode is restricted to
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
    
         * @var int[]
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
        protected mixed $userIds = [];
    
    Patrick Müller's avatar
    Patrick Müller committed
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * IDs of groups that this CouponCode is restricted to
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
    
         * @var int[]
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
        protected mixed $groupIds = [];
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
        /**
         * IDs of all linked discounts
         *
    
        protected array $discountIds = [];
    
    Patrick Müller's avatar
    Patrick Müller committed
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * List of usages of this CouponCode
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
    
    Patrick Müller's avatar
    Patrick Müller committed
         * @var array
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
        protected mixed $usages = [];
    
    Patrick Müller's avatar
    Patrick Müller committed
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * Creation Date
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
    
         * @var DateTime|null
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
        protected ?DateTime $CreateDate = null;
    
    Patrick Müller's avatar
    Patrick Müller committed
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * Date until the CouponCode is valid
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
    
         * @var DateTime|null
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
        protected ?DateTime $ValidUntilDate = null;
    
    Patrick Müller's avatar
    Patrick Müller committed
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * CouponCode title
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
        protected ?string $title = null;
    
    Patrick Müller's avatar
    Patrick Müller committed
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * Flag - Is the CouponCode valid?
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
         * @var bool
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        protected bool $valid = true;
    
    Patrick Müller's avatar
    Patrick Müller committed
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
        protected string $maxUsages = Handler::MAX_USAGE_ONCE_PER_USER;
    
    Patrick Müller's avatar
    Patrick Müller committed
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * CouponCode constructor.
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
         * @param int $id - Invite Code ID
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @throws CouponCodeException
    
         * @throws Exception
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function __construct(int $id)
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
    
    Henning Leutz's avatar
    Henning Leutz committed
            try {
                $result = QUI::getDataBase()->fetch([
    
                    'from' => Handler::getTable(),
    
    Henning Leutz's avatar
    Henning Leutz committed
                    '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);
            }
    
    Patrick Müller's avatar
    Patrick Müller committed
    
            if (empty($result)) {
    
    Patrick Müller's avatar
    Patrick Müller committed
                throw new CouponCodeException([
                    'quiqqer/coupons',
                    'exception.CouponCode.not_found',
                    [
    
    Patrick Müller's avatar
    Patrick Müller committed
                        'id' => $id
    
    Patrick Müller's avatar
    Patrick Müller committed
                    ]
                ], 404);
    
    Patrick Müller's avatar
    Patrick Müller committed
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $data = current($result);
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
            $this->id = (int)$data['id'];
            $this->code = $data['code'];
    
    Patrick Müller's avatar
    Patrick Müller committed
            $this->title = $data['title'];
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
    Patrick Müller's avatar
    Patrick Müller committed
            if (!empty($data['usages'])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $this->usages = json_decode($data['usages'], true);
    
    Patrick Müller's avatar
    Patrick Müller committed
            }
    
    
    Patrick Müller's avatar
    Patrick Müller committed
            if (!empty($data['userIds'])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $this->userIds = json_decode($data['userIds'], true);
    
    Patrick Müller's avatar
    Patrick Müller committed
            }
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
            // migrate user ids
            foreach ($this->userIds as $k => $userId) {
                if (is_numeric($userId)) {
                    try {
                        $this->userIds[$k] = QUI::getUsers()->get($userId)->getUUID();
                    } catch (QUI\Exception) {
                    }
                }
            }
    
    
    Patrick Müller's avatar
    Patrick Müller committed
            if (!empty($data['groupIds'])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $this->groupIds = json_decode($data['groupIds'], true);
    
    Patrick Müller's avatar
    Patrick Müller committed
            }
    
    
            // migrate user ids
            foreach ($this->groupIds as $k => $groupId) {
                if (is_numeric($groupId)) {
                    try {
                        $this->groupIds[$k] = QUI::getGroups()->get($groupId)->getUUID();
                    } catch (QUI\Exception) {
                    }
                }
            }
    
    
            if (!empty($data['maxUsages'])) {
                $this->maxUsages = $data['maxUsages'];
    
    Patrick Müller's avatar
    Patrick Müller committed
            }
    
    
            if (!empty($data['discountIds'])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $this->discountIds = json_decode($data['discountIds'], true);
    
    Henning Leutz's avatar
    Henning Leutz committed
            $this->CreateDate = new DateTime($data['createDate']);
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
    Patrick Müller's avatar
    Patrick Müller committed
            if (!empty($data['validUntilDate'])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $this->ValidUntilDate = new DateTime($data['validUntilDate']);
    
                $this->ValidUntilDate->setTime(23, 59, 59);
    
    Patrick Müller's avatar
    Patrick Müller committed
            }
    
    Patrick Müller's avatar
    Patrick Müller committed
    
            $this->checkValidity();
    
    Patrick Müller's avatar
    Patrick Müller committed
        }
    
        /**
         * @return int
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getId(): int
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
            return $this->id;
        }
    
        /**
         * @return string
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getCode(): string
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
            return $this->code;
        }
    
        /**
    
         * @return DateTime
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getCreateDate(): DateTime
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
            return $this->CreateDate;
        }
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * Get usage data
         *
    
         * @return array
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getUsages(): array
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
    
    Patrick Müller's avatar
    Patrick Müller committed
            return $this->usages;
    
    Patrick Müller's avatar
    Patrick Müller committed
        }
    
        /**
    
         * @return DateTime|null
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getValidUntilDate(): ?DateTime
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
            return $this->ValidUntilDate;
        }
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getTitle(): ?string
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
            return $this->title;
        }
    
    
        /**
         * @return int[]
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getDiscountIds(): array
    
        {
            return $this->discountIds;
        }
    
    
        /**
         * Get all discounts associated with this CouponCode
         *
         * @return QUI\ERP\Discount\Discount[]
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getDiscounts(): array
    
            $discounts = [];
    
            $DiscountHandler = DiscountHandler::getInstance();
    
            foreach ($this->discountIds as $discountId) {
                try {
                    $discounts[] = $DiscountHandler->getChild($discountId);
    
    Henning Leutz's avatar
    Henning Leutz committed
                } catch (Exception $Exception) {
    
                    QUI\System\Log::writeDebugException($Exception);
                }
            }
    
            return $discounts;
        }
    
    
    Patrick Müller's avatar
    Patrick Müller committed
        /**
         * @return int[]
         */
        public function getUserIds(): array
        {
            return $this->userIds;
        }
    
        /**
         * @return int[]
         */
        public function getGroupIds(): array
        {
            return $this->groupIds;
        }
    
    
    Patrick Müller's avatar
    Patrick Müller committed
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * Redeems this CouponCode
         *
         * Hint: This may invalidate the code for future use
         *
    
         * @param User|null $User - The user that redeems the CouponCode [if omitted use Session User]
         * @param AbstractOrder|null $Order (optional) - Link redemption to a specific Order
    
    Patrick Müller's avatar
    Patrick Müller committed
         * @return void
         * @throws CouponCodeException
    
         * @throws QUI\Database\Exception
         * @throws ExceptionStack
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
        public function redeem(QUI\Interfaces\Users\User $User = null, AbstractOrder $Order = null): void
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (is_null($User)) {
    
    Patrick Müller's avatar
    Patrick Müller committed
                $User = QUI::getUserBySession();
            }
    
            $this->checkRedemption($User);
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $Now = new DateTime();
    
                'userId' => $User->getUUID(),
    
                'date' => $Now->format('Y-m-d H:i:s'),
    
                'orderPrefixedId' => false
    
    Patrick Müller's avatar
    Patrick Müller committed
            ];
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if ($Order instanceof QUI\ERP\Order\Order) {
    
                $usage['orderPrefixedId'] = $Order->getPrefixedNumber();
    
    Patrick Müller's avatar
    Patrick Müller committed
            QUI::getDataBase()->update(
                Handler::getTable(),
    
                ['usages' => json_encode($this->usages)],
    
                ['id' => $this->id]
    
    Patrick Müller's avatar
    Patrick Müller committed
            );
    
            $this->checkValidity();
    
    Patrick Müller's avatar
    Patrick Müller committed
    
            QUI::getEvents()->fireEvent(
                'quiqqerCouponsRedeem',
                [
    
                    'User' => $User,
    
    Patrick Müller's avatar
    Patrick Müller committed
                    'CouponCode' => $this
                ]
            );
    
    Patrick Müller's avatar
    Patrick Müller committed
        }
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * Check if the given User can redeem this CouponCode
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
    
         * @param QUI\Interfaces\Users\User $User - If omitted, use session user
    
    Patrick Müller's avatar
    Patrick Müller committed
         * @return void
    
    Patrick Müller's avatar
    Patrick Müller committed
         * @throws CouponCodeException - Thrown if not redeemable by the given User
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
        public function checkRedemption(QUI\Interfaces\Users\User $User): void
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
    
            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);
    
    Henning Leutz's avatar
    Henning Leutz committed
                } catch (Exception $Exception) {
    
                    $discountError = $Exception->getMessage();
                    continue;
                }
    
                if ($Discount->canUsedBy($User)) {
                    $discountsValid = true;
                    break;
                }
            }
    
            if (!$discountsValid) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                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)
    
    Patrick Müller's avatar
    Patrick Müller committed
            if (!empty($this->userIds)) {
    
                if (in_array($User->getUUID(), $this->userIds)) {
    
                    if (
                        $this->maxUsages !== Handler::MAX_USAGE_UNLIMITED
                        && $this->hasUserRedeemed($User)
                    ) {
    
    Patrick Müller's avatar
    Patrick Müller committed
                        throw new CouponCodeException([
                            'quiqqer/coupons',
                            'exception.CouponCode.already_used'
                        ]);
                    }
                } else {
                    throw new CouponCodeException([
                        'quiqqer/coupons',
                        'exception.CouponCode.user_not_allowed'
                    ]);
                }
    
    Patrick Müller's avatar
    Patrick Müller committed
            }
    
    
            // Restriction to QUIQQER group(s)
    
    Patrick Müller's avatar
    Patrick Müller committed
            if (!empty($this->groupIds)) {
                $userInGroup = false;
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
    Patrick Müller's avatar
    Patrick Müller committed
                foreach ($this->groupIds as $groupId) {
                    if ($User->isInGroup($groupId)) {
                        $userInGroup = true;
                        break;
                    }
                }
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
    Patrick Müller's avatar
    Patrick Müller committed
                if ($userInGroup) {
    
                    if (
                        $this->maxUsages !== Handler::MAX_USAGE_UNLIMITED
                        && $this->hasUserRedeemed($User)
                    ) {
    
    Patrick Müller's avatar
    Patrick Müller committed
                        throw new CouponCodeException([
                            'quiqqer/coupons',
                            'exception.CouponCode.already_used'
                        ]);
                    }
                } else {
                    throw new CouponCodeException([
                        'quiqqer/coupons',
                        'exception.CouponCode.user_not_allowed_group'
                    ]);
                }
            }
    
    Patrick Müller's avatar
    Patrick Müller committed
        }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
         * Check if the given Order can redeem this CouponCode
         *
         * @param OrderInterface|null $Order
         * @throws CouponCodeException
         */
    
        public function checkOrderRedemption(?OrderInterface $Order): void
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            if ($Order === null) {
                return;
            }
    
            $DiscountHandler = DiscountHandler::getInstance();
    
            $discountsValid = false;
            $discountError = false;
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            foreach ($this->discountIds as $discountId) {
                try {
                    /** @var QUI\ERP\Discount\Discount $Discount */
                    $Discount = $DiscountHandler->getChild($discountId);
    
    Henning Leutz's avatar
    Henning Leutz committed
                } catch (Exception $Exception) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    $discountError = $Exception->getMessage();
                    continue;
                }
    
                if ($Discount->canUsedInOrder($Order)) {
                    $discountsValid = true;
                    break;
                }
            }
    
            if (!$discountsValid) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                if (count($this->discountIds) === 1) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    throw new CouponCodeException([
                        'quiqqer/coupons',
                        'exception.CouponCode.discount_invalid',
                        [
                            'reason' => $discountError
                        ]
                    ]);
                } else {
                    throw new CouponCodeException([
                        'quiqqer/coupons',
                        'exception.CouponCode.discounts_invalid'
                    ]);
                }
            }
        }
    
    
    Patrick Müller's avatar
    Patrick Müller committed
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * Check if the given User can redeem this CouponCode
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
    
         * @param User|null $User - If omitted, use session user
    
         * @param OrderInterface|null $Order
    
    Patrick Müller's avatar
    Patrick Müller committed
         * @return bool
         */
    
        public function isRedeemable(QUI\Interfaces\Users\User $User = null, OrderInterface $Order = null): bool
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
    
    Patrick Müller's avatar
    Patrick Müller committed
            try {
                $this->checkRedemption($User);
    
            } catch (CouponCodeException) {
    
    Patrick Müller's avatar
    Patrick Müller committed
                return false;
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if ($Order) {
                try {
                    $this->checkOrderRedemption($Order);
                } catch (CouponCodeException $Exception) {
                    $Order->addFrontendMessage($Exception->getMessage());
    
                    return false;
                }
            }
    
    
    Patrick Müller's avatar
    Patrick Müller committed
            return true;
    
    Patrick Müller's avatar
    Patrick Müller committed
        }
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * Check if this CouponCode is still valid
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
         * @return bool
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function isValid(): bool
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
    
    Patrick Müller's avatar
    Patrick Müller committed
            return $this->valid;
    
    Patrick Müller's avatar
    Patrick Müller committed
        }
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * Checks if an CouponCode has been redeemed by a user
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @param QUI\Interfaces\Users\User $User
    
    Patrick Müller's avatar
    Patrick Müller committed
         * @return bool
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function hasUserRedeemed(QUI\Interfaces\Users\User $User): bool
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
    
            $userId = $User->getUUID();
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
    Patrick Müller's avatar
    Patrick Müller committed
            foreach ($this->usages as $usage) {
                if ($usage['userId'] === $userId) {
                    return true;
                }
    
    Patrick Müller's avatar
    Patrick Müller committed
            }
    
    
    Patrick Müller's avatar
    Patrick Müller committed
            return false;
    
    Patrick Müller's avatar
    Patrick Müller committed
        }
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * Permanently delete this CouponCode
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
         * @return void
    
         * @throws QUI\Permissions\Exception
    
    Patrick Müller's avatar
    Patrick Müller committed
         */
    
        public function delete(): void
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
            Permission::checkPermission(Handler::PERMISSION_DELETE);
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            try {
                QUI::getDataBase()->delete(
                    Handler::getTable(),
                    ['id' => $this->id]
                );
            } catch (QUI\DataBase\Exception $Exception) {
                QUI\System\Log::addError($Exception->getMessage());
            }
    
            // If hidden discount are connected to this coupon -> delete them as well
    
            foreach ($this->getDiscounts() as $Discount) {
                if (!empty($Discount->getAttribute('hidden'))) {
                    try {
                        $Discount->delete();
    
    Henning Leutz's avatar
    Henning Leutz committed
                    } catch (Exception $Exception) {
    
    Patrick Müller's avatar
    Patrick Müller committed
        }
    
        /**
    
    Patrick Müller's avatar
    Patrick Müller committed
         * Get CouponCode attributes as array
    
    Patrick Müller's avatar
    Patrick Müller committed
         *
         * @return array
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function toArray(): array
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
    
    Patrick Müller's avatar
    Patrick Müller committed
            $data = [
    
                'id' => $this->getId(),
                'code' => $this->getCode(),
                'userIds' => $this->userIds,
                'groupIds' => $this->groupIds,
                'createDate' => $this->getCreateDate()->format('Y-m-d H:i:s'),
                'usages' => $this->usages,
    
    Patrick Müller's avatar
    Patrick Müller committed
                'validUntilDate' => false,
    
                'title' => $this->getTitle() ?: false,
                'isValid' => $this->isValid(),
                'maxUsages' => $this->maxUsages,
                'discountIds' => $this->discountIds
    
    Patrick Müller's avatar
    Patrick Müller committed
            ];
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
    Patrick Müller's avatar
    Patrick Müller committed
            $ValidUntilDate = $this->getValidUntilDate();
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
    Patrick Müller's avatar
    Patrick Müller committed
            if ($ValidUntilDate) {
    
                $data['validUntilDate'] = $ValidUntilDate->format('Y-m-d');
    
    Patrick Müller's avatar
    Patrick Müller committed
            }
    
    
    Patrick Müller's avatar
    Patrick Müller committed
            return $data;
        }
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
    Patrick Müller's avatar
    Patrick Müller committed
        /**
         * Checks if this CouponCode is still valid
         *
         * @return void
         */
    
        protected function checkValidity(): void
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
            // Check if the expiration date has been reached
            if (!empty($this->ValidUntilDate)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $Now = new DateTime();
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
    Patrick Müller's avatar
    Patrick Müller committed
                if ($Now > $this->ValidUntilDate) {
                    $this->valid = false;
    
    Patrick Müller's avatar
    Patrick Müller committed
                    return;
                }
            }
    
    Patrick Müller's avatar
    Patrick Müller committed
    
    
            if ($this->maxUsages === Handler::MAX_USAGE_UNLIMITED) {
                return;
            }
    
            if ($this->maxUsages === Handler::MAX_USAGE_ONCE && !empty($this->usages)) {
                $this->valid = false;
    
    Patrick Müller's avatar
    Patrick Müller committed
                return;
    
    Patrick Müller's avatar
    Patrick Müller committed
            }
    
    
    Patrick Müller's avatar
    Patrick Müller committed
            // 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): void
    
        {
            $coupons = $Order->getDataEntry('quiqqer-coupons');
    
            if (!$coupons) {
                return;
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (!is_array($coupons)) {
    
                return;
    
    Patrick Müller's avatar
    Patrick Müller committed
            }
    
    
            $priceFactors = [];
    
            $articles = [];
    
            $calculations = $Order->getArticles()->getCalculations();
    
            $vatArray = $calculations['vatArray'];
            $vat = false;
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (count($vatArray) === 1) {
                $vat = array_key_first($vatArray);
    
    
            foreach ($coupons as $coupon) {
                /* @var $Coupon CouponCode */
                try {
                    $Coupon = Handler::getCouponCodeByCode($coupon);
    
                    continue;
                }
    
                // coupon check
    
    Henning Leutz's avatar
    Henning Leutz committed
                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([
    
                        'articleNo' => $Coupon->getCode(),
                        'title' => $PriceFactor->getTitle(),
    
    Henning Leutz's avatar
    Henning Leutz committed
                        'description' => '',
    
                        'unitPrice' => 0,
                        'control' => '',
                        'quantity' => 1,
                        'customData' => [
    
    Henning Leutz's avatar
    Henning Leutz committed
                            'package' => 'quiqqer/coupon',
    
                            'code' => $Coupon->getCode()
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (empty($priceFactors)) {
                return;
    
    Henning Leutz's avatar
    Henning Leutz committed
             * @param $Article
    
    Henning Leutz's avatar
    Henning Leutz committed
             * @return boolean
             */
            $isInArticles = function ($Article) use ($Order) {
                $articles = $Order->getArticles();
    
                $code = $Article->getCustomData()['code'];
    
    Henning Leutz's avatar
    Henning Leutz committed
    
                foreach ($articles as $Entry) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    if (!method_exists($Entry, 'getCustomData')) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                        continue;
                    }
    
                    $customData = $Entry->getCustomData();
    
    
    Henning Leutz's avatar
    Henning Leutz committed
                    if (!$customData || !is_array($customData)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                        continue;
                    }
    
                    if (!isset($customData['package']) || !isset($customData['code'])) {
                        continue;
                    }
    
                    return $customData['package'] === 'quiqqer/coupon'
    
                        && $customData['code'] === $code;
    
    Henning Leutz's avatar
    Henning Leutz committed
                }
    
                return false;
            };
    
            foreach ($articles as $Article) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                /* @var $PriceFactor QUI\ERP\Accounting\Articles\Text */
    
    Henning Leutz's avatar
    Henning Leutz committed
                if ($isInArticles($Article) === false) {
                    $Order->addArticle($Article);
                }
            }
    
            $Order->update();
            $Order->addPriceFactors($priceFactors);
    
    Patrick Müller's avatar
    Patrick Müller committed
        }
    }