--- /dev/null
+<?php
+
+use yii\db\Migration;
+
+/**
+ * BR-132: Расширение поля code до 20 символов для формата PROMO-XXXX-XXXX.
+ */
+class m260220_120000_alter_promocode_code_length extends Migration
+{
+ public function safeUp()
+ {
+ $this->alterColumn('{{%erp24.promocode}}', 'code', $this->string(20)->notNull()->comment('Промокод'));
+ }
+
+ public function safeDown()
+ {
+ $this->alterColumn('{{%erp24.promocode}}', 'code', $this->string(13)->notNull()->comment('Промокод'));
+ }
+}
const BASE_BASE = 1;
const BASE_SINGLE_USE = 2;
+ const FORMAT_DIGITS = 'digits';
+ const FORMAT_ALPHANUMERIC = 'alphanumeric';
+
public $generatePromocodeCount;
+ public $generateFormat = self::FORMAT_DIGITS;
public static function tableName() { return 'promocode'; }
public function rules() {
return [
[['code', 'bonus', 'duration', 'active', 'date_start', 'date_end', 'created_by', 'created_at'], 'required'],
- [['code'], 'string', 'max' => 13],
+ [['code'], 'string', 'max' => 20],
[['bonus', 'duration', 'active', 'used', 'base', 'parent_id', 'created_by', 'updated_by'], 'integer'],
[['date_start', 'date_end', 'created_at', 'updated_at'], 'datetime', 'format' => 'php:Y-m-d H:i:s'],
- [['updated_by', 'updated_at', 'generatePromocodeCount'], 'safe'],
+ [['updated_by', 'updated_at', 'generatePromocodeCount', 'generateFormat'], 'safe'],
+ ['generateFormat', 'in', 'range' => [self::FORMAT_DIGITS, self::FORMAT_ALPHANUMERIC]],
];
}
class PromocodeService
{
+ /** Без 0, O, 1, l, I — исключают путаницу при ручном вводе */
+ private const SAFE_CHARSET = 'ABCDEFGHJKMNPQRSTUVWXYZ23456789';
+
private static function generateThreeNums() {
return (rand() % 10) . (rand() % 10) . (rand() % 10);
}
+ private static function generateAlphanumericGroup(int $length = 4): string
+ {
+ $charset = self::SAFE_CHARSET;
+ $max = strlen($charset) - 1;
+ $group = '';
+ for ($i = 0; $i < $length; $i++) {
+ $group .= $charset[random_int(0, $max)];
+ }
+ return $group;
+ }
+
+ private static function generateSuffix(string $format): string
+ {
+ if ($format === Promocode::FORMAT_ALPHANUMERIC) {
+ return '-' . self::generateAlphanumericGroup(4) . '-' . self::generateAlphanumericGroup(4);
+ }
+ return self::generateThreeNums();
+ }
+
public static function generateSingleUsePromocodes(Promocode $basePromocode) {
+ $format = $basePromocode->generateFormat ?: Promocode::FORMAT_DIGITS;
+
foreach (range(1, $basePromocode->generatePromocodeCount) as $num) {
- $word = self::generateThreeNums();
- while (Promocode::find()->where(['code' => $basePromocode->code . $word])->one()) {
- $word = self::generateThreeNums();
+ $suffix = self::generateSuffix($format);
+ $code = mb_strtoupper($basePromocode->code . $suffix, 'UTF-8');
+ while (Promocode::find()->where(['code' => $code])->exists()) {
+ $suffix = self::generateSuffix($format);
+ $code = mb_strtoupper($basePromocode->code . $suffix, 'UTF-8');
}
$singleUsePromocode = new Promocode;
- $singleUsePromocode->code = mb_strtoupper($basePromocode->code . $word, 'UTF-8');
+ $singleUsePromocode->code = $code;
$singleUsePromocode->bonus = $basePromocode->bonus;
$singleUsePromocode->duration = $basePromocode->duration;
$singleUsePromocode->active = $basePromocode->active;
<?php if ($model->base < 2): ?>
<?php PrintBlockHelper::printBlock('Количество дополнительных одноразовых промокодов', $form->field($model, 'generatePromocodeCount')->textInput(['type' => 'number'])->label(false)) ?>
+ <?php PrintBlockHelper::printBlock('Формат генерации кодов', $form->field($model, 'generateFormat')->dropDownList([
+ Promocode::FORMAT_DIGITS => 'Цифровой (CODE123)',
+ Promocode::FORMAT_ALPHANUMERIC => 'Буквенно-цифровой (CODE-XXXX-XXXX, без 0/O/1/l)',
+ ])->label(false)) ?>
<?php endif; ?>
<div class="form-group">