Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
discountcouponsmanagerbase.php
1<?php
2
3namespace Bitrix\Sale;
4
10use Bitrix\Sale;
11
13{
14 public const MODE_CLIENT = 0x0001;
15 public const MODE_MANAGER = 0x0002;
16 public const MODE_ORDER = 0x0004;
17 public const MODE_SYSTEM = 0x0008;
18 public const MODE_EXTERNAL = 0x0010;
19
20 public const STATUS_NOT_FOUND = 0x0001;
21 public const STATUS_ENTERED = 0x0002;
22 public const STATUS_APPLYED = 0x0004;
23 public const STATUS_NOT_APPLYED = 0x0008;
24 public const STATUS_FREEZE = 0x0010;
25
26 public const COUPON_CHECK_OK = 0x0000;
27 public const COUPON_CHECK_NOT_FOUND = 0x0001;
28 public const COUPON_CHECK_NO_ACTIVE = 0x0002;
29 public const COUPON_CHECK_RANGE_ACTIVE_FROM = 0x0004;
30 public const COUPON_CHECK_RANGE_ACTIVE_TO = 0x0008;
31 public const COUPON_CHECK_NO_ACTIVE_DISCOUNT = 0x0010;
34 public const COUPON_CHECK_BAD_USER_ID = 0x0080;
35 public const COUPON_CHECK_ALREADY_MAX_USED = 0x0100;
36 public const COUPON_CHECK_UNKNOWN_TYPE = 0x0200;
37 public const COUPON_CHECK_CORRUPT_DATA = 0x0400;
38 public const COUPON_CHECK_NOT_APPLIED = 0x0800;
39
40 public const COUPON_MODE_SIMPLE = 0x0001;
41 public const COUPON_MODE_FULL = 0x0002;
42
43 public const EVENT_ON_BUILD_COUPON_PROVIDES = 'onBuildCouponProviders';
44 public const EVENT_ON_SAVE_APPLIED_COUPONS = 'onManagerSaveApplied';
45 public const EVENT_ON_COUPON_ADD = 'onManagerCouponAdd';
46 public const EVENT_ON_COUPON_DELETE = 'onManagerCouponDelete';
47 public const EVENT_ON_COUPON_APPLY_PRODUCT = 'onManagerCouponApplyByProduct';
48 public const EVENT_ON_COUPON_APPLY = 'onManagerCouponApply';
49
50 public const STORAGE_MANAGER_COUPONS = 'CATALOG_MANAGE_COUPONS';
51 public const STORAGE_CLIENT_COUPONS = 'CATALOG_USER_COUPONS';
52
53 protected static array $coupons = [];
54 protected static bool $init = false;
55 protected static int $useMode = self::MODE_CLIENT;
56 protected static array $errors = [];
57 protected static ?bool $onlySaleDiscount = null;
58 protected static ?int $userId = null;
59 protected static array $couponProviders = [];
60 protected static array $couponTypes = [];
61 protected static int $couponIndex = 0;
62 protected static ?int $orderId = null;
63 protected static bool $allowedSave = false;
64 protected static bool $checkActivity = true;
65 protected static bool $useOrderCoupons = true;
66
67 protected static array $clearFields = [
68 'STATUS',
69 'CHECK_CODE',
70 'DISCOUNT_NAME',
71 'DISCOUNT_ACTIVE',
72 'SAVED',
73 'BASKET',
74 'DELIVERY',
75 ];
76 protected static array $timeFields = [
77 'DISCOUNT_ACTIVE_FROM',
78 'DISCOUNT_ACTIVE_TO',
79 'ACTIVE_FROM',
80 'ACTIVE_TO',
81 ];
82
83 protected static int $allowCouponStorage = 0;
84
85 protected static array $lockedCoupons = [];
86
91 public static function getRegistryType()
92 {
94 }
95
109 public static function initUseMode($mode = self::MODE_CLIENT, $params = [])
110 {
111 $mode = (int)$mode;
112 if (!is_array($params))
113 {
114 $params = [];
115 }
116 self::$checkActivity = true;
117 self::$userId = null;
118 self::$orderId = null;
119 self::$allowedSave = false;
120 self::$useOrderCoupons = true;
121
122 self::$useMode = self::MODE_SYSTEM;
123 switch ($mode)
124 {
126 if (!isset($params['userId']) || (int)$params['userId'] < 0)
127 {
128 self::$errors[] = Loc::getMessage('BX_SALE_DCM_ERR_BAD_USER_ID');
129 }
130 if (isset($params['orderId']))
131 {
132 self::$errors[] = Loc::getMessage('BX_SALE_DCM_ERR_ORDER_ID_EXIST');
133 }
134 if (empty(self::$errors))
135 {
136 self::$userId = (int)$params['userId'];
137 self::$orderId = null;
138 self::$allowedSave = true;
139 self::$useMode = self::MODE_MANAGER;
140 if (isset($params['oldUserId']))
141 {
142 self::migrateStorage($params['oldUserId']);
143 }
144 }
145 break;
146 case self::MODE_ORDER:
147 if (!isset($params['userId']) || (int)$params['userId'] < 0)
148 {
149 self::$errors[] = Loc::getMessage('BX_SALE_DCM_ERR_BAD_USER_ID');
150 }
151 if (!isset($params['orderId']) || (int)$params['orderId'] <= 0)
152 {
153 self::$errors[] = Loc::getMessage('BX_SALE_DCM_ERR_ORDER_ID_ABSENT');
154 }
155 if (empty(self::$errors))
156 {
157 self::$userId = (int)$params['userId'];
158 self::$orderId = (int)$params['orderId'];
159 self::$allowedSave = true;
160 self::$useMode = self::MODE_ORDER;
161 if (isset($params['oldUserId']))
162 {
163 self::migrateStorage($params['oldUserId']);
164 }
165
166 }
167 break;
169 self::$useMode = self::MODE_CLIENT;
170 if (isset($params['userId']) && (int)$params['userId'] >= 0)
171 {
172 self::$userId = (int)$params['userId'];
173 }
174 else
175 {
177 }
178 if (self::isSuccess())
179 {
180 self::$allowedSave = true;
181 }
182 break;
184 self::$useMode = self::MODE_EXTERNAL;
185 self::$userId = (
186 isset($params['userId']) && (int)$params['userId'] >= 0
187 ? (int)$params['userId']
188 : \CSaleUser::GetAnonymousUserID()
189 );
190 break;
192 break;
193 default:
194 self::$errors[] = Loc::getMessage('BX_SALE_DCM_ERR_BAD_MODE');
195 break;
196 }
197 }
198
204 public static function getUseMode()
205 {
206 return self::$useMode;
207 }
208
214 public static function usedByClient()
215 {
216 return (self::$useMode === self::MODE_CLIENT);
217 }
218
224 public static function usedByManager()
225 {
226 return (self::$useMode === self::MODE_MANAGER || self::$useMode === self::MODE_ORDER);
227 }
228
234 public static function usedByExternal()
235 {
236 return (self::$useMode === self::MODE_EXTERNAL);
237 }
238
244 public static function getUserId()
245 {
246 if ((self::$userId === null || self::$userId === 0) && self::usedByClient())
247 {
248 self::$userId = null;
250 }
251
252 return self::$userId;
253 }
254
260 public static function getOrderId()
261 {
262 return self::$orderId;
263 }
264
272 protected static function getSession(): ?Session
273 {
275 $session = Application::getInstance()->getSession();
276 if (!$session->isAccessible())
277 {
278 self::$errors[] = Loc::getMessage('BX_SALE_DCM_ERR_SESSION_NOT_ACCESSIBLE');
279
280 return null;
281 }
282
283 return $session;
284 }
285
291 public static function isSuccess()
292 {
293 return empty(self::$errors);
294 }
295
301 public static function getErrors()
302 {
303 return self::$errors;
304 }
305
311 public static function clearErrors()
312 {
313 self::$errors = [];
314 }
315
322 public static function getStatusList($extendedMode = false)
323 {
324 $extendedMode = ($extendedMode === true);
325 if ($extendedMode)
326 {
327 return [
328 self::STATUS_NOT_FOUND => Loc::getMessage('BX_SALE_DCM_STATUS_NOT_FOUND'),
329 self::STATUS_ENTERED => Loc::getMessage('BX_SALE_DCM_STATUS_ENTERED'),
330 self::STATUS_NOT_APPLYED => Loc::getMessage('BX_SALE_DCM_STATUS_NOT_APPLYED'),
331 self::STATUS_APPLYED => Loc::getMessage('BX_SALE_DCM_STATUS_APPLYED'),
332 self::STATUS_FREEZE => Loc::getMessage('BX_SALE_DCM_STATUS_FREEZE'),
333 ];
334 }
335
336 return [
342 ];
343 }
344
351 public static function getCheckCodeList($extendedMode = false)
352 {
353 $extendedMode = ($extendedMode === true);
354 if ($extendedMode)
355 {
356 return [
357 self::COUPON_CHECK_OK => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_OK'),
358 self::COUPON_CHECK_NOT_FOUND => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_NOT_FOUND'),
359 self::COUPON_CHECK_NO_ACTIVE => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_NO_ACTIVE'),
360 self::COUPON_CHECK_RANGE_ACTIVE_FROM => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_RANGE_ACTIVE_FROM'),
361 self::COUPON_CHECK_RANGE_ACTIVE_TO => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_RANGE_ACTIVE_TO'),
362 self::COUPON_CHECK_NO_ACTIVE_DISCOUNT => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_NO_ACTIVE_DISCOUNT'),
363 self::COUPON_CHECK_RANGE_ACTIVE_FROM_DISCOUNT => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_RANGE_ACTIVE_FROM_DISCOUNT'),
364 self::COUPON_CHECK_RANGE_ACTIVE_TO_DISCOUNT => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_RANGE_ACTIVE_TO_DISCOUNT'),
365 self::COUPON_CHECK_BAD_USER_ID => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_BAD_USER_ID'),
366 self::COUPON_CHECK_ALREADY_MAX_USED => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_ALREADY_MAX_USED'),
367 self::COUPON_CHECK_UNKNOWN_TYPE => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_UNKNOWN_TYPE'),
368 self::COUPON_CHECK_CORRUPT_DATA => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_CORRUPT_DATA'),
369 self::COUPON_CHECK_NOT_APPLIED => Loc::getMessage('BX_SALE_DCM_COUPON_CHECK_NOT_APPLIED'),
370 ];
371 }
372
373 return [
387 ];
388 }
389
396 public static function getCheckCodeMessage($code)
397 {
398 $codes = self::getCheckCodeList(true);
399 if (isset($codes[$code]))
400 {
401 return $codes[$code];
402 }
403
404 return null;
405 }
406
413 public static function useSavedCouponsForApply($state)
414 {
415 if ($state !== true && $state !== false)
416 {
417 return;
418 }
419 self::$useOrderCoupons = $state;
420 }
421
427 public static function isUsedOrderCouponsForApply()
428 {
430 }
431
437 public static function unFreezeCouponStorage()
438 {
439 self::$allowCouponStorage++;
440 }
441
447 public static function freezeCouponStorage()
448 {
449 self::$allowCouponStorage--;
450 }
451
457 public static function isFrozenCouponStorage()
458 {
459 return (self::$allowCouponStorage < 0);
460 }
461
476 public static function init($mode = self::MODE_CLIENT, $params = [], $clearStorage = false)
477 {
478 if (self::$init)
479 {
480 return;
481 }
482 self::$onlySaleDiscount = null;
483 self::$couponTypes = Internals\DiscountCouponTable::getCouponTypes(true);
484 self::$couponIndex = 0;
485 self::$lockedCoupons = [];
487 self::initUseMode($mode, $params);
489 if (!self::isSuccess())
490 {
491 return;
492 }
493 if (self::$useMode !== self::MODE_SYSTEM)
494 {
495 $session = self::getSession();
496 if (!$session)
497 {
498 return;
499 }
500
501 self::clear($clearStorage);
502 $couponsList = [];
503 switch (self::$useMode)
504 {
507 if (
508 !empty($session[self::STORAGE_CLIENT_COUPONS])
509 && is_array($session[self::STORAGE_CLIENT_COUPONS])
510 )
511 {
512 $couponsList = $session[self::STORAGE_CLIENT_COUPONS];
513 }
514 break;
516 if (
517 !empty($session[self::STORAGE_MANAGER_COUPONS])
518 && !empty($session[self::STORAGE_MANAGER_COUPONS][self::$userId])
519 && is_array($session[self::STORAGE_MANAGER_COUPONS][self::$userId])
520 )
521 {
522 $couponsList = $session[self::STORAGE_MANAGER_COUPONS][self::$userId];
523 }
524 break;
525 case self::MODE_ORDER:
526 self::load();
527 if (
528 !empty($session[self::STORAGE_MANAGER_COUPONS])
529 && !empty($session[self::STORAGE_MANAGER_COUPONS][self::$userId])
530 && is_array($session[self::STORAGE_MANAGER_COUPONS][self::$userId])
531 )
532 {
533 $couponsList = $session[self::STORAGE_MANAGER_COUPONS][self::$userId];
534 }
535 break;
536 }
537 if (!empty($couponsList))
538 {
539 self::setCoupons($couponsList);
540 }
541 unset($couponsList);
542 if (self::$useMode === self::MODE_ORDER)
543 {
545 }
546 }
547 self::$init = true;
548 }
549
564 public static function reInit($mode = self::MODE_CLIENT, $params = [], $clearStorage = false)
565 {
566 if (self::isFrozenCouponStorage())
567 {
568 return;
569 }
570 self::$init = false;
571 self::init($mode, $params, $clearStorage);
572 }
573
579 public static function isEntered()
580 {
581 return !empty(self::$coupons);
582 }
583
590 public static function add($coupon)
591 {
592 if (!self::$init)
593 {
594 self::init();
595 }
596 if (self::$useMode === self::MODE_SYSTEM || !self::isSuccess())
597 {
598 return false;
599 }
600
601 $coupon = trim((string)$coupon);
602 if ($coupon === '')
603 {
604 return false;
605 }
606 if (!isset(self::$coupons[$coupon]))
607 {
608 $couponData = self::getData($coupon);
609 if (!isset(self::$coupons[$couponData['COUPON']]))
610 {
611 $couponData['SORT'] = self::$couponIndex;
612 self::createApplyFields($couponData);
613 self::$coupons[$couponData['COUPON']] = $couponData;
614 self::$couponIndex++;
616 $event = new Main\Event('sale', self::EVENT_ON_COUPON_ADD, $couponData);
617 $event->send();
618 }
619 if (self::$coupons[$couponData['COUPON']]['MODE'] === self::COUPON_MODE_FULL)
620 {
621 return (self::$coupons[$couponData['COUPON']]['STATUS'] != self::STATUS_NOT_FOUND);
622 }
623 else
624 {
625 return (
626 self::$coupons[$couponData['COUPON']]['STATUS'] != self::STATUS_NOT_FOUND
627 && self::$coupons[$couponData['COUPON']]['STATUS'] != self::STATUS_FREEZE
628 );
629 }
630 }
631 else
632 {
633 if (self::$coupons[$coupon]['MODE'] === self::COUPON_MODE_FULL)
634 {
635 return (self::$coupons[$coupon]['STATUS'] != self::STATUS_NOT_FOUND);
636 }
637 else
638 {
639 return (
640 self::$coupons[$coupon]['STATUS'] != self::STATUS_NOT_FOUND
641 && self::$coupons[$coupon]['STATUS'] != self::STATUS_FREEZE
642 );
643 }
644 }
645 }
646
653 public static function delete($coupon)
654 {
655 if (!self::$init)
656 {
657 self::init();
658 }
659 if (self::$useMode === self::MODE_SYSTEM || !self::isSuccess())
660 {
661 return false;
662 }
663
664 $coupon = trim((string)$coupon);
665 if ($coupon === '')
666 {
667 return false;
668 }
669 $founded = false;
670 if (isset(self::$coupons[$coupon]))
671 {
672 $couponData = self::$coupons[$coupon];
673 unset(self::$coupons[$coupon]);
674 $founded = true;
675 }
676 else
677 {
678 $couponData = self::getData($coupon, false);
679 if (isset(self::$coupons[$couponData['COUPON']]))
680 {
681 unset(self::$coupons[$couponData['COUPON']]);
682 $founded = true;
683 }
684 }
685 if ($founded)
686 {
688 $event = new Main\Event('sale', self::EVENT_ON_COUPON_DELETE, $couponData);
689 $event->send();
690
691 return true;
692 }
693
694 return false;
695 }
696
703 public static function clear($clearStorage = false)
704 {
705 if (self::$useMode === self::MODE_SYSTEM || !self::isSuccess())
706 {
707 return false;
708 }
709
710 $clearStorage = ($clearStorage === true);
711 self::$coupons = [];
712 if ($clearStorage)
713 {
715 }
716
717 return true;
718 }
719
726 public static function clearByOrder($order)
727 {
728 if (!self::isSuccess())
729 {
730 return false;
731 }
732 $order = (int)$order;
733 if ($order <= 0)
734 {
735 return false;
736 }
737 $userId = 0;
738
739 $registry = Registry::getInstance(static::getRegistryType());
740
742 $orderClassName = $registry->getOrderClassName();
743
744 $orderIterator = $orderClassName::getList([
745 'select' => ['ID', 'USER_ID'],
746 'filter' => ['=ID' => $order],
747 ]);
748 if ($orderData = $orderIterator->fetch())
749 {
750 $userId = (int)$orderData['USER_ID'];
751 }
752 unset($orderData, $orderIterator);
753 if ($userId <= 0)
754 {
755 return false;
756 }
758 self::MODE_ORDER,
759 [
760 'userId' => $userId,
761 'orderId' => $order,
762 ]
763 );
764 if (!self::isSuccess())
765 {
766 return false;
767 }
768 self::$coupons = [];
770
771 return true;
772 }
773
780 public static function migrateStorage($oldUser)
781 {
782 if (self::$useMode !== self::MODE_MANAGER && self::$useMode !== self::MODE_ORDER || self::$userId === null)
783 {
784 return;
785 }
786
787 $oldUser = (int)$oldUser;
788 if ($oldUser < 0)
789 {
790 return;
791 }
792
793 $session = self::getSession();
794 if (!$session)
795 {
796 return;
797 }
798
799 if (empty($session[self::STORAGE_MANAGER_COUPONS]))
800 {
801 $session[self::STORAGE_MANAGER_COUPONS] = [];
802 }
803
804 if (
805 empty($session[self::STORAGE_MANAGER_COUPONS][self::$userId])
806 || !is_array($session[self::STORAGE_MANAGER_COUPONS][self::$userId])
807 )
808 {
810 }
811
812 if (!empty($session[self::STORAGE_MANAGER_COUPONS][$oldUser]))
813 {
814 if (is_array($session[self::STORAGE_MANAGER_COUPONS][$oldUser]))
815 {
817 }
818 unset($session[self::STORAGE_MANAGER_COUPONS][$oldUser]);
819 }
820 }
821
827 public static function load()
828 {
829 if (self::$useMode !== self::MODE_ORDER)
830 {
831 return;
832 }
833
834 self::$checkActivity = false;
835 $couponsList = [];
836
837 $registry = Registry::getInstance(static::getRegistryType());
838
840 $storageClassName = $registry->getOrderDiscountClassName();
841
842 $couponIterator = $storageClassName::getOrderCouponIterator([
843 'select' => [
844 '*',
845 'MODULE_ID' => 'ORDER_DISCOUNT.MODULE_ID',
846 'DISCOUNT_ID' => 'ORDER_DISCOUNT.DISCOUNT_ID',
847 'DISCOUNT_NAME' => 'ORDER_DISCOUNT.NAME',
848 ],
849 'filter' => ['=ORDER_ID' => self::$orderId],
850 'order' => ['ID' => 'ASC'],
851 ]);
852 while ($coupon = $couponIterator->fetch())
853 {
854 $couponData = $coupon['DATA'];
855 $couponData['COUPON'] = $coupon['COUPON'];
856 $couponData['STATUS'] = self::STATUS_ENTERED;
857 $couponData['CHECK_CODE'] = self::COUPON_CHECK_OK;
858 $couponData['MODULE'] = $coupon['MODULE_ID'];
859 $couponData['MODULE_ID'] = $coupon['MODULE_ID'];
860 $couponData['ID'] = $coupon['COUPON_ID'];
861 $couponData['DISCOUNT_ID'] = $coupon['DISCOUNT_ID'];
862 $couponData['DISCOUNT_NAME'] = (string)$coupon['DISCOUNT_NAME'];
863 $couponData['DISCOUNT_ACTIVE'] = 'Y';
864 $couponData['TYPE'] = $coupon['TYPE'];
865 $couponData['ACTIVE'] = 'Y';
866 $couponData['SAVED'] = 'Y';
867 foreach (self::$timeFields as $fieldName)
868 {
869 if (isset($couponData[$fieldName]))
870 {
871 $couponData[$fieldName] = Main\Type\DateTime::createFromTimestamp($couponData[$fieldName]);
872 }
873 }
874 unset($fieldName);
875 if (empty($couponData['USER_INFO']) && $couponData['MODE'] === self::COUPON_MODE_FULL)
876 {
877 $couponData['USER_INFO'] = [
878 'USER_ID' => 0,
879 'MAX_USE' => 0,
880 'USE_COUNT' => 0,
881 'ACTIVE_FROM' => null,
882 'ACTIVE_TO' => null,
883 ];
884 }
885 if (!empty($couponData['USER_INFO']))
886 {
887 foreach (self::$timeFields as $fieldName)
888 {
889 if (isset($couponData['USER_INFO'][$fieldName]))
890 {
891 $couponData['USER_INFO'][$fieldName] = Main\Type\DateTime::createFromTimestamp($couponData['USER_INFO'][$fieldName]);
892 }
893 }
894 unset($fieldName);
895 foreach ($couponData['USER_INFO'] as $fieldName => $fieldValue)
896 {
897 $couponData[$fieldName] = $fieldValue;
898 }
899 }
900 $couponsList[$couponData['COUPON']] = $couponData;
901 }
902 unset($coupon, $couponIterator);
903
904 if (!empty($couponsList))
905 {
906 self::setCoupons($couponsList, false);
907 }
908
909 self::$checkActivity = true;
910 }
911
921 public static function get($extMode = true, $filter = [], $show = false, $final = false)
922 {
923 if (self::$useMode === self::MODE_SYSTEM)
924 {
925 return false;
926 }
927 $extMode = ($extMode === true);
928 if (!is_array($filter))
929 {
930 $filter = [];
931 }
932 static::convertOldFilterFields($filter);
933 $show = ($show === true);
934 if (!self::$init)
935 {
936 self::init();
937 }
938 if (!self::isSuccess())
939 {
940 return false;
941 }
942
943 if (self::isFrozenCouponStorage() || !self::isEntered())
944 {
945 return [];
946 }
947
948 $final = ($final === true);
949 if ($final)
950 {
952 }
953 $validCoupons = (
954 $show
956 : array_filter(self::$coupons, '\Bitrix\Sale\DiscountCouponsManager::filterFreezeCoupons')
957 );
958 if (empty($validCoupons))
959 {
960 return [];
961 }
962 if (!empty($filter))
963 {
964 self::filterArrayCoupons($validCoupons, $filter);
965 }
966 if (!empty($validCoupons))
967 {
968 self::clearSystemData($validCoupons);
969 }
970 if ($show && !empty($validCoupons))
971 {
972 self::fillCouponHints($validCoupons);
973 }
974
975 return ($extMode ? $validCoupons : array_keys($validCoupons));
976 }
977
986 public static function getForApply($filter, $product = [], $uniqueDiscount = false)
987 {
988 if (self::$useMode === self::MODE_SYSTEM)
989 {
990 return [];
991 }
992 if (self::$useMode === self::MODE_ORDER && static::isUsedOrderCouponsForApply())
993 {
994 $filter['SAVED'] = ['Y', 'N'];
995 }
996 else
997 {
998 $filter['SAVED'] = 'N';
999 }
1000
1001 $couponsList = self::get(true, $filter, false);
1002 if ($couponsList === false)
1003 {
1004 return [];
1005 }
1006 if (!empty($couponsList))
1007 {
1008 $uniqueDiscount = ($uniqueDiscount === true);
1009 if ($uniqueDiscount)
1010 {
1011 self::filterUniqueDiscount($couponsList);
1012 }
1013 if (!empty($product))
1014 {
1015 $hash = self::getProductHash($product);
1016 if ($hash !== '')
1017 {
1018 $productCoupons = [];
1019 foreach ($couponsList as $id => $data)
1020 {
1021 if (self::filterOneRowCoupons($data, $hash))
1022 {
1023 $productCoupons[$id] = $data;
1024 }
1025 }
1026 $couponsList = $productCoupons;
1027 unset($productCoupons);
1028 }
1029 else
1030 {
1031 $couponsList = [];
1032 }
1033 }
1034 }
1035
1036 static::filterLockedCoupons($couponsList);
1037
1038 return $couponsList;
1039 }
1040
1048 public static function getOrderedCoupons($extMode = true, $filter = [])
1049 {
1050 $extMode = ($extMode === true);
1051 $result = [];
1052 if (self::$useMode !== self::MODE_ORDER)
1053 {
1054 return $result;
1055 }
1056 if (!self::isSuccess())
1057 {
1058 return $result;
1059 }
1060
1061 if (!self::isEntered())
1062 {
1063 return $result;
1064 }
1065
1066 $result = array_filter(self::$coupons, '\Bitrix\Sale\DiscountCouponsManager::filterFreezeCoupons');
1067 if (empty($result))
1068 {
1069 return $result;
1070 }
1071 $result = array_filter($result, '\Bitrix\Sale\DiscountCouponsManager::filterFreezeOrderedCoupons');
1072 if (empty($result))
1073 {
1074 return $result;
1075 }
1076
1077 $filter['SAVED'] = 'Y';
1078 static::filterArrayCoupons($result, $filter);
1079 if (!empty($result))
1080 {
1081 static::clearSystemData($result);
1082 }
1083
1084 return ($extMode ? $result : array_keys($result));
1085 }
1086
1092 public static function verifyApplied()
1093 {
1094 $result = new Sale\Result();
1095
1096 if (
1097 self::$useMode === self::MODE_SYSTEM
1098 || !self::isEntered()
1099 )
1100 {
1101 return $result;
1102 }
1103
1104 $appliedCoupons = self::filterCoupons(['STATUS' => self::STATUS_APPLYED, 'SAVED' => 'N'], true);
1105 if (!empty($appliedCoupons))
1106 {
1107 $badCoupons = [];
1108 $appliedCoupons = array_keys($appliedCoupons);
1109 foreach ($appliedCoupons as $coupon)
1110 {
1111 $row = self::getData($coupon, true);
1112 if ($row['STATUS'] == self::STATUS_NOT_FOUND || $row['STATUS'] == self::STATUS_FREEZE)
1113 {
1114 $badCoupons[$coupon] = $row;
1115 }
1116 }
1117 unset($row, $coupon);
1118 if (!empty($badCoupons))
1119 {
1120 self::fillCouponHints($badCoupons);
1121 $errorData = [];
1122 foreach ($badCoupons as $row)
1123 {
1124 $errorData[$row['COUPON']] = implode(', ', $row['CHECK_CODE_TEXT']);
1125 }
1126 unset($row);
1127 $result->addError(new Main\Error(
1128 Loc::getMessage('BX_SALE_DCM_COUPONS_VERIFY_ERR'),
1129 'COUPON',
1130 $errorData
1131 ));
1132 unset($errorData);
1133 }
1134 unset($badCoupons);
1135 }
1136 unset($appliedCoupons);
1137
1138 return $result;
1139 }
1140
1146 public static function saveApplied(): Main\Result
1147 {
1148 $commonResult = new Main\Result();
1149 if (
1150 self::$useMode === self::MODE_SYSTEM
1151 || !self::isEntered()
1152 || !self::$allowedSave
1153 )
1154 {
1155 return $commonResult;
1156 }
1157
1158 $result = [];
1159 $currentTime = new Main\Type\DateTime();
1161
1162 $appliedCoupons = self::filterCoupons(
1163 [
1164 'STATUS' => self::STATUS_APPLYED,
1165 'MODULE_ID' => 'sale',
1166 'SAVED' => 'N',
1167 ],
1168 true
1169 );
1170
1171 if (!empty($appliedCoupons))
1172 {
1173 $result['sale'] = [
1174 'COUPONS' => $appliedCoupons,
1175 ];
1176 $saveResult = Internals\DiscountCouponTable::saveApplied($appliedCoupons, $userId, $currentTime);
1177
1178 if ($saveResult === false)
1179 {
1180 $result['sale']['ERROR'] = true;
1181 }
1182 else
1183 {
1184 if ($saveResult['STATUS'])
1185 {
1186 $result['sale']['DEACTIVATE'] = $saveResult['DEACTIVATE'];
1187 $result['sale']['LIMITED'] = $saveResult['LIMITED'];
1188 $result['sale']['INCREMENT'] = $saveResult['INCREMENT'];
1189 self::eraseAppliedCoupons($result['sale']);
1190 }
1191 else
1192 {
1193 $commonResult->addError(new Main\Error(
1194 Loc::getMessage('BX_SALE_DCM_ERR_SAVE_APPLIED'),
1195 'sale',
1196 $saveResult['ERROR']
1197 ));
1198
1199 return $commonResult;
1200 }
1201 }
1202 }
1203 if (!self::$onlySaleDiscount && !empty(self::$couponProviders))
1204 {
1205 foreach (self::$couponProviders as $provider)
1206 {
1207 $appliedCoupons = self::filterCoupons(
1208 [
1209 'STATUS' => self::STATUS_APPLYED,
1210 'MODULE_ID' => $provider['module'],
1211 'SAVED' => 'N',
1212 ],
1213 true
1214 );
1215 if (empty($appliedCoupons))
1216 {
1217 continue;
1218 }
1219 $result[$provider['module']] = [
1220 'COUPONS' => $appliedCoupons,
1221 ];
1222 $saveResult = call_user_func_array(
1223 $provider['saveApplied'],
1224 [
1225 $appliedCoupons,
1226 $userId,
1227 $currentTime,
1228 ]
1229 );
1230 if (empty($saveResult) || !is_array($saveResult))
1231 {
1232 $result[$provider['module']]['ERROR'] = true;
1233 }
1234 else
1235 {
1236 if (!isset($saveResult['STATUS']) || $saveResult['STATUS'])
1237 {
1238 $result[$provider['module']]['DEACTIVATE'] = ($saveResult['DEACTIVATE'] ?? []);
1239 $result[$provider['module']]['LIMITED'] = ($saveResult['LIMITED'] ?? []);
1240 $result[$provider['module']]['INCREMENT'] = ($saveResult['INCREMENT'] ?? []);
1241 self::eraseAppliedCoupons($result[$provider['module']]);
1242 }
1243 else
1244 {
1245 $commonResult->addError(new Main\Error(
1246 Loc::getMessage('BX_SALE_DCM_ERR_SAVE_APPLIED'),
1247 $provider['module'],
1248 $saveResult['ERROR']
1249 ));
1250
1251 return $commonResult;
1252 }
1253 }
1254 }
1255 }
1257 self::$allowedSave = false;
1258 $event = new Main\Event('sale', self::EVENT_ON_SAVE_APPLIED_COUPONS, $result);
1259 $event->send();
1260
1261 return $commonResult;
1262 }
1263
1272 public static function setApplyByProduct($product, $couponsList, $oldMode = false)
1273 {
1274 static $count = null;
1275 if ($count === null)
1276 {
1277 $count = 0;
1278 }
1279 if (self::$useMode === self::MODE_SYSTEM)
1280 {
1281 return false;
1282 }
1283 if (empty($couponsList) || empty($product))
1284 {
1285 return false;
1286 }
1287 $oldMode = ($oldMode === true);
1288 if ($oldMode)
1289 {
1290 if (!isset($product['BASKET_ID']))
1291 {
1292 $product['BASKET_ID'] = 'c'.$count;
1293 }
1294 $count++;
1295 }
1296 $hash = ($oldMode ? self::getCatalogProductHash($product) : self::getProductHash($product));
1297
1298 if ($hash === '')
1299 {
1300 return false;
1301 }
1302 $applyed = false;
1303 $applyList = [];
1304 foreach ($couponsList as $coupon)
1305 {
1306 $coupon = trim((string)$coupon);
1307 if ($coupon === '' || !isset(self::$coupons[$coupon]))
1308 {
1309 continue;
1310 }
1311 if (
1312 self::$coupons[$coupon]['STATUS'] == self::STATUS_NOT_FOUND
1313 || self::$coupons[$coupon]['STATUS'] == self::STATUS_FREEZE
1314 )
1315 {
1316 continue;
1317 }
1318 if (
1319 self::$coupons[$coupon]['TYPE'] == Internals\DiscountCouponTable::TYPE_BASKET_ROW
1320 && !empty(self::$coupons[$coupon]['BASKET'])
1321 )
1322 {
1323 continue;
1324 }
1325 self::$coupons[$coupon]['BASKET'][$hash] = true;
1326 self::$coupons[$coupon]['STATUS'] = self::STATUS_APPLYED;
1327 $applyed = true;
1328 $applyList[$coupon] = self::$coupons[$coupon];
1329 }
1330 unset($coupon);
1331 if ($applyed)
1332 {
1333 $event = new Main\Event(
1334 'sale',
1335 self::EVENT_ON_COUPON_APPLY_PRODUCT,
1336 [
1337 'PRODUCT' => $product,
1338 'COUPONS' => $applyList,
1339 ]
1340 );
1341 $event->send();
1342 }
1343 unset($applyList);
1344
1345 return $applyed;
1346 }
1347
1355 public static function setApply($coupon, $data)
1356 {
1357 if (self::$useMode === self::MODE_SYSTEM)
1358 {
1359 return false;
1360 }
1361 $coupon = trim((string)$coupon);
1362 if ($coupon === '' || empty($data) || !is_array($data))
1363 {
1364 return false;
1365 }
1366 if (!isset(self::$coupons[$coupon]))
1367 {
1368 return false;
1369 }
1370 if (
1371 self::$coupons[$coupon]['STATUS'] == self::STATUS_NOT_FOUND
1372 || self::$coupons[$coupon]['STATUS'] == self::STATUS_FREEZE
1373 )
1374 {
1375 return false;
1376 }
1377 $result = [];
1378 if ((!empty($data['BASKET']) && is_array($data['BASKET'])) || !empty($data['DELIVERY']))
1379 {
1380 if (!empty($data['BASKET']) && is_array($data['BASKET']))
1381 {
1382 if (self::$coupons[$coupon]['TYPE'] == Internals\DiscountCouponTable::TYPE_BASKET_ROW && count($data['BASKET']) > 1)
1383 {
1384 return false;
1385 }
1386 foreach ($data['BASKET'] as $product)
1387 {
1388 if (empty($product))
1389 {
1390 continue;
1391 }
1392 $hash = self::getProductHash($product);
1393 if ($hash === '')
1394 {
1395 continue;
1396 }
1397 if (
1398 self::$coupons[$coupon]['TYPE'] == Internals\DiscountCouponTable::TYPE_BASKET_ROW
1399 && !empty(self::$coupons[$coupon]['BASKET'])
1400 )
1401 {
1402 continue;
1403 }
1404 self::$coupons[$coupon]['BASKET'][$hash] = true;
1405 self::$coupons[$coupon]['STATUS'] = self::STATUS_APPLYED;
1406 $result['COUPON'] = self::$coupons[$coupon];
1407 if (!isset($result['BASKET']))
1408 {
1409 $result['BASKET'] = [];
1410 }
1411 $result['BASKET'][] = $product;
1412 }
1413 unset($product);
1414 }
1415 if (!empty($data['DELIVERY']))
1416 {
1417 self::$coupons[$coupon]['DELIVERY'] = $data['DELIVERY'];
1418 self::$coupons[$coupon]['STATUS'] = self::STATUS_APPLYED;
1419 $result['COUPON'] = self::$coupons[$coupon];
1420 $result['DELIVERY'] = self::$coupons[$coupon]['DELIVERY'];
1421 }
1422 $event = new Main\Event('sale', self::EVENT_ON_COUPON_APPLY, $result);
1423 unset($result);
1424 $event->send();
1425
1426 return true;
1427 }
1428
1429 return false;
1430 }
1431
1438 public static function deleteApplyByProduct($product)
1439 {
1440 if (self::$useMode === self::MODE_SYSTEM || empty($product))
1441 {
1442 return false;
1443 }
1444 $hash = self::getProductHash($product);
1445 if ($hash === '')
1446 {
1447 return false;
1448 }
1449 $success = false;
1450 foreach (self::$coupons as &$oneCoupon)
1451 {
1452 if ($oneCoupon['STATUS'] == self::STATUS_NOT_FOUND || $oneCoupon['STATUS'] == self::STATUS_FREEZE)
1453 {
1454 continue;
1455 }
1456 if ($oneCoupon['SAVED'] === 'Y')
1457 {
1458 continue;
1459 }
1460 if (isset($oneCoupon['BASKET'][$hash]))
1461 {
1462 unset($oneCoupon['BASKET'][$hash]);
1463 if (empty($oneCoupon['BASKET']) && empty($oneCoupon['DELIVERY']))
1464 {
1465 $oneCoupon['STATUS'] = self::STATUS_NOT_APPLYED;
1466 }
1467 $success = true;
1468 }
1469 }
1470 unset($oneCoupon);
1471
1472 return $success;
1473 }
1474
1480 public static function finalApply()
1481 {
1482 if (self::$useMode === self::MODE_SYSTEM || !self::isSuccess() || empty(self::$coupons))
1483 {
1484 return;
1485 }
1486
1487 foreach (self::$coupons as &$oneCoupon)
1488 {
1489 if ($oneCoupon['STATUS'] == self::STATUS_ENTERED)
1490 {
1491 $oneCoupon['STATUS'] = self::STATUS_NOT_APPLYED;
1492 if ($oneCoupon['CHECK_CODE'] == self::COUPON_CHECK_OK)
1493 {
1494 $oneCoupon['CHECK_CODE'] = self::COUPON_CHECK_NOT_APPLIED;
1495 }
1496 }
1497 }
1498 unset($oneCoupon);
1499 }
1500
1507 public static function clearApplyCoupon($coupon)
1508 {
1509 if (self::$useMode === self::MODE_SYSTEM || !self::isSuccess())
1510 {
1511 return false;
1512 }
1513 if (empty(self::$coupons))
1514 {
1515 return true;
1516 }
1517 $coupon = trim((string)$coupon);
1518 if ($coupon === '')
1519 {
1520 return false;
1521 }
1522 if (!isset(self::$coupons[$coupon]))
1523 {
1524 return false;
1525 }
1526 if (
1527 self::$coupons[$coupon]['STATUS'] == self::STATUS_NOT_FOUND
1528 || self::$coupons[$coupon]['STATUS'] == self::STATUS_FREEZE
1529 )
1530 {
1531 return false;
1532 }
1533 self::$coupons[$coupon]['STATUS'] = self::STATUS_ENTERED;
1534 self::createApplyFields(self::$coupons[$coupon]);
1535
1536 return true;
1537 }
1538
1545 public static function clearApply($all = true)
1546 {
1547 if (self::$useMode === self::MODE_SYSTEM || !self::isSuccess())
1548 {
1549 return false;
1550 }
1551 if (self::isFrozenCouponStorage())
1552 {
1553 return false;
1554 }
1555 if (empty(self::$coupons))
1556 {
1557 return true;
1558 }
1559 $all = ($all !== false);
1560 foreach (self::$coupons as &$coupon)
1561 {
1562 if (
1563 $coupon['STATUS'] == self::STATUS_NOT_FOUND
1564 || $coupon['STATUS'] == self::STATUS_FREEZE
1565 )
1566 {
1567 continue;
1568 }
1569 if (!$all && $coupon['SAVED'] === 'Y')
1570 {
1571 continue;
1572 }
1573 $coupon['STATUS'] = self::STATUS_ENTERED;
1574 self::createApplyFields($coupon);
1575 }
1576 unset($coupon);
1577
1578 return true;
1579 }
1580
1588 public static function getData($coupon, $checkCoupon = true)
1589 {
1590 $currentTime = new Main\Type\DateTime();
1591 $currentTimestamp = $currentTime->getTimestamp();
1593 $coupon = trim((string)$coupon);
1594 if ($coupon === '')
1595 {
1596 return false;
1597 }
1598 $checkCoupon = ($checkCoupon === true);
1599
1600 $result = static::getEmptyCouponFields($coupon);
1601
1602 $resultKeyList = [
1603 'ID',
1604 'COUPON',
1605 'DISCOUNT_ID',
1606 'TYPE',
1607 'ACTIVE',
1608 'DISCOUNT_NAME',
1609 'DISCOUNT_ACTIVE',
1610 'DISCOUNT_ACTIVE_FROM',
1611 'DISCOUNT_ACTIVE_TO',
1612 ];
1613
1614 $couponIterator = Internals\DiscountCouponTable::getList([
1615 'select' => [
1616 'ID',
1617 'COUPON',
1618 'DISCOUNT_ID',
1619 'TYPE',
1620 'ACTIVE',
1621 'USER_ID',
1622 'MAX_USE',
1623 'USE_COUNT',
1624 'ACTIVE_FROM',
1625 'ACTIVE_TO',
1626 'DISCOUNT_NAME' => 'DISCOUNT.NAME',
1627 'DISCOUNT_ACTIVE' => 'DISCOUNT.ACTIVE',
1628 'DISCOUNT_ACTIVE_FROM' => 'DISCOUNT.ACTIVE_FROM',
1629 'DISCOUNT_ACTIVE_TO' => 'DISCOUNT.ACTIVE_TO',
1630 ],
1631 'filter' => [
1632 '=COUPON' => $coupon,
1633 ],
1634 ]);
1635 if ($existCoupon = $couponIterator->fetch())
1636 {
1637 $result['MODE'] = self::COUPON_MODE_FULL;
1638 $result['MODULE'] = 'sale';
1639 $result['MODULE_ID'] = 'sale';
1640 $checkCode = self::checkBaseData($existCoupon, self::COUPON_CHECK_OK);
1641 foreach ($resultKeyList as $resultKey)
1642 {
1643 $result[$resultKey] = $existCoupon[$resultKey];
1644 }
1645 unset($resultKey);
1646
1647 if ($checkCoupon)
1648 {
1649 $checkCode = self::checkFullData($existCoupon, $result['MODE'], $checkCode, $currentTimestamp);
1650 self::fillUserInfo($result, $existCoupon, $checkCode);
1651 }
1652 $result['STATUS'] = ($checkCode == self::COUPON_CHECK_OK ? self::STATUS_ENTERED : self::STATUS_FREEZE);
1653 $result['CHECK_CODE'] = $checkCode;
1654 unset($checkCode);
1655 }
1656 elseif (!self::$onlySaleDiscount && !empty(self::$couponProviders))
1657 {
1658 foreach (self::$couponProviders as $provider)
1659 {
1660 $existCoupon = call_user_func_array(
1661 $provider['getData'],
1662 [
1663 $coupon,
1664 ]
1665 );
1666 if (!empty($existCoupon) && is_array($existCoupon))
1667 {
1668 $result['MODE'] = (int)$provider['mode'];
1669 $result['MODULE'] = $provider['module'];
1670 $result['MODULE_ID'] = $provider['module'];
1671 $checkCode = self::checkBaseData($existCoupon, self::COUPON_CHECK_OK);
1672 foreach ($resultKeyList as $resultKey)
1673 {
1674 $result[$resultKey] = $existCoupon[$resultKey];
1675 }
1676 unset($resultKey);
1677
1678 if ($checkCoupon)
1679 {
1680 $checkCode = self::checkFullData($existCoupon, $result['MODE'], $checkCode, $currentTimestamp);
1681 self::fillUserInfo($result, $existCoupon, $checkCode);
1682 }
1683 $result['STATUS'] = ($checkCode == self::COUPON_CHECK_OK ? self::STATUS_ENTERED : self::STATUS_FREEZE);
1684 $result['CHECK_CODE'] = $checkCode;
1685 unset($checkCode);
1686 break;
1687 }
1688 }
1689 unset($provider);
1690 }
1691
1692 return $result;
1693 }
1694
1701 public static function isExist($coupon)
1702 {
1703 $coupon = trim((string)$coupon);
1704 if ($coupon === '')
1705 {
1706 return false;
1707 }
1708
1710 $couponIterator = Internals\DiscountCouponTable::getList([
1711 'select' => [
1712 'ID',
1713 'COUPON',
1714 ],
1715 'filter' => [
1716 '=COUPON' => $coupon,
1717 ],
1718 ]);
1719 if ($existCoupon = $couponIterator->fetch())
1720 {
1721 return [
1722 'ID' => $existCoupon['ID'],
1723 'COUPON' => $existCoupon['COUPON'],
1724 'MODULE' => 'sale',
1725 'MODULE_ID' => 'sale',
1726 ];
1727 }
1728 else
1729 {
1730 if (!self::$onlySaleDiscount && !empty(self::$couponProviders))
1731 {
1732 foreach (self::$couponProviders as $provider)
1733 {
1734 $existCoupon = call_user_func_array(
1735 $provider['isExist'],
1736 [
1737 $coupon,
1738 ]
1739 );
1740 if (!empty($existCoupon) && is_array($existCoupon))
1741 {
1742 if (!isset($existCoupon['ID']) || !isset($existCoupon['COUPON']))
1743 {
1744 continue;
1745 }
1746 return [
1747 'ID' => $existCoupon['ID'],
1748 'COUPON' => $existCoupon['COUPON'],
1749 'MODULE' => $provider['module'],
1750 'MODULE_ID' => $provider['module'],
1751 ];
1752 }
1753 }
1754 unset($provider);
1755 }
1756 }
1757
1758 return false;
1759 }
1760
1768 public static function getEnteredCoupon($coupon, $clearData = false)
1769 {
1770 if (!self::$init)
1771 {
1772 self::init();
1773 }
1774 $result = false;
1775 if (self::$useMode === self::MODE_SYSTEM || !self::isSuccess())
1776 {
1777 return false;
1778 }
1779
1780 $clearData = ($clearData === true);
1781 $coupon = trim((string)$coupon);
1782 if ($coupon === '')
1783 {
1784 return false;
1785 }
1786 if (!isset(self::$coupons[$coupon]))
1787 {
1788 $couponData = self::getData($coupon);
1789 if (isset(self::$coupons[$couponData['COUPON']]))
1790 {
1791 $result = self::$coupons[$couponData['COUPON']];
1792 }
1793 }
1794 else
1795 {
1796 $result = self::$coupons[$coupon];
1797 }
1798 if (!empty($result))
1799 {
1800 if ($result['MODE'] === self::COUPON_MODE_FULL)
1801 {
1802 $result['USER_INFO'] = $result['SYSTEM_DATA'];
1803 unset($result['SYSTEM_DATA']);
1804 }
1805 if ($clearData)
1806 {
1807 foreach (self::$clearFields as $fieldName)
1808 {
1809 unset($result[$fieldName]);
1810 }
1811 unset($fieldName);
1812 foreach (self::$timeFields as $fieldName)
1813 {
1814 if (isset($result[$fieldName]) && $result[$fieldName] instanceof Main\Type\DateTime)
1815 {
1816 $result[$fieldName] = $result[$fieldName]->getTimestamp();
1817 }
1818 }
1819 unset($fieldName);
1820
1821 if (!empty($result['USER_INFO']))
1822 {
1823 foreach (self::$timeFields as $fieldName)
1824 {
1825 if (isset($result['USER_INFO'][$fieldName]) && $result['USER_INFO'][$fieldName] instanceof Main\Type\DateTime)
1826 {
1827 $result['USER_INFO'][$fieldName] = $result['USER_INFO'][$fieldName]->getTimestamp();
1828 }
1829 }
1830 unset($fieldName);
1831 }
1832 }
1833 }
1834
1835 return $result;
1836 }
1837
1843 public static function logout()
1844 {
1845 if (!self::$init)
1846 {
1847 self::init();
1848 }
1849 if (self::$useMode !== self::MODE_CLIENT)
1850 {
1851 return;
1852 }
1853 if (self::isSuccess())
1854 {
1855 self::clear(true);
1856 }
1857 }
1858
1865 public static function filterOrderCoupons($coupon)
1866 {
1867 return (isset($coupon['SAVED']) && $coupon['SAVED'] === 'Y');
1868 }
1869
1877 public static function setUseOnlySaleDiscounts($mode)
1878 {
1879 if (!is_bool($mode))
1880 {
1881 return;
1882 }
1883 if (self::getUseMode() != self::MODE_ORDER)
1884 {
1885 return;
1886 }
1887 self::$onlySaleDiscount = $mode;
1888 self::loadCouponProviders();
1889 }
1890
1898 protected static function checkBaseData(&$data, $checkCode = self::COUPON_CHECK_OK)
1899 {
1900 if (empty(self::$couponTypes))
1901 {
1902 self::$couponTypes = Internals\DiscountCouponTable::getCouponTypes(true);
1903 }
1904
1905 if (!isset($data['ID']))
1906 {
1907 $data['ID'] = 0;
1908 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1909 }
1910 else
1911 {
1912 $data['ID'] = (int)$data['ID'];
1913 if ($data['ID'] <= 0 && self::$checkActivity)
1914 {
1915 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1916 }
1917 }
1918 if (!isset($data['DISCOUNT_ID']))
1919 {
1920 $data['DISCOUNT_ID'] = 0;
1921 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1922 }
1923 else
1924 {
1925 $data['DISCOUNT_ID'] = (int)$data['DISCOUNT_ID'];
1926 if ($data['DISCOUNT_ID'] <= 0 && self::$checkActivity)
1927 {
1928 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1929 }
1930 }
1931 if (!isset($data['TYPE']))
1932 {
1933 $data['TYPE'] = Internals\DiscountCouponTable::TYPE_UNKNOWN;
1934 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1935 }
1936 else
1937 {
1938 $data['TYPE'] = (int)$data['TYPE'];
1939 if (!isset(self::$couponTypes[$data['TYPE']]) && $data['TYPE'] != Internals\DiscountCouponTable::TYPE_ARCHIVED)
1940 {
1941 $data['TYPE'] = Internals\DiscountCouponTable::TYPE_UNKNOWN;
1942 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1943 }
1944 }
1945 if (!isset($data['ACTIVE']))
1946 {
1947 $data['ACTIVE'] = '';
1948 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1949 }
1950 else
1951 {
1952 $data['ACTIVE'] = (string)$data['ACTIVE'];
1953 if ($data['ACTIVE'] !== 'Y' && $data['ACTIVE'] !== 'N')
1954 {
1955 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1956 }
1957 }
1958 if (isset($data['ACTIVE_FROM']) && !($data['ACTIVE_FROM'] instanceof Main\Type\DateTime))
1959 {
1960 $data['ACTIVE_FROM'] = null;
1961 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1962 }
1963 if (isset($data['ACTIVE_TO']) && !($data['ACTIVE_TO'] instanceof Main\Type\DateTime))
1964 {
1965 $data['ACTIVE_TO'] = null;
1966 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1967 }
1968 $data['DISCOUNT_NAME'] = (isset($data['DISCOUNT_NAME']) ? (string)$data['DISCOUNT_NAME'] : '');
1969 if (!isset($data['DISCOUNT_ACTIVE']))
1970 {
1971 $data['DISCOUNT_ACTIVE'] = '';
1972 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1973 }
1974 else
1975 {
1976 $data['DISCOUNT_ACTIVE'] = (string)$data['DISCOUNT_ACTIVE'];
1977 if ($data['DISCOUNT_ACTIVE'] !== 'Y' && $data['DISCOUNT_ACTIVE'] !== 'N')
1978 {
1979 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1980 }
1981 }
1982 if (isset($data['DISCOUNT_ACTIVE_FROM']) && !($data['DISCOUNT_ACTIVE_FROM'] instanceof Main\Type\DateTime))
1983 {
1984 $data['DISCOUNT_ACTIVE_FROM'] = null;
1985 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1986 }
1987 if (isset($data['DISCOUNT_ACTIVE_TO']) && !($data['DISCOUNT_ACTIVE_TO'] instanceof Main\Type\DateTime))
1988 {
1989 $data['DISCOUNT_ACTIVE_TO'] = null;
1990 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
1991 }
1992
1993 return $checkCode;
1994 }
1995
2005 protected static function checkFullData(&$data, $mode, $checkCode, $currentTimestamp)
2006 {
2007 $mode = ((int)$mode !== self::COUPON_MODE_SIMPLE ? self::COUPON_MODE_FULL : self::COUPON_MODE_SIMPLE);
2008
2009 if (self::$checkActivity)
2010 {
2011 if ($data['ACTIVE'] !== 'Y')
2012 {
2013 $checkCode |= self::COUPON_CHECK_NO_ACTIVE;
2014 }
2015 if ($data['DISCOUNT_ACTIVE'] !== 'Y')
2016 {
2018 }
2019 if ($data['DISCOUNT_ACTIVE_FROM'] instanceof Main\Type\DateTime && $data['DISCOUNT_ACTIVE_FROM']->getTimestamp() > $currentTimestamp)
2020 {
2022 }
2023 if ($data['DISCOUNT_ACTIVE_TO'] instanceof Main\Type\DateTime && $data['DISCOUNT_ACTIVE_TO']->getTimestamp() < $currentTimestamp)
2024 {
2026 }
2027 }
2028
2029 if ($mode === self::COUPON_MODE_FULL)
2030 {
2031 if (self::$checkActivity)
2032 {
2033 if ($data['ACTIVE_FROM'] instanceof Main\Type\DateTime && $data['ACTIVE_FROM']->getTimestamp() > $currentTimestamp)
2034 {
2036 }
2037 if ($data['ACTIVE_TO'] instanceof Main\Type\DateTime && $data['ACTIVE_TO']->getTimestamp() < $currentTimestamp)
2038 {
2040 }
2041 }
2042 if (!isset($data['USER_ID']))
2043 {
2044 $data['USER_ID'] = 0;
2045 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
2046 }
2047 else
2048 {
2049 $data['USER_ID'] = (int)$data['USER_ID'];
2050 if ($data['USER_ID'] > 0 && $data['USER_ID'] != self::$userId)
2051 {
2052 $checkCode |= self::COUPON_CHECK_BAD_USER_ID;
2053 }
2054 }
2055 if (!isset($data['MAX_USE']))
2056 {
2057 $data['MAX_USE'] = 0;
2058 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
2059 }
2060 else
2061 {
2062 $data['MAX_USE'] = (int)$data['MAX_USE'];
2063 }
2064 if (!isset($data['USE_COUNT']))
2065 {
2066 $data['USE_COUNT'] = 0;
2067 $checkCode |= self::COUPON_CHECK_CORRUPT_DATA;
2068 }
2069 else
2070 {
2071 if (self::$checkActivity)
2072 {
2073 $data['USE_COUNT'] = (int)$data['USE_COUNT'];
2074 if ($data['MAX_USE'] > 0 && $data['USE_COUNT'] >= $data['MAX_USE'])
2075 {
2077 }
2078 }
2079 }
2080 }
2081
2082 return $checkCode;
2083 }
2084
2093 protected static function fillUserInfo(&$result, $existCoupon, $checkCode)
2094 {
2095 if ($checkCode == self::COUPON_CHECK_OK && $result['MODE'] === self::COUPON_MODE_FULL)
2096 {
2097 $result['SYSTEM_DATA'] = [
2098 'USER_ID' => $existCoupon['USER_ID'],
2099 'MAX_USE' => $existCoupon['MAX_USE'],
2100 'USE_COUNT' => $existCoupon['USE_COUNT'],
2101 'ACTIVE_FROM' => $existCoupon['ACTIVE_FROM'],
2102 'ACTIVE_TO' => $existCoupon['ACTIVE_TO'],
2103 ];
2104 if (self::usedByManager() || ($existCoupon['USER_ID'] > 0 && $existCoupon['USER_ID'] == self::$userId))
2105 {
2106 $result['USER_INFO'] = $result['SYSTEM_DATA'];
2107 }
2108 }
2109 }
2110
2116 protected static function initUserId(): void
2117 {
2118 if (
2119 self::isSuccess()
2120 && self::$useMode === self::MODE_CLIENT
2121 && self::$userId === null
2122 )
2123 {
2124 $currentUserId = self::getCurrentUserId();
2125 if ($currentUserId === null)
2126 {
2127 $fuserId = Fuser::getId(true);
2128 if ($fuserId !== null)
2129 {
2130 // TODO: replace this code after refactoring Fuser::getUserIdById
2131 $row = Internals\FuserTable::getRow([
2132 'select' => [
2133 'ID',
2134 'USER_ID',
2135 ],
2136 'filter' => [
2137 '=ID' => $fuserId,
2138 ],
2139 'order' => [
2140 'ID' => 'DESC',
2141 ],
2142 ]);
2143 if ($row !== null)
2144 {
2145 $currentUserId = (int)$row['USER_ID'];
2146 }
2147 // end TODO
2148 }
2149 unset($fuserId);
2150 }
2151 if ($currentUserId === null)
2152 {
2153 self::$errors[] = Loc::getMessage('BX_SALE_DCM_ERR_BAD_FUSER_ID');
2154 }
2155 else
2156 {
2157 self::$userId = $currentUserId;
2158 }
2159 unset($currentUserId);
2160 }
2161 }
2162
2168 protected static function saveToStorage()
2169 {
2170 if (self::isSuccess())
2171 {
2172 $session = self::getSession();
2173 if (!$session)
2174 {
2175 return;
2176 }
2177
2178 $couponsList = [];
2179 if (!empty(self::$coupons))
2180 {
2181 $couponsList = array_filter(self::$coupons, '\Bitrix\Sale\DiscountCouponsManager::clearSavedCoupons');
2182 if (!empty($couponsList))
2183 {
2184 $couponsList = array_keys($couponsList);
2185 }
2186 }
2187
2188 if (self::usedByManager())
2189 {
2190 if (!isset($session[self::STORAGE_MANAGER_COUPONS]) || !is_array($session[self::STORAGE_MANAGER_COUPONS]))
2191 {
2192 $session[self::STORAGE_MANAGER_COUPONS] = [];
2193 }
2194 $session[self::STORAGE_MANAGER_COUPONS][self::$userId] = $couponsList;
2195 }
2196 else
2197 {
2198 $session[self::STORAGE_CLIENT_COUPONS] = $couponsList;
2199 }
2200 unset($couponsList);
2201 }
2202 }
2203
2210 protected static function eraseAppliedCoupons($result)
2211 {
2212 if (!empty($result['DEACTIVATE']) || !empty($result['LIMITED']))
2213 {
2214 $clear = array_keys(array_merge($result['DEACTIVATE'], $result['LIMITED']));
2215 foreach ($clear as $coupon)
2216 {
2217 if (isset(self::$coupons[$coupon]))
2218 {
2219 unset(self::$coupons[$coupon]);
2220 }
2221 if (isset(self::$lockedCoupons[$coupon]))
2222 {
2223 unset(self::$lockedCoupons[$coupon]);
2224 }
2225 }
2226 unset($coupon, $clear);
2227 }
2228 }
2229
2236 protected static function createApplyFields(&$couponData)
2237 {
2238 $couponData['BASKET'] = [];
2239 $couponData['DELIVERY'] = [];
2240 }
2241
2247 protected static function loadCouponProviders()
2248 {
2249 self::$couponProviders = [];
2250 if (!self::$onlySaleDiscount)
2251 {
2252 $eventData = [
2253 'COUPON_UNKNOWN' => Internals\DiscountCouponTable::TYPE_UNKNOWN,
2254 'COUPON_TYPES' => Internals\DiscountCouponTable::getCouponTypes(false),
2255 ];
2256 $event = new Main\Event('sale', self::EVENT_ON_BUILD_COUPON_PROVIDES, $eventData);
2257 $event->send();
2258 $resultList = $event->getResults();
2259 if (empty($resultList) || !is_array($resultList))
2260 return;
2262 foreach ($resultList as $eventResult)
2263 {
2264 if ($eventResult->getType() != Main\EventResult::SUCCESS)
2265 {
2266 continue;
2267 }
2268 $module = (string)$eventResult->getModuleId();
2269 $provider = $eventResult->getParameters();
2270 if (empty($provider) || !is_array($provider))
2271 {
2272 continue;
2273 }
2274 if (empty($provider['getData']) || empty($provider['isExist']) || empty($provider['saveApplied']))
2275 {
2276 continue;
2277 }
2278 self::$couponProviders[] = [
2279 'module' => $module,
2280 'getData' => $provider['getData'],
2281 'isExist' => $provider['isExist'],
2282 'saveApplied' => $provider['saveApplied'],
2283 'mode' => (
2284 (int)($provider['mode'] ?? self::COUPON_MODE_SIMPLE) === self::COUPON_MODE_FULL
2287 ),
2288 ];
2289 }
2290 unset($provider, $module, $eventResult, $resultList, $event, $eventData);
2291 }
2292 }
2293
2299 protected static function initUseDiscount()
2300 {
2301 if (self::$onlySaleDiscount !== null)
2302 {
2303 return;
2304 }
2305
2306 self::$onlySaleDiscount = Option::get('sale', 'use_sale_discount_only') === 'Y';
2307 self::loadCouponProviders();
2308 }
2309
2316 protected static function filterUnknownCoupons($coupon)
2317 {
2318 if (empty(self::$couponTypes))
2319 {
2320 self::$couponTypes = Internals\DiscountCouponTable::getCouponTypes(true);
2321 }
2322
2323 return (isset($coupon['TYPE']) && isset(self::$couponTypes[$coupon['TYPE']]));
2324 }
2325
2332 protected static function filterFreezeCoupons($coupon)
2333 {
2334 if (empty(self::$couponTypes))
2335 {
2336 self::$couponTypes = Internals\DiscountCouponTable::getCouponTypes(true);
2337 }
2338
2339 return (
2340 isset($coupon['TYPE'])
2341 && isset(self::$couponTypes[$coupon['TYPE']])
2342 && $coupon['STATUS'] != self::STATUS_FREEZE
2343 );
2344 }
2345
2352 protected static function filterFreezeOrderedCoupons($coupon)
2353 {
2354 static $currentTimeStamp = null;
2355 if ($currentTimeStamp === null)
2356 {
2357 $currentTimeStamp = time();
2358 }
2359 if (!isset($coupon['SAVED']) || $coupon['SAVED'] !== 'Y')
2360 {
2361 return true;
2362 }
2363 if (isset($coupon['MODE']) && $coupon['MODE'] === self::COUPON_MODE_FULL)
2364 {
2365 if (
2366 isset($coupon['ACTIVE_FROM']) && $coupon['ACTIVE_FROM'] instanceof Main\Type\DateTime
2367 && $coupon['ACTIVE_FROM']->getTimestamp() > $currentTimeStamp
2368 )
2369 {
2370 return false;
2371 }
2372 if (
2373 isset($coupon['ACTIVE_TO']) && $coupon['ACTIVE_TO'] instanceof Main\Type\DateTime
2374 && $coupon['ACTIVE_TO']->getTimestamp() < $currentTimeStamp
2375 )
2376 {
2377 return false;
2378 }
2379 }
2380
2381 return true;
2382 }
2383
2391 protected static function filterOneRowCoupons($coupon, $hash)
2392 {
2393 return (
2394 $coupon['TYPE'] != Internals\DiscountCouponTable::TYPE_BASKET_ROW
2395 || empty($coupon['BASKET'])
2396 || (count($coupon['BASKET']) === 1 && isset($coupon['BASKET'][$hash]))
2397 );
2398 }
2399
2406 protected static function filterUniqueDiscount(&$coupons)
2407 {
2408 $existDiscount = [];
2409 $hash = '';
2410 foreach ($coupons as $key => $oneCoupon)
2411 {
2412 $hash = $oneCoupon['MODULE_ID'].':'.$oneCoupon['DISCOUNT_ID'];
2413 if (
2414 isset($existDiscount[$hash])
2415 && (
2416 $oneCoupon['TYPE'] == Internals\DiscountCouponTable::TYPE_ONE_ORDER
2417 || $oneCoupon['TYPE'] == Internals\DiscountCouponTable::TYPE_MULTI_ORDER
2418 )
2419 )
2420 {
2421 unset($coupons[$key]);
2422 }
2423 else
2424 {
2425 $existDiscount[$hash] = true;
2426 }
2427 }
2428 unset($hash, $existDiscount);
2429 }
2430
2431 protected static function filterLockedCoupons(array &$couponList): void
2432 {
2433 if (empty($couponList) || !static::usedByClient())
2434 {
2435 return;
2436 }
2437
2438 $locker = Sale\Discount\CouponLocker::getInstance();
2439 foreach (array_keys($couponList) as $coupon)
2440 {
2441 if (!static::needLockCoupon($coupon))
2442 {
2443 continue;
2444 }
2445 if (isset(self::$lockedCoupons[$coupon]))
2446 {
2447 continue;
2448 }
2449 $locker->lock($coupon);
2450 if ($locker->isLocked($coupon))
2451 {
2452 self::$lockedCoupons[$coupon] = true;
2453 }
2454 else
2455 {
2456 unset($couponList[$coupon]);
2457 }
2458 }
2459 unset($locker);
2460 }
2461
2469 protected static function filterCoupons($filter, $getId = false)
2470 {
2471 $getId = ($getId === true);
2472 $result = [];
2473 if (empty(self::$coupons) || empty($filter) || !is_array($filter))
2474 {
2475 return $result;
2476 }
2477
2478 foreach (self::$coupons as $id => $data)
2479 {
2480 $copy = true;
2481 foreach ($filter as $filterKey => $filterValue)
2482 {
2483 if (is_array($filterValue) && isset($filterValue['LOGIC']))
2484 {
2485 $logic = mb_strtolower($filterValue['LOGIC']);
2486 if ($logic !== 'and' && $logic !== 'or')
2487 {
2488 break 2;
2489 }
2490 unset($filterValue['LOGIC']);
2491 if (empty($filterValue))
2492 {
2493 break 2;
2494 }
2495 $subresult = [];
2496 foreach ($filterValue as $subfilterKey => $subfilterValue)
2497 {
2498 $invert = strncmp($subfilterKey, '!', 1) === 0;
2499 $fieldName = ($invert? mb_substr($subfilterKey, 1) : $subfilterKey);
2500 if (!isset($data[$fieldName]))
2501 {
2502 break 3;
2503 }
2504 else
2505 {
2506 $compare = (
2507 is_array($subfilterValue)
2508 ? in_array($data[$fieldName], $subfilterValue)
2509 : $data[$fieldName] == $subfilterValue
2510 );
2511 if ($invert)
2512 {
2513 $compare = !$compare;
2514 }
2515 $subresult[] = $compare;
2516 }
2517 }
2518 $compare = (
2519 $logic === 'and'
2520 ? !in_array(false, $subresult, true)
2521 : in_array(true, $subresult, true)
2522 );
2523 if (!$compare)
2524 {
2525 $copy = false;
2526 break;
2527 }
2528 }
2529 else
2530 {
2531 $invert = strncmp($filterKey, '!', 1) === 0;
2532 $fieldName = ($invert? mb_substr($filterKey, 1) : $filterKey);
2533 if (!isset($data[$fieldName]))
2534 {
2535 break 2;
2536 }
2537 else
2538 {
2539 $compare = (
2540 is_array($filterValue)
2541 ? in_array($data[$fieldName], $filterValue)
2542 : $data[$fieldName] == $filterValue
2543 );
2544 if ($invert)
2545 {
2546 $compare = !$compare;
2547 }
2548 if (!$compare)
2549 {
2550 $copy = false;
2551 break;
2552 }
2553 }
2554 }
2555 }
2556 if ($copy)
2557 {
2558 $result[$id] = ($getId ? $data['ID'] : $data);
2559 }
2560 }
2561
2562 return $result;
2563 }
2564
2572 protected static function filterArrayCoupons(&$coupons, $filter)
2573 {
2574 if (empty($coupons) || !is_array($coupons) || empty($filter) || !is_array($filter))
2575 {
2576 return;
2577 }
2578 $result = [];
2579 foreach ($coupons as $id => $data)
2580 {
2581 $copy = true;
2582 foreach ($filter as $filterKey => $filterValue)
2583 {
2584 if (is_array($filterValue) && isset($filterValue['LOGIC']))
2585 {
2586 $logic = mb_strtolower($filterValue['LOGIC']);
2587 if ($logic !== 'and' && $logic !== 'or')
2588 {
2589 break 2;
2590 }
2591 unset($filterValue['LOGIC']);
2592 if (empty($filterValue))
2593 {
2594 break 2;
2595 }
2596 $subresult = [];
2597 foreach ($filterValue as $subfilterKey => $subfilterValue)
2598 {
2599 $invert = strncmp($subfilterKey, '!', 1) === 0;
2600 $fieldName = ($invert? mb_substr($subfilterKey, 1) : $subfilterKey);
2601 if (!isset($data[$fieldName]))
2602 {
2603 break 3;
2604 }
2605 else
2606 {
2607 $compare = (
2608 is_array($subfilterValue)
2609 ? in_array($data[$fieldName], $subfilterValue)
2610 : $data[$fieldName] == $subfilterValue
2611 );
2612 if ($invert)
2613 {
2614 $compare = !$compare;
2615 }
2616 $subresult[] = $compare;
2617 }
2618 }
2619 $compare = (
2620 $logic === 'and'
2621 ? !in_array(false, $subresult, true)
2622 : in_array(true, $subresult, true)
2623 );
2624 if (!$compare)
2625 {
2626 $copy = false;
2627 break;
2628 }
2629 }
2630 else
2631 {
2632 $invert = strncmp($filterKey, '!', 1) === 0;
2633 $fieldName = ($invert? mb_substr($filterKey, 1) : $filterKey);
2634 if (!isset($data[$fieldName]))
2635 {
2636 break 2;
2637 }
2638 else
2639 {
2640 $compare = (
2641 is_array($filterValue)
2642 ? in_array($data[$fieldName], $filterValue)
2643 : $data[$fieldName] == $filterValue
2644 );
2645 if ($invert)
2646 {
2647 $compare = !$compare;
2648 }
2649 if (!$compare)
2650 {
2651 $copy = false;
2652 break;
2653 }
2654 }
2655 }
2656 }
2657 if ($copy)
2658 {
2659 $result[$id] = $data;
2660 }
2661 }
2662 $coupons = $result;
2663 unset($result);
2664 }
2665
2672 protected static function getProductHash($product)
2673 {
2674 $hash = '';
2675 if (!empty($product) && is_array($product))
2676 {
2677 $module = '';
2678 if (isset($product['MODULE_ID']))
2679 {
2680 $module = trim((string)$product['MODULE_ID']);
2681 }
2682 elseif (isset($product['MODULE']))
2683 {
2684 $module = trim((string)$product['MODULE']);
2685 }
2686 $productId = (isset($product['PRODUCT_ID']) ? (int)$product['PRODUCT_ID'] : 0);
2687 $basketId = (isset($product['BASKET_ID']) ? trim((string)$product['BASKET_ID']) : '0');
2688 if ($productId > 0 && $basketId !== '')
2689 {
2690 $hash = $module.':'.$productId.':'.$basketId;
2691 }
2692 }
2693
2694 return $hash;
2695 }
2696
2703 protected static function getCatalogProductHash($product)
2704 {
2705 $hash = '';
2706 $module = 'catalog';
2707 $productId = 0;
2708 $basketId = '';
2709 if (!empty($product) && is_array($product))
2710 {
2711 if (isset($product['MODULE_ID']))
2712 {
2713 $module = trim((string)$product['MODULE_ID']);
2714 }
2715 elseif (isset($product['MODULE']))
2716 {
2717 $module = trim((string)$product['MODULE']);
2718 }
2719 if (isset($product['PRODUCT_ID']))
2720 {
2721 $productId = (int)$product['PRODUCT_ID'];
2722 }
2723 $basketId = (isset($product['BASKET_ID']) ? trim((string)$product['BASKET_ID']) : '0');
2724 }
2725 if ($productId >= 0 && $basketId !== '')
2726 {
2727 $hash = $module.':'.$productId.':'.$basketId;
2728 }
2729
2730 return $hash;
2731 }
2738 protected static function fillCouponHints(&$coupons)
2739 {
2740 $statusList = self::getStatusList(true);
2741 $checkCode = self::getCheckCodeList(true);
2742 foreach ($coupons as &$oneCoupon)
2743 {
2744 $oneCoupon['STATUS_TEXT'] = $statusList[$oneCoupon['STATUS']];
2745 if ($oneCoupon['CHECK_CODE'] == self::COUPON_CHECK_OK || $oneCoupon['CHECK_CODE'] == self::COUPON_CHECK_NOT_APPLIED)
2746 {
2747 if ($oneCoupon['CHECK_CODE'] == self::COUPON_CHECK_OK)
2748 {
2749 $oneCoupon['CHECK_CODE_TEXT'] = (
2750 $oneCoupon['STATUS'] == self::STATUS_APPLYED
2751 ? [$statusList[$oneCoupon['STATUS']]]
2752 : [$checkCode[self::COUPON_CHECK_OK]]
2753 );
2754 }
2755 else
2756 {
2757 $oneCoupon['CHECK_CODE_TEXT'] = [$checkCode[self::COUPON_CHECK_NOT_APPLIED]];
2758 }
2759 }
2760 else
2761 {
2762 $oneCoupon['CHECK_CODE_TEXT'] = [];
2763 foreach ($checkCode as $code => $text)
2764 {
2765 if ($code == self::COUPON_CHECK_OK)
2766 {
2767 continue;
2768 }
2769 if (($oneCoupon['CHECK_CODE'] & $code) == $code)
2770 {
2771 $oneCoupon['CHECK_CODE_TEXT'][] = $checkCode[$code];
2772 }
2773 }
2774 }
2775 }
2776 unset($oneCoupon);
2777 }
2778
2786 protected static function setCoupons($couponsList, $checkCoupons = true)
2787 {
2788 if (empty($couponsList) || !is_array($couponsList))
2789 {
2790 return;
2791 }
2792
2793 $checkCoupons = ($checkCoupons !== false);
2794 if ($checkCoupons)
2795 {
2796 foreach ($couponsList as $coupon)
2797 {
2798 $coupon = trim((string)$coupon);
2799 if ($coupon === '')
2800 {
2801 continue;
2802 }
2803 $couponData = self::getData($coupon);
2804 if (!isset(self::$coupons[$couponData['COUPON']]))
2805 {
2806 $couponData['SORT'] = self::$couponIndex;
2807 self::createApplyFields($couponData);
2808 self::$coupons[$couponData['COUPON']] = $couponData;
2809 self::$couponIndex++;
2810 }
2811 }
2812 unset($couponData, $coupon);
2813 }
2814 else
2815 {
2816 $currentTime = new Main\Type\DateTime();
2817 $currentTimestamp = $currentTime->getTimestamp();
2818 unset($currentTime);
2819 foreach ($couponsList as $coupon)
2820 {
2821 if (empty($coupon) || !is_array($coupon))
2822 {
2823 continue;
2824 }
2825 $checkCode = self::checkBaseData($coupon, self::COUPON_CHECK_OK);
2826 $checkCode = self::checkFullData($coupon, $coupon['MODE'], $checkCode, $currentTimestamp);
2827 $coupon['STATUS'] = ($checkCode == self::COUPON_CHECK_OK ? self::STATUS_ENTERED : self::STATUS_FREEZE);
2828 $coupon['CHECK_CODE'] = $checkCode;
2829 unset($checkCode);
2830 if (!isset(self::$coupons[$coupon['COUPON']]))
2831 {
2832 $coupon['SORT'] = self::$couponIndex;
2833 self::createApplyFields($coupon);
2834 self::$coupons[$coupon['COUPON']] = $coupon;
2835 self::$couponIndex++;
2836 }
2837 }
2838 unset($coupon, $currentTimestamp);
2839 }
2840 }
2841
2849 protected static function clearSavedCoupons($coupon)
2850 {
2851 return (!isset($coupon['SAVED']) || $coupon['SAVED'] !== 'Y');
2852 }
2853
2861 protected static function clearSystemData(&$coupons)
2862 {
2863 $result = [];
2864 foreach ($coupons as $couponIndex => $couponData)
2865 {
2866 if (array_key_exists('SYSTEM_DATA', $couponData))
2867 {
2868 unset($couponData['SYSTEM_DATA']);
2869 }
2870 $result[$couponIndex] = $couponData;
2871 }
2872 unset($couponIndex, $couponData);
2873 $coupons = $result;
2874 }
2875
2883 protected static function convertOldFilterFields(array &$filter)
2884 {
2885 if (array_key_exists('MODULE', $filter))
2886 {
2887 if (!isset($filter['MODULE_ID']))
2888 {
2889 $filter['MODULE_ID'] = $filter['MODULE'];
2890 }
2891 unset($filter['MODULE']);
2892 }
2893 if (array_key_exists('!MODULE', $filter))
2894 {
2895 if (!isset($filter['!MODULE_ID']))
2896 {
2897 $filter['!MODULE_ID'] = $filter['!MODULE'];
2898 }
2899 unset($filter['!MODULE']);
2900 }
2901 }
2902
2910 protected static function getEmptyCouponFields($coupon)
2911 {
2912 /* field MODULE - unused, for compatibility only */
2913 return [
2914 'COUPON' => $coupon,
2915 'MODE' => self::COUPON_MODE_SIMPLE,
2916 'STATUS' => self::STATUS_NOT_FOUND,
2917 'CHECK_CODE' => self::COUPON_CHECK_NOT_FOUND,
2918 'MODULE' => '',
2919 'MODULE_ID' => '',
2920 'ID' => 0,
2921 'DISCOUNT_ID' => 0,
2922 'DISCOUNT_NAME' => '',
2923 'TYPE' => Internals\DiscountCouponTable::TYPE_UNKNOWN,
2924 'ACTIVE' => '',
2925 'USER_INFO' => [],
2926 'SAVED' => 'N',
2927 ];
2928 }
2929
2930 private static function getCurrentUserId(): ?int
2931 {
2932 global $USER;
2933
2934 if (!(
2935 isset($USER)
2936 && $USER instanceof \CUser
2937 ))
2938 {
2939 return null;
2940 }
2941
2942 $userId = (int)$USER->GetID();
2943
2944 return $userId > 0 ? $userId : null;
2945 }
2946
2947 protected static function needLockCoupon(string $coupon): bool
2948 {
2949 $type = self::$coupons[$coupon]['TYPE'] ?? Internals\DiscountCouponTable::TYPE_UNKNOWN;
2950
2951 return (
2952 $type === Internals\DiscountCouponTable::TYPE_BASKET_ROW
2953 || $type === Internals\DiscountCouponTable::TYPE_ONE_ORDER
2954 );
2955 }
2956}
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static setCoupons($couponsList, $checkCoupons=true)
static fillUserInfo(&$result, $existCoupon, $checkCode)
static checkBaseData(&$data, $checkCode=self::COUPON_CHECK_OK)
static getForApply($filter, $product=[], $uniqueDiscount=false)
static getEnteredCoupon($coupon, $clearData=false)
static checkFullData(&$data, $mode, $checkCode, $currentTimestamp)
static get($extMode=true, $filter=[], $show=false, $final=false)
static init($mode=self::MODE_CLIENT, $params=[], $clearStorage=false)
static reInit($mode=self::MODE_CLIENT, $params=[], $clearStorage=false)
static setApplyByProduct($product, $couponsList, $oldMode=false)
static getOrderedCoupons($extMode=true, $filter=[])
static initUseMode($mode=self::MODE_CLIENT, $params=[])
static getId($skipCreate=false)
Definition fuser.php:33
static getInstance($type)
Definition registry.php:183