Your IP : 3.135.194.165
<?php
namespace Sale\Handlers\DiscountPreset;
use Bitrix\Main;
use Bitrix\Main\Error;
use Bitrix\Main\Localization\Loc;
use Bitrix\Sale\Discount\Actions;
use Bitrix\Sale\Discount\CumulativeCalculator;
use Bitrix\Sale\Discount\Preset\ArrayHelper;
use Bitrix\Sale\Discount\Preset\BasePreset;
use Bitrix\Sale\Discount\Preset\HtmlHelper;
use Bitrix\Sale\Discount\Preset\Manager;
use Bitrix\Sale\Discount\Preset\State;
Loc::loadMessages(__FILE__);
final class Cumulative extends BasePreset
{
const TYPE_FIXED = Actions::VALUE_TYPE_FIX;
const TYPE_PERCENT = Actions::VALUE_TYPE_PERCENT;
const TYPE_COUNT_PERIOD_ALL_TIME = CumulativeCalculator::TYPE_COUNT_PERIOD_ALL_TIME;
const TYPE_COUNT_PERIOD_INTERVAL = CumulativeCalculator::TYPE_COUNT_PERIOD_INTERVAL;
const TYPE_COUNT_PERIOD_RELATIVE = CumulativeCalculator::TYPE_COUNT_PERIOD_RELATIVE;
const MARK_DEFAULT_EMPTY_ROW = PHP_INT_MIN;
public function getTitle()
{
return Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_NAME');
}
public function getDescription()
{
return '';
}
/**
* Tells if preset is available or not. It's possible that preset can't work in some license.
* @return bool
*/
public function isAvailable()
{
return \CBXFeatures::isFeatureEnabled('CatDiscountSave');
}
/**
* @return int
*/
public function getCategory()
{
return Manager::CATEGORY_PRODUCTS;
}
public function getFirstStepName()
{
return 'InputName';
}
public function processShowInputName(State $state)
{
return $this->processShowInputNameInternal($state);
}
public function processSaveInputName(State $state)
{
return $this->processSaveInputNameInternal($state, 'InputRanges');
}
public function processShowInputRanges(State $state)
{
$lid = $state->get('discount_lid');
$currency = \CSaleLang::getLangCurrency($lid);
$rows = $this->generateRows($state);
$templateRow = $this->generateRow(-1, array(), 'display: none');
return $this->generateJavascript() . '
<table width="100%" border="0" cellspacing="7" cellpadding="0">
<tbody>
<tr>
<td class="adm-detail-content-cell-l" style="width:25%;"><strong>' . Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_LABEL_RANGES') . ':</strong></td>
<td class="adm-detail-content-cell-r" style="width:75%;">
<table id="range_table" style="width: auto;" class="internal" border="0" cellspacing="7" cellpadding="0">
<tbody>
<tr class="heading">
<td align="center">' . Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_H_SUM', array('#CURRENCY#' => $currency,)) . '</td>
<td align="center">' . Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_H_DISCOUNT_VALUE') . '</td>
</tr>
' . $rows . '
' . $templateRow . '
</table>
<div style="width: 100%; text-align: left; margin-top: 10px;">
<input id="clone_range" class="adm-btn" type="button" value="' . Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_DISCOUNT_ADD_RANGE') . '">
</div>
</td>
</tr>
<tr>
<td class="adm-detail-content-cell-l" style="width:25%;"><strong>' . Loc::getMessage('SALE_BASE_PRESET_ACTIVE_PERIOD') . ':</strong></td>
<td class="adm-detail-content-cell-r">' .
HtmlHelper::generateSelect(
'discount_type_sum_period',
array(
self::TYPE_COUNT_PERIOD_ALL_TIME => Loc::getMessage("SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_TYPE_COUNT_PERIOD_ALL_TIME"),
self::TYPE_COUNT_PERIOD_INTERVAL => Loc::getMessage("SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_TYPE_COUNT_PERIOD_INTERVAL"),
self::TYPE_COUNT_PERIOD_RELATIVE => Loc::getMessage("SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_TYPE_COUNT_PERIOD_RELATIVE"),
),
$state['discount_type_sum_period']
) . '
</td>
</tr>
<tr id="tr_interval_start" class="js-date-interval" style="display: none;">
<td class="adm-detail-content-cell-l" width="25%">' . Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_PERIOD_START') . ':</td>
<td class="adm-detail-content-cell-r" width="75%">' . \CAdminCalendar::CalendarDate('discount_sum_order_start', $state['discount_sum_order_start'], 19, true) . '</td>
</tr>
<tr id="tr_interval_end" class="js-date-interval" style="display: none;">
<td class="adm-detail-content-cell-l" width="25%">' . Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_PERIOD_END') . ':</td>
<td class="adm-detail-content-cell-r" width="75%">' . \CAdminCalendar::CalendarDate('discount_sum_order_end', $state['discount_sum_order_end'], 19, true) . '</td>
</tr>
<tr id="tr_relative" class="js-date-relative" style="display: none;">
<td class="adm-detail-content-cell-l" width="25%">' . Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_PERIOD_RELATIVE') . ':</td>
<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"> ' .
HtmlHelper::generateSelect('discount_sum_period_type',
array(
'Y' => Loc::getMessage("SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_PERIOD_RELATIVE_Y"),
'M' => Loc::getMessage("SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_PERIOD_RELATIVE_M"),
'D' => Loc::getMessage("SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_PERIOD_RELATIVE_D"),
),
$state['discount_sum_period_type']
) . '
</td>
</tr>
<tr>
<td class="adm-detail-content-cell-l" style="width:25%;"><strong>' . Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_DONT_APPLY_IF_THERE_IS_DISCOUNTS') . ':</strong></td>
<td class="adm-detail-content-cell-r">
<input type="checkbox" name="discount_skip_if_there_were_discounts" value="Y" ' . ($state->get('discount_skip_if_there_were_discounts', 'N') == 'Y'? 'checked' : '') . '>
</td>
</tr>
<tr>
<td class="adm-detail-content-cell-l" style="width:25%;"><strong>' . Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_APPLY_IF_MORE_PROFITABLE_DISCOUNT') . ':</strong></td>
<td class="adm-detail-content-cell-r">
<input type="checkbox" name="discount_apply_if_more_profitable" value="Y" ' . ($state->get('discount_apply_if_more_profitable', 'N') == 'Y'? 'checked' : '') . '>
</td>
</tr>
</tbody>
</table>
<script type="text/javascript">
BX.ready(function(){
BX.bind(BX("discount_type_sum_period"), "change", function(){
var table = BX("count_period_table");
var trIntervalStart = BX("tr_interval_start");
var trIntervalEnd = BX("tr_interval_end");
var trRelative = BX("tr_relative");
switch(this.value)
{
case "' . self::TYPE_COUNT_PERIOD_ALL_TIME . '":
BX.hide(trIntervalStart, "table-row");
BX.hide(trIntervalEnd, "table-row");
BX.hide(trRelative, "table-row");
break;
case "' . self::TYPE_COUNT_PERIOD_INTERVAL . '":
BX.hide(trRelative, "table-row");
BX.show(trIntervalStart, "table-row");
BX.show(trIntervalEnd, "table-row");
break;
case "' . self::TYPE_COUNT_PERIOD_RELATIVE . '":
BX.show(trRelative, "table-row");
BX.hide(trIntervalStart, "table-row");
BX.hide(trIntervalEnd, "table-row");
break;
}
});
setTimeout(function(){
BX.fireEvent(BX("discount_type_sum_period"), "change");
}, 300);
})
</script>
';
}
protected function generateJavascript()
{
return '
<script type="text/javascript">
BX.ready(function(){
BX.bind(BX("clone_range"), "click", function(){
var row = BX("range_-1").cloneNode(true);
row.id = "";
BX.insertAfter(row, BX.lastChild(BX("range_table")));
row.style.display = "";
});
});
</script>
';
}
protected function generateRows(State $state)
{
$html = '';
foreach ($state->get('discount_ranges', $this->getDefaultRowValues()) as $i => $range)
{
if (
empty($range['sum']) ||
empty($range['value']) ||
empty($range['type'])
)
{
continue;
}
$html .= $this->generateRow($i, $range);
}
return $html;
}
private function fillValueInsteadMarkedEmpty(&$value)
{
if ($value === self::MARK_DEFAULT_EMPTY_ROW)
{
$value = '';
}
}
protected function generateRow($index, array $range, $style = '')
{
$sum = $range['sum'];
$value = $range['value'];
$type = $range['type'];
$this->fillValueInsteadMarkedEmpty($sum);
$this->fillValueInsteadMarkedEmpty($value);
$this->fillValueInsteadMarkedEmpty($type);
return '
<tr id="range_' . $index . '" style="' . $style . '">
<td>
' . Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_DISCOUNT_SUM_GREATER_THAN') . '
<input type="text" name="range_sum[]" size="13" value="' . $sum . '">
</td>
<td>
<input type="text" name="range_value[]" size="13" value="' . $value . '">
' . $this->generateSelectWithDiscountType("range_type[]", $type) . '
</td>
</tr>
';
}
protected function generateSelectWithDiscountType($name, $selectedValue)
{
return HtmlHelper::generateSelect(
$name,
array(
self::TYPE_PERCENT => Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_DISCOUNT_TYPE_PERCENT'),
self::TYPE_FIXED => Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_DISCOUNT_TYPE_VALUE'),
),
$selectedValue
);
}
protected function buildRangesFromState(State $state)
{
/** @var array $rangeSum */
$rangeSum = $state->get('range_sum', array());
/** @var array $rangeValue */
$rangeValue = $state->get('range_value', array());
/** @var array $rangeType */
$rangeType = $state->get('range_type', array());
$matrix = array();
foreach ($rangeSum as $i => $item)
{
if (empty($rangeValue[$i]) && empty($rangeSum[$i]))
{
continue;
}
if (!isset($rangeValue[$i]))
{
$this->errorCollection[] = new Error(Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_ERROR_BAD_RANGE'));
return null;
}
$rangeValue[$i] = str_replace(",", ".", $rangeValue[$i]);
$rangeValue[$i] = doubleval($rangeValue[$i]);
if ($rangeValue[$i] <= 0)
{
$this->errorCollection[] = new Error(Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_ERROR_RANGE_VALUE'));
return null;
}
if ($rangeType[$i] === self::TYPE_PERCENT && $rangeValue[$i] > 100)
{
$this->errorCollection[] = new Error(Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_ERROR_RANGE_VALUE'));
return null;
}
$matrix[] = array(
'sum' => $rangeSum[$i],
'value' => $rangeValue[$i],
'type' => $rangeType[$i]?: self::TYPE_PERCENT,
);
}
if (!$matrix)
{
return null;
}
Main\Type\Collection::sortByColumn($matrix, 'sum');
$prevSum = null;
foreach ($matrix as $row)
{
if ($row['sum'] === $prevSum)
{
$this->errorCollection[] = new Error(Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_CUMULATIVE_ERROR_RANGE_FROM_DUPLICATE'));
return null;
}
}
return $matrix;
}
public function processSaveInputRanges(State $state)
{
$ranges = $this->buildRangesFromState($state);
$state['discount_ranges'] = $ranges;
if ($ranges)
{
unset($state['range_sum']);
unset($state['range_value']);
unset($state['range_type']);
}
switch ($state['discount_type_sum_period'])
{
case self::TYPE_COUNT_PERIOD_ALL_TIME:
unset($state['discount_sum_order_start']);
unset($state['discount_sum_order_end']);
unset($state['discount_sum_period_value']);
unset($state['discount_sum_period_type']);
break;
case self::TYPE_COUNT_PERIOD_INTERVAL:
unset($state['discount_sum_period_value']);
unset($state['discount_sum_period_type']);
break;
case self::TYPE_COUNT_PERIOD_RELATIVE:
unset($state['discount_sum_order_start']);
unset($state['discount_sum_order_end']);
break;
}
if($state['discount_skip_if_there_were_discounts'] !== 'Y' || !$this->request->getPost('discount_skip_if_there_were_discounts'))
{
$state['discount_skip_if_there_were_discounts'] = 'N';
}
if($state['discount_apply_if_more_profitable'] !== 'Y' || !$this->request->getPost('discount_apply_if_more_profitable'))
{
$state['discount_apply_if_more_profitable'] = 'N';
}
if(!$ranges)
{
$this->errorCollection[] = new Error(Loc::getMessage('SALE_HANDLERS_DISCOUNTPRESET_ERROR_EMPTY_VALUE'));
}
if(!$this->errorCollection->isEmpty())
{
return array($state, 'InputRanges');
}
return array($state, 'CommonSettings');
}
protected function getAllowableUserGroups()
{
$allowableUserGroups = parent::getAllowableUserGroups();
unset($allowableUserGroups[2]); //There is nonsense to use cumulative discounts for guests.
return $allowableUserGroups;
}
public function processShowCommonSettings(State $state)
{
return $this->processShowCommonSettingsInternal($state);
}
public function processSaveCommonSettings(State $state)
{
return $this->processSaveCommonSettingsInternal($state);
}
public function generateState(array $discountFields)
{
$discountFields = $this->normalizeDiscountFields($discountFields);
$firstChildrenControlId = ArrayHelper::getByPath($discountFields, 'ACTIONS.CHILDREN.0.CHILDREN.0.CLASS_ID') === \CSaleActionCondCtrlBasketFields::CONTROL_ID_APPLIED_DISCOUNT;
$stateFields = array(
'discount_lid' => $discountFields['LID'],
'discount_name' => $discountFields['NAME'],
'discount_groups' => $this->getUserGroupsByDiscount($discountFields['ID']),
'discount_ranges' => ArrayHelper::getByPath($discountFields, 'ACTIONS.CHILDREN.0.DATA.ranges'),
'discount_type_sum_period' => ArrayHelper::getByPath($discountFields, 'ACTIONS.CHILDREN.0.DATA.type_sum_period'),
'discount_skip_if_there_were_discounts' => $firstChildrenControlId? 'Y' : '',
'discount_apply_if_more_profitable' => ArrayHelper::getByPath($discountFields, 'ACTIONS.CHILDREN.0.DATA.apply_if_more_profitable'),
'discount_sum_order_start' => '',
'discount_sum_order_end' => '',
'discount_sum_period_value' => '',
'discount_sum_period_type' => '',
);
$periodData = ArrayHelper::getByPath($discountFields, 'ACTIONS.CHILDREN.0.DATA.sum_period_data', array());
$stateFields = array_merge($stateFields, array_filter(array_intersect_key($periodData, array(
'discount_sum_order_start' => true,
'discount_sum_order_end' => true,
'discount_sum_period_value' => true,
'discount_sum_period_type' => true,
))));
return parent::generateState($discountFields)->append($stateFields);
}
public function generateDiscount(State $state)
{
$periodData = array(
'discount_sum_order_start' => $state['discount_sum_order_start'],
'discount_sum_order_end' => $state['discount_sum_order_end'],
'discount_sum_period_value' => $state['discount_sum_period_value'],
'discount_sum_period_type' => $state['discount_sum_period_type'],
);
$filterChildren = array();
if ($state['discount_skip_if_there_were_discounts'] === 'Y')
{
$filterChildren = array(
array(
'CLASS_ID' => \CSaleActionCondCtrlBasketFields::CONTROL_ID_APPLIED_DISCOUNT,
'DATA' => array(
'logic' => 'Equal',
'value' => 'N',
),
)
);
}
return array_merge(parent::generateDiscount($state), array(
'CONDITIONS' => array(
'CLASS_ID' => 'CondGroup',
'DATA' => array(
'All' => 'AND',
'True' => 'True',
),
'CHILDREN' => array(),
),
'ACTIONS' => array(
'CLASS_ID' => 'CondGroup',
'DATA' => array(
'All' => 'AND',
),
'CHILDREN' => array(
array(
'CLASS_ID' => \CSaleCumulativeAction::getControlID(),
'DATA' => array(
'ranges' => $state['discount_ranges'],
'type_sum_period' => $state['discount_type_sum_period'],
'sum_period_data' => $periodData,
'apply_if_more_profitable' => $state['discount_apply_if_more_profitable'],
'All' => 'AND',
'True' => 'True',
),
'CHILDREN' => $filterChildren,
),
),
),
));
}
/**
* @return array
*/
protected function getDefaultRowValues()
{
return array(
array(
'sum' => self::MARK_DEFAULT_EMPTY_ROW,
'value' => self::MARK_DEFAULT_EMPTY_ROW,
'type' => self::TYPE_PERCENT,
),
array(
'sum' => self::MARK_DEFAULT_EMPTY_ROW,
'value' => self::MARK_DEFAULT_EMPTY_ROW,
'type' => self::TYPE_PERCENT,
),
array(
'sum' => self::MARK_DEFAULT_EMPTY_ROW,
'value' => self::MARK_DEFAULT_EMPTY_ROW,
'type' => self::TYPE_PERCENT,
),
array(
'sum' => self::MARK_DEFAULT_EMPTY_ROW,
'value' => self::MARK_DEFAULT_EMPTY_ROW,
'type' => self::TYPE_PERCENT,
),
);
}
}