За последние 24 часа нас посетили 22295 программистов и 1165 роботов. Сейчас ищут 690 программистов ...

Короткий уникальный номер заказа

Тема в разделе "PHP и базы данных", создана пользователем zhenia3003, 22 ноя 2019.

  1. zhenia3003

    zhenia3003 Активный пользователь

    С нами с:
    20 авг 2012
    Сообщения:
    179
    Симпатии:
    3
    Приветствую!
    Подскажите как сделать уникальный номер заказа - A001, А002, А003.. когда число доходит до А999, меняем букву В001, В002 и тд, все это будет записываться в БД, где нужно проверить номер на уникальность
     
  2. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    Сгенерируй таблицу в БД с двумя полями идентификатор и желаемые номера. Обращайся к таблице когда надо получить очередной номер.
     
  3. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.825
    Симпатии:
    738
    Адрес:
    Татарстан
    Нафига себе гемморой придумывать?
    Использовать в качестве номера заказа обычный id autoincrement который уникальный в БД
    но если хочется прям извращаться
    1. поле в БД - unique
    2. Если нет ни одной записи - генерим первую
    3. Если есть - считываем последнюю, разбиваем на первый символ и число, числ + 1, если выходит за 999, то число = 001 а символ первый на следующий меняем

    но это такой гемор... а что - когда символы кончатся? а это обязательно случится
    + 1 запрос всегда для формирования нового номера заказа
     
  4. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    Никакого геморроя нет.
    полный номер может выглядеть например так 2019-А001 или так 2019-11-А015
    такие номера гораздо легче воспринимаются человеком в отличии от голого id autoincrement (который должен быть в самой системе обязательно, но на уровне кода)
     
  5. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    PHP:
    1. function getNextOrder($prev) {
    2.   $res = preg_match('/^([a-z]+)(\d+)$/i', $prev, $matches);
    3.    if(!$res) {
    4.      throw new Exception('Wrong order format');
    5.    }
    6.    list(,$prefix, $num) = $matches;
    7.    if($num == 999) {
    8.      $prefix++;
    9.      $num = 0;
    10.    }
    11.    return $prefix . sprintf('%03d', ++$num);
    12. }
    13. echo getNextOrder('Z999'); // AA001
     
    artoodetoo нравится это.
  6. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
  7. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.591
    Симпатии:
    360
    @zhenia3003, например, в MySql есть last_insert_id().
    Тогда можно сделать таким образом:
    Код (Text):
    1. -- табличка:
    2. CREATE TABLE `sequence` (
    3.   `letter` varchar(1) NOT NULL,
    4.   `number` int(11) NOT NULL
    5. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    6. -- инициализация
    7. insert into sequence values('A',0);
    8. -- триггер
    9. CREATE TRIGGER `sequence_BEFORE_UPDATE` BEFORE UPDATE ON `sequence` FOR EACH ROW
    10. begin
    11. if new.number > 999 then
    12.     set new.number = 1;
    13.     set new.letter = char(ord(old.letter)+1);
    14. end if;
    15. end
    16. -- получение нового значения:
    17. update sequence set number = last_insert_id(`number` + 1);
    18. select concat(`letter`,'-',lpad(case when last_insert_id()=1000 then 1 else last_insert_id() end,3,'0')) as docnumber from sequence;
    Впрочем, как всегда - надо проверять :)
     
  8. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    Триггеры, спец таблицы... вам не кажется что вы слишком усложняете?

    В чем суть задачи? Показать юзеру короткий и удобный, при этом уникальный номер заказа. Плюс хочется чтобы на уровне БД, для заказов, юзался быстрый INTEGER ключ. так?

    Всё элементарно. У нас есть таблица заказов, и там УЖЕ есть PK. те дополнительно ничего придумывать в БД не надо.
    осталось придумать как показать юзеру красивый номер заказа. и вот это мы можем делать уже на уровне php, например так:

    PHP:
    1. function idToHumanFriendly($orderId) {
    2.     $prefix = floor($orderId/999);
    3.     $orderTail = $orderId - 999 * $prefix;
    4.     // Convert integer to letters
    5.     $letters = array_merge(range('A', 'Z'));
    6.     $base = sizeof($letters);
    7.     $head = '';
    8.     while($prefix >= $base) {
    9.         $d1 = floor($prefix/$base);
    10.         $ost = $prefix-$d1*$base;
    11.         $prefix = $d1;
    12.         $head .= $letters[$ost];
    13.     }
    14.     return strrev($head . $letters[$prefix]) . sprintf('%03d', $orderTail);
    15. }
    16.  
    17. $orderId = 102304; // ID from DB
    18. $humanFriendlyOrderId = idToHumanFriendly($orderId);
    19. echo $humanFriendlyOrderId; // DY406
    и всё! все довольны.
     
    artoodetoo нравится это.
  9. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    @runcore, триггеры лишние совершенно согласен. Но вот на счёт всего остального, я вообще не понимаю почему приходится что-то объяснять.
    @runcore, уникальный номер заказа, это не просто " показать на сайте". Своими махинациями, вы можете убить уникальность.
     
  10. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    уникальность обеспечивается свойствами PK INTEGER autoincrement.
    Функция реализует лишь дополнительный вариант отображения(удобный для человека), упаковывая число в структуру с большим количеством возможных символов.
     
  11. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Вы решаете задачу как программисты. А ещё есть правила документопроизводства. В частности, вполне могут быть правила строгой последовательности нумерации. И тогда, если дырка в нумерации, то это ЧП, ибо это потеря документа.
    С другой стороны, ТС просто спросил, как сделать такую, буквенно-цифровую, нумерацию, без особых ограничений. И в этом случае самый простой вариант будет самым оптимальным.

    Кстати, поле с AUTO_INCREMENT использовать для нумерации документов нельзя в принципе. Независимо, допустимы дырки или нет.
     
  12. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Почему?
     
  13. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Если на уровне PHP, то можно использовать его особенность.
    Как у @runcore, только проще. Например, так:
    PHP:
    1. $docNum = 'A999'; // Это предыдущий номер
    2. $docNum = preg_replace('/0$/', '1', ++$docNum); // B001
     
  14. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    нельзя
     
  15. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Автоинкремент может меняться как хочет и когда хочет - база не пострадает, если всё сделано правильно.
    А номер документа назначается единожды и не может быть изменён (пресловутое делопроизводство).
    --- Добавлено ---
    Убеди.
     
  16. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Я надеялся услышать что-то более вменяемое.
    Ты не путаешь процесс и состояние?
    Что значит автоинкремент может меняться? Мы создали запись с определенным ключём. Гарантируется что это значение уникально. Пусть автоинкремент после этого меняется как угодно. Плевать. Первичный ключ по определению уникален.
     
  17. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Предполагаю, что это ты путаешь базу с делопроизводством.
    Первичен Документ, а база это просто информация о нём. Почитай, например, о правилах ведения бухгалтерии предприятий, для понимания.
     
  18. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Я ничего не путаю. Это ты неудачно ответил, а теперь уворачиваешся. :)
    Я про делопроизводство знаю столько, что мог бы народ учить. Сертифицированный разработчик и админ ЭДО. Только не моё это.
     
  19. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    Это обычное поведение @Chushkin'a. За много лет удачных ответов я от него не видел вообще. Тут даже по теории вероятности они должны были бы быть, но их нет.
     
  20. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    "Каждый заблуждается в меру своих возможностей" ;) (с) не мой
    Удачи в поисках...
     
  21. Дюран

    Дюран Активный пользователь

    С нами с:
    9 мар 2018
    Сообщения:
    257
    Симпатии:
    19
    Твой код не работает.
    На A099 следующую выдает A101
     
  22. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    @Дюран, даже если бы он работал, он всё равно логически не верный. @runcore предложил единственно верный вариант - это строгое соответствие идентификатору (я сначала не понял, думал он тоже инкрементит, но ошибся), о котором я говорил с самого начала, только я говорил о том, что нет нужды тащить это на уровень РНР, всё можно прекрасно сделать на уровне СУРБД.
     
  23. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Угу, не работает. :(
    А так?
    PHP:
    1. $docNum = 'A999'; // Это предыдущий номер
    2. $docNum = preg_replace('/(\D[0]*)0$/U', '${1}1', ++$docNum); // B001
    3. $docNum = 'A099';
    4. $docNum = preg_replace('/(\D[0]*)0$/U', '${1}1', ++$docNum); // A100
     
  24. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    PHP:
    1. <?php
    2. ini_set('display_errors', 'On');
    3. header('Content-Type: text/html; charset=utf-8');
    4.  
    5. /**
    6. * Модель
    7. */
    8. // Подключение к базе данных
    9. // можно вынести в отдельный файл вместе с параметрами подключения
    10. // и подключать в скриптах при помощи require_once
    11. function connectDB(){
    12.     $mysqli = @new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
    13.     if ($mysqli->connect_error) {
    14.         throw new Exception('Невозможно подключиться к серверу БД: ' . $mysqli->connect_error);
    15.     }
    16.     $mysqli->query('set names utf8');
    17.     if ($mysqli->error) {
    18.         throw new Exception('Невозможно установить кодировку подключения к БД: ' . $mysqli->error);
    19.     }
    20.     return $mysqli;
    21. }
    22. // Создание таблицы с номерами заказов
    23. function createIdentifierTable($mysqli) {
    24.     $mysqli->query("CREATE TABLE IF NOT EXISTS `test`.`identifier` (
    25.                    `id` INT(5) NOT NULL ,
    26.                    `order` CHAR(4) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
    27.                    PRIMARY KEY (`id`)) ENGINE = InnoDB;");
    28.     if ($mysqli->error) {
    29.         throw new Exception('Ошибка создания таблицы: ' . $mysqli->error);
    30.     }
    31.     $mysqli->query("TRUNCATE TABLE `test`.`identifier`");
    32.     if ($mysqli->error) {
    33.         throw new Exception('Ошибка очистки таблицы: ' . $mysqli->error);
    34.     }
    35.     $counter = 0;
    36.     for($i = 65; $i <= 90; $i++) {
    37.         for($n = 1; $n < 1000; $n++) {
    38.             $insertValue[++$counter] = "(" . $counter . ", '" .  chr($i) . sprintf('%03d', $n) . "')";
    39.         }
    40.     }
    41.     $query = "INSERT INTO `test`.`identifier` (`id`, `order`) VALUES " . implode(', ', $insertValue);
    42.     $mysqli->query($query);
    43.     if ($mysqli->error) {
    44.         throw new Exception('Ошибка добавления данных в таблицу: ' . $mysqli->error);
    45.     }
    46. }
    47. // Создание таблицы заказов
    48. function createOrderTable($mysqli) {
    49.     $mysqli->query("CREATE TABLE IF NOT EXISTS `test`.`order` (
    50.                    `id` INT(5) NOT NULL AUTO_INCREMENT ,
    51.                    `order` CHAR(4) CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
    52.                    `title` VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
    53.                    PRIMARY KEY (`id`)) ENGINE = InnoDB;");
    54.     if ($mysqli->error) {
    55.         throw new Exception('Ошибка создания таблицы: ' . $mysqli->error);
    56.     }
    57.     $mysqli->query("TRUNCATE TABLE `test`.`order`");
    58.     if ($mysqli->error) {
    59.         throw new Exception('Ошибка очистки таблицы: ' . $mysqli->error);
    60.     }
    61. }
    62. // Получение заказов из базы данных
    63. function getOrder($mysqli) {
    64.     $query = "SELECT `id`, `order`, `title` FROM `order` WHERE `order` IS NOT NULL";
    65.     $result = $mysqli->query($query);
    66.     if ($mysqli->error) {
    67.         throw new Exception('Ошибка выборки из базы данных: ' . $mysqli->error);
    68.     }
    69.     if ($result->num_rows > 0) {
    70.         while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
    71.             $table[] = '<td>'
    72.                     . $row['id']
    73.                     .  '</td><td>'
    74.                     . $row['order']
    75.                     . '</td><td>'
    76.                     . $row['title']
    77.                     . '</td>'
    78.                     . '<td><a href="?action=del_order&id=' . $row['id'] . '">Удалить</a></td>'
    79.                     . PHP_EOL;
    80.         }
    81.         return '<tr>' . PHP_EOL . implode('</tr>' . PHP_EOL . '<tr>' . PHP_EOL , $table) . '</tr>' . PHP_EOL;
    82.     }
    83. }
    84. // Создание заказа
    85. function addOrder($mysqli, $title) {
    86.     if (empty($title)) {
    87.         return false;
    88.     }
    89.     $title = $mysqli->real_escape_string($title);
    90.     $query = "INSERT INTO `order` (`title`) VALUES('" . $title . "')";
    91.     $result = $mysqli->query($query);
    92.     if ($mysqli->error) {
    93.         throw new Exception('Ошибка добавления записи в базу данных: ' . $mysqli->error);
    94.     }
    95.     if ($mysqli->affected_rows > 0) {
    96.         $query = "UPDATE `order` o
    97.                    LEFT JOIN `identifier` i USING (`id`)
    98.                    SET o.order = i.order
    99.                    WHERE o.id = LAST_INSERT_ID()";
    100.         $result = $mysqli->query($query);
    101.         if ($mysqli->affected_rows > 0) {
    102.             return true;
    103.         }
    104.         throw new Exception('Не удалось присвоить уникальный номер заказа');
    105.     }
    106. }
    107. // Удаление заказа
    108. function delOrder($mysqli, $id) {
    109.     if ($id = (int)$id) {
    110.         $query = "UPDATE `order` SET `order` = NULL WHERE id = " . $id . " LIMIT 1";
    111.         $result = $mysqli->query($query);
    112.         if ($mysqli->error) {
    113.             throw new Exception('Ошибка "удаления" заказа из базы данных: ' . $mysqli->error);
    114.         }
    115.         return true;
    116.     }
    117.     return false;
    118. }
    119. // Восстановление заказа
    120. function restOrder($mysql, $id) {
    121.     // В качестве домашнего задания написать функцию восстановления заказа
    122. }
    123. /**
    124. * Контроллер
    125. */
    126. try {
    127.     // Инициализация переменных
    128.     $table = false;
    129.     $action = false;
    130.     $template = false;
    131.     $array_action = [
    132.         'order'     => 'order',
    133.         'add_order' => 'add_order',
    134.         'del_order' => 'del_order',
    135.     ];
    136.  
    137.     // Параметры подключения к базе данных
    138.     define('DB_HOST', 'localhost');
    139.     define('DB_USER', 'mysql');
    140.     define('DB_PASSWORD', 'mysql');
    141.     define('DB_NAME', 'test');
    142.  
    143.     // Устанавливаем соединение с базой данных
    144.     $mysqli = connectDB();
    145.  
    146.     // Инициализация таблиц базы данных
    147.     if ($_REQUEST['create_db']??false == 'yes') {
    148.         createOrderTable($mysqli);
    149.         createIdentifierTable($mysqli);
    150.         header("Location: " . $_SERVER['PHP_SELF'] . '?action=order');
    151.     }
    152.  
    153.     // Обработка параметра action
    154.     if ($_REQUEST['action']??false) {
    155.         $action = $array_action[$_REQUEST['action']]??false;
    156.     }
    157.  
    158.     switch ($action) {
    159.         case 'order':
    160.             $template = 'order';
    161.             $table = getOrder($mysqli);
    162.             break;
    163.         case 'add_order':
    164.             $template = 'add_order';
    165.             $title = trim($_POST['title']??false);
    166.             if (!empty($title) && addOrder($mysqli, $title)) {
    167.                 header("Location: " . $_SERVER['PHP_SELF'] . '?action=order');
    168.             }
    169.             break;
    170.         case 'del_order':
    171.             $id = $_GET['id']??false;
    172.             if (!empty($id) && delOrder($mysqli, $id)) {
    173.                 header("Location: " . $_SERVER['PHP_SELF'] . '?action=order');
    174.             }
    175.             $template = 'order';
    176.             $table = getOrder($mysqli);
    177.             break;
    178.         default:
    179.     }
    180. } catch (Exception $e) {
    181.     echo $e->getMessage();
    182. }
    183. /**
    184. * Шаблоны страниц
    185. */
    186. ?>
    187. <html>
    188. <head>
    189. <title></title>
    190. <link   rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
    191.         integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
    192.         crossorigin="anonymous">
    193. <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
    194.         integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
    195.         crossorigin="anonymous"></script>
    196. <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
    197.         integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
    198.         crossorigin="anonymous"></script>
    199. <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
    200.         integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
    201.         crossorigin="anonymous"></script>
    202. </head>
    203. <body>
    204.   <div class="container">
    205.   <hr />
    206.   <div class="row">
    207.   <div class="col-md">
    208.     <small>
    209.     <h5>Отладочная информация</h5>
    210.     <hr />
    211.     <h6 class ="table-danger">Массив $_GET <?php echo 'count ('.count($_GET).')';?></h6>
    212.     <pre><?php print_r($_GET);?></pre>
    213.     <hr />
    214.     <h6 class ="table-danger">Массив $_POST <?php echo 'count ('.count($_POST).')';?></h6>
    215.     <pre><?php print_r($_POST);?></pre>
    216.     </small>
    217.   </div>
    218.  
    219.   <div class="col-md-9">
    220. <? switch ($template):
    221.         case 'order': ?>
    222.     <h2>Список заказов</h2>
    223.     <table class="table">
    224.       <?=$table?>
    225.     </table>
    226.       <a href="?action=add_order">Новый заказ</a>
    227.          <? break; ?>
    228.      <? case 'add_order': ?>
    229.       <h2>Форма создания нового заказа</h2>
    230.       <hr />
    231.         <form method="POST">
    232.           <div class="form-group">
    233.             <input type="hidden" name="action" value="add_order">
    234.             <label for="title">Введите название заказа</label>
    235.             <input type="text" class="form-control" id="title" aria-describedby="titleHelp" name="title">
    236.             <small id="titleHelp" class="form-text text-muted">Не более 100 символов</small>
    237.           </div>
    238.           <button type="submit" class="btn btn-primary">Создать</button>
    239.         </form>
    240.         <hr />
    241.         <a href="?action=order">Вернуться к списку заказов</a>
    242.          <? break; ?>
    243.      <? default: ?>
    244.      <hr />
    245.      <ul>
    246.       <li><a href="?action=order">Список заказов</a></li>
    247.       <li><a href="?action=add_order">Новый заказ</a></li>
    248.       <li><a href="?create_db=yes">Инициализация БД</a></li>
    249.      </ul>
    250. <? endswitch; ?>
    251.   </div>
    252.   </div>
    253.   <hr />
    254.   </div>
    255. </body>
    256. </html>
    257. </body>
    258. </html>

    Основная функция создания заказа, всё остальное "обвес" для демострации
    PHP:
    1. // Создание заказа
    2. function addOrder($mysqli, $title) {
    3.     if (empty($title)) {
    4.         return false;
    5.     }
    6.     $title = $mysqli->real_escape_string($title);
    7.     $query = "INSERT INTO `order` (`title`) VALUES('" . $title . "')";
    8.     $result = $mysqli->query($query);
    9.     if ($mysqli->error) {
    10.         throw new Exception('Ошибка добавления записи в базу данных: ' . $mysqli->error);
    11.     }
    12.     if ($mysqli->affected_rows > 0) {
    13.         $query = "UPDATE `order` o
    14.                    LEFT JOIN `identifier` i USING (`id`)
    15.                    SET o.order = i.order
    16.                    WHERE o.id = LAST_INSERT_ID()";
    17.         $result = $mysqli->query($query);
    18.         if ($mysqli->affected_rows > 0) {
    19.             return true;
    20.         }
    21.         throw new Exception('Не удалось присвоить уникальный номер заказа');
    22.     }
    23. }
     
    #24 Valick, 25 ноя 2019
    Последнее редактирование: 25 ноя 2019
  25. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    @Valick
    Это для задачи строгой последовательности нумерации документов.
    Базовая мысль правильная, но решение на уровне юниора. Фактически, не рабочее.
    Попытайся улучшить.