Резервное копирование PostgreSQL для 1С: BASH, pg_dump, cron, ротация и почта на Ubuntu

05.10.26

База данных - Архивирование (backup)

Пошаговая настройка регламентного резервного копирования перечня баз PostgreSQL под 1С:Предприятие 8.3 на Ubuntu одним bash-скриптом с pg_dump, pigz, ротацией копий, журналом и e-mail по cron. Разобраны .pgpass, проверка дампа и формат -Fc для больших баз.

Резервное копирование нескольких баз PostgreSQL для 1С:Предприятие 8.3 на Ubuntu я оформляю одним басн-файлом: pg_dump со сжатием, ротация локальных файлов, журнал backupres.log и письмо по cron. Дальше - пошаговая настройка регламента, чтобы не запускать pg_dump вручную на каждой базе.

 

Регламент логического бэкапа: границы и результат для администратора 1С

На сервере 1С 8.3 с PostgreSQL от вас обычно ждут дампы всех рабочих баз по расписанию, контроль диска и короткий отчёт, что цикл отработал. Это логическое резервное копирование через pg_dump при работающей платформе. Физическая репликация, архив WAL и pg_basebackup - другой уровень: они нужны, когда важна точка восстановления «между транзакциями» или полная гибель кластера. Для выгрузки содержимого баз на тестовый стенд, переноса или архива «на вчера» хватает потока pg_dump в сжатие и файлов в PATHCORE.

cron гоняет один скрипт; для каждой строки LISTBASE появляется каталог PATHCORE/<имя_базы>/, внутри до четырёх свежих файлов.dump.gz и отдельная чистка по возрасту 30 дней. В backupres.log пишутся время старта и размеры, на почту уходит тот же список - администратор видит состав дампов без входа по SSH. Так и задуман регламент после каждого цикла.

Окружение в материале - Ubuntu, клиент PostgreSQL с pg_dump, pigz и отправка почты (sendEmail по классической схеме или msmtp, если пакета sendEmail уже нет). Файловую базу 1С и выгрузку.dt через конфигуратор здесь не разбираем.

 

PATHCORE, LISTBASE и пакеты postgresql-client, pigz, почта

Задайте PATHCORE и LISTBASE, затем установите postgresql-client и pigz - без каталога и списка баз cron некуда складывать результат.

Каталоги PATHCORE и файлы журнала для каждой базы LISTBASE

pg_dump входит в postgresql-client; версию клиента разумно держать не ниже серверной PostgreSQL на этом хосте или рядом.

sudo apt update
sudo apt install -y postgresql-client pigz bc
sudo apt install -y sendemail libio-socket-ssl-perl libnet-ssleay-perl

sendEmail давно помечен как unmaintained: на свежих Ubuntu пакета может не быть. Я чаще ставлю msmtp с ~/.msmtprc (chmod 600) или mailx с SMTP и TLS. Тело письма по-прежнему собираем в файл, тему и UTF-8 задаём явно - меняется только вызов отправки в конце скрипта.

Имена баз - как в pg_database, регистр важен. В контуре 1С это отдельные информационные базы на одном инстансе PostgreSQL.

Один PATHCORE, подкаталог на каждую базу из LISTBASE, общий backupres.log и временный backupres_log.txt для письма. Пользователь cron должен писать в PATHCORE и читать ~/.pgpass и файл SMTP; обычно завожу пользователя backup, не root.

sudo mkdir -p /var/backups/postgres-onec
sudo chown backup:backup /var/backups/postgres-onec

Список баз в скрипте - многострочная переменная:

LISTBASE=$'prod_buh
prod_zup
test_erp'
PATHCORE=/var/backups/postgres-onec

Опечатка в имени базы - частая поломка регламента: pg_dump упадёт, а без очистки FORBODY и проверки ERR письмо может выглядеть «успешным» хвостом прошлого цикла. В рабочем скрипте это закрыто флагом ERR и обнулением FORBODY в начале run.

 

Задание cron: запуск backup-onec.sh каждые 12 часов

Расписание - два раза в сутки, в ноль минут каждого двенадцатого часа.

Контекст: Задание cron: запуск backup-onec.sh каждые 12 часов
0 */12 * * * /bin/bash /var/backups/postgres-onec/backup-onec.sh >> /var/backups/postgres-onec/cron.log 2>&1

crontab редактируем у того же пользователя ОС, что выполняет pg_dump (backup). Проверка - ручной запуск тем же путём. Если cron «не видит» pigz, надёжнее полные пути /usr/bin/pg_dump, как в скрипте ниже.

Для 1С 8.3 окно обслуживания согласуйте с нагрузкой: pg_dump читает данные, pigz пишет на том PATHCORE, на больших базах растёт длительность цикла. Платформа при этом работает; pg_dump для одной базы держит одну длинную транзакцию дампа, изR09;за этого растёт I/O и отдельные операции DDL или VACUUM могут подождать. Смотрю df на PATHCORE и длительность последних строк в backupres.log, прежде чем ставить cron на часы пиковой проводки.

Роль backup_dump должна проходить pg_hba.conf (часто local или scram для хоста 127.0.0.1) - иначе cron будет падать с «password authentication failed», хотя вручную под тем же пользователем всё ок.

 

backup-onec.sh: цикл pg_dump, pigz и имена файлов с датой

Один проход - от строки LISTBASE до файла с датой в имени; на схеме видно, где cron и почта.

Контекст: backup-onec.sh: цикл pg_dump, pigz и имена файлов с датой

 

Цикл cron: дамп, сжатие, ротация, лог и уведомление

 

Цикл cron: дамп, сжатие, ротация, лог и уведомление

В исходных how-to дамп идёт от суперпользователя postgres; ниже подключение через роль backup_dump и.pgpass - отдельная учётная запись с минимальными правами вместо postgres «по умолчанию». Поток тот же: pg_dump с ключом -c, pipe в pigz, имя PATHCORE/<база>/<дата>-<база>.dump.gz. Ключ -c удобен при восстановлении на пустую базу через psql: в начале скрипта дампа идут DROP. На прод восстановление только после прогона на копии. mkdir -p создаёт каталог базы перед первым дампом.

Ниже цельный backup-onec.sh: дамп, проверка gzip -t, ротация, журнал, отправка почты. Паролей PostgreSQL и SMTP в файле нет.

#!/bin/bash
set -uo pipefail

DATA=$(date +"%Y-%m-%d_%H-%M")
PATHCORE=/var/backups/postgres-onec
BACKUPRES="${PATHCORE}/backupres.log"
FORBODY="${PATHCORE}/backupres_log.txt"
n=1048576
LISTBASE=$'prod_buh
prod_zup'

PGUSER=backup_dump
export PGUSER

source "${PATHCORE}/.backup_env" 2>/dev/null || true

ERR=0: > "$FORBODY"

echo "" >> "$BACKUPRES"
echo "Start backup from $(date +"%Y-%m-%d_%H-%M-%S")" | tee -a "$BACKUPRES" >> "$FORBODY"

while IFS= read -r line; do
  [ -z "$line" ] && continue
  path="${PATHCORE}/${line}"
  mkdir -p "$path"
  outfile="${path}/${DATA}-${line}.dump.gz"
  if! /usr/bin/pg_dump -U "$PGUSER" -c "$line" | /usr/bin/pigz -c > "$outfile"; then
    echo "ERROR pg_dump/pigz for ${line} at $(date +"%Y-%m-%d_%H-%M-%S")" >> "$BACKUPRES"
    ERR=1
    continue
  fi
  if! gzip -t "$outfile"; then
    echo "ERROR gzip -t failed for ${outfile}" >> "$BACKUPRES"
    ERR=1
    rm -f "$outfile"
    continue
  fi
  colfile=$(find "$path" -maxdepth 1 -type f -name '*.dump.gz' 2>/dev/null | wc -l)
  if [ "$colfile" -gt 4 ]; then
    oldfile=$(ls -1rt "$path"/*.dump.gz 2>/dev/null | head -1)
    rm -f "$oldfile"
  fi
  find "$path" -maxdepth 1 -type f -name '*.dump.gz' -mtime +30 -delete
done <<< "$LISTBASE"

while IFS= read -r linee; do
  [ -z "$linee" ] && continue
  find "${PATHCORE}/${linee}/" -maxdepth 1 -type f -name '*.dump.gz' -print0 2>/dev/null | while IFS= read -r -d '' file; do
    sum=$(stat --printf="%s" "$file")
    result=$(LC_NUMERIC="en_US.UTF-8" printf "%.2fMb" "$(echo "$sum/$n" | bc -l)")
    shortfile=$(basename "$file")
    echo "$shortfile $result" >> "$BACKUPRES"
    echo "$shortfile $result" >> "$FORBODY"
  done
done <<< "$LISTBASE"

if [ "$ERR" -eq 0 ]; then
  if command -v sendemail >/dev/null 2>&1; then
    sendemail -f "$FROM" -t "$MAILTO" -u "PostgreSQL backup OK $(hostname -s)" \
      -m "$(cat "$FORBODY")" -s "$SMTPSERVER" -o tls=yes \
      -xu "$SMTPLOGIN" -xp "$SMTPPASS" -o message-charset=utf-8
  elif command -v msmtp >/dev/null 2>&1; then
    {
      echo "To: $MAILTO"
      echo "From: $FROM"
      echo "Subject: PostgreSQL backup OK $(hostname -s)"
      echo "Content-Type: text/plain; charset=utf-8"
      echo ""
      cat "$FORBODY"
    } | msmtp -a default "$MAILTO"
  fi: > "$FORBODY"
else
  tail -n 50 "$BACKUPRES" > "${PATHCORE}/backup_fail_snippet.txt"
  if command -v sendemail >/dev/null 2>&1; then
    sendemail -f "$FROM" -t "$MAILTO" -u "BACKUP FAILED $(hostname -s)" \
      -m "$(cat "${PATHCORE}/backup_fail_snippet.txt")" -s "$SMTPSERVER" -o tls=yes \
      -xu "$SMTPLOGIN" -xp "$SMTPPASS" -o message-charset=utf-8
  elif command -v msmtp >/dev/null 2>&1; then
    {
      echo "To: $MAILTO"
      echo "From: $FROM"
      echo "Subject: BACKUP FAILED $(hostname -s)"
      echo "Content-Type: text/plain; charset=utf-8"
      echo ""
      cat "${PATHCORE}/backup_fail_snippet.txt"
    } | msmtp -a default "$MAILTO"
  fi: > "$FORBODY"
fi

Фрагмент ротации внутри того же цикла (после успешного gzip -t):

  colfile=$(find "$path" -maxdepth 1 -type f -name '*.dump.gz' 2>/dev/null | wc -l)
  if [ "$colfile" -gt 4 ]; then
    oldfile=$(ls -1rt "$path"/*.dump.gz 2>/dev/null | head -1)
    rm -f "$oldfile"
  fi
  find "$path" -maxdepth 1 -type f -name '*.dump.gz' -mtime +30 -delete

 

Ротация: четыре последние копии и find -mtime +30

В каталоге каждой базы считаем только файлы *.dump.gz - посторонние файлы в PATHCORE/<база>/ ротацию не ломают. Если дампов больше четырёх, удаляем один самый старый по времени модификации. find с -mtime +30 снимает архивы старше 30 календарных дней. Это два независимых ограничения.

При cron каждые 12 часов «четыре файла» - это примерно двое суток хвоста по четырём запускам, а не «четыре последние ночи». Четыре полных дампа крупной ERP на одном томе - заметный объём; df по PATHCORE обязателен. Обрыв pg_dump или pigz при нехватке места даёт битый файл - поэтому сразу после записи идёт gzip -t. Локальная ротация не заменяет вынос: после успешного цикла имеет смысл rsync или scp на другой хост поверх правил «четыре копии и тридцать дней».

colfile=$(find "$path" -maxdepth 1 -type f -name '*.dump.gz' 2>/dev/null | wc -l)
if [ "$colfile" -gt 4 ]; then
  oldfile=$(ls -1rt "$path"/*.dump.gz 2>/dev/null | head -1)
  rm -f "$oldfile"
fi
find "$path" -maxdepth 1 -type f -name '*.dump.gz' -mtime +30 -delete

 

backupres.log, backupres_log.txt и письмо по SMTP

После дампов администратору нужен отчёт на почту; на схеме - как тело уходит на SMTP с TLS.

 

СМТР-отчёт после цикла pg_dump: тело из backupres_log.txt

 

СМТР-отчёт после цикла pg_dump: тело из backupres_log.txt

backupres.log копит историю; FORBODY (backupres_log.txt) - только текущий цикл. В начале run обнуляем FORBODY, затем tee пишет время старта. Список файлов с размерами в мегабайтах собираем вторым проходом по тем же строкам, что LISTBASE, а не по содержимому FORBODY:

: > "$FORBODY"
echo "" >> "$BACKUPRES"
echo "Start backup from $(date +"%Y-%m-%d_%H-%M-%S")" | tee -a "$BACKUPRES" >> "$FORBODY"

while IFS= read -r linee; do
  [ -z "$linee" ] && continue
  find "${PATHCORE}/${linee}/" -maxdepth 1 -type f -name '*.dump.gz' -print0 2>/dev/null | while IFS= read -r -d '' file; do
    sum=$(stat --printf="%s" "$file")
    result=$(LC_NUMERIC="en_US.UTF-8" printf "%.2fMb" "$(echo "$sum/$n" | bc -l)")
    shortfile=$(basename "$file")
    echo "$shortfile $result" >> "$BACKUPRES"
    echo "$shortfile $result" >> "$FORBODY"
  done
done <<< "$LISTBASE"

FROM, MAILTO, SMTPSERVER, логин и пароль - в.backup_env (chmod 600) или EnvironmentFile= у systemd timer. Кодировка письма - UTF-8. При ERR равном нулю тема вроде «PostgreSQL backup OK»; при ошибке - «BACKUP FAILED», тело из хвоста backupres.log. Успешное письмо при сбое дампа регламент обнуляет.

Полный цикл отправки уже в backup-onec.sh (sendemail или msmtp). Для msmtp заранее настройте аккаунт умолчанию в ~/.msmtprc у пользователя cron.

 

.pgpass, проверка дампа, формат -Fc и секреты для 1С 8.3

Пароль PostgreSQL - в ~/.pgpass (600), строка hostname:port:база:username:password. Роль backup_dump подключается к каждой базе из LISTBASE и читает схему для pg_dump. Одного GRANT SELECT ON ALL TABLES IN SCHEMA public на одну базу для типовой ERP часто мало: pg_dump может потребовать sequences, large объекты, иногда представления; в PG 10+ на практике проще выдать pg_read_all_data (если политика безопасности позволяет) или калибровать права по тексту ошибок pg_dump. Для первого внедрения иногда оставляют владельца БД или read-only реплику - но не путать с логическим дампом на бою.

CREATE ROLE backup_dump LOGIN PASSWORD 'задайте_сильный_пароль';

GRANT CONNECT ON DATABASE prod_buh TO backup_dump;
GRANT CONNECT ON DATABASE prod_zup TO backup_dump;

\c prod_buh
GRANT USAGE ON SCHEMA public TO backup_dump;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO backup_dump;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO backup_dump;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO backup_dump;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON SEQUENCES TO backup_dump;

\c prod_zup
GRANT USAGE ON SCHEMA public TO backup_dump;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO backup_dump;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO backup_dump;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO backup_dump;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON SEQUENCES TO backup_dump;

-- PostgreSQL 14+: при согласии политики безопасности
-- GRANT pg_read_all_data TO backup_dump;

Имена для сверки с LISTBASE:

SELECT datname
FROM pg_database
WHERE datistemplate = false
  AND datname NOT IN ('postgres');

Лишняя строка в LISTBASE - ошибка pg_dump и ERR=1; пропущенная база - дыра в регламенте.

После.dump.gz проверяем gzip -t; коды pg_dump и pigz пишем в backupres.log. set -e на весь скрипт жёсткий: одна база с ошибкой оборвёт цикл, поэтому удобнее ERR и continue по базам.

Крупные базы 1С: pipe в pigz даёт привычный.sql.gz и gunzip | psql. Когда цикл не укладывается в окно, перехожу на формат -Fc (custom): pg_dump -Fc -f file.dump без pipe, восстановление pg_restore -j N. Пока места и времени хватает, оставляю.sql.gz; когда узкое место - однопоточный psql при восстановлении. Для архива -Fc проверка: pg_restore --list file.dump > /dev/null.

Секреты SMTP в.backup_env:

FROM=noreply@example.com
MAILTO=admin@example.com
SMTPSERVER=smtp.example.com
SMTPLOGIN=noreply@example.com
SMTPPASS=секрет

chmod 600. Пароли из примеров в прод без отдельного защищённого файла - риск утечки вместе с копией самого скрипта из бэкапа конфигов.

Пример.pgpass: localhost:5432:prod_buh:backup_dump:пароль; для всех баз пользователя - localhost:5432:*:backup_dump:пароль. PGPASSWORD в cron не нужен.

Восстановление 1С - не только pg_restore или psql: версия платформы, права на каталоги сервера, иногда блокировка пользователей на время развёртывания. Логический дамп не заменяет WAL и не спасает при уничтожении всего кластера без отдельного бэкапа ролей (pg_dumpall --globals-only периодически, если переносите на другой сервер).

Сеансы 1С продолжают работать, но I/O на томе данных PostgreSQL и на PATHCORE растёт. Если дампы лежат на том же диске, что data_directory, четыре полных копии нескольких баз упираются в лимит раньше, чем кажется по одной базе.

После успешного цикла и gzip -t для новых файлов можно добавить rsync -a path/ user@backup-host:/archive/postgres/ или scp только свежего outfile. Локальная ротация экономит место на сервере приложений; удалённая копия закрывает отказ диска или ВМ.

Кратко по рискам:

Ситуация Решение Риск
Несколько баз 1С на одном PostgreSQL LISTBASE и цикл while read Опечатка в имени базы, пропуск в списке
Пароль в скрипте или в git ~/.pgpass,.backup_env chmod 600 Утечка учётных данных
Диск PATHCORE заполнен df, ротация 4+30, вынос rsync/scp Битый или неполный дамп
sendEmail недоступен msmtp, mailx с SMTP Нет отчёта при успешном бэкапе
Очень большая база pg_dump -Fc, pg_restore -j Долгий цикл, нагрузка в часы пика
Нужен PITR / физический бэкап WAL, pg_basebackup (отдельная тема) Логический дамп не покрывает сценарий
  • Опечатка или лишняя база в LISTBASE - сверка с pg_database; pg_dump падает, ERR=1, письмо о сбое.
  • Недостаточно прав backup_dump - неполный дамп или ошибка pg_dump; pg_read_all_data или донастройка sequences и CONNECT на каждую базу.
  • Том PATHCORE заполнен - мониторинг df; битый.dump.gz отлавливает gzip -t.
  • Четыре копии при cron 0 */12 - около двух суток истории на диске; рост ERP умножает объём.
  • Только локальные файлы - пожар диска; rsync/scp после успешного цикла.
  • Логический дамп - не PITR; для DR нужны другие инструменты и бэкап globals.
  • sendEmail отсутствует в репозитории - msmtp или mailx с тем же телом из FORBODY.
  • pg_hba не пускает backup - правило для пользователя cron и метода подключения.

Перед включением cron прогоните backup-onec.sh вручную дважды: появились.dump.gz, gzip -t без ошибок, строки в backupres.log, одно тестовое письмо. Потом остаётся строка в crontab и контроль места на PATHCORE раз в неделю.

Вступайте в нашу телеграмм-группу Инфостарт

PostgreSQL 1С:Предприятие 8.3 резервное копирование администрирование Linux cron bash PostgreSQL 1С pg_dump BASH Ubuntu pigz бэкап базы

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

Архивирование (backup) Инструменты администратора БД 1С:Предприятие 8 1C:Бухгалтерия 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Платные (руб)

Данная разработка позволит решить вопрос с резервным копированием Ваших баз в автоматическом режиме, расположенных на сервере 1С. Система умеет ставить блокировки на вход, блокировать фоновые задания, принудительно отключать сеансы пользователей. И все это система делает в автоматически при создании бэкапа (или через команду). Выгрузка происходит в родной формат 1С - .dt. Так же система умеет архивировать данные выгрузки с установкой пароля. Умеет менять расширение файла zip или dt на любое указанное вами, что позволит сохранить выгрузки от шифровальщика. Может удалять старые копии выгрузок, оставляя указанное количество резервных копий, начиная с самой поздней. Только для WINDOWS! Версия 1.4 от 28.05.2026

7320 руб.

06.11.2012    80398    635    45    

94

Администрирование СУБД Системный администратор Разработчик Бесплатно (free)

5,5 тысячи пользователей в единой базе 1С, розница в режиме 24/7 и SLA 99,98% – в таких условиях любая авария быстро превращается в очереди на кассах, потерю денег и давление со стороны бизнеса. Показываем, как выстроить процесс аварийно-восстановительных работ: от первых алертов и базового скрининга системы до подключения команды, проверки гипотез и дебрифа после инцидента. Разбираем, как метрики, дашборды, техжурнал, Zabbix, Prometheus, Grafana, Telegram-боты и скрипты помогают не гадать, а быстро находить причину проблемы. На реальных авариях объясняем, почему «быстро» не должно означать «рискованно», как работа над ошибками снижает панику и почему каждая авария может сделать систему надежнее.

11.08.2026    3424    jul.dolganova    9    

24

Администрирование СУБД Системный администратор Разработчик Бесплатно (free)

Статья рассказывает об опыте перевода больших баз с MSSQL на Postgres и годовой эксплуатации после перехода. Показано, с какими ограничениями утилиты ibcmd можно столкнуться при миграции больших баз и какие подходы помогают безопасно обходить эти проблемы. Приведены наиболее интересные кейсы, выявленные в эксплуатации: особенности настроек Postgres, поведение оптимизатора, тонкости работы логики и статистики, а также редкие, но критичные ситуации с производительностью. Материал будет полезен тем, кто планирует переход на Postgres и хочет заранее понимать реальные риски, подводные камни и проверенные практики их преодоления.

20.04.2026    10464    berserg    12    

27

Архивирование (backup) Групповая разработка (Git, хранилище) Системный администратор Разработчик Бесплатно (free)

Как дать возможность каждому разработчику 1С вести разработку, тестирование и оптимизацию на собственной полноразмерной копии базы и при этом не тратить миллиарды рублей и тысячи часов на развертывание тестового окружения, а так же экономить дисковое пространство? Расскажем о том, как с помощью инструмента Database Lab получать полноразмерные копии базы 1C на СУБД PostgreSQL за считанные секунды (даже в случае использования многотерабайтных баз).

15.12.2025    14204    nasonkin    19    

31

Администрирование СУБД Разработчик 1С:Предприятие 8 Россия Бесплатно (free)

Ошибка реструктуризации: "Запись не найдена в менеджере имен баз данных". Диагностика и решение проблемы.

22.08.2025    5789    a13k55    1    

19

HighLoad оптимизация Администрирование СУБД Системный администратор Разработчик 1С:Предприятие 8 Бесплатно (free)

Во второй статье по докладу «Дамп – не приговор, а повод задуматься», с которым выступили на конференции INFOSTART TECH EVENT 2024, рассмотрим, какую информацию содержат файлы дампа, чем она полезна и как ее анализировать.

14.04.2025    6247    it-expertise    7    

20

Архивирование (backup) Учет документов Бухгалтер 1С:Предприятие 8 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Платные (руб)

В текущих версиях 1С пока нет функции, позволяющей автоматически отмечать возврат оригиналов документов с помощью сканера штрих-кодов. Многие контрагенты часто сталкиваются с проблемой утери оригиналов УПД или их невозврата. В ответ на эти запросы было разработано расширение, которое упрощает контроль за возвратом оригиналов документов и помогает лучше организовать их хранение.

12200 руб.

19.02.2025    2945    3    0    

3
Для отправки сообщения требуется регистрация/авторизация