[Назад] [Дальше] [Оглавление]

      convertstat [-uuser|-a] [-ofile] [-ifile] [-Yyear] [-Mmonth]
                  [-xlevel]

Конвертирует статистику из файлов *.st в SQL таблицу statistic (по умолчанию) или выходной файл, руководствуясь прайс-листами (указываются директивой prices в настройке пользователя - user.cf).

Расчет может производиться сразу для всех пользователей, если задан ключ `-a' , или для конкретного пользователя, заданного ключом `-u user' .

Если входной файл не задан, то производится чтение всех `.st' файлов в каталоге пользователя и суммирование содержимого. В противном случае (файл задан с помощью `-i file' ) производится чтение указанного файла.

Как имя входного файла, так и имя выходного может начинаться с символа `~' (тильда). В этом случае соответствующий файл ищется в персональном каталоге пользователя - это удобно для пакетной обработки. Кроме того, в качестве имени файла может быть в использован знак - ( `-i-' или `-o-' ). В этом случае будет использован стандартный входной или выходной поток соответственно.

Период, за который происходит расчет, convertstat определяет по содержимому файла `.month', находящегося в домашнем каталоге сервера. Этот файл формируется модулем monthly и меняется им же один раз в месяц, редактировать его вручную нет необходимости (за исключением создания при первоначальном запуске сервера).

Иногда возникает необходимость пересчитать данные за какой-либо из прошедших месяцев (хотя это и крайне не рекомендуемая операция). Для того, чтобы сделать это корректно необходимо задать текущий месяц (ключ `-M' ), год (ключ `-Y' ) и, чаще всего, имя входного файла. Для проверки можно воспользоваться выводом в стандартный поток (ключ `-o-' ). Делайте так только если Вы полностью понимаете структуру информации сервера статистики и изменения, которые повлечет за собой пересчет.

При выводе информации в SQL таблицу вся существующая информация за расчитываемый месяц уничтожается и замещается новой. Будьте осторожны с этим!

Флаг `-x' может быть использован для отладки.

Файлы хранят статистику использования произвольных видов сервиса - именно они являются единственным источником статистической информации для сервера. Вся иная статистика должна приводиться к ним - смотрите описание принципа работы сервера и примеры конвертеров - calcmail и calctime.

Файлы текстовые; строки, начинающиеся с символа `#', и пустые строки игнорируются. Каждая значащая строка должна содержать два поля, разделенных пробелами и/или табуляциями - "имя сервиса" (соответствующее прайс-листу) и "количество сервиса". В файле может встречаться несколько строк с одинаковым именем сервиса - итогом будет сумма значений.

Например:

# Комментарий
#
t_uucp   10
m_nserv  1234
t_uucp   34

Итогом чтения такого файла будет значение сервиса "t_uucp=44" и значение "m_nserv=1234". В именах сервисов допустимы английские строчные и прописные буквы, цифры и символ '_' (подчерк). Недопустимы имена, начинающиеся с цифры. Рекомендуемый способ формирования имен таков - первая буква означает тип сервиса (t - время, m - почта и т.п.); далее, через подчерк, название. Большие и маленькие буквы в именах различаются - mail и Mail - разные названия.

"Количество сервиса" может быть целым или десятичной дробью; положительным или отрицательным.

Прайс-листы определяют оплачиваемые виды сервиса, их стоимость, единицу измерения, названия видов сервиса и групп сервиса, формулы пересчета из .st-файлов. Прайс-листы хранятся в подкаталоге `prices/' домашнего каталога сервера либо в персональном каталоге пользователя. В последнем случае, ссылка на прайс-лист из персональной конфигурации пользователя ( user.cfs) должна начинаться с символа `~' (тильда). Если в конфигурации пользователя указано несколько прайс-листов, то они читаются в порядке указания как один большой файл.

Файл прайс-листа текстовый; пустые строки и строки, начинающиеся с символа `#' игнорируются. Длинные строки можно переносить; для этого последним символом строки надо поместить символ `\' (обратная косая черта). Каждая запись прайс-листа состоит из одной или более строк; гарантируется, что записи будут отработаны в том порядке, как они размещены в прайс-листе. Первая строка состоит из 4 полей, разделенных пробелами и/или табуляциями:

итоговое имя сервиса

Задает имя сервиса после пересчета. Именно оно помещается в результирующую сводку за месяц. Ограничения на итоговое имя сервиса такие-же как и для имени сервиса в .st-файлах - оно должно состоять из не не более, чем 20 символов. Допустимы маленькие и большие английские буквы, цифры и символ '_'. Итоговое имя сервиса не должно начинаться с цифры. Кроме того, недопустимо использовать как имя несколько зарезервированных слов (смотрите ниже).

формула расчета

Формула задает соответствие между итоговым именем сервиса и сервисами в .st файлах. Сложные формулы, содержащие пробелы можно заключать в кавычки. Формулы вычисляются по обычным правилам арифметических действий, допустимы скобки. Подробнее о способах записи формул смотрите в описании генератора отчетов.

Пример формулы:

      "m_ncomm==0 ? (m_nserv+m_nnormal > 50000 ? 1 : 0) : 0"

В этом примере проверяется значение m_ncomm (объем полученных коммерческих новостей); если оно равно нулю (абонент не использовал коммерческие новости), то сумма m_nserv (ответов сервера) и m_nnormal (собственно некоммерческих статей) сравнивается с 50000 (чтобы не карать за получение help'ов и ошибки абонента/сервера); если "больше" - то значением становится '1', иначе '0'. Таким образом, в словесном выражении, значением формулы будет единица только тогда, когда абонент не использовал коммерческих новостей и объем использования некоммерческих превысил 50000 байт.

стоимость единицы

Стоимость единицы сервиса. Вполне может быть дробной величиной, или отрицательной в случае расчетов с поставщиками информации. После стоимости без пробела может быть указано наименование валюты. В этом случае соответствующая цена умножается на курс этой валюты, полученный из SQL таблицы rates. Подробнее о курсах валют смотрите ниже и в описании модуля setrate.

По умолчанию подразумевается, что цены указаны в единицах основной валюты или в единицах валюты, указанной параметром price-currency основного конфигурационного файла сервера. Допустимо указывать и наименование основной валюты в качестве единицы. При этом преобразование курса не производится, что особенно удобно для задания исключений в случае, если задан параметр price-currency.

наименование единицы сервиса

Наименование единицы (мин, кбайт, раз) используется генератором отчетов при составлении сводки или акта об оказанных услугах.

Следом за строкой с формулой может идти название сервиса для использования в результирующей таблице (акте о проделанных работах, например). Описание может быть разбито на несколько строк - необходимо лишь не забывать, что каждая строка описания должна начинаться по меньшей мере с одного пробела или табуляции.

Если описание отсутствует, то сервер просматривает описание установленного для пользователя языка ( смотрите ниже) и, если не находит описания там, SQL таблицу snames в поиске описания для соответствующего вида сервиса. Обычно нет нужды вручную формировать эту таблицу - она автоматически поддерживается актуальной на основе данных прайс-листов.

Некоторые итоговые имена сервисов зарезервированы для специального использования:

group

Часто бывает удобно выделить в итоговом акте группы сервиса (почта, on-line, bbs и т.п.). Просто поместите название группы на строке после ключевого слова group -- все последующие описания сервисов попадут в указанную Вами группу.

Кроме того, для совместимости с предыдущими версиями, вместо group можно просто начать строку с символа : (двоеточие).

Пример:

# Пример прайс-листа
#
group   Почтовые файловые серверы
#
ms_kiae         ms_kiae/1024                            0.026   кбайт
        Работа с файловым сервером KIAE
ms_elvis        ms_elvis/1024                           0.026   кбайт
        Работа с файловым сервером или системой
        WaisMail Elvis+
ms_f1           ms_f1/1024                              0.004   кбайт
        Получение файлов от файлового сервера F1
#
group   Повременно оплачиваемые услуги
#
t_dip           t_dip/100                               0.040   мин
        Dialup TCP/IP (работа в Internet)
t_unix          t_unix/100                              0.030   мин
        Работа в Unix
t_uucp          "t_uucp/100/60>5        \
                 ? t_uucp/100/60-5      \
                 : 0                    \
                "                                       1.0     час
        Связь по протоколу UUCP
        (время превышения 5 часов)

gid

Позволяет задать идентификатор группы сервиса, ссылку на описание в SQL таблице sgroups. Возможно, что эта директива отомрет в следующих версиях сервера, ее применение без необходимости не рекомендуется.

let

Выполнение вычислений. Очень полезно для вычисления промежуточных величин при расчетах по сложным формулам или для задания некоторых констант.

Вслед за ключевым словом let через пробелы/табуляции должно следовать ровно два поля - название результата вычислений и формула расчета. Как и при вычислении сервиса, формулы, содержащие пробелы, должны быть заключены в двойные кавычки.

В отличие от описаний сервиса, результат вычислений по формуле размещается в той-же области данных, что и исходная статистика. Таким образом, при последующих вычислениях он может быть использован как обычно (напомним, что последовательный порядок вычислений гарантируется).

Рассмотрим ситуацию в качестве примера (нечто довольно близкое используется автором сервера в проекте Долина ИНТЕРНЕТ). Имеем для каждого пользователя время его работы днем (v_time_d), вечером (v_time_e) и ночью (v_time_n). Каждому пользователю могло быть предоставлено некоторое бесплатное время (v_ftime) и 3 часа (v_atime) он мог работать в счет абонентской платы. Поскольку цена в разное время суток разная, то и время ночью/вечером должно идти медленнее в те периоды, когда счет идет не по цене, а по количеству времени.

Возможная реализация с использованием let:

#
# Допустимое время работы в счет абонентской платы (может быть задано из
# персонального static.st пользователя, например)
#
let     v_atime         "v_atime ? v_atime : 3*60"
#
# Коэффициенты учета дневного/вечернего/ночного времени в абонентской плате
#
let     _kd             1
let     _ke             0.5
let     _kn             0.25
#
# Пересчитаем в минуты традиционные сотые доли для упрощения
#
let     v_time_d        v_time_d/100
let     v_time_e        v_time_e/100
let     v_time_n        v_time_n/100
let     v_ftime         v_ftime/100
#
# Считаем общее реальное время и общее приведенное к дневному
#
let     _time           "v_time_d + v_time_e + v_time_n"
let     _time_d         "v_time_d*_kd + v_time_e*_ke + v_time_n*_kn"
let     _time_df        "_time_d - v_ftime"
#
# Расчитаем группу скидок (>=20 часов, >=50 часов и более 100 часов)
#
let     _dis            "_time_df <  20*60 ? 0 :        \
                        (_time_df <  50*60 ? 1 :        \
                        (_time_df < 100*60 ? 2 : 3))"
#
# Время сверх бесплатного и абон-платы по категориям.
#
let     _x              "_time_d ? 1 - (v_atime+v_ftime)/_time_d : 0"
let     _x              "_x > 0 ? _x : 0"
let     _td             "v_time_d * _x"
let     _te             "v_time_e * _x"
let     _tn             "v_time_n * _x"
#
# Собственно расчеты сервисов
#
v_abon          "_time_df>10 && v_atime>0 ? 1 : 0"              41.667  -
        Абонентская плата
v_abon_t        "_time_df > v_atime ? v_atime                   \
                                    : (_time_df>0 ? _time_df    \
                                                  : 0)"         0       мин
        Время работы в счет абонентской платы
v_free          "v_ftime ? (_time_d < v_ftime ? _time_d : v_ftime) : 0" 0       мин
        Отработано бесплатного времени
v_ftl           "_time_d > v_ftime ? 0 : v_ftime-_time_d"       0       мин
        Остаток бесплатного время
v_time_0d       "_dis==0 ? _td : 0"                             0.2083  мин
        Время работы сверх абонентской платы (07:00..20:00)
v_time_0e       "_dis==0 ? _te : 0"                             0.1250  мин
        Время работы сверх абонентской платы (20:00..00:00)
v_time_0n       "_dis==0 ? _tn : 0"                             0.0750  мин
        Время работы сверх абонентской платы (00:00..07:00)
v_time_1d       "_dis==1 ? _td : 0"                             0.1979  мин
        Время работы сверх абонентской платы (07:00..20:00,
        свыше 20 часов, скидка 5%)
v_time_1e       "_dis==1 ? _te : 0"                             0.1186  мин
        Время работы сверх абонентской платы (20:00..00:00,
        свыше 20 часов, скидка 5%)
v_time_1n       "_dis==1 ? _tn : 0"                             0.0713  мин
        Время работы сверх абонентской платы (00:00..07:00,
        свыше 20 часов, скидка 5%)
v_time_2d       "_dis==2 ? _td : 0"                             0.1875  мин
        Время работы сверх абонентской платы (07:00..20:00,
        свыше 50 часов, скидка 10%)
v_time_2e       "_dis==2 ? _te : 0"                             0.1125  мин
        Время работы сверх абонентской платы (20:00..00:00,
        свыше 50 часов, скидка 10%)
v_time_2n       "_dis==2 ? _tn : 0"                             0.0675  мин
        Время работы сверх абонентской платы (00:00..07:00,
        свыше 50 часов, скидка 10%)
v_time_3d       "_dis==3 ? _td : 0"                             0.1667  мин
        Время работы сверх абонентской платы (07:00..20:00,
        свыше 100 часов, скидка 20%)
v_time_3e       "_dis==3 ? _te : 0"                             0.1000  мин
        Время работы сверх абонентской платы (20:00..00:00,
        свыше 100 часов, скидка 20%)
v_time_3n       "_dis==3 ? _tn : 0"                             0.0600  мин
        Время работы сверх абонентской платы (00:00..07:00,
        свыше 100 часов, скидка 20%)

setprices

Эта директива позволяет Вам изменить цены на все виды сервиса, прочитанные к этому времени разом. Обычно это бывает удобно, если для какого-то конкретного пользователя или всех разом в какой-то период Вы хотите временно снизить или увеличить цены. В этом случае, директива setprices должна быть самой последней строкой самого последнего прайс-листа - только в этом случае она будет воздействовать на все цены. Пересчет цен происходит по указанной формуле, где вместо price подставляется исходное значение цены. Пример:

...
ms_kiae         ms_kiae/1024                            0.026   кбайт
        Работа с файловым сервером KIAE
ms_elvis        ms_elvis/1024                           0.026   кбайт
        Работа с файловым сервером или системой
        WaisMail Elvis+
...
#
# Понижаем цены на 10%
#
setprices       price*0.9

Если в прайс-листе (или следующих друг за другом прайс-листах) встречается повторное описание уже описанного выше сервиса, то описание замещается новым. Это свойство удобно использовать для внесения небольших индивидуальных корректировок некоторым пользователям. Например:

# Общий прайс-лист
#
m_russia        m_russia/1024                           0.02    кбайт
        Российская почта
m_foreign       m_foreign/1024                          0.06    кбайт
        Зарубежная почта
...

# Корректирующий файл у пользователя, которому эти сервисы сделаны дешевле
#
m_russia        m_russia/1024                           0.01    кбайт
m_foreign       m_foreign/1024                          0.04    кбайт
...

# Корректирующий файл у пользователя, которому эти сервисы объединены
#
m_russia        0                                       0.02    кбайт
m_foreign       0                                       0.06    кбайт
m_any           (m_russia+m_foreign)/1024               0.03    кбайт
        Электронная почта
...

При открытии прайс листа сначала делается попытка открыть файл, перед последней точкой в имени которого вставлено `.XX', где XX - код языка. Например, если указан прайс-лист `prices.cf' и для пользователя установлен язык `ru', то сначала будет сделана попытка прочитать файл `prices.ru.cf'. После этого, сервер пытается открыть файл с тем именем, как оно указано, и в случае ошибки - со вставленным кодом для системного языка. Таким образом, если системный язык - `en', пользовательский - `ru' и требуется открыть файл `prices.cf', то сервер будет пытаться открыть прайс-лист в следующей последовательности:

  1. `.../prices/prices.ru.cf'
  2. `.../prices/prices.cf'
  3. `.../prices/prices.en.cf'

У такого способа создания многоязычных прайс-листов есть один недостаток - в случае изменения цен, формул расчета или наименований сервисов изменения придется вносить во все прайс-листы синхронно. Для того, чтобы этого избежать, можно воспользоваться другим способом локализации прайс-листов:

  1. Создать единый прайс-лист для всех языков, не включающий описаний сервисов и групп сервиса (однако названия групп следует включить командой `gid' - смотрите ниже).
  2. В описание всех языков включить описания сервисов и групп. При этом имя ресурса в описании языка формируется добавлением к названию из прайс-листа приставки `serv_' для сервисов и `sgrp_' для имен групп.

Указанные два способа локализации могут быть и совмещены.

Пример настройки с названиями в описании языка:

# Пример прайс-листа без описаний сервисов
#
gid    fbmserv
ms_kiae  ms_kiae/1024                   0.026  kb
ms_f1    ms_f1/1024                     0.004  kb
#
gid    time
t_dip    t_dip/100                      0.040  min
t_unix   t_unix/100                     0.030  min

# Пример вставки в описание языка
#
sgrp_fbmserv  "Почтовые файловые серверы"
serv_ms_kiae  "Файловый сервер KIAE - KiArchive"
serv_ms_f1    "Файловый сервер F1"
sgrp_time     "Повременно обплачиваемые услуги"
serv_t_dip    "Доступ к Internet по коммутируемой линии"
serv_t_unix   "Доступ к Unix"
min           "мин."
kb            "кбайт"

Сервер может использовать произвольное количество валют, но только в одном месте - при пересчете цен из указанной валюты в основную. Более нигде иные валюты, кроме основной не учитываются.

Курсы валют хранятся в SQL таблице rates и заносятся туда с помощью модуля setrate. При выборке курса из таблицы (например при автоматическом запуске модуля convertstat из daily) происходит поиск ближайшего более раннего курса. При этом, если в текущем месяце курс валюты еще не был задан, то об этом отсылается предупреждение администратору сервера по почте и используется последний известный курс за прошлые месяцы. Таким образом, рекомендуется задавать курс по меньшей мере один раз в месяц (автор использует систему ценообразования, когда прайс-листы задаются в долларах, и пересчитываются в рубли один раз в месяц по результатам первых торгов; Вы можете использовать такую систему, или какую-то иную).

Если Вы не используете привязки цен к иным валютам, то формировать курсы нет необходимости, однако таблица rates (хотя-бы пустая) должна присутствовать.


[Назад] [Дальше] [Оглавление]