3namespace Sale\Handlers\DiscountPreset;
7use Bitrix\Main\Localization\Loc;
9use Bitrix\Sale\Discount\Actions;
10use Bitrix\Sale\Discount\CumulativeCalculator;
11use Bitrix\Sale\Discount\Preset\ArrayHelper;
12use Bitrix\Sale\Discount\Preset\BasePreset;
13use Bitrix\Sale\Discount\Preset\HtmlHelper;
14use Bitrix\Sale\Discount\Preset\Manager;
15use Bitrix\Sale\Discount\Preset\State;
19 const TYPE_FIXED = Actions::VALUE_TYPE_FIX;
20 const TYPE_PERCENT = Actions::VALUE_TYPE_PERCENT;
22 const TYPE_COUNT_PERIOD_ALL_TIME = CumulativeCalculator::TYPE_COUNT_PERIOD_ALL_TIME;
23 const TYPE_COUNT_PERIOD_INTERVAL = CumulativeCalculator::TYPE_COUNT_PERIOD_INTERVAL;
24 const TYPE_COUNT_PERIOD_RELATIVE = CumulativeCalculator::TYPE_COUNT_PERIOD_RELATIVE;
26 const MARK_DEFAULT_EMPTY_ROW = PHP_INT_MIN;
30 return Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_NAME');
40 if (Sale\Config\Feature::isCumulativeDiscountsEnabled())
42 return BasePreset::AVAILABLE_STATE_ALLOW;
44 if ($this->bitrix24Included)
46 return BasePreset::AVAILABLE_STATE_TARIFF;
49 return BasePreset::AVAILABLE_STATE_DISALLOW;
56 return Sale\Config\Feature::getCumulativeDiscountsHelpLink();
68 return Manager::CATEGORY_PRODUCTS;
76 public function processShowInputName(State $state)
81 public function processSaveInputName(State $state)
86 public function processShowInputRanges(State $state)
88 $lid = $state->get(
'discount_lid');
89 $currency = \Bitrix\Sale\Internals\SiteCurrencyTable::getSiteCurrency($lid);
91 $rows = $this->generateRows($state);
92 $templateRow = $this->generateRow(-1,
array(),
'display: none');
94 return $this->generateJavascript() .
'
95 <table width="100%" border="0" cellspacing="7" cellpadding="0">
98 <td class="adm-detail-content-cell-l" style="width:25%;"><strong>' . Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_LABEL_RANGES') .
':</strong></td>
99 <td class="adm-detail-content-cell-r" style="width:75%;">
100 <table id="range_table" style="width: auto;" class="internal" border="0" cellspacing="7" cellpadding="0">
103 <td align="center">' . Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_H_SUM',
array(
'#CURRENCY#' =>
$currency,)) .
'</td>
104 <td align="center">' . Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_H_DISCOUNT_VALUE') .
'</td>
109 <div style="width: 100%; text-align: left; margin-top: 10px;">
110 <input id="clone_range" class="adm-btn" type="button" value="' . Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_DISCOUNT_ADD_RANGE') .
'">
116 <td class="adm-detail-content-cell-l" style="width:25%;"><strong>' . Loc::getMessage(
'SALE_BASE_PRESET_ACTIVE_PERIOD') .
':</strong></td>
117 <td class="adm-detail-content-cell-r">' .
118 HtmlHelper::generateSelect(
119 'discount_type_sum_period',
121 self::TYPE_COUNT_PERIOD_ALL_TIME => Loc::getMessage(
"SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_TYPE_COUNT_PERIOD_ALL_TIME"),
122 self::TYPE_COUNT_PERIOD_INTERVAL => Loc::getMessage(
"SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_TYPE_COUNT_PERIOD_INTERVAL"),
123 self::TYPE_COUNT_PERIOD_RELATIVE => Loc::getMessage(
"SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_TYPE_COUNT_PERIOD_RELATIVE"),
125 $state[
'discount_type_sum_period']
130 <tr id="tr_interval_start" class="js-date-interval" style="display: none;">
131 <td class="adm-detail-content-cell-l" width="25%">' . Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_PERIOD_START') .
':</td>
132 <td class="adm-detail-content-cell-r" width="75%">' . \CAdminCalendar::CalendarDate(
'discount_sum_order_start', $state[
'discount_sum_order_start'], 19,
true) .
'</td>
134 <tr id="tr_interval_end" class="js-date-interval" style="display: none;">
135 <td class="adm-detail-content-cell-l" width="25%">' . Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_PERIOD_END') .
':</td>
136 <td class="adm-detail-content-cell-r" width="75%">' . \CAdminCalendar::CalendarDate(
'discount_sum_order_end', $state[
'discount_sum_order_end'], 19,
true) .
'</td>
138 <tr id="tr_relative" class="js-date-relative" style="display: none;">
139 <td class="adm-detail-content-cell-l" width="25%">' . Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_PERIOD_RELATIVE') .
':</td>
140 <td class="adm-detail-content-cell-r" width="75%"><input type="text" name="discount_sum_period_value" id="discount_sum_period_value" value="' . $state[
'discount_sum_period_value'] .
'" size="7" maxlength="10"> ' .
141 HtmlHelper::generateSelect(
'discount_sum_period_type',
143 'Y' => Loc::getMessage(
"SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_PERIOD_RELATIVE_Y"),
144 'M' => Loc::getMessage(
"SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_PERIOD_RELATIVE_M"),
145 'D' => Loc::getMessage(
"SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_PERIOD_RELATIVE_D"),
147 $state[
'discount_sum_period_type']
152 <td class="adm-detail-content-cell-l" style="width:25%;"><strong>' . Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_DONT_APPLY_IF_THERE_IS_DISCOUNTS') .
':</strong></td>
153 <td class="adm-detail-content-cell-r">
154 <input type="checkbox" name="discount_skip_if_there_were_discounts" value="Y" ' . ($state->get(
'discount_skip_if_there_were_discounts',
'N') ==
'Y'?
'checked' :
'') .
'>
158 <td class="adm-detail-content-cell-l" style="width:25%;"><strong>' . Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_APPLY_IF_MORE_PROFITABLE_DISCOUNT') .
':</strong></td>
159 <td class="adm-detail-content-cell-r">
160 <input type="checkbox" name="discount_apply_if_more_profitable" value="Y" ' . ($state->get(
'discount_apply_if_more_profitable',
'N') ==
'Y'?
'checked' :
'') .
'>
168 BX.bind(BX("discount_type_sum_period"), "change", function(){
169 var table = BX("count_period_table");
170 var trIntervalStart = BX("tr_interval_start");
171 var trIntervalEnd = BX("tr_interval_end");
172 var trRelative = BX("tr_relative");
176 case "' . self::TYPE_COUNT_PERIOD_ALL_TIME .
'":
177 BX.hide(trIntervalStart, "table-row");
178 BX.hide(trIntervalEnd, "table-row");
179 BX.hide(trRelative, "table-row");
182 case "' . self::TYPE_COUNT_PERIOD_INTERVAL .
'":
183 BX.hide(trRelative, "table-row");
184 BX.show(trIntervalStart, "table-row");
185 BX.show(trIntervalEnd, "table-row");
188 case "' . self::TYPE_COUNT_PERIOD_RELATIVE .
'":
189 BX.show(trRelative, "table-row");
190 BX.hide(trIntervalStart, "table-row");
191 BX.hide(trIntervalEnd, "table-row");
196 setTimeout(function(){
197 BX.fireEvent(BX("discount_type_sum_period"), "change");
204 protected function generateJavascript()
209 BX.bind(BX("clone_range"), "click", function(){
210 var row = BX("range_-1").cloneNode(true);
212 BX.insertAfter(row, BX.lastChild(BX("range_table")));
213 row.style.display = "";
220 protected function generateRows(State $state)
223 foreach ($state->get(
'discount_ranges', $this->getDefaultRowValues()) as
$i => $range)
226 ($range[
'sum'] ===
'' || $range[
'sum'] ===
null) ||
227 empty($range[
'value']) ||
228 empty($range[
'type'])
234 $html .= $this->generateRow(
$i, $range);
240 private function fillValueInsteadMarkedEmpty(&$value)
242 if ($value === self::MARK_DEFAULT_EMPTY_ROW)
248 protected function generateRow($index,
array $range, $style =
'')
250 $sum = $range[
'sum'] ??
'';
251 $value = $range[
'value'] ??
'';
252 $type = $range[
'type'] ??
'';
254 $this->fillValueInsteadMarkedEmpty(
$sum);
255 $this->fillValueInsteadMarkedEmpty($value);
256 $this->fillValueInsteadMarkedEmpty(
$type);
259 <tr id="range_' . $index .
'" style="' . $style .
'">
261 ' . Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_DISCOUNT_SUM_GREATER_THAN') .
'
262 <input type="text" name="range_sum[]" size="13" value="' .
$sum .
'">
265 <input type="text" name="range_value[]" size="13" value="' .
$value .
'">
266 ' . $this->generateSelectWithDiscountType(
"range_type[]",
$type) .
'
272 protected function generateSelectWithDiscountType(
$name, $selectedValue)
274 return HtmlHelper::generateSelect(
277 self::TYPE_PERCENT => Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_DISCOUNT_TYPE_PERCENT'),
278 self::TYPE_FIXED => Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_DISCOUNT_TYPE_VALUE'),
284 protected function buildRangesFromState(State $state)
287 $rangeSum = $state->get(
'range_sum',
array());
289 $rangeValue = $state->get(
'range_value',
array());
291 $rangeType = $state->get(
'range_type',
array());
294 foreach ($rangeSum as
$i => $item)
296 if (empty($rangeValue[
$i]) && empty($rangeSum[
$i]))
301 if (!isset($rangeValue[
$i]))
303 $this->errorCollection[] =
new Error(Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_ERROR_BAD_RANGE'));
308 $rangeValue[
$i] = str_replace(
",",
".", $rangeValue[
$i]);
309 $rangeValue[
$i] = doubleval($rangeValue[
$i]);
311 if ($rangeValue[
$i] <= 0)
313 $this->errorCollection[] =
new Error(Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_ERROR_RANGE_VALUE'));
318 if ($rangeType[
$i] === self::TYPE_PERCENT && $rangeValue[
$i] > 100)
320 $this->errorCollection[] =
new Error(Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_ERROR_RANGE_VALUE'));
326 'sum' => $rangeSum[
$i],
327 'value' => $rangeValue[
$i],
328 'type' => $rangeType[
$i]?: self::TYPE_PERCENT,
337 Main\Type\Collection::sortByColumn($matrix,
'sum');
340 foreach ($matrix as $row)
342 if ($row[
'sum'] === $prevSum)
344 $this->errorCollection[] =
new Error(Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_ERROR_RANGE_FROM_DUPLICATE'));
353 public function processSaveInputRanges(State $state)
355 $ranges = $this->buildRangesFromState($state);
356 $state[
'discount_ranges'] = $ranges;
360 unset($state[
'range_sum']);
361 unset($state[
'range_value']);
362 unset($state[
'range_type']);
365 switch ($state[
'discount_type_sum_period'])
367 case self::TYPE_COUNT_PERIOD_ALL_TIME:
368 unset($state[
'discount_sum_order_start']);
369 unset($state[
'discount_sum_order_end']);
370 unset($state[
'discount_sum_period_value']);
371 unset($state[
'discount_sum_period_type']);
374 case self::TYPE_COUNT_PERIOD_INTERVAL:
375 unset($state[
'discount_sum_period_value']);
376 unset($state[
'discount_sum_period_type']);
379 case self::TYPE_COUNT_PERIOD_RELATIVE:
380 unset($state[
'discount_sum_order_start']);
381 unset($state[
'discount_sum_order_end']);
386 if($state[
'discount_skip_if_there_were_discounts'] !==
'Y' || !$this->request->getPost(
'discount_skip_if_there_were_discounts'))
388 $state[
'discount_skip_if_there_were_discounts'] =
'N';
391 if($state[
'discount_apply_if_more_profitable'] !==
'Y' || !$this->request->getPost(
'discount_apply_if_more_profitable'))
393 $state[
'discount_apply_if_more_profitable'] =
'N';
398 $this->errorCollection[] =
new Error(Loc::getMessage(
'SALE_HANDLERS_DISCOUNTPRESET_ERROR_EMPTY_VALUE'));
401 if(!$this->errorCollection->isEmpty())
403 return array($state,
'InputRanges');
406 return array($state,
'CommonSettings');
411 $allowableUserGroups = parent::getAllowableUserGroups();
413 unset($allowableUserGroups[2]);
415 return $allowableUserGroups;
418 public function processShowCommonSettings(State $state)
423 public function processSaveCommonSettings(State $state)
428 public function generateState(
array $discountFields)
433 $stateFields =
array(
434 'discount_lid' => $discountFields[
'LID'],
435 'discount_name' => $discountFields[
'NAME'],
437 'discount_ranges' => ArrayHelper::getByPath($discountFields,
'ACTIONS.CHILDREN.0.DATA.ranges'),
438 'discount_type_sum_period' => ArrayHelper::getByPath($discountFields,
'ACTIONS.CHILDREN.0.DATA.type_sum_period'),
439 'discount_skip_if_there_were_discounts' => $firstChildrenControlId?
'Y' :
'',
440 'discount_apply_if_more_profitable' => ArrayHelper::getByPath($discountFields,
'ACTIONS.CHILDREN.0.DATA.apply_if_more_profitable'),
441 'discount_sum_order_start' =>
'',
442 'discount_sum_order_end' =>
'',
443 'discount_sum_period_value' =>
'',
444 'discount_sum_period_type' =>
'',
447 $periodData = ArrayHelper::getByPath($discountFields,
'ACTIONS.CHILDREN.0.DATA.sum_period_data',
array());
448 $stateFields = array_merge($stateFields, array_filter(array_intersect_key($periodData,
array(
449 'discount_sum_order_start' =>
true,
450 'discount_sum_order_end' =>
true,
451 'discount_sum_period_value' =>
true,
452 'discount_sum_period_type' =>
true,
455 return parent::generateState($discountFields)->append($stateFields);
458 public function generateDiscount(State $state)
461 'discount_sum_order_start' => $state[
'discount_sum_order_start'],
462 'discount_sum_order_end' => $state[
'discount_sum_order_end'],
463 'discount_sum_period_value' => $state[
'discount_sum_period_value'],
464 'discount_sum_period_type' => $state[
'discount_sum_period_type'],
467 $filterChildren =
array();
468 if ($state[
'discount_skip_if_there_were_discounts'] ===
'Y')
470 $filterChildren =
array(
481 return array_merge(parent::generateDiscount($state),
array(
482 'CONDITIONS' =>
array(
483 'CLASS_ID' =>
'CondGroup',
488 'CHILDREN' =>
array(),
491 'CLASS_ID' =>
'CondGroup',
497 'CLASS_ID' => \CSaleCumulativeAction::getControlID(),
499 'ranges' => $state[
'discount_ranges'],
500 'type_sum_period' => $state[
'discount_type_sum_period'],
501 'sum_period_data' => $periodData,
502 'apply_if_more_profitable' => $state[
'discount_apply_if_more_profitable'],
506 'CHILDREN' => $filterChildren,
516 protected function getDefaultRowValues()
520 'sum' => self::MARK_DEFAULT_EMPTY_ROW,
521 'value' => self::MARK_DEFAULT_EMPTY_ROW,
522 'type' => self::TYPE_PERCENT,
525 'sum' => self::MARK_DEFAULT_EMPTY_ROW,
526 'value' => self::MARK_DEFAULT_EMPTY_ROW,
527 'type' => self::TYPE_PERCENT,
530 'sum' => self::MARK_DEFAULT_EMPTY_ROW,
531 'value' => self::MARK_DEFAULT_EMPTY_ROW,
532 'type' => self::TYPE_PERCENT,
535 'sum' => self::MARK_DEFAULT_EMPTY_ROW,
536 'value' => self::MARK_DEFAULT_EMPTY_ROW,
537 'type' => self::TYPE_PERCENT,
normalizeDiscountFields(array $discountFields)
processSaveCommonSettingsInternal(State $state, $nextStep=self::FINAL_STEP)
processSaveInputNameInternal(State $state, $nextStep)
processShowInputNameInternal(State $state)
processShowCommonSettingsInternal(State $state)
getUserGroupsByDiscount($discountId)
const CONTROL_ID_APPLIED_DISCOUNT
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)