Отчёты за период, исходный текст (page_report_period.cpp, модифицирован 12/02/2016)


#include <windows.h>
#include <stdio.h> // sprintf ()
#include <string>
#include "\works\h\maelstrom.h"
#include "client.h"
#include "config.h"
#include "expense.h"
#include "main.h" // fnGetToday ()
#include "page_reg.h"
#include "page_sms.h" // fnGetPhone ()
#include "page_tuning.h"
#include "read_ini.h"
#include "s_date.h"
#include "s_file_io.h"
#include "s_forms.h"
#include "s_group.h"
#include "s_org.h"
#include "s_service.h"
#include "s_spec.h"
#include "visit.h"

using namespace std;

// ассоциативные массивы
static std::auto_ptr<A_ARRAY> login_date1 (new A_ARRAY); // "имя входа/дата1"
static std::auto_ptr<A_ARRAY> login_date2 (new A_ARRAY); // "имя входа/дата2"
static std::auto_ptr<A_ARRAY> login_time1 (new A_ARRAY); // "имя входа/время1"
static std::auto_ptr<A_ARRAY> login_time2 (new A_ARRAY); // "имя входа/время2"
static std::auto_ptr<A_ARRAY> login_prefix (new A_ARRAY); // "имя входа/префикс"
static std::auto_ptr<A_ARRAY> login_group (new A_ARRAY); // "имя входа/группа"
static std::auto_ptr<A_ARRAY> login_visitflag (new A_ARRAY); // "имя входа/флажок посещения"
static std::auto_ptr<A_ARRAY> login_org (new A_ARRAY); // "имя входа/организация-плательщик"

// меню выбора флажка посещений для фильтра
static void fnVisitFlagsSelectFilter (QUERY *query,int iId)
{
	string s;

	if (iId < 0)
		s = "<select name=visit_flag><option selected value=\"-1\">Не использовать";
	else
		s = "<select name=visit_flag><option value=\"-1\">Не использовать";
	if (config.bUseVisitFlag1)
	{
		if (iId == 11)
			s += "<option selected value=\"11\">'";
		else
			s += "<option value=\"11\">'";
		s += config.szVisitFlagName1;
		s += "' включён";
		if (iId == 10)
			s += "<option selected value=\"10\">'";
		else
			s += "<option value=\"10\">'";
		s += config.szVisitFlagName1;
		s += "' выключен";
	}
	if (config.bUseVisitFlag2)
	{
		if (iId == 21)
			s += "<option selected value=\"21\">'";
		else
			s += "<option value=\"21\">'";
		s += config.szVisitFlagName2;
		s += "' включён";
		if (iId == 20)
			s += "<option selected value=\"20\">'";
		else
			s += "<option value=\"20\">'";
		s += config.szVisitFlagName2;
		s += "' выключен";
	}
	if (config.bUseVisitFlag3)
	{
		if (iId == 31)
			s += "<option selected value=\"31\">'";
		else
			s += "<option value=\"31\">'";
		s += config.szVisitFlagName3;
		s += "' включён";
		if (iId == 30)
			s += "<option selected value=\"30\">'";
		else
			s += "<option value=\"30\">'";
		s += config.szVisitFlagName3;
		s += "' выключен";
	}
	if (config.bUseVisitFlag4)
	{
		if (iId == 41)
			s += "<option selected value=\"41\">'";
		else
			s += "<option value=\"41\">'";
		s += config.szVisitFlagName4;
		s += "' включён";
		if (iId == 40)
			s += "<option selected value=\"40\">'";
		else
			s += "<option value=\"40\">'";
		s += config.szVisitFlagName4;
		s += "' выключен";
	}
	s += "</select>";
	query->dst->fnAddLine (s.c_str ());
}

/*
static string fnGetVisitFlagsDescription (int iId)
{
	static string s;

	s.clear ();
	if (iId >= 0)
	{
		s += ", флажок: '";
		switch (iId)
		{
			case 10:
			case 11:
			s += config.szVisitFlagName1;
			break;

			case 20:
			case 21:
			s += config.szVisitFlagName2;
			break;

			case 30:
			case 31:
			s += config.szVisitFlagName3;
			break;

			case 40:
			case 41:
			s += config.szVisitFlagName4;
			break;
		}
		switch (iId)
		{
			case 10:
			case 20:
			case 30:
			case 40:
			s += "' выключен";
			break;

			case 11:
			case 21:
			case 31:
			case 41:
			s += "' включён";
			break;
		}
	}
	return s;
}
*/

void fnAppReportPeriod (QUERY *query)
{
	string s;
	char szTmp [20];
	char szDate1 [11];
	char szDate2 [11];
	char szTime1 [5 +1];
	char szTime2 [5 +1];
	char szPrefix [WS_MAX_NAME_LEN +1];
	char szGroupId [2 +1];
	char szVisitFlagId [2 +1];
	int iCycle;
	int iTuningIconSize = fnGetTuningIconSize (query);
	int iOrg = -1;

	fnFormContent (query);
	query->dst->fnAddLine ("<p>Отчёты за период</p>");

	query->dst->fnLoad ("templates/app_help_report_period.tpl");

	// загружаем данные из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	if (! login_time1->fnGetValue (szTime1,query->szLogin))
	{
		strcpy (szTime1,"00:00");
		login_time1->fnAdd (query->szLogin,szTime1);
	}
	if (! login_time2->fnGetValue (szTime2,query->szLogin))
	{
		strcpy (szTime2,"23:59");
		login_time2->fnAdd (query->szLogin,szTime2);
	}
	if (! login_prefix->fnGetValue (szPrefix,query->szLogin))
	{
		*szPrefix = 0;
		login_prefix->fnAdd (query->szLogin,szPrefix);
	}
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	if (! login_visitflag->fnGetValue (szVisitFlagId,query->szLogin))
	{
		strcpy (szVisitFlagId,"-1");
		login_visitflag->fnAdd (query->szLogin,szVisitFlagId);
	}
	if (login_org->fnGetValue (szTmp,query->szLogin))
		iOrg = atoi (szTmp);
	else
		login_org->fnAdd (query->szLogin,"-1");

	s = "<form action=\"/report_period_accept\" method=post>";
	s += "<table border=0><tr><td valign=top>Период:</td><td>";
	// время 1
	s += "<input type=text name=from_time size=20 maxlength=5 value=\"";
	s += szTime1;
	s += "\">";
	query->dst->fnAddLine (s.c_str ());
	// дата 1
	fnSelectDate (query,"from_",szDate1);
	query->dst->fnAddLine ("&mdash;<br>");
	// время 2
	s = "<input type=text name=to_time size=20 maxlength=5 value=\"";
	s += szTime2;
	s += "\">";
	query->dst->fnAddLine (s.c_str ());
	// дата 2
	fnSelectDate (query,"to_",szDate2);
	query->dst->fnAddLine ("</td></tr>");
	// префикс филиала
	s = "<tr><td>Префикс филиала:</td><td><input type=text name=prefix size=20 maxlength=";
	sprintf (szTmp,"%i",WS_MAX_NAME_LEN);
	s += szTmp;
	s += " value=\"";
	s += szPrefix;
	s += "\"></td></tr>";
	// группа
	s += "<tr><td>Группа:</td><td>";
	query->dst->fnAddLine (s.c_str ());
	fnServicesGroupsSelectFilter (query,atoi (szGroupId));
	s = "</td></tr>";
	// флажок посещения
	s += "<tr><td>Флажок посещения:</td><td>";
	query->dst->fnAddLine (s.c_str ());
	fnVisitFlagsSelectFilter (query,atoi (szVisitFlagId));
	query->dst->fnAddLine ("</td></tr>");
	// организация-плательщик
	query->dst->fnAddLine ("<tr><td>Плательщик:</td><td>");
	fnSelectOrgPayer (query,iOrg);
	query->dst->fnAddLine ("</td></tr>");

	// кнопка "Применить"
	s = "<tr><td>&nbsp;</td><td><input type=submit value=\"Применить\"></td></tr>";
	s += "</table></form>";
	query->dst->fnAddLine (s.c_str ());

	s = "<p><table border=1 width=\"100%\">";
	s += "<tr><td>Наименование</td><td>Время</td><td>Период</td><td>Префикс</td><td>Группа</td>\
<td>Флажки</td><td>Плательщик</td><td>Описание</td><td>Столбцы</td></tr>";

	if ((query->uiAccessMap & ACCESS_ANALISE)
		|| ((! config.bLimitedClientsInfo) && (query->uiAccessMap & ACCESS_REG)))
	{
		// сальдо клиентов
		s += "<tr><td><a href=\"/report_debts_form\" target=\"_blank\">Сальдо клиентов</a></td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>Упорядоченный по алфавиту список клиентов, у которых есть долг или переплата.</td>";
		s += "<td>ФИО клиента, дата рождения, телефоны, сальдо.</td></tr>";

		// отчёт о днях рождения клиентов
		s += "<tr><td><a href=\"/report_birthday_form\" target=\"_blank\">Отчёт о днях рождения клиентов</a></td>";
		s += "<td>&nbsp;</td>";
		if (iTuningIconSize == 16)
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
		else
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>Список именинников за период, упорядоченный по дням рождения.</td>";
		s += "<td>Дата рождения, ФИО клиента, адрес, телефоны.</td></tr>";

		// реестр амбулаторных карт
		s += "<tr><td><a href=\"/report_map_order_form\" target=\"_blank\">Реестр амбулаторных карт</a></td>";
		s += "<td>&nbsp;</td>";
		if (iTuningIconSize == 16)
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
		else
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>Упорядоченный список амбулаторных карт за период.</td>";
		s += "<td>Номер (карты), дата (оформления), ФИО клиента.</td></tr>";

		// история посещений
		s += "<tr><td><a href=\"/report_visits_history_form\" target=\"_blank\">История посещений, сортировка по фамилиям</a><br>";
		s += "<a href=\"/report_visits_history_form?sort=2\" target=\"_blank\">История посещений, сортировка по суммам</a></td>";
		if (iTuningIconSize == 16)
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
		}
		else
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
		}
		s += "<td>История посещений за период.</td>";
		s += "<td>№, ФИО, дата рождения, телефоны, даты посещений (список), кол-во посещений, сумма.</td></tr>";

		// реестр назначений внутренний
		s += "<tr><td><a href=\"/report_prescriptions_order_form\" target=\"_blank\">Реестр назначений внутренний</a></td>";
		if (iTuningIconSize == 16)
		{
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
		}
		else
		{
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
		}
		s += "<td></td><td></td></tr>";

		// реестр назначений лабораторный
		s += "<tr><td><a href=\"/report_prescriptions_types_order_form\" target=\"_blank\">Реестр назначений лабораторный</a></td>";
		if (iTuningIconSize == 16)
		{
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
		}
		else
		{
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
		}
		s += "<td></td><td></td></tr>";

		// сотовые телефоны клиентов
		s += "<tr><td><a href=\"/report_cellphones_form\" target=\"_blank\">Сотовые телефоны клиентов</a></td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td></td><td></td></tr>";

		// оценка количества SMS для рассылки
		s += "<tr><td><a href=\"/report_sms_qty_form\" target=\"_blank\">Оценка количества SMS для рассылки</a></td>";
		if (iTuningIconSize == 16)
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
		}
		else
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
		}
		s += "<td>Оценка количества клиентов с федеральными телефонными номерами, прошедших через установленные фильтры.</td><td></td></tr>";
	}

	if (query->uiAccessMap & ACCESS_ANALISE)
	{
		// *********************
		// * финансовые отчёты *
		// *********************
		s += "<tr><td colspan=9>Финансовые отчёты:</td></tr>";
		// отчёт о доходах
		s += "<tr><td><a href=\"/report_income_form\" target=\"_blank\">Отчёт о доходах</a></td>";
		if (iTuningIconSize == 16)
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
		}
		else
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
		}
		s += "<td></td><td></td></tr>";

		if (config.bInputCons)
		{
			// отчёт о доходах по организациям
			s += "<tr><td><a href=\"/report_orgs_income_form\" target=\"_blank\">Отчёт о доходах по организациям</a></td>";
			if (iTuningIconSize == 16)
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
			}
			else
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
			}
			s += "<td></td><td></td></tr>";

			// отчёт о доходах по менеджерам
			s += "<tr><td><a href=\"/report_managers_income_form\" target=\"_blank\">Отчёт о доходах по менеджерам</a></td>";
			if (iTuningIconSize == 16)
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
			}
			else
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
			}
			s += "<td></td><td></td></tr>";
		}

		// отчёт по видам товаров и услуг
		s += "<tr><td><a href=\"/report_services_form\" target=\"_blank\">Отчёт по видам товаров и услуг</a></td>";
		if (iTuningIconSize == 16)
		{
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
		}
		else
		{
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
		}
		s += "<td></td><td></td></tr>";

		// отчёт по видам товаров и услуг (по филиалам)
		s += "<tr><td><a href=\"/report_services_form?prefix=1\" target=\"_blank\">Отчёт по видам товаров и услуг (по филиалам)</a></td>";
		if (iTuningIconSize == 16)
		{
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
		}
		else
		{
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
		}
		s += "<td></td><td></td></tr>";

		// отчёт о первичных и повторных обращениях
		s += "<tr><td><a href=\"/report_primary_visits_form\" target=\"_blank\">Отчёт о первичных и повторных обращениях</a></td>";
		if (iTuningIconSize == 16)
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
		}
		else
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
		}
		s += "<td></td><td></td></tr>";

		// акт выполненных работ
		s += "<tr><td><a href=\"/report_act_work_form\" target=\"_blank\">Акт выполненных работ</a></td>";
		if (iTuningIconSize == 16)
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
		}
		else
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
		}
		s += "<td></td><td></td></tr>";

		// реестр медицинских услуг для страховой организации
		s += "<tr><td><a href=\"/report_insurance_order_form\" target=\"_blank\">Реестр медицинских услуг \
для страховой организации</a></td>";
		if (iTuningIconSize == 16)
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
		}
		else
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
		}
		s += "<td></td><td></td></tr>";

		// отчёт о расходах
		s += "<tr><td><a href=\"/report_expenses_form\" target=\"_blank\">Отчёт о расходах</a></td>";
		s += "<td>&nbsp;</td>";
		if (iTuningIconSize == 16)
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
		else
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td></td><td></td></tr>";

		// отчёт о предоставленных скидках
		s += "<tr><td><a href=\"/report_discount_form\" target=\"_blank\">Отчёт о предоставленных скидках</a></td>";
		if (iTuningIconSize == 16)
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
		}
		else
		{
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
		}
		s += "<td>Отчёт о предоставленных скидках за период, содержащий отдельные таблицы для каждого используемого \
вида скидок. Записи упорядочены по дате оформления. Формула расчёта размера скидки: \"(исходная цена * количество) - сумма\".</td>";
		s += "<td>Дата (оформления), № договора, ФИО клиента, услуга, исходная цена, % скидки, цена, кол-во, \
сумма, размер скидки в рублях.</td></tr>";

		// **************************
		// * отчёты модуля контроля *
		// **************************
		s += "<tr><td colspan=9>Отчёты модуля контроля:</td></tr>";
		// МК2: предоставление единовременной скидки
		s += "<tr><td><a href=\"/report_control2_form\" target=\"_blank\">МК2: Предоставленные единовременные скидки более ";
		sprintf (szTmp,"%i",config.iCheck2Max);
		s += szTmp;
		s += "%</a></td>";
		s += "<td>&nbsp;</td>";
		if (iTuningIconSize == 16)
			s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
		else
			s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td></td><td></td></tr>";

		// отчёт о созданных договорах
		s += "<tr><td><a href=\"/report_contracts_form\" target=\"_blank\">Отчёт о созданных договорах</a></td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>Отчёт о действиях по объединению записей в договоры и формированию документов для печати. \
Эта информация хранится 31 день.</td>";
		s += "<td>Дата и время, подтип события, логин пользователя, событие, номер и дата договора, ФИО клиента, \
сумма, номер страницы.</td></tr>";

		// отчёт о редактировании прейскуранта в конструкторе видов услуг
		s += "<tr><td><a href=\"/report_services_edit_form\" target=\"_blank\">Отчёт о редактировании прейскуранта \
в конструкторе видов услуг</a></td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>&nbsp;</td>";
		s += "<td>Отчёт о событиях изменения прейскуранта, включающий в себя события создания и удаления услуг \
и разделов, а также о редактировании цен и себестоимости услуг. Эта информация хранится 365 дней.</td>";
		s += "<td>Дата и время, подтип события, логин пользователя, событие, уникальный номер, наименование, \
прежнее значение, новое значение.</td></tr>";

		// ********************************
		// * отчёты о работе специалистов *
		// ********************************
		s += "<tr><td colspan=9>Отчёты о работе специалистов:</td></tr>";

		// ведение амбулаторных карт
		if (ini1.bSpecMedical
			&& config.bInputSpec)
		{
			s += "<tr><td><a href=\"/report_map_keeping_form\" target=\"_blank\">Ведение амбулаторных карт</a></td>";
			s += "<td>&nbsp;</td>";
			if (iTuningIconSize == 16)
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			else
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
			s += "<td>&nbsp;</td>";
			s += "<td></td><td></td></tr>";
		}

		if (config.bInputSpec)
		{
			// выполненные работы и заработная плата
			s += "<tr><td><a href=\"/report_salary_form\" target=\"_blank\">Выполненные работы и заработная плата</a></td>";
			if (iTuningIconSize == 16)
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			}
			else
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			}
			s += "<td></td><td></td></tr>";

			// заработная плата (итоги)
			s += "<tr><td><a href=\"/report_salary_short_form\" target=\"_blank\">Заработная плата (итоги)</a></td>";
			if (iTuningIconSize == 16)
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
			}
			else
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
			}
			s += "<td></td><td></td></tr>";

			// история посещений по специалистам
			s += "<tr><td><a href=\"/report_specs_history_form\" target=\"_blank\">История посещений по специалистам</a><br>";
			s += "<a href=\"/report_specs_history_form?primary=1\" target=\"_blank\">История первичных посещений по специалистам</a></td>";
			if (iTuningIconSize == 16)
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td>&nbsp;</td>";
			}
			else
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td>&nbsp;</td>";
			}
			s += "<td></td><td></td></tr>";
		}

		if (config.bInputCons)
		{
			// начисления консультантам
			s += "<tr><td><a href=\"/report_cons_payments_form\" target=\"_blank\">Начисления консультантам</a></td>";
			if (iTuningIconSize == 16)
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
			}
			else
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
			}
			s += "<td></td><td></td></tr>";

			// начисления консультантам по организациям
			s += "<tr><td><a href=\"/report_orgs_payments_form\" target=\"_blank\">Начисления консультантам по организациям</a></td>";
			if (iTuningIconSize == 16)
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
			}
			else
			{
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
			}
			s += "<td></td><td></td></tr>";
		}

		// ********************
		// * шаблонные отчёты *
		// ********************
		if (iRepTemplatesQty)
		{
			s += "<tr><td colspan=5 align=center>Шаблонные отчёты:</td></tr>";
			for (iCycle = 0; iCycle < iRepTemplatesQty; iCycle++)
			{
				s += "<tr><td><a href=\"/report_template_form?num=";
				sprintf (szTmp,"%i",iCycle);
				s += szTmp;
				s += "\" target=\"_blank\">";
				s += rep_template [iCycle]->szName;
				s += "</a></td>";
				s += "<td>&nbsp;</td>";
				if (iTuningIconSize == 16)
					s += "<td><img src=\"/images/16x16/agt_action_success.png\"></td>";
				else
					s += "<td><img src=\"/images/24x24/agt_action_success.png\"></td>";
				s += "<td>&nbsp;</td>";
				s += "<td>&nbsp;</td>";
				s += "<td></td><td></td></tr>";
			}
		}
	}
	s += "</table></p>";
	query->dst->fnAddLine (s.c_str ());

	if (query->uiAccessMap & ACCESS_ANALISE)
	{
		s = "<p><table border=0 width=\"100%\"><tr><td>";
		// годовой отчёт
		s += "<a href=\"/report_base\">Годовой отчёт</a><br>";

		s += "</td><td>";
		// графики

		s += "</td></tr></table></p>";
		query->dst->fnAddLine (s.c_str ());
	}

	fnFormEnd (query);
} // end of fnAppReportPeriod ()

void fnAppReportPeriodAccept (QUERY *query)
{
	char sz [INI_MAX_LEXEM_LEN +1];
	int iDay1 = 0;
	int iMonth1 = 0;
	int iYear1 = 0;
	int iDay2 = 0;
	int iMonth2 = 0;
	int iYear2 = 0;
	RING *args = query->args;
	char szDate1 [11];
	char szDate2 [11];
	char szTime1 [5 +1];
	char szTime2 [5 +1];
	char szPrefix [WS_MAX_NAME_LEN +1];
	char szGroupId [2 +1];
	char szVisitFlagId [2 +1];
	int iOrg = -1;
	char szTmp [20];

	while (args->fnGetQty ())
	{
		args->fnPop (sz);
		if (! strcmp (sz,"from_day"))
		{
			args->fnPop (sz);
			iDay1 = atoi (sz);
			continue;
		}
		if (! strcmp (sz,"from_month"))
		{
			args->fnPop (sz);
			iMonth1 = atoi (sz);
			continue;
		}
		if (! strcmp (sz,"from_year"))
		{
			args->fnPop (sz);
			iYear1 = atoi (sz);
			continue;
		}
		if (! strcmp (sz,"to_day"))
		{
			args->fnPop (sz);
			iDay2 = atoi (sz);
			continue;
		}
		if (! strcmp (sz,"to_month"))
		{
			args->fnPop (sz);
			iMonth2 = atoi (sz);
			continue;
		}
		if (! strcmp (sz,"to_year"))
		{
			args->fnPop (sz);
			iYear2 = atoi (sz);
			continue;
		}
		if (! strcmp (sz,"from_time"))
		{
			args->fnPop (szTime1);
			continue;
		}
		if (! strcmp (sz,"to_time"))
		{
			args->fnPop (szTime2);
			continue;
		}
		if (! strcmp (sz,"prefix"))
		{
			args->fnPop (szPrefix);
			continue;
		}
		if (! strcmp (sz,"group"))
		{
			args->fnPop (szGroupId);
			continue;
		}
		if (! strcmp (sz,"visit_flag"))
		{
			args->fnPop (szVisitFlagId);
			continue;
		}
		if (! strcmp (sz,"org_payer"))
		{
			args->fnPop (sz);
			iOrg = atoi (sz);
			continue;
		}
	}
	sprintf (szDate1,"%02u/%02u/%04u",iDay1,iMonth1,iYear1);
	sprintf (szDate2,"%02u/%02u/%04u",iDay2,iMonth2,iYear2);
	fnNormalizeDate (szDate1);
	fnNormalizeDate (szDate2);

	if (fnCompareDate (szDate1,szDate2) <= 0)
	{
		login_date1->fnAdd (query->szLogin,szDate1);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// проверяем заполнение времени
	if (fnCheckTimeHM (szTime1) && fnCheckTimeHM (szTime2))
	{
		// если начальная и конечная даты одинаковы
		if (fnCompareDate (szDate1,szDate2) == 0)
		{
			int iTime1;
			int iTime2;

			iTime1 = fnGetMinutesAfterMidnightHM (szTime1);
			iTime2 = fnGetMinutesAfterMidnightHM (szTime2);
			if (iTime1 <= iTime2)
			{
				login_time1->fnAdd (query->szLogin,szTime1);
				login_time2->fnAdd (query->szLogin,szTime2);
			}
		}
		else
		{
			login_time1->fnAdd (query->szLogin,szTime1);
			login_time2->fnAdd (query->szLogin,szTime2);
		}
	}
	login_prefix->fnAdd (query->szLogin,szPrefix);
	login_group->fnAdd (query->szLogin,szGroupId);
	login_visitflag->fnAdd (query->szLogin,szVisitFlagId);
	// организация-плательщик
	sprintf (szTmp,"%i",iOrg);
	login_org->fnAdd (query->szLogin,szTmp);

} // end of fnAppReportPeriodAccept ()

// **********************************
// * отчёт о днях рождения клиентов *
// **********************************
void fnAppReportBirthdayForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	string s;
	char szTmp [20];
	char szClientFIO [100];
	int iCycle;
	char szBirthday [11];
	int iDay,iMonth;
	char szPhones [CLIENT_PHONES_LEN +1];
	std::auto_ptr<RING> table (new RING (10 kb));
	char *szBuf;
	char szAddress [CLIENT_ADDRESS_LEN +1];

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}

	s = "Отчёт о днях рождения клиентов за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	fnReportTitle (query,s.c_str ());

	// цикл с единицы, т.к. нулевой клиент - Анонимный
	for (iCycle = 1; iCycle < iClientsQty; iCycle++)
	{
		// пропускаем удалённые записи
		if (client [iCycle]->fnGetDelete())
			continue;
		// пропускаем клиентов с некорректной датой рождения
		if (! fnCheckDate (client [iCycle]->fnGetBirthday()))
			continue;
		// год рождения не должен быть меньше 1900
		if (fnGetYear(client [iCycle]->fnGetBirthday()) < 1900)
			continue;
		// определяем дату дня рождения
		iDay = fnGetDay (client [iCycle]->fnGetBirthday());
		iMonth = fnGetMonth (client [iCycle]->fnGetBirthday());
		sprintf (szBirthday,"%02u/%02u/%04u",iDay,iMonth,
			fnGetYear (szDate1)); // год начала периода
		// szDate1 более поздняя
		if (fnCompareDate (szDate1,szBirthday) == 1)
		{
			if (fnGetYear (szDate1) == fnGetYear (szDate2))
				continue;
			else
				sprintf (szBirthday,"%02u/%02u/%04u",
					iDay,iMonth,
					// год окончания периода
					fnGetYear (szDate2));
		}
		if (! fnCheckDateRange (szDate1,szBirthday,szDate2))
			continue;

		// формируем строку таблицы
		// внутри комментария дата рождения и ФИО клиента
		// в формате ММ/ДД_ФИО для сортировки
		sprintf (szTmp,"<!-- %02u/%02u_",
			fnGetMonth (client [iCycle]->fnGetBirthday ()),
			fnGetDay (client [iCycle]->fnGetBirthday ()));
		s = szTmp;
		sprintf (szClientFIO,"%s %s %s",
			client [iCycle]->fnGetFamily (),
			client [iCycle]->fnGetName (),
			client [iCycle]->fnGetName2 ());
		s += szClientFIO;
		s += " -->";
		// видимая информация
		s += "<tr><td>";
		s += client [iCycle]->fnGetBirthday ();
		s += "</td><td>";
		s += szClientFIO;
		s += "</td><td>";
		s += client [iCycle]->fnGetAddress (szAddress);
		s += "&nbsp;</td><td>";
		s += client [iCycle]->fnGetPhones (szPhones);
		s += "&nbsp;</td></tr>";
		table->fnPushStr (s.c_str ());
	}
	if (table->fnGetQty ())
	{
		table->fnSort (0); // сортировка в кольце

		query->dst->fnAddLine (
"<table width=\"100%\" border=1><tr>\
<td align=center>Дата рождения</td>\
<td align=center>ФИО клиента</td>\
<td align=center>Адрес</td>\
<td align=center>Телефоны</td></tr>");

		while (table->fnGetQty ())
		{
			szBuf = new char [table->fnGetLen ()];
			table->fnPop (szBuf);
			query->dst->fnAddLine (szBuf);
			delete [] szBuf;
		}
		query->dst->fnAddLine ("</table>");
	}
	fnReportEnd (query);
} // end of fnAppReportBirthdayForm ()

// *****************************
// * сотовые телефоны клиентов *
// *****************************
void fnAppReportCellPhonesForm (QUERY *query)
{
	string s;
	char szTmp [20];
	char szClientFIO [100];
	int iCycle;
	std::auto_ptr<RING> table (new RING (10 kb));
	char *szBuf;

	fnReportTitle (query,"Сотовые телефоны клиентов");

	// цикл с единицы, т.к. нулевой клиент - Анонимный
	for (iCycle = 1; iCycle < iClientsQty; iCycle++)
	{
		// пропускаем удалённые записи
		if (client [iCycle]->fnGetDelete ())
			continue;
		// если в строке отсутствует федеральный номер
		if (! fnGetPhone (szTmp,client [iCycle]->fnGetPhoneCell ()))
			continue;

		// формируем строку таблицы
		// ФИО клиента
		s = "<tr><td>";
		sprintf (szClientFIO,"%s %s %s",
			client [iCycle]->fnGetFamily (),
			client [iCycle]->fnGetName (),
			client [iCycle]->fnGetName2 ());
		s += szClientFIO;
		s += "</td>";
		// дата рождения
		s += "<td>";
		s += client [iCycle]->fnGetBirthday ();
		s += "</td>";
		// сотовые телефоны
		s += "<td>";
		s += client [iCycle]->fnGetPhoneCell ();
		s += "</td></tr>";
		table->fnPushStr (s.c_str ());
	}
	if (table->fnGetQty ())
	{
		table->fnSort (0); // сортировка в кольце

		query->dst->fnAddLine (
"<table width=\"100%\" border=1><tr>\
<td align=center>ФИО клиента</td>\
<td align=center>Дата рождения</td>\
<td align=center>Сотовый телефон</td></tr>");

		while (table->fnGetQty ())
		{
			szBuf = new char [table->fnGetLen ()];
			table->fnPop (szBuf);
			query->dst->fnAddLine (szBuf);
			delete [] szBuf;
		}
		query->dst->fnAddLine ("</table>");
	}
	fnReportEnd (query);
} // end of fnAppReportCellPhonesForm ()

// **************************************
// * оценка количества SMS для рассылки *
// **************************************
void fnAppReportSmsQtyForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	char szGroupId [2 +1];

	int iGroupId;
	string s;
	int iCycle;
	int iClientNum;
	std::auto_ptr<A_KEY_INT> clients_nums (new A_KEY_INT (16 kb));
	int iQty;
	char szTmp [20];

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);

	s = "Оценка количества SMS для рассылки (период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	s += ")";
	fnReportTitle (query,s.c_str ());

	// выбираем актуальные посещения
	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		if (! visit [iCycle]->fnGetClientNum()) // анонимный клиент
			continue;
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetDate (),szDate2))
			continue;
		if (visit [iCycle]->fnGetPreEntry ())
			continue;
		// группа
		if (iGroupId >= 0)
			if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
				continue;

		// добавляем уникальный номер клиента в массив clients_found
		iClientNum = visit [iCycle]->fnGetClientNum();
		if (! clients_nums->fnCheck(iClientNum))
			clients_nums->fnAdd(iClientNum);
	}
	iQty = clients_nums->fnGetQty ();

	s = "<table width=\"100%\" border=1>";
	s += "<tr><td>Количество клиентов, прошедших через фильтр:</td><td align=right>";
	sprintf (szTmp,"%i",iQty);
	s += szTmp;
	s += "</td></tr>";

	if (iQty)
	{
		RING *buf;
		std::auto_ptr<RING> clients_found (new RING (16 kb));
		int iClientNum;
		int iClient;

		buf = new RING (16 kb);
		clients_nums->fnCopyBuf (buf);
		for (iCycle = 0; iCycle < iQty; iCycle++)
		{
			buf->fnPop((char *) &iClientNum,iCycle);
			iClient = fnClientSearchByNum(iClientNum);
			if (iClient == -1)
				continue;
			// пропускаем удалённые записи
			if (client [iCycle]->fnGetDelete ())
				continue;
			// если в строке отсутствует федеральный номер
			if (! fnGetPhone (szTmp,client [iClient]->fnGetPhoneCell ()))
				continue;
			clients_found->fnPush((char *) &iClientNum,sizeof (iClientNum));
		}
		delete buf;

		s += "<tr><td>Из них с федеральными телефонными номерами:</td><td align=right>";
		sprintf (szTmp,"%i",clients_found->fnGetQty());
		s += szTmp;
		s += "</td></tr>";
	}

	s += "</table>";
	query->dst->fnAddLine (s.c_str());

	fnReportEnd (query);
} // end of fnAppReportSmsQtyForm()

// ****************************
// * реестр амбулаторных карт *
// ****************************
void fnAppReportMapOrderForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	string s;
	int iCycle;
	char szMapOrderDate [11];
	char szTmp [20];
	char szClientFIO [100]; // для вывода FIO
	std::auto_ptr<RING> table (new RING (10 kb));
	char *szBuf;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}

	s = "Реестр амбулаторных карт за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	fnReportTitle (query,s.c_str ());

	// цикл с единицы, т.к. нулевой клиент - Анонимный
	for (iCycle = 1; iCycle < iClientsQty; iCycle++)
	{
		if (client [iCycle]->fnGetDelete ())
			continue;
		if (! client [iCycle]->fnGetMapOrderNum ())
			continue;
		client [iCycle]->fnMapOrderDate ()->fnGetDate (szMapOrderDate);
		if (! fnCheckDateRange (szDate1,szMapOrderDate,szDate2))
			continue;

		// формируем строку таблицы
		s = "<!--";
		sprintf (szTmp,"%06i",client [iCycle]->fnGetMapOrderNum ()); // шестизначный номер для сортировки
		s += szTmp;
		s += "--><tr><td align=right>";
		sprintf (szTmp,"%i",client [iCycle]->fnGetMapOrderNum ());
		s += szTmp;
		s += "</td><td>";
		s += szMapOrderDate;
		s += "</td><td>";
		sprintf (szClientFIO,"%s %s %s",
			client [iCycle]->fnGetFamily (),
			client [iCycle]->fnGetName (),
			client [iCycle]->fnGetName2 ());
		s += szClientFIO;
		s += "</td></tr>";
		table->fnPushStr (s.c_str ());
	}
	if (table->fnGetQty ())
	{
		table->fnSort (0); // сортировка в кольце

		query->dst->fnAddLine (
"<table width=\"100%\" border=1><tr>\
<td align=center>Номер</td>\
<td align=center>Дата</td>\
<td align=center>ФИО клиента</td></tr>");

		while (table->fnGetQty ())
		{
			szBuf = new char [table->fnGetLen ()];
			table->fnPop (szBuf);
			query->dst->fnAddLine (szBuf);
			delete [] szBuf;
		}
		query->dst->fnAddLine ("</table>");
	}
	fnReportEnd (query);
} // end of fnAppReportMapOrderForm ()

// ****************************************************************************
// *                                                                          *
// *                           ФИНАНСОВЫЕ ОТЧЁТЫ                              *
// *                                                                          *
// ****************************************************************************

// *******************
// * отчёт о доходах *
// *******************
void fnAppReportIncomeForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	char szGroupId [2 +1];
	char szVisitFlagId [2 +1];

	int iGroupId;
	int iVisitFlagId;
	string s;
	int iCycle;
	std::auto_ptr<RING> visits_found (new RING (64 kb));
	int iQty;
	int iDaysQty;
	int iCycleDay;
	char szCycleDate [11];
	double dSum;
	double dSumBank;
	double dSumTerminal;
	double dSumInsurance;
	int iVisit;
	double dPayment;
	char szTmp [20];
	double dSumTotal = 0.0;
	double dSumTotalBank = 0.0;
	double dSumTotalTerminal = 0.0;
	double dSumTotalInsurance = 0.0;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);
	// флажок посещения
	if (! login_visitflag->fnGetValue (szVisitFlagId,query->szLogin))
	{
		strcpy (szVisitFlagId,"-1");
		login_visitflag->fnAdd (query->szLogin,szVisitFlagId);
	}
	iVisitFlagId = atoi (szVisitFlagId);

	s = "Отчёт о доходах за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	fnReportTitle (query,s.c_str ());

	// выбираем актуальные посещения
	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetPaymentDate (),szDate2))
			continue;
		if (visit [iCycle]->fnGetPreEntry ())
			continue;
		// флажок посещения
		switch (iVisitFlagId)
		{
			case 11:
			if (visit [iCycle]->fnGetFlag1 () == false)
				continue;
			break;

			case 10:
			if (visit [iCycle]->fnGetFlag1 () == true)
				continue;
			break;

			case 21:
			if (visit [iCycle]->fnGetFlag2 () == false)
				continue;
			break;

			case 20:
			if (visit [iCycle]->fnGetFlag2 () == true)
				continue;
			break;

			case 31:
			if (visit [iCycle]->fnGetFlag3 () == false)
				continue;
			break;

			case 30:
			if (visit [iCycle]->fnGetFlag3 () == true)
				continue;
			break;

			case 41:
			if (visit [iCycle]->fnGetFlag4 () == false)
				continue;
			break;

			case 40:
			if (visit [iCycle]->fnGetFlag4 () == true)
				continue;
		}
		// группа
		if (iGroupId >= 0)
			if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
				continue;
		// размещаем номер записи в кольцо visits_found
		visits_found->fnPush ((char *) &iCycle,sizeof (iCycle));
	}
	iQty = visits_found->fnGetQty ();

	query->dst->fnAddLine (
"<table width=\"100%\" border=1><tr>\
<td align=center>Дата</td>\
<td width=\"15%\" align=center>Наличные</td>\
<td width=\"15%\" align=center>Ч/банк</td>\
<td width=\"15%\" align=center>Терминал</td>\
<td width=\"15%\" align=center>ОМС</td>\
<td width=\"15%\" align=center>Всего</td></tr>");

	// цикл по дням
	iDaysQty = fnGetDaysQty (szDate1,szDate2);
	for (iCycleDay = 0; iCycleDay < iDaysQty; iCycleDay++)
	{
		fnCreateDate (szCycleDate,szDate1,iCycleDay);
		dSum = 0.0;
		dSumBank = 0.0;
		dSumTerminal = 0.0;
		dSumInsurance = 0.0;

		for (iCycle = 0; iCycle < iQty; iCycle++)
		{
			visits_found->fnPop ((char *) &iVisit,iCycle);
			if (fnCompareDate (szCycleDate,visit [iVisit]->fnGetPaymentDate ()))
				continue;

			dPayment = visit [iVisit]->fnGetPaymentSum ();
			// подсчитываем сумму
			switch (visit [iVisit]->fnGetPaymentType ())
			{
				case 0: // оплата наличными
				dSum += dPayment;
				break;

				case 1: // оплата через банк
				dSumBank += dPayment;
				break;

				case 2: // терминал
				dSumTerminal += dPayment;
				break;

				case 3: // ОМС
				dSumInsurance += dPayment;
				break;
			}
		}

		// формируем строку таблицы
		s = "<tr><td>";
		s += szCycleDate;
		s += "</td><td align=right>";
		sprintf (szTmp,"%.2f",dSum);
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td><td align=right>";
		sprintf (szTmp,"%.2f",dSumBank);
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td><td align=right>";
		sprintf (szTmp,"%.2f",dSumTerminal);
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td><td align=right>";
		sprintf (szTmp,"%.2f",dSumInsurance);
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td><td align=right>";
		sprintf (szTmp,"%.2f",dSum+dSumBank+dSumTerminal+dSumInsurance);
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td></tr>";
		query->dst->fnAddLine (s.c_str ());

		dSumTotal += dSum;
		dSumTotalBank += dSumBank;
		dSumTotalTerminal += dSumTerminal;
		dSumTotalInsurance += dSumInsurance;
	}

	// строка итогов
	s = "<tr><td align=right><b>Итого:</b></td><td align=right><b>";
	sprintf (szTmp,"%.2f",dSumTotal);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</b></td><td align=right><b>";
	sprintf (szTmp,"%.2f",dSumTotalBank);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</b></td><td align=right><b>";
	sprintf (szTmp,"%.2f",dSumTotalTerminal);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</b></td><td align=right><b>";
	sprintf (szTmp,"%.2f",dSumTotalInsurance);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</b></td><td align=right><b>";
	sprintf (szTmp,"%.2f",dSumTotal+dSumTotalBank+dSumTotalTerminal+dSumTotalInsurance);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</b></td></tr></table>";
	query->dst->fnAddLine (s.c_str ());

	fnReportEnd (query);
} // end of fnAppReportIncomeForm ()

// ***********************************
// * отчёт о доходах по организациям *
// ***********************************
void fnAppReportOrgsIncomeForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	char szGroupId [2 +1];
	char szVisitFlagId [2 +1];

	int iGroupId;
	int iVisitFlagId;
	string s;
	int iOrgsQty;
	int iCycleOrg;
	ORG s_org;
	int iCycleSpec;
	int iCycle;
	double dConsIncome;
	double dOrgTotal;
	char szTmp [20];
	double dIncomeTotal = 0.0;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);
	// флажок посещения
	if (! login_visitflag->fnGetValue (szVisitFlagId,query->szLogin))
	{
		strcpy (szVisitFlagId,"-1");
		login_visitflag->fnAdd (query->szLogin,szVisitFlagId);
	}
	iVisitFlagId = atoi (szVisitFlagId);

	s = "Отчёт о доходах по организациям за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	fnReportTitle (query,s.c_str ());

	iOrgsQty = orgs->fnGetQty ();
	for (iCycleOrg = 0; iCycleOrg < iOrgsQty; iCycleOrg++)
	{
		dOrgTotal = 0.0;
		orgs->fnPop ((char *) &s_org,iCycleOrg); // s_org.iKey
		// таблица "организация"
		s = "<p><table border=0><tr><td>Наименование:</td><td><b>";
		s += s_org.szName;
		s += "</b></td></tr><tr><td>Адрес:</td><td>";
		s += s_org.szAddress;
		s += "&nbsp;</td></tr><tr><td>Телефоны:</td><td>";
		s += s_org.szPhones;
		s += "&nbsp;</td></tr><tr><td>Менеджер:</td><td>";
		s += s_org.szManager;
		s += "&nbsp;</td></tr></table>";
		// заголовок таблицы "доход"
		s += "<table border=1 width=\"100%\"><tr>\
<td width=\"50%\" align=center>Консультант</td>\
<td width=\"50%\" align=center>Доход</td></tr>";

		for (iCycleSpec = 0; iCycleSpec < iSpecsQty; iCycleSpec++)
		{
			// пропускаем специалистов
			if (! fnGetSpecCons (fnGetSpecType (iCycleSpec)))
				continue;
			// пропускаем консультантов из других организаций
			if (fnGetConsOrg (fnGetSpecType (iCycleSpec)) != s_org.iKey)
				continue;
			// рассчитываем доход по консультанту
			dConsIncome = 0.0;
			for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
			{
				if (visit [iCycle]->fnGetDelete ())
					continue;
				if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetPaymentDate (),szDate2))
					continue;
				if (visit [iCycle]->fnGetPreEntry ())
					continue;
				// флажок посещения
				switch (iVisitFlagId)
				{
					case 11:
					if (visit [iCycle]->fnGetFlag1 () == false)
						continue;
					break;

					case 10:
					if (visit [iCycle]->fnGetFlag1 () == true)
						continue;
					break;

					case 21:
					if (visit [iCycle]->fnGetFlag2 () == false)
						continue;
					break;

					case 20:
					if (visit [iCycle]->fnGetFlag2 () == true)
						continue;
					break;

					case 31:
					if (visit [iCycle]->fnGetFlag3 () == false)
						continue;
					break;

					case 30:
					if (visit [iCycle]->fnGetFlag3 () == true)
						continue;
					break;

					case 41:
					if (visit [iCycle]->fnGetFlag4 () == false)
						continue;
					break;

					case 40:
					if (visit [iCycle]->fnGetFlag4 () == true)
						continue;
				}
				// группа
				if (iGroupId >= 0)
					if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
						continue;
				if (visit [iCycle]->fnGetCons () != fnGetSpecType (iCycleSpec))
					continue;
				if (visit [iCycle]->fnGetAbsence ())
					continue;
				dConsIncome += visit [iCycle]->fnGetSum ();
			}
			if (dConsIncome)
			{
				dOrgTotal += dConsIncome;
				dIncomeTotal += dConsIncome;
				// формируем строку таблицы
				s += "<tr><td>";
				s += fnGetSpecFIO (fnGetSpecType (iCycleSpec));
				s += "</td><td align=right>";
				sprintf (szTmp,"%.2f",dConsIncome);
				if (config.bReportSepComma)
					fnCharToComma (szTmp,'.');
				s += szTmp;
				s += "</td></tr>";
			}
		}
		s += "<table width=\"100%\"><tr><td align=right>Итого: <b>";
		sprintf (szTmp,"%.2f",dOrgTotal);
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</b></td></tr></table></p>";
		query->dst->fnAddLine (s.c_str ());
	}
	s = "<p align=center>Общая сумма доходов по организациям: <b>";
	sprintf (szTmp,"%.2f",dIncomeTotal);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</b></p>";
	query->dst->fnAddLine (s.c_str ());

	fnReportEnd (query);
} // end of fnAppReportOrgsIncomeForm ()

// *********************************
// * отчёт о доходах по менеджерам *
// *********************************
void fnAppReportManagersIncomeForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	char szGroupId [2 +1];
	char szVisitFlagId [2 +1];

	int iGroupId;
	int iVisitFlagId;
	string s;
	int iOrgsQty;
	int iCycleOrg;
	ORG s_org;
	int iCycle;
	double dOrgTotal;
	char szTmp [20];
	A_ARRAY *manager_income;
	RING *buf;
	int iManagersQty;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);
	// флажок посещения
	if (! login_visitflag->fnGetValue (szVisitFlagId,query->szLogin))
	{
		strcpy (szVisitFlagId,"-1");
		login_visitflag->fnAdd (query->szLogin,szVisitFlagId);
	}
	iVisitFlagId = atoi (szVisitFlagId);

	s = "Отчёт о доходах по менеджерам за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	fnReportTitle (query,s.c_str ());

	// таблица "организации"
	s = "<p><table border=1 width=\"100%\"><tr>\
<td width=\"25%\" align=center>Наименование</td>\
<td width=\"25%\" align=center>Адрес</td>\
<td width=\"25%\" align=center>Менеджер</td>\
<td width=\"25%\" align=center>Доход</td></tr>";

	manager_income = new A_ARRAY ();
	iOrgsQty = orgs->fnGetQty ();
	for (iCycleOrg = 0; iCycleOrg < iOrgsQty; iCycleOrg++)
	{
		dOrgTotal = 0.0;
		orgs->fnPop ((char *) &s_org,iCycleOrg); // s_org.iKey
		if (! strlen (s_org.szManager))
			continue; // организация не прикреплена к менеджеру

		// рассчитываем доход по организации
		for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
		{
			if (visit [iCycle]->fnGetDelete ())
					continue;
			if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetPaymentDate (),szDate2))
				continue;
			if (visit [iCycle]->fnGetPreEntry ())
				continue;
			// флажок посещения
			switch (iVisitFlagId)
			{
				case 11:
				if (visit [iCycle]->fnGetFlag1 () == false)
					continue;
				break;

				case 10:
				if (visit [iCycle]->fnGetFlag1 () == true)
					continue;
				break;

				case 21:
				if (visit [iCycle]->fnGetFlag2 () == false)
					continue;
				break;

				case 20:
				if (visit [iCycle]->fnGetFlag2 () == true)
					continue;
				break;

				case 31:
				if (visit [iCycle]->fnGetFlag3 () == false)
					continue;
				break;

				case 30:
				if (visit [iCycle]->fnGetFlag3 () == true)
					continue;
				break;

				case 41:
				if (visit [iCycle]->fnGetFlag4 () == false)
					continue;
				break;

				case 40:
				if (visit [iCycle]->fnGetFlag4 () == true)
					continue;
			}
			// группа
			if (iGroupId >= 0)
				if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
					continue;
			if (visit [iCycle]->fnGetAbsence ())
				continue;
			// пропускаем консультантов из других организаций
			if (fnGetConsOrg (visit [iCycle]->fnGetCons ()) != s_org.iKey)
				continue;
			dOrgTotal += visit [iCycle]->fnGetSum ();
		}

		s += "<tr><td>";
		s += s_org.szName;
		s += "</td><td>";
		s += s_org.szAddress;
		s += "</td><td>";
		s += s_org.szManager;
		s += "</td><td align=right>";
		sprintf (szTmp,"%.2f",dOrgTotal);
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td></tr>";

		// добавляем доход по организации в ассоциативный массив
		if (manager_income->fnGetValue (szTmp,s_org.szManager))
			dOrgTotal += atof (szTmp);
		sprintf (szTmp,"%.2f",dOrgTotal);
		manager_income->fnAdd (s_org.szManager,szTmp);

	}
	s += "</table></p>";
	query->dst->fnAddLine (s.c_str ());

	// таблица "менеджеры"
	s = "<p><table border=1 width=\"100%\"><tr>\
<td width=\"50%\" align=center>Менеджер</td>\
<td width=\"50%\" align=center>Доход</td></tr>";

	buf = new RING (1 kb);
	manager_income->fnCopyBuf (buf);
	delete manager_income;

	iManagersQty = buf->fnGetQty ()>>1;
	for (iCycle = 0; iCycle < iManagersQty; iCycle++)
	{
		s += "<tr><td>";
		buf->fnPop (s_org.szManager);
		s += s_org.szManager;
		s += "</td><td align=right>";
		buf->fnPop (szTmp);
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td></tr>";
	}
	delete buf;

	s += "</table></p>";
	query->dst->fnAddLine (s.c_str ());

	fnReportEnd (query);
} // end of fnAppReportManagersIncomeForm ()

// **********************************
// * отчёт по видам товаров и услуг *
// **********************************
void fnAppReportServicesForm (QUERY *query)
{
	RING *args = query->args;
	char sz [INI_MAX_LEXEM_LEN +1];
	bool bPrefix = false;
//	bool bVisitDate = false;

	char szDate1 [11];
	char szDate2 [11];
	char szTime1 [5 +1];
	char szTime2 [5 +1];
	char szPrefix [WS_MAX_NAME_LEN +1];
	char szGroupId [2 +1];
	char szVisitFlagId [2 +1];
	int iOrg = -1;

	std::auto_ptr<RING> visits_found (new RING (64 kb));
	int iQty;
	int iVisit;
	string s;
	int iCycleService,iCycle;
	double dPriceSum;
	double dQtySum;
	double dSumSum;
	double dQtyTotal = 0.0;
	double dSumTotal = 0.0;
	char szTmp [20];
	int iTime1;
	int iTime2;
	int iGroupId;
	int iVisitFlagId;
	int iPaymentTime;
//	int iVisitTime;
	bool bOneDay = false;
	double dCostSum;
	double dCostTotal = 0.0;
	A_ARRAY *aa_price_qty;
	RING *buf;
	char szKeyPrice [20];
	char szValueQty [20];
	double dKeyPrice;
	double dValueQty;
	int iPricesQty;
	double dTmpPrice;
	double dTmpQty;
	double dTmpSum;
	double dTmpCost;

	while (args->fnGetQty ())
	{
		args->fnPop (sz);
		if (! strcmp (sz,"prefix"))
		{
			args->fnPop (sz);
			bPrefix = true;
			continue;
		}
	}

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	if (fnCompareDate (szDate1,szDate2) == 0)
		bOneDay = true;
	// время
	if (! login_time1->fnGetValue (szTime1,query->szLogin))
	{
		strcpy (szTime1,"00:00");
		login_time1->fnAdd (query->szLogin,szTime1);
	}
	if (! login_time2->fnGetValue (szTime2,query->szLogin))
	{
		strcpy (szTime2,"23:59");
		login_time2->fnAdd (query->szLogin,szTime2);
	}
	// преобразуем время в формат кол-ва минут после полуночи
	iTime1 = fnGetMinutesAfterMidnightHM (szTime1);
	iTime2 = fnGetMinutesAfterMidnightHM (szTime2);
	// префикс
	if (bPrefix)
	{
		if (! login_prefix->fnGetValue (szPrefix,query->szLogin))
		{
			*szPrefix = 0;
			login_prefix->fnAdd (query->szLogin,szPrefix);
		}
	}
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);
	// флажок посещения
	if (! login_visitflag->fnGetValue (szVisitFlagId,query->szLogin))
	{
		strcpy (szVisitFlagId,"-1");
		login_visitflag->fnAdd (query->szLogin,szVisitFlagId);
	}
	iVisitFlagId = atoi (szVisitFlagId);
	// организация-плательщик
	if (login_org->fnGetValue (szTmp,query->szLogin))
		iOrg = atoi (szTmp);
	else
		login_org->fnAdd (query->szLogin,"-1");

	s = "Отчёт по видам товаров и услуг<br>(период: ";
	s += szTime1;
	s += "&nbsp;";
	s += szDate1;
	s += " &mdash; ";
	s += szTime2;
	s += "&nbsp;";
	s += szDate2;
	s += ")";
	if (bPrefix)
	{
		s += ", префикс филиала: \"";
		s += szPrefix;
		s += "\"";
	}
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	if (iOrg != -1)
	{
		char szOrgName [WS_MAX_DESC_LEN +1];

		s += ", плательщик: ";
		s += fnGetOrgName (szOrgName,iOrg);
	}
	fnReportTitle (query,s.c_str ());

	query->dst->fnAddLine (
"<table width=\"100%\" border=1><tr>\
<td align=center>Вид услуг</td>\
<td align=center>Кол-во</td>\
<td align=center>Цена ср.</td>\
<td align=center>Сумма</td>\
<td align=center>С/с ср.</td>\
<td align=center>Прибыль</td></tr>");

	// выбираем актуальные посещения
	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		// префикс
		if (bPrefix)
			if (strcmp (szPrefix,visit [iCycle]->fnGetPrefix ()))
				continue;
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetPaymentDate (),szDate2))
			continue;
		if (visit [iCycle]->fnGetPreEntry ())
			continue;
		// организация-плательщик
		if (iOrg != -1)
			if (visit [iCycle]->fnGetOrg () != iOrg)
				continue;
		// флажок посещения
		switch (iVisitFlagId)
		{
			case 11:
			if (visit [iCycle]->fnGetFlag1 () == false)
				continue;
			break;

			case 10:
			if (visit [iCycle]->fnGetFlag1 () == true)
				continue;
			break;

			case 21:
			if (visit [iCycle]->fnGetFlag2 () == false)
				continue;
			break;

			case 20:
			if (visit [iCycle]->fnGetFlag2 () == true)
				continue;
			break;

			case 31:
			if (visit [iCycle]->fnGetFlag3 () == false)
				continue;
			break;

			case 30:
			if (visit [iCycle]->fnGetFlag3 () == true)
				continue;
			break;

			case 41:
			if (visit [iCycle]->fnGetFlag4 () == false)
				continue;
			break;

			case 40:
			if (visit [iCycle]->fnGetFlag4 () == true)
				continue;
		}
		// группа
		if (iGroupId >= 0)
			if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
				continue;

		// период
		iPaymentTime = fnGetMinutesAfterMidnightHM (visit [iCycle]->fnGetPaymentTime ());
		if (bOneDay) // период охватывает только один день
		{
			if ((iPaymentTime < iTime1) || (iPaymentTime > iTime2))
				continue;
		}
		else // период охватывает несколько дней
		{
			// первый день периода
			if ((fnCompareDate (szDate1,visit [iCycle]->fnGetPaymentDate ()) == 0)
				&& (iPaymentTime < iTime1))
				continue;
			// последний день периода
			if ((fnCompareDate (szDate2,visit [iCycle]->fnGetPaymentDate ()) == 0)
				&& (iPaymentTime > iTime2))
				continue;
		}

		// размещаем номер записи в кольцо visits_found
		visits_found->fnPush ((char *) &iCycle,sizeof (iCycle));
	}

	iQty = visits_found->fnGetQty ();
	aa_price_qty = new A_ARRAY ();
	buf = new RING (1 kb);
	for (iCycleService = 0; iCycleService < iServicesQty; iCycleService++)
	{
		dPriceSum = 0.0;
		dQtySum = 0.0;
		dSumSum = 0.0;
		dCostSum = 0.0;

		aa_price_qty->fnClear ();
		for (iCycle = 0; iCycle < iQty; iCycle++)
		{
			visits_found->fnPop ((char *) &iVisit,iCycle);

			if (visit [iVisit]->fnGetType () != fnGetServiceType (iCycleService))
				continue;

			// цена
			dTmpPrice = visit [iVisit]->fnGetPrice();
			dPriceSum += dTmpPrice;

			// количество
			dTmpQty = visit [iVisit]->fnGetQty();
			dQtySum += dTmpQty;

			// сумма
			dTmpSum = dTmpPrice*dTmpQty;
			dSumSum += dTmpSum;

			// учёт цены и кол-ва
			sprintf(szKeyPrice,"%.2f",dTmpPrice);
			dValueQty = dTmpQty;
			if (aa_price_qty->fnGetValue(szValueQty,szKeyPrice))
				dValueQty += atof (szValueQty);
			sprintf(szValueQty,"%.2f",dValueQty);
			aa_price_qty->fnAdd(szKeyPrice,szValueQty);

			// затраты
			dTmpCost = visit [iVisit]->fnGetCost ();
			dCostSum += dTmpCost;
		}

		buf->fnClear ();
		aa_price_qty->fnCopyBuf (buf);
		iPricesQty = buf->fnGetQty ()>>1;
		// выводим дополнительные строки
		if ((iPricesQty > 1) // если количество цен за услугу больше 1
			&& config.bReportServicesDetailed) // если детализация разрешена
		{
			for (iCycle = 0; iCycle < iPricesQty; iCycle++)
			{
				buf->fnPop (szKeyPrice);
				buf->fnPop (szValueQty);
				dKeyPrice = atof (szKeyPrice);
				dValueQty = atof (szValueQty);

				s = "<tr><td><div style=\"color:silver;\">";

				// наименование
				s += fnGetServiceName (fnGetServiceType (iCycleService));

				// кол-во
				s += "</div></td><td width=\"10%\" align=right><div style=\"color:silver;\">";
				if (config.bReportSepComma)
					fnCharToComma (szValueQty,'.');
				s += szValueQty;

				// цена
				s += "</div></td><td width=\"10%\" align=right><div style=\"color:silver;\">";
				if (config.bReportSepComma)
					fnCharToComma (szKeyPrice,'.');
				s += szKeyPrice;

				// сумма
				s += "</div></td><td width=\"10%\" align=right><div style=\"color:silver;\">";
				sprintf (szTmp,"%.2f",dKeyPrice*dValueQty);
				if (config.bReportSepComma)
					fnCharToComma (szTmp,'.');
				s += szTmp;

				// с/с ср.
				s += "</div></td><td width=\"10%\">&nbsp;";

				// прибыль
				s += "</td><td width=\"10%\">&nbsp;";

				s += "</td></tr>";
				query->dst->fnAddLine (s.c_str ());
			}
		}

		// раздел
		if (! fnGetServiceSelect (fnGetServiceType (iCycleService)))
		{
			s = "<tr><td><b>";
			s += fnGetServiceName (fnGetServiceType (iCycleService));
			s += "</b></td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>";
			query->dst->fnAddLine (s.c_str ());
		}
		else // товар или услуга
		{
			do
			{
				if (config.bReportServicesBrief
					&& dQtySum == 0.0)
					continue;

				// формируем строку таблицы
				s = "<tr><td>";

				// наименование
				s += fnGetServiceName (fnGetServiceType (iCycleService));

				// кол-во
				s += "</td><td width=\"10%\" align=right>";
				sprintf (szTmp,"%.2f",dQtySum);
				if (config.bReportSepComma)
					fnCharToComma (szTmp,'.');
				s += szTmp;
				dQtyTotal += dQtySum;

				// цена средняя
				s += "</td><td width=\"10%\" align=right>";
				sprintf (szTmp,"%.2f",dQtySum ? dSumSum/dQtySum : 0.0);
				if (config.bReportSepComma)
					fnCharToComma (szTmp,'.');
				s += szTmp;

				// сумма
				s += "</td><td width=\"10%\" align=right>";
				sprintf (szTmp,"%.2f",dSumSum);
				if (config.bReportSepComma)
					fnCharToComma (szTmp,'.');
				s += szTmp;
				dSumTotal += dSumSum;

				// с/с ср.
				s += "</td><td width=\"10%\" align=right>";
				sprintf (szTmp,"%.2f",dCostSum);
				if (config.bReportSepComma)
					fnCharToComma (szTmp,'.');
				s += szTmp;
				dCostTotal += dCostSum;

				// прибыль
				s += "</td><td width=\"10%\" align=right>";
				sprintf (szTmp,"%.2f",dSumSum-dCostSum);
				if (config.bReportSepComma)
					fnCharToComma (szTmp,'.');
				s += szTmp;

				s += "</td></tr>";
				query->dst->fnAddLine (s.c_str ());
			} while (false);
		}
	}
	delete buf;
	delete aa_price_qty;
	s = "</table>";

	s += "<table border=0 width=\"100%\"><tr><td align=right>Итого сумма: <b>";
	sprintf (szTmp,"%.2f",dSumTotal);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</b>, прибыль: <b>";
	sprintf (szTmp,"%.2f",dSumTotal-dCostTotal);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</b>, общее кол-во: ";
	sprintf (szTmp,"%.2f",dQtyTotal);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</td></tr></table>";
	query->dst->fnAddLine (s.c_str ());

	fnReportEnd (query);
} // end of fnAppReportServicesForm ()

// ***********************************
// * отчёт о предоставленных скидках *
// ***********************************
void fnAppReportDiscountForm(QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	char szGroupId [2 +1];

	int iGroupId;
	std::auto_ptr<RING> visits_found (new RING (64 kb));
	int iQty;
	int iVisit;
	string s;
	int iCycleDiscount,iCycle;
	double dTmp;
	double dSum;
//	int iClientNum;
	int iClient;
	char szClientFIO [100]; // для вывода ФИО
	char szTmp [20];
	std::auto_ptr<RING> table (new RING (512 kb));
	char *szBuf;
	double dSumTotal = 0.0;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue(szDate1,query->szLogin))
	{
		fnGetToday(szDate1);
		login_date1->fnAdd(query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue(szDate2,query->szLogin))
	{
		fnGetToday(szDate2);
		login_date2->fnAdd(query->szLogin,szDate2);
	}
	// группа
	if (! login_group->fnGetValue(szGroupId,query->szLogin))
	{
		strcpy(szGroupId,"-1");
		login_group->fnAdd(query->szLogin,szGroupId);
	}
	iGroupId = atoi(szGroupId);

	s = "Отчёт о предоставленных скидках<br>(период: ";
	s += szDate1;
	s += " &mdash; ";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	s += ")";
	fnReportTitle(query,s.c_str ());

	// выбираем актуальные посещения
	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete())
			continue;
		if (visit [iCycle]->fnGetPreEntry())
			continue;
		if (! visit [iCycle]->fnGetDiscountType())
			continue;
		if (! fnCheckDateRange(szDate1,visit [iCycle]->fnGetPaymentDate (),szDate2))
			continue;
		// группа
		if (iGroupId >= 0)
			if (! fnServicesGroupsGetMember(visit [iCycle]->fnGetType (),iGroupId))
				continue;

		// размещаем номер записи в кольцо visits_found
		visits_found->fnPush((char *) &iCycle,sizeof (iCycle));
	}

	iQty = visits_found->fnGetQty ();
	for (iCycleDiscount = 1; iCycleDiscount <= 11; iCycleDiscount++)
	{
		dSum = 0.0;

		for (iCycle = 0; iCycle < iQty; iCycle++)
		{
			visits_found->fnPop((char *) &iVisit,iCycle);

			if (visit [iVisit]->fnGetDiscountType() != iCycleDiscount)
				continue;

//			iClientNum = visit [iVisit]->fnGetClientNum();
			iClient = visit [iVisit]->fnGetClientIndex();
			if (iClient < 1)
				continue;

			// формируем строку таблицы
			// критерий сортировки
			s = "<!--";
			if (iCycleDiscount == 11)
			{
				sprintf (szTmp,"%08u_",visit [iVisit]->fnGetDiscountCardNum());
				s += szTmp;
			}
			sprintf (szTmp,"%4u/%02u/%02u",
				fnGetYear(visit [iVisit]->fnGetPaymentDate()),
				fnGetMonth(visit [iVisit]->fnGetPaymentDate()),
				fnGetDay(visit [iVisit]->fnGetPaymentDate()));
			s += szTmp;
			s += "-->";

			s += "<tr>";

			if (iCycleDiscount == 11)
			{
				s += "<td valign=top align=right>";
				sprintf (szTmp,"%i",visit [iVisit]->fnGetDiscountCardNum());
				s += szTmp;
				s += "</td>";
			}

			// дата
			s += "<td valign=top>";
			s += visit [iVisit]->fnGetPaymentDate();
			s += "</td>";

			// № договора
			s += "<td valign=top align=right>";
			if (visit [iVisit]->fnGetContractNum())
			{
				if (strlen(visit [iVisit]->fnGetPrefix()))
				{
					s += visit [iVisit]->fnGetPrefix();
					s += "-";
				}
				sprintf(szTmp,"%i",visit [iVisit]->fnGetContractNum());
				s += szTmp;
			}
			s += "&nbsp;</td>";

			// ФИО клиента
			s += "<td valign=top>";
			sprintf (szClientFIO,"%s %s %s",
				client [iClient]->fnGetFamily(),
				client [iClient]->fnGetName(),
				client [iClient]->fnGetName2());
			s += szClientFIO;
			s += "</td>";

			// услуга
			s += "<td valign=top>";
			s += fnGetServiceName (visit [iVisit]->fnGetType());
			s += "</td>";

			// исходная цена
			s += "<td valign=top align=right>";
			sprintf (szTmp,"%.2f",visit [iVisit]->fnGetOriginalPrice());
			s += szTmp;
			s += "</td>";

			// % скидки (наценки)
			s += "<td valign=top align=right>";
			sprintf (szTmp,"%.2f",visit [iVisit]->fnGetDiscountPercent());
			s += szTmp;
			s += "</td>";

			// цена
			s += "<td valign=top align=right>";
			sprintf (szTmp,"%.2f",visit [iVisit]->fnGetPrice());
			s += szTmp;
			s += "</td>";

			// кол-во
			s += "<td valign=top align=right>";
			sprintf (szTmp,"%.2f",visit [iVisit]->fnGetQty());
			s += szTmp;
			s += "</td>";

			// сумма
			s += "<td valign=top align=right>";
			sprintf (szTmp,"%.2f",visit [iVisit]->fnGetSum());
			s += szTmp;
			s += "</td>";

			// размер скидки, руб.
			if (iCycleDiscount != 7)
				// (исходная цена * количество) - сумма
				dTmp = (visit [iVisit]->fnGetOriginalPrice()*visit [iVisit]->fnGetQty())-visit [iVisit]->fnGetSum();
			else
				// наценка
				dTmp = visit [iVisit]->fnGetSum()-(visit [iVisit]->fnGetOriginalPrice()*visit [iVisit]->fnGetQty());
			dSum += dTmp;
			dSumTotal += dTmp;
			s += "<td valign=top align=right>";
			sprintf (szTmp,"%.2f",dTmp);
			s += szTmp;
			s += "</td></tr>";

			table->fnPushStr (s.c_str ());
		}

		if (table->fnGetQty ())
		{
			table->fnSort (0); // сортировка в кольце

			s = "<p>";
			switch (iCycleDiscount)
			{
				case 1: s += "С1 единовременная скидка"; break;
				case 2: s += "С2 накопительная скидка"; break;
				case 3: s += "С3 скидка пенсионерам"; break;
				case 4: s += "С4 скидка детям"; break;
				case 5: s += "С5 индивидуальная скидка"; break;
				case 6: s += "С6 скидка от консультанта"; break;
				case 7: s += "С7 наценка"; break;
				case 8: s += "С8 скидка по расписанию"; break;
				case 9: s += "С9 скидка от организации-плательщика"; break;
				case 10: s += "С10 абонемент"; break;
				case 11: s += "С11 скидка по дисконтной карте"; break;
			}
			s += "<table width=\"100%\" border=1><tr>";
			if (iCycleDiscount == 11)
				s += "<td align=center>№ карты</td>";
			s += "<td align=center>Дата</td>";
			s += "<td align=center>№ договора</td>";
			s += "<td align=center>ФИО клиента</td>";
			s += "<td align=center>Услуга</td>";
			s += "<td align=center>Исходная цена</td>";
			if (iCycleDiscount != 7)
				s += "<td align=center>% скидки</td>";
			else
				s += "<td align=center>% наценки</td>";
			s += "<td align=center>Цена</td>";
			s += "<td align=center>Кол-во</td>";
			s += "<td align=center>Сумма</td>";
			s += "<td align=center>Размер скидки, руб.</td></tr>";
			query->dst->fnAddLine(s.c_str());

			while (table->fnGetQty ())
			{
				szBuf = new char [table->fnGetLen ()];
				table->fnPop (szBuf);
				query->dst->fnAddLine (szBuf);
				delete [] szBuf;
			}

			s = "</table>";
			s += "<table border=0 width=\"100%\"><tr><td align=right>Итого, руб.: ";
			sprintf (szTmp,"%.2f",dSum);
			s += szTmp;
			s += "</td></tr></table>";
			s += "</p>";
			query->dst->fnAddLine(s.c_str());
		}
	}

	s = "<p>Таблица \"Итоги\".";
	s += "<table width=\"100%\" border=1>";
	s += "<tr><td width=\"50%\" align=center>Итого предоставлено скидок на сумму:</td><td align=right>";
	sprintf (szTmp,"%.2f",dSumTotal);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</td></tr>";
	s += "</table></p>";
	query->dst->fnAddLine (s.c_str ());

	fnReportEnd (query);
} // end of fnAppReportDiscountForm()

// ********************************************
// * отчёт о первичных и повторных обращениях *
// ********************************************
void fnAppReportPrimaryVisitsForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	char szGroupId [2 +1];
	int iOrg = -1;

	int iGroupId;
	string s;
	int iCycle,iCycle2;
	std::auto_ptr<RING> primary_visits (new RING (4 kb));
	std::auto_ptr<RING> total_visits (new RING (32 kb));
	int iClientNum;
	int iClient;
	char szRegDate [11];
	A_KEY_INT *client_nums;
	int iQty;
	int iVisit;
	char szClientFIO [100]; // для вывода FIO
	bool bPrev;
	double dSum;
	char szTmp [20];
	std::auto_ptr<RING> table (new RING (10 kb));
	char *szBuf;
	double dSumTotal = 0.0;
	int iPrimaryClientsQty;
	int iTotalClientsQty;
	A_KEY_INT *referred_client_nums;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);
	// организация-плательщик
	if (login_org->fnGetValue (szTmp,query->szLogin))
		iOrg = atoi (szTmp);
	else
		login_org->fnAdd (query->szLogin,"-1");

	s = "Отчёт о первичных и повторных обращениях за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	if (iOrg != -1)
	{
		char szOrgName [WS_MAX_DESC_LEN +1];

		s += ", плательщик: ";
		s += fnGetOrgName (szOrgName,iOrg);
	}
	fnReportTitle (query,s.c_str ());

	// выбираем актуальные посещения
	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetPaymentDate (),szDate2))
			continue;
		if (visit [iCycle]->fnGetPreEntry ())
			continue;
		// организация-плательщик
		if (iOrg != -1)
			if (visit [iCycle]->fnGetOrg () != iOrg)
				continue;
		// группа
		if (iGroupId >= 0)
			if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
				continue;
		if (visit [iCycle]->fnGetType () < 0)
			continue;

//		iClientNum = visit [iCycle]->fnGetClientNum ();
//		iClient = fnClientSearchByNum (iClientNum);
		iClient = visit [iCycle]->fnGetClientIndex();
		if (iClient == -1)
			continue;

		if (iClient == 0) // Анонимный
			continue;
		client [iClient]->fnCreationDate ()->fnGetDate (szRegDate);
		// размещаем номер записи в кольцо
		if (fnCheckDateRange (szDate1,szRegDate,szDate2))
			primary_visits->fnPush ((char *) &iCycle,sizeof (iCycle));
		total_visits->fnPush ((char *) &iCycle,sizeof (iCycle));
	}

	// таблица "Первичные обращения"
	client_nums = new A_KEY_INT ();
	iQty = primary_visits->fnGetQty ();
	for (iCycle = 0; iCycle < iQty; iCycle++)
	{
		primary_visits->fnPop ((char *) &iVisit,iCycle);
		iClientNum = visit [iVisit]->fnGetClientNum ();
		// если номера клиента в массиве нет
		if (! client_nums->fnCheck (iClientNum))
		{
			client_nums->fnAdd (iClientNum);

//			iClient = fnClientSearchByNum (iClientNum);
			iClient = visit [iVisit]->fnGetClientIndex();

			// дата регистрации
			client [iClient]->fnCreationDate ()->fnGetDate (szRegDate);
			// дата внутри комментария в формате ГГГГ/ММ/ДД для сортировки
			sprintf (szTmp,"<!-- %4u/%02u/%02u -->",
				fnGetYear (szRegDate),
				fnGetMonth (szRegDate),
				fnGetDay (szRegDate));
			s = szTmp;
			s += "<tr><td>";
			s += szRegDate;
			s += "</td><td>";
			// ФИО клиента
			sprintf (szClientFIO,"%s %s %s",
				client [iClient]->fnGetFamily (),
				client [iClient]->fnGetName (),
				client [iClient]->fnGetName2 ());
			s += szClientFIO;
			s += "</td><td>";
			// список предоставленных услуг
			bPrev = false;
			dSum = 0.0;
			for (iCycle2 = iCycle; iCycle2 < iQty; iCycle2++)
			{
				primary_visits->fnPop ((char *) &iVisit,iCycle2);
				if (visit [iVisit]->fnGetClientNum () == iClientNum)
				{
					if (bPrev)
						s += ", "; // разделитель
					s += fnGetServiceName (visit [iVisit]->fnGetType ());
					bPrev = true;

					// сумма к оплате
					dSum += visit [iVisit]->fnGetSum ();
				}
			}
			s += "</td><td align=right>";
			// на сумму
			sprintf (szTmp,"%.2f",dSum);
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</td></tr>";
			table->fnPushStr (s.c_str ());

			dSumTotal += dSum;
		}
	}
	// сохраняем кол-во первичных обращений
	iPrimaryClientsQty = client_nums->fnGetQty ();
	delete client_nums;

	query->dst->fnAddLine ("<p>Таблица 1. Первичные обращения.");
	query->dst->fnAddLine (
"<table width=\"100%\" border=1><tr>\
<td align=center>Дата регистрации</td>\
<td align=center>ФИО клиента</td>\
<td align=center>Список предоставленных услуг</td>\
<td align=center>Сумма</td></tr>");

	if (table->fnGetQty ())
	{
		table->fnSort (0); // сортировка в кольце

		while (table->fnGetQty ())
		{
			szBuf = new char [table->fnGetLen ()];
			table->fnPop (szBuf);
			query->dst->fnAddLine (szBuf);
			delete [] szBuf;
		}
	}
	query->dst->fnAddLine ("</table></p>");

	query->dst->fnAddLine ("<p>Таблица 2. Соотношение.");
	query->dst->fnAddLine (
"<table border=1><tr><td>&nbsp;</td>\
<td align=center>Кол-во</td>\
<td align=center>Оказано услуг</td>\
<td align=center>На сумму</td></tr>");

	s = "<tr><td>Первичные обращения:</td><td align=right>";
	sprintf (szTmp,"%i",iPrimaryClientsQty);
	s += szTmp;
	s += "</td><td align=right>";
	sprintf (szTmp,"%i",primary_visits->fnGetQty ());
	s += szTmp;
	s += "</td><td align=right>";
	sprintf (szTmp,"%.2f",dSumTotal);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</td></tr>";
	query->dst->fnAddLine (s.c_str ());

	// рассчитываем данные для второй строки таблицы соотношения
	client_nums = new A_KEY_INT ();
	iQty = total_visits->fnGetQty ();
	dSumTotal = 0.0;
	for (iCycle = 0; iCycle < iQty; iCycle++)
	{
		total_visits->fnPop ((char *) &iVisit,iCycle);
		iClientNum = visit [iVisit]->fnGetClientNum ();
		// если номера клиента в массиве нет
		if (! client_nums->fnCheck (iClientNum))
			client_nums->fnAdd (iClientNum);

		// сумма к оплате
		dSumTotal += visit [iVisit]->fnGetSum ();
	}
	// сохраняем кол-во первичных обращений
	iTotalClientsQty = client_nums->fnGetQty ();
	delete client_nums;

	s = "<tr><td>Всего:</td><td align=right>";
	sprintf (szTmp,"%i",iTotalClientsQty);
	s += szTmp;
	s += "</td><td align=right>";
	sprintf (szTmp,"%i",total_visits->fnGetQty ());
	s += szTmp;
	s += "</td><td align=right>";
	sprintf (szTmp,"%.2f",dSumTotal);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</td></tr>";
	query->dst->fnAddLine (s.c_str ());

	query->dst->fnAddLine ("</table></p>");

	// таблица "Клиенты по направлению"
	if (config.bInputCons)
	{
		referred_client_nums = new A_KEY_INT ();
		iQty = primary_visits->fnGetQty ();
		for (iCycle = 0; iCycle < iQty; iCycle++)
		{
			primary_visits->fnPop ((char *) &iVisit,iCycle);
			if (visit [iVisit]->fnGetCons () < 0)
				continue;
			iClientNum = visit [iVisit]->fnGetClientNum ();
			// если номера клиента в массиве нет
			if (! referred_client_nums->fnCheck (iClientNum))
				referred_client_nums->fnAdd (iClientNum);
		}
		query->dst->fnAddLine ("<p>Таблица 3. Клиенты по направлению.");
		query->dst->fnAddLine (
"<table border=1><tr><td>&nbsp;</td>\
<td align=center>Кол-во</td></tr>");

		s = "<tr><td>Первичные обращения:</td><td align=right>";
		sprintf (szTmp,"%i",iPrimaryClientsQty);
		s += szTmp;
		s += "</td></tr>";

		s += "<tr><td>Из них по направлению:</td><td align=right>";
		sprintf (szTmp,"%i",referred_client_nums->fnGetQty ());
		s += szTmp;
		s += "</td></tr>";

		s += "</table></p>";
		query->dst->fnAddLine (s.c_str ());

		delete referred_client_nums;
	}

	fnReportEnd (query);
} // end of fnAppReportPrimaryVisitsForm ()

// *********************
// * история посещений *
// *********************
void fnAppReportVisitsHistoryForm (QUERY *query)
{
	RING *args = query->args;
	char sz [INI_MAX_LEXEM_LEN +1];
	int iSort = 1;

	char szDate1 [11];
	char szDate2 [11];
	char szGroupId [2 +1];

	int iGroupId;
	int iCycle;
	char szTmp [20];
	string s;
	std::auto_ptr<RING> visits_found (new RING (512 kb));
	A_KEY_INT *client_nums;
	int iQty;
	int iClientNum;
	int iClient;
	char szClientFIO [100]; // для вывода FIO
	char szPhones [CLIENT_PHONES_LEN +1];
	int iCycle2;
	int iVisit;
	bool bPrev;
	double dSum;
	std::auto_ptr<RING> table (new RING (512 kb));
	double dSumTotal = 0.0;
	int iCounter = 1;
	char *szBuf;
	A_KEY_SZ *client_visits_dates;

	while (args->fnGetQty ())
	{
		args->fnPop (sz);
		if (! strcmp (sz,"sort"))
		{
			args->fnPop (sz);
			iSort = atoi (sz);
			continue;
		}
	}

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);

	s = "История посещений за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	fnReportTitle (query,s.c_str ());

	// очищаем накопительные переменные у всех клиентов
	for (iCycle = 0; iCycle < iClientsQty; iCycle++)
		client [iCycle]->fnClearTmpSum ();

	// выбираем актуальные посещения
	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetDate (),szDate2))
			continue;
		if (visit [iCycle]->fnGetPreEntry ())
			continue;
		if (visit [iCycle]->fnGetType () < 0)
			continue;
		// группа
		if (iGroupId >= 0)
			if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
				continue;

		// подсчитываем сумму для каждого клиента
		client [visit [iCycle]->fnGetClientIndex ()]->fnAddTmpSum (visit [iCycle]->fnGetSum ());
		// размещаем номер записи в кольцо visits_found
		visits_found->fnPush ((char *) &iCycle,sizeof (iCycle));
	}

	client_nums = new A_KEY_INT ();
	iQty = visits_found->fnGetQty ();
	for (iCycle = 0; iCycle < iQty; iCycle++)
	{
		visits_found->fnPop ((char *) &iVisit,iCycle);
		iClientNum = visit [iVisit]->fnGetClientNum ();
		iClient = visit [iVisit]->fnGetClientIndex ();
		if (iClient == -1)
			continue;
		dSum = client [iClient]->fnGetTmpSum ();

		if (dSum < config.dReportVisitsHistoryMinSum) // сумма меньше минимальной
			continue;

		// если номера клиента в массиве нет
		if (! client_nums->fnCheck (iClientNum))
		{
			client_nums->fnAdd (iClientNum);

			s.clear ();
			client_visits_dates = new A_KEY_SZ ();
			// начало строки не заполняем! ("<tr><td>№</td>")
			// если сортировка по cуммам
			if (iSort == 2)
			{
				s += "<!--";
				sprintf (szTmp,"%09.2f",999999.00-dSum);
				s += szTmp;
				s += "-->";
			}
			// ФИО клиента
			s += "<td>";
			sprintf (szClientFIO,"%s %s %s",
				client [iClient]->fnGetFamily (),
				client [iClient]->fnGetName (),
				client [iClient]->fnGetName2 ());
			s += szClientFIO;
			s += "</td>";
			// дата рождения
			s += "<td>";
			s += client [iClient]->fnGetBirthday ();
			s += "</td>";
			// телефоны
			s += "<td>";
			s += client [iClient]->fnGetPhones (szPhones);
			s += "&nbsp;</td>";
			// даты посещений
			s += "<td>";
			bPrev = false;
			for (iCycle2 = iCycle; iCycle2 < iQty; iCycle2++)
			{
				visits_found->fnPop ((char *) &iVisit,iCycle2);
				if (visit [iVisit]->fnGetClientNum () == iClientNum)
				{
					// подсчитываем количество посещений (разных дат)
					if (! client_visits_dates->fnCheck (visit [iVisit]->fnGetDate ()))
					{
						if (bPrev)
							s += ", "; // разделитель
						s += visit [iVisit]->fnGetDate ();
						bPrev = true;

						client_visits_dates->fnAdd (visit [iVisit]->fnGetDate ());
					}
				}
			}
			s += "</td>";
			// количество посещений
			s += "<td>";
			sprintf (szTmp,"%i",client_visits_dates->fnGetQty ());
			s += szTmp;
			s += "</td>";
			// на сумму
			s += "<td align=right>";
			sprintf (szTmp,"%.2f",dSum);
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</td></tr>";

			table->fnPushStr (s.c_str ());
			dSumTotal += dSum;

			delete client_visits_dates;
		}
	}
	delete client_nums;

	query->dst->fnAddLine (
"<table width=\"100%\" border=1><tr>\
<td align=center>№</td>\
<td align=center>ФИО</td>\
<td align=center>Дата рождения</td>\
<td align=center>Телефоны</td>\
<td align=center>Даты посещений</td>\
<td align=center>Кол-во посещений</td>\
<td align=center>Сумма</td></tr>");

	if (table->fnGetQty ())
	{
		table->fnSort (0); // сортировка в кольце

		while (table->fnGetQty ())
		{
			s = "<tr><td>";
			sprintf (szTmp,"%i",iCounter++);
			s += szTmp;
			s += "</td>";
			szBuf = new char [table->fnGetLen ()];
			table->fnPop (szBuf);
			s += szBuf;
			delete [] szBuf;
			query->dst->fnAddLine (s.c_str ());
		}
	}
	query->dst->fnAddLine ("</table></p>");

	s = "<p align=right>";
	sprintf (szTmp,"Итого: %.2f",dSumTotal);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</p>";
	query->dst->fnAddLine (s.c_str ());

	fnReportEnd (query);
} // end of fnAppReportVisitsHistoryForm ()

// *************************
// * акт выполненных работ *
// *************************
void fnAppReportActWorkForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	int iOrg = -1;
	char szVisitFlagId [2 +1];
	int iVisitFlagId;

	int iCycle;
	char szTmp [20];
	string s;
	char szOrgName [WS_MAX_DESC_LEN +1];
	std::auto_ptr<RING> visits_found (new RING (512 kb));
	A_KEY_INT *client_nums;
	int iQty;
	int iClientNum;
	int iClient;
	char szClientFIO [100]; // для вывода FIO
	int iCycle2;
	int iVisit;
	bool bPrev;
	double dSum;
	std::auto_ptr<RING> table (new RING (512 kb));
	double dSumTotal = 0.0;
	int iCounter = 1;
	char *szBuf;
	char szAddress [CLIENT_ADDRESS_LEN +1];

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// организация-плательщик
	if (login_org->fnGetValue (szTmp,query->szLogin))
		iOrg = atoi (szTmp);
	else
		login_org->fnAdd (query->szLogin,"-1");
	// флажок посещения
	if (! login_visitflag->fnGetValue (szVisitFlagId,query->szLogin))
	{
		strcpy (szVisitFlagId,"-1");
		login_visitflag->fnAdd (query->szLogin,szVisitFlagId);
	}
	iVisitFlagId = atoi (szVisitFlagId);

	s = "Акт выполненных работ за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	s += ", организация: ";
	if (iOrg != -1)
		s += fnGetOrgName (szOrgName,iOrg);
	else
		s += "не выбрана";
	fnReportTitle (query,s.c_str ());
	if (iOrg == -1)
	{
		fnReportEnd (query);
		return;
	}

	// выбираем актуальные посещения
	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		if (visit [iCycle]->fnGetOrg () != iOrg)
			continue;
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetPaymentDate (),szDate2))
			continue;
		if (visit [iCycle]->fnGetPreEntry ())
			continue;
		// флажок посещения
		switch (iVisitFlagId)
		{
			case 11:
			if (visit [iCycle]->fnGetFlag1 () == false)
				continue;
			break;

			case 10:
			if (visit [iCycle]->fnGetFlag1 () == true)
				continue;
			break;

			case 21:
			if (visit [iCycle]->fnGetFlag2 () == false)
				continue;
			break;

			case 20:
			if (visit [iCycle]->fnGetFlag2 () == true)
				continue;
			break;

			case 31:
			if (visit [iCycle]->fnGetFlag3 () == false)
				continue;
			break;

			case 30:
			if (visit [iCycle]->fnGetFlag3 () == true)
				continue;
			break;

			case 41:
			if (visit [iCycle]->fnGetFlag4 () == false)
				continue;
			break;

			case 40:
			if (visit [iCycle]->fnGetFlag4 () == true)
				continue;
		}
		if (visit [iCycle]->fnGetType () < 0)
			continue;
		// размещаем номер записи в кольцо
		visits_found->fnPush ((char *) &iCycle,sizeof (iCycle));
	}

	client_nums = new A_KEY_INT ();
	iQty = visits_found->fnGetQty ();
	for (iCycle = 0; iCycle < iQty; iCycle++)
	{
		visits_found->fnPop ((char *) &iVisit,iCycle);
		iClientNum = visit [iVisit]->fnGetClientNum ();
		// если номера клиента в массиве нет
		if (! client_nums->fnCheck (iClientNum))
		{
			client_nums->fnAdd (iClientNum);

			iClient = fnClientSearchByNum (iClientNum);
			if (iClient == -1)
				continue;
			// начало строки не заполняем! ("<tr><td>№</td>")
			s = "<td>";
			// ФИО клиента
			sprintf (szClientFIO,"%s %s %s",
				client [iClient]->fnGetFamily (),
				client [iClient]->fnGetName (),
				client [iClient]->fnGetName2 ());
			s += szClientFIO;
			s += "</td><td>";
			// дата рождения
			s += client [iClient]->fnGetBirthday ();
			s += "</td><td>";
			// адрес
			s += client [iClient]->fnGetAddress (szAddress);
			s += "&nbsp;</td><td style=\"font-size: 8pt\">";
			// список предоставленных услуг
			bPrev = false;
			dSum = 0.0;
			for (iCycle2 = iCycle; iCycle2 < iQty; iCycle2++)
			{
				visits_found->fnPop ((char *) &iVisit,iCycle2);
				if (visit [iVisit]->fnGetClientNum () == iClientNum)
				{
					if (bPrev)
						s += "; "; // разделитель
					s += visit [iVisit]->fnGetDate ();
					s += "&nbsp;";
					s += visit [iVisit]->fnGetTime ();
					s += ": ";
					s += fnGetServiceName (visit [iVisit]->fnGetType ());
					sprintf (szTmp," %.2f",visit [iVisit]->fnGetPrice ());
					s += szTmp;
					s += "x";
					sprintf (szTmp,"%.2f",visit [iVisit]->fnGetQty ());
					s += szTmp;
					s += "=<b>";
					sprintf (szTmp,"%.2f</b>",visit [iVisit]->fnGetPrice ()*visit [iVisit]->fnGetQty ());
					s += szTmp;
					bPrev = true;

					// сумма к оплате
					dSum += visit [iVisit]->fnGetPrice ()*visit [iVisit]->fnGetQty ();
				}
			}
			s += "</td><td align=right>";
			// на сумму
			sprintf (szTmp,"%.2f",dSum);
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</td></tr>";
			table->fnPushStr (s.c_str ());

			dSumTotal += dSum;
		}
	}
	delete client_nums;

	query->dst->fnAddLine (
"<table width=\"100%\" border=1><tr>\
<td align=center>№</td>\
<td align=center>ФИО</td>\
<td align=center>Дата рождения</td>\
<td align=center>Адрес</td>\
<td align=center>Список предоставленных услуг</td>\
<td align=center>Сумма</td></tr>");

	if (table->fnGetQty ())
	{
		table->fnSort (0); // сортировка в кольце

		while (table->fnGetQty ())
		{
			s = "<tr><td>";
			sprintf (szTmp,"%i",iCounter++);
			s += szTmp;
			s += "</td>";
			szBuf = new char [table->fnGetLen ()];
			table->fnPop (szBuf);
			s += szBuf;
			delete [] szBuf;
			query->dst->fnAddLine (s.c_str ());
		}
	}
	query->dst->fnAddLine ("</table></p>");

	s = "<p align=right>";
	sprintf (szTmp,"Итого: %.2f",dSumTotal);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</p>";

	s += "<table border=0 width=\"100%\"><tr><td width=\"50%\">Исполнитель:<br>";
	s += fnGetFilialName(query->szPrefix);
	s += "<br>&nbsp;<br><img src=\"images/color-dark-gray.gif\" width=\"75%\" height=1><br>";
	s += fnGetToday (szTmp);
	s += "</td><td>Заказчик:<br>";
	s += szOrgName;
	s += "<br>&nbsp;<br><img src=\"images/color-dark-gray.gif\" width=\"75%\" height=1><br>";
	s += "\"____\"________ 20___</td></tr></table>";
	query->dst->fnAddLine (s.c_str ());

	fnReportEnd (query);
} // end of fnAppReportActWorkForm ()

// ******************************************************
// * реестр медицинских услуг для страховой организации *
// ******************************************************
void fnAppReportInsuranceOrderForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	int iOrg;
	char sz [INI_MAX_LEXEM_LEN +1];
	char szInsurerTemplate [WS_MAX_DESC_LEN +1];
	VDL_TEXT *tpl;
	int iCycle,iCycle2,iCycleVisit;
	std::auto_ptr<RING> visits_found (new RING (4 kb));
	double dSumTotal = 0.0;
	int iQty;
	int iClientNum;
	int iClient;
	const char *psz;
	string s;
	char szTmp [20];

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// организация-плательщик
	if (login_org->fnGetValue (szTmp,query->szLogin))
		iOrg = atoi (szTmp);
	else
		return;

	strcpy (sz,ini0.szBaseDir);
	// имя файла шаблона реестра
	strcat (sz,fnGetOrgInsurerTemplate (szInsurerTemplate,iOrg));
	tpl = new VDL_TEXT;
	tpl->fnLoad (sz); // загрузка шаблона договора

	// выбираем актуальные посещения
	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		if (visit [iCycle]->fnGetOrg () != iOrg)
			continue;
		if (visit [iCycle]->fnGetPaymentType () != 3) // ОМС
			continue;
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetPaymentDate (),szDate2))
			continue;
		if (visit [iCycle]->fnGetPreEntry ())
			continue;
		if (visit [iCycle]->fnGetType () < 0)
			continue;
		// размещаем номер записи в кольцо
		visits_found->fnPush ((char *) &iCycle,sizeof (iCycle));
		// подготовка переменной dSumTotal
		dSumTotal += visit [iCycleVisit]->fnGetSum ();
	}
	iQty = visits_found->fnGetQty ();

	// формирование страницы
	for (iCycle = 0; iCycle < (int) tpl->fnGetLinesQty (); iCycle++)
	{
		psz = tpl->fnGetLine (iCycle);
		if (! strcmp (psz,"{n_fio_policy_date_ds_service_price_qty_sum_order}"))
		{
			for (iCycle2 = 0; iCycle2 < iQty; iCycle2++)
			{
				visits_found->fnPop ((char *) &iCycleVisit,iCycle2);
				iClientNum = visit [iCycleVisit]->fnGetClientNum ();
				iClient = fnClientSearchByNum (iClientNum);
				if (iClient == -1)
					continue;
				// № п/п
				s = "<tr><td align=right>";
				sprintf (szTmp,"%i",iCycle2 +1);
				s += szTmp;
				// фамилия
				s += "</td><td>";
				s += client [iClient]->fnGetFamily ();
				// имя
				s += "</td><td>";
				s += client [iClient]->fnGetName ();
				// отчество
				s += "</td><td>";
				s += client [iClient]->fnGetName2 ();
				// номер полиса (договора) ОМС/ДМС
				s += "</td><td>";
				s += visit [iCycleVisit]->fnGetPolicy ();
				// дата оказания мед.услуги
				s += "</td><td>";
				s += visit [iCycleVisit]->fnGetDate ();
				// диагноз по МКБ
				s += "</td><td>&nbsp;";
				// наименование, код мед.услуги по прейскуранту, № зуба
				s += "</td><td>";
				s += fnGetServiceName (visit [iCycleVisit]->fnGetType ());
				// цена мед.услуги по прейскуранту
				s += "</td><td align=right>";
				sprintf (szTmp,"%.2f",visit [iCycleVisit]->fnGetPrice ());
				s += szTmp;
				// кол-во
				s += "</td><td align=right>";
				sprintf (szTmp,"%.2f",visit [iCycleVisit]->fnGetQty ());
				s += szTmp;
				// сумма
				s += "</td><td align=right>";
				sprintf (szTmp,"%.2f",visit [iCycleVisit]->fnGetSum ());
				s += szTmp;
				s += "</td></tr>";
				query->dst->fnAddLine (s.c_str ());
			}
			continue;
		}
		// итоговая сумма
		if (! strcmp (psz,"{sum_total}"))
		{
			sprintf (szTmp,"%.2f",dSumTotal);
			query->dst->fnAddLine (szTmp);
			continue;
		}
		// итоговая сумма числительными
		if (! strcmp (psz,"{sum_total_numeral}"))
		{
			fnSumToString (sz,dSumTotal,true);
			query->dst->fnAddLine (sz);
			continue;
		}
		query->dst->fnAddLine (psz);
	}
	delete tpl;
} // end of fnAppReportInsuranceOrderForm ()

// ********************************
// * реестр назначений внутренний *
// ********************************
void fnAppReportPrescriptionsOrderForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	char szTime1 [5 +1];
	char szTime2 [5 +1];
	char szGroupId [2 +1];

	int iTime1;
	int iTime2;
	int iGroupId;
	int iTime;
	bool bOneDay = false;
	int iCycle;
	char szTmp [20];
	string s;
	std::auto_ptr<RING> visits_found (new RING (512 kb));
	int iQty;
	int iVisit;
	std::auto_ptr<A_KEY_SZ> contracts (new A_KEY_SZ (16 kb));
	int iCurrentContractNum;
	char szCurrentContractDate [11];
	int iClientNum;
	int iClient;
	char szClientFIO [100]; // для вывода ФИО
	int iCycle2;
	string sCodes;
	string sServices;
	int iVisit2;
	std::auto_ptr<RING> table (new RING (512 kb));
	char *szBuf;
	string sComments;
	EXPORT1_ARGS s_export1_args;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	if (fnCompareDate (szDate1,szDate2) == 0)
		bOneDay = true;
	// время
	if (! login_time1->fnGetValue (szTime1,query->szLogin))
	{
		strcpy (szTime1,"00:00");
		login_time1->fnAdd (query->szLogin,szTime1);
	}
	if (! login_time2->fnGetValue (szTime2,query->szLogin))
	{
		strcpy (szTime2,"23:59");
		login_time2->fnAdd (query->szLogin,szTime2);
	}
	// преобразуем время в формат кол-ва минут после полуночи
	iTime1 = fnGetMinutesAfterMidnightHM (szTime1);
	iTime2 = fnGetMinutesAfterMidnightHM (szTime2);
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);

	s = "Реестр назначений внутренний за период с ";
	s += szTime1;
	s += "&nbsp;";
	s += szDate1;
	s += " по ";
	s += szTime2;
	s += "&nbsp;";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	fnReportTitle (query,s.c_str ());

	// выбираем актуальные посещения
	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetTakingDate (),szDate2))
			continue;
		if (visit [iCycle]->fnGetPreEntry ())
			continue;
		if (visit [iCycle]->fnGetType () < 0)
			continue;
		// группа
		if (iGroupId >= 0)
			if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
				continue;
		// период
		iTime = fnGetMinutesAfterMidnightHM (visit [iCycle]->fnGetTakingTime ());
		if (bOneDay) // период охватывает только один день
		{
			if ((iTime < iTime1) || (iTime > iTime2))
				continue;
		}
		else // период охватывает несколько дней
		{
			// первый день периода
			if ((fnCompareDate (szDate1,visit [iCycle]->fnGetTakingDate ()) == 0)
				&& (iTime < iTime1))
				continue;
			// последний день периода
			if ((fnCompareDate (szDate2,visit [iCycle]->fnGetTakingDate ()) == 0)
				&& (iTime > iTime2))
				continue;
		}

		// размещаем номер записи в кольцо visits_found
		visits_found->fnPush ((char *) &iCycle,sizeof (iCycle));
	}

	iQty = visits_found->fnGetQty ();
	for (iCycle = 0; iCycle < iQty; iCycle++)
	{
		visits_found->fnPop ((char *) &iVisit,iCycle); // неразрушающее чтение

		// формируем строковый ключ в формате "НОМЕР_ДАТА" договора
		sprintf (szTmp,"%i_%s",visit [iVisit]->fnGetContractNum (),visit [iVisit]->fnGetContractDate ());
		if (contracts->fnCheck (szTmp)) // для этого договора строка таблицы уже сформирована
			continue;

		contracts->fnAdd (szTmp); // добавляем ключ в массив
		iCurrentContractNum = visit [iVisit]->fnGetContractNum ();
		strcpy (szCurrentContractDate,visit [iVisit]->fnGetContractDate ());

		// формируем строку таблицы
		// номер договора
		s = "<tr><td valign=top>";
		if (strlen (visit [iVisit]->fnGetPrefix ()))
		{
			s += visit [iVisit]->fnGetPrefix ();
			s += "-";
		}
		sprintf (szTmp,"%i",visit [iVisit]->fnGetContractNum ());
		s += szTmp;
		s += "</td>";

		// ФИО клиента
		s += "<td valign=top>";
		iClientNum = visit [iVisit]->fnGetClientNum ();
		iClient = visit [iVisit]->fnGetClientIndex ();
		if (iClient == -1)
			continue;
		sprintf (szClientFIO,"%s %s %s",
			client [iClient]->fnGetFamily (),
			client [iClient]->fnGetName (),
			client [iClient]->fnGetName2 ());
		s += szClientFIO;
		// добавляем после запятой дату рождения, если она введена
		if (fnCheckDate (client [iClient]->fnGetBirthday ()))
		{
			s += ", ";
			s += client [iClient]->fnGetBirthday ();
		}
		// добавляем после точки с запятой идентификатор договора
		sprintf (szTmp,"; %i_%i_",iClientNum,visit [iVisit]->fnGetContractNum ());
		s += szTmp;
		sprintf (szTmp,"%02u%02u%02u",
			fnGetDay (visit [iVisit]->fnGetContractDate ()),
			fnGetMonth (visit [iVisit]->fnGetContractDate ()),
			fnGetYear (visit [iVisit]->fnGetContractDate ()) -2000);
		s += szTmp;
		// добавляем после точки с запятой данные для лаборатории
		if (client [iClient]->fnGetSex () == CLIENT_FEMALE)
		{
			bool bArgsFound = false;
			bool bLastArgsFound = false;
/*
struct EXPORT1_ARGS
{
	int iClientNum;
	char szDate [11];
	int iCycleDay;
	int iCyclePeriod;
	int iPregnancy;
};
void fnAddArgsExport1 (EXPORT1_ARGS *src);
void fnGetArgsExport1 (EXPORT1_ARGS *dst,int iClientNum);
*/
			bArgsFound = fnGetArgsExport1(&s_export1_args,iClientNum,visit[iVisit]->fnGetContractDate());
			if (! bArgsFound)
			{
				bArgsFound = fnGetLastArgsExport1 (&s_export1_args,iClientNum);
				if (bArgsFound)
				{
					// если данные достаточно свежие
					if (fnGetDayIndex(s_export1_args.szDate,szDate2) <= 31)
						bLastArgsFound = true;
					else
						bArgsFound = false;
				}
			}
			if (bArgsFound)
			{
				if (s_export1_args.iCycleDay)
				{
					s += "; день цикла ";
					sprintf (szTmp,"%i",s_export1_args.iCycleDay);
					s += szTmp;
				}
				if (s_export1_args.iCyclePeriod)
				{
					s += "; фаза цикла ";
					switch (s_export1_args.iCyclePeriod)
					{
						case 1: s += "овуляция"; break;
						case 2: s += "фолликулиновая"; break;
						case 3: s += "лютеиновая"; break;
						case 4: s += "менопауза"; break;
					}
				}
				if (s_export1_args.iPregnancy)
				{
					s += "; срок берем/задержки ";
					sprintf (szTmp,"%i",s_export1_args.iPregnancy);
					s += szTmp;
				}
				if (bLastArgsFound)
				{
					s += " (";
					s += s_export1_args.szDate;
					s += ")";
				}
			}
		}
		s += "</td>";

		// пол
		s += "<td valign=top>";
		if (client [iClient]->fnGetSex () == 1)
			s += "М";
		else
			s += "Ж";
		s += "</td>";

		// собираем пачки кодов и наименований услуг
		sCodes.clear ();
		sServices.clear ();
		sComments.clear ();
		for (iCycle2 = iCycle; iCycle2 < iQty; iCycle2++)
		{
			visits_found->fnPop ((char *) &iVisit2,iCycle2); // неразрушающее чтение

			if (visit [iVisit2]->fnGetContractNum () != iCurrentContractNum)
				continue;
			if (strcmp (visit [iVisit2]->fnGetContractDate (),szCurrentContractDate))
				continue;

			sCodes += "<div>";
			sCodes += fnGetServiceExtCode (visit [iVisit2]->fnGetType ());
			sCodes += "</div>";

			sServices += "<div>";
			sServices += fnGetServiceName (visit [iVisit2]->fnGetType ());
			sServices += "</div>";

			if (strlen (visit [iVisit2]->fnGetComments ()))
			{
				sComments += "<div>";
				sComments += visit [iVisit2]->fnGetComments ();
				sComments += "</div>";
			}
		}

		// коды услуг
		s += "<td valign=top>";
		s += sCodes;
		s += "</td>";

		// виды услуг
		s += "<td valign=top>";
		s += sServices;
		s += "</td>";

		// примечания
		s += "<td valign=top>";
		s += sComments;
		s += "</td>";

		// штрих код
		s += "<td><img src=\"images/color-white.gif\" width=";
		sprintf (szTmp,"%i",config.iReportBarcodeWidth);
		s += szTmp;
		s += " height=";
		sprintf (szTmp,"%i",config.iReportBarcodeHeight);
		s += szTmp;
		s += "></td></tr>";

		table->fnPushStr (s.c_str ());
	}

	query->dst->fnAddLine ("<table width=\"100%\" border=1><tr>\
<td align=center>№ договора</td>\
<td align=center>Клиент</td>\
<td align=center>Пол</td>\
<td align=center>Коды услуг</td>\
<td align=center>Виды услуг</td>\
<td align=center>Примечания</td>\
<td align=center>Штрих-код</td></tr>");

	if (table->fnGetQty ())
	{
		table->fnSort (0); // сортировка в кольце

		while (table->fnGetQty ())
		{
			szBuf = new char [table->fnGetLen ()];
			table->fnPop (szBuf);
			query->dst->fnAddLine (szBuf);
			delete [] szBuf;
		}
	}
	query->dst->fnAddLine ("</table></p>");

	fnReportEnd (query);
} // end of fnAppReportPrescriptionsOrderForm ()

// **********************************
// * реестр назначений лабораторный *
// **********************************
void fnAppReportPrescriptionsTypesOrderForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	char szTime1 [5 +1];
	char szTime2 [5 +1];
	char szGroupId [2 +1];

	int iTime1;
	int iTime2;
	int iGroupId;
	int iTime;
	bool bOneDay = false;
	int iCycle;
	char szTmp [20];
	string s;
	std::auto_ptr<RING> visits_found (new RING (512 kb));
	int iQty;
	int iVisit;
	std::auto_ptr<A_KEY_SZ> contracts (new A_KEY_SZ (16 kb));
	int iCurrentContractNum;
	char szCurrentContractDate [11];
	int iClientNum;
	int iClient;
	char szClientFIO [100]; // для вывода ФИО
	int iCycle2;
	string sCodes;
	string sServices;
	int iVisit2;
	std::auto_ptr<RING> table (new RING (512 kb));
	char *szBuf;
	string sComments;
	EXPORT1_ARGS s_export1_args;
	int iCycleGroup;
	char szName [WS_MAX_NAME_LEN +1];

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	if (fnCompareDate (szDate1,szDate2) == 0)
		bOneDay = true;
	// время
	if (! login_time1->fnGetValue (szTime1,query->szLogin))
	{
		strcpy (szTime1,"00:00");
		login_time1->fnAdd (query->szLogin,szTime1);
	}
	if (! login_time2->fnGetValue (szTime2,query->szLogin))
	{
		strcpy (szTime2,"23:59");
		login_time2->fnAdd (query->szLogin,szTime2);
	}
	// преобразуем время в формат кол-ва минут после полуночи
	iTime1 = fnGetMinutesAfterMidnightHM (szTime1);
	iTime2 = fnGetMinutesAfterMidnightHM (szTime2);
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);

	s = "Реестр назначений лабораторный за период с ";
	s += szTime1;
	s += "&nbsp;";
	s += szDate1;
	s += " по ";
	s += szTime2;
	s += "&nbsp;";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	fnReportTitle (query,s.c_str ());

	for (iCycleGroup = 0; iCycleGroup < 52; iCycleGroup++)
	{
		// если группа не является видом биоматериала, пропускаем
		if (! fnServicesGroupsGetBiomaterialType (iCycleGroup))
			continue;

		// выбираем актуальные посещения
		visits_found->fnClear ();
		contracts->fnClear ();
		for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
		{
			if (visit [iCycle]->fnGetDelete ())
				continue;
			// если услуга не включена в группу-вид биоматериала, пропускаем
			if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iCycleGroup))
				continue;
			if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetTakingDate (),szDate2))
				continue;
			if (visit [iCycle]->fnGetPreEntry ())
				continue;
			if (visit [iCycle]->fnGetType () < 0)
				continue;
			// группа
			if (iGroupId >= 0)
				if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
					continue;
			// период
			iTime = fnGetMinutesAfterMidnightHM (visit [iCycle]->fnGetTakingTime ());
			if (bOneDay) // период охватывает только один день
			{
				if ((iTime < iTime1) || (iTime > iTime2))
					continue;
			}
			else // период охватывает несколько дней
			{
				// первый день периода
				if ((fnCompareDate (szDate1,visit [iCycle]->fnGetTakingDate ()) == 0)
					&& (iTime < iTime1))
					continue;
				// последний день периода
				if ((fnCompareDate (szDate2,visit [iCycle]->fnGetTakingDate ()) == 0)
					&& (iTime > iTime2))
					continue;
			}

			// размещаем номер записи в кольцо visits_found
			visits_found->fnPush ((char *) &iCycle,sizeof (iCycle));
		}

		iQty = visits_found->fnGetQty ();
		if (! iQty) // назначения не найдены
			continue;

		for (iCycle = 0; iCycle < iQty; iCycle++)
		{
			visits_found->fnPop ((char *) &iVisit,iCycle); // неразрушающее чтение

			// формируем строковый ключ в формате "НОМЕР_ДАТА" договора
			sprintf (szTmp,"%i_%s",visit [iVisit]->fnGetContractNum (),visit [iVisit]->fnGetContractDate ());
			if (contracts->fnCheck (szTmp)) // для этого договора строка таблицы уже сформирована
				continue;

			contracts->fnAdd (szTmp); // добавляем ключ в массив
			iCurrentContractNum = visit [iVisit]->fnGetContractNum ();
			strcpy (szCurrentContractDate,visit [iVisit]->fnGetContractDate ());

			// формируем строку таблицы
			// номер договора
			s = "<tr><td valign=top>";
			if (strlen (visit [iVisit]->fnGetPrefix ()))
			{
				s += visit [iVisit]->fnGetPrefix ();
				s += "-";
			}
			sprintf (szTmp,"%i",visit [iVisit]->fnGetContractNum ());
			s += szTmp;
			s += "</td>";

			// ФИО клиента
			s += "<td valign=top>";
			iClientNum = visit [iVisit]->fnGetClientNum ();
			iClient = visit [iVisit]->fnGetClientIndex ();
			if (iClient == -1)
				continue;
			sprintf (szClientFIO,"%s %s %s",
				client [iClient]->fnGetFamily (),
				client [iClient]->fnGetName (),
				client [iClient]->fnGetName2 ());
			s += szClientFIO;
			// добавляем после запятой дату рождения, если она введена
			if (fnCheckDate (client [iClient]->fnGetBirthday ()))
			{
				s += ", ";
				s += client [iClient]->fnGetBirthday ();
			}
			// добавляем после точки с запятой идентификатор договора
			sprintf (szTmp,"; %i_%i_",iClientNum,visit [iVisit]->fnGetContractNum ());
			s += szTmp;
			sprintf (szTmp,"%02u%02u%02u",
				fnGetDay (visit [iVisit]->fnGetContractDate ()),
				fnGetMonth (visit [iVisit]->fnGetContractDate ()),
				fnGetYear (visit [iVisit]->fnGetContractDate ()) -2000);
			s += szTmp;
			// добавляем после точки с запятой данные для лаборатории
			if (client [iClient]->fnGetSex () == CLIENT_FEMALE)
			{
				bool bArgsFound = false;
				bool bLastArgsFound = false;
/*
struct EXPORT1_ARGS
{
	int iClientNum;
	char szDate [11];
	int iCycleDay;
	int iCyclePeriod;
	int iPregnancy;
};
void fnAddArgsExport1 (EXPORT1_ARGS *src);
void fnGetArgsExport1 (EXPORT1_ARGS *dst,int iClientNum);
*/
				bArgsFound = fnGetArgsExport1(&s_export1_args,iClientNum,visit[iVisit]->fnGetContractDate());
				if (! bArgsFound)
				{
					bArgsFound = fnGetLastArgsExport1 (&s_export1_args,iClientNum);
					if (bArgsFound)
					{
						// если данные достаточно свежие
						if (fnGetDayIndex(s_export1_args.szDate,szDate2) <= 31)
							bLastArgsFound = true;
						else
							bArgsFound = false;
					}
				}
				if (bArgsFound)
				{
					if (s_export1_args.iCycleDay)
					{
						s += "; день цикла ";
						sprintf (szTmp,"%i",s_export1_args.iCycleDay);
						s += szTmp;
					}
					if (s_export1_args.iCyclePeriod)
					{
						s += "; фаза цикла ";
						switch (s_export1_args.iCyclePeriod)
						{
							case 1: s += "овуляция"; break;
							case 2: s += "фолликулиновая"; break;
							case 3: s += "лютеиновая"; break;
							case 4: s += "менопауза"; break;
						}
					}
					if (s_export1_args.iPregnancy)
					{
						s += "; срок берем/задержки ";
						sprintf (szTmp,"%i",s_export1_args.iPregnancy);
						s += szTmp;
					}
					if (bLastArgsFound)
					{
						s += " (";
						s += s_export1_args.szDate;
						s += ")";
					}
				}
			}
			s += "</td>";

			// пол
			s += "<td valign=top>";
			if (client [iClient]->fnGetSex () == 1)
				s += "М";
			else
				s += "Ж";
			s += "</td>";

			// собираем пачки кодов и наименований услуг
			sCodes.clear ();
			sServices.clear ();
			sComments.clear ();
			for (iCycle2 = iCycle; iCycle2 < iQty; iCycle2++)
			{
				visits_found->fnPop ((char *) &iVisit2,iCycle2); // неразрушающее чтение

				if (visit [iVisit2]->fnGetContractNum () != iCurrentContractNum)
					continue;
				if (strcmp (visit [iVisit2]->fnGetContractDate (),szCurrentContractDate))
					continue;

				sCodes += "<div>";
				sCodes += fnGetServiceExtCode (visit [iVisit2]->fnGetType ());
				sCodes += "</div>";

				sServices += "<div>";
				sServices += fnGetServiceName (visit [iVisit2]->fnGetType ());
				sServices += "</div>";

				if (strlen (visit [iVisit2]->fnGetComments ()))
				{
					sComments += "<div>";
					sComments += visit [iVisit2]->fnGetComments ();
					sComments += "</div>";
				}
			}

			// коды услуг
			s += "<td valign=top>";
			s += sCodes;
			s += "</td>";

			// виды услуг
			s += "<td valign=top>";
			s += sServices;
			s += "</td>";

			// примечания
			s += "<td valign=top>";
			s += sComments;
			s += "</td>";

			// штрих код
			s += "<td><img src=\"images/color-white.gif\" width=";
			sprintf (szTmp,"%i",config.iReportBarcodeWidth);
			s += szTmp;
			s += " height=";
			sprintf (szTmp,"%i",config.iReportBarcodeHeight);
			s += szTmp;
			s += "></td></tr>";

			table->fnPushStr (s.c_str ());
		}

		s = "<h1>";
		s += fnServicesGroupsGetName (szName,iCycleGroup);
		s += "</h1>";
		query->dst->fnAddLine (s.c_str ());

		query->dst->fnAddLine ("<table width=\"100%\" border=1><tr>\
<td align=center>№ договора</td>\
<td align=center>Клиент</td>\
<td align=center>Пол</td>\
<td align=center>Коды услуг</td>\
<td align=center>Виды услуг</td>\
<td align=center>Примечания</td>\
<td align=center>Штрих-код</td></tr>");

		if (table->fnGetQty ())
		{
			table->fnSort (0); // сортировка в кольце

			while (table->fnGetQty ())
			{
				szBuf = new char [table->fnGetLen ()];
				table->fnPop (szBuf);
				query->dst->fnAddLine (szBuf);
				delete [] szBuf;
			}
		}
		query->dst->fnAddLine ("</table></p>");
	}

	fnReportEnd (query);
} // end of fnAppReportPrescriptionsTypesOrderForm ()

// ********************
// * отчёт о расходах *
// ********************
void fnAppReportExpensesForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	string s;
	int iCycle,iCycleType;
	std::auto_ptr<RING> table (new RING (10 kb));
	double dSum;
	char szTmp [20];
	double dSumTotal = 0.0;
	char *szBuf;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}

	s = "Отчёт о расходах за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	fnReportTitle (query,s.c_str ());

	// список расходов
	for (iCycle = 0; iCycle < iExpensesQty; iCycle++)
	{
		// пропускаем удалённые записи
		if (expense [iCycle]->fnGetDelete ())
			continue;
		// пропускаем записи вне периода
		if (! fnCheckDateRange (szDate1,expense [iCycle]->fnGetDate (),szDate2))
			continue;
		// формируем строку таблицы
		// дата внутри комментария в формате ГГГГ/ММ/ДД для сортировки
		sprintf (szTmp,"<!-- %4u/%02u/%02u -->",
			fnGetYear (expense [iCycle]->fnGetDate ()),
			fnGetMonth (expense [iCycle]->fnGetDate ()),
			fnGetDay (expense [iCycle]->fnGetDate ()));
		s = szTmp;
		s += "<tr><td>";
		s += expense [iCycle]->fnGetDate ();
		s += "</td><td>";
		s += fnGetExpenseName (expense [iCycle]->fnGetType ());
		s += "</td><td align=right>";
		sprintf (szTmp,"%.2f",expense [iCycle]->fnGetSum ());
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td><td>";
		s += expense [iCycle]->fnGetBasis ();
		s += "</td></tr>";
		table->fnPushStr (s.c_str ());
	}
	table->fnSort (0);

	query->dst->fnAddLine ("Таблица 1. Список расходов.");
	query->dst->fnAddLine (
"<p><table width=\"100%\" border=1><tr>\
<td align=center>Дата</td>\
<td align=center>Вид расхода</td>\
<td align=center>Сумма</td>\
<td align=center>Основание</td></tr>");
	while (table->fnGetQty ())
	{
		szBuf = new char [table->fnGetLen ()];
		table->fnPop (szBuf);
		query->dst->fnAddLine (szBuf);
		delete [] szBuf;
	}
	query->dst->fnAddLine ("</table></p>");

	// расходы по видам
	query->dst->fnAddLine ("Таблица 2. Расходы по видам.");
	query->dst->fnAddLine (
"<p><table width=\"100%\" border=1><tr>\
<td align=center>Вид расходов</td>\
<td align=center>Сумма</td></tr>");
	for (iCycleType = 0; iCycleType < iExpenseTypesQty; iCycleType++)
	{
		dSum = 0.0;
		for (iCycle = 0; iCycle < iExpensesQty; iCycle++)
		{
			if (expense [iCycle]->fnGetDelete ())
				continue;
			if (expense [iCycle]->fnGetType () != ini4 [iCycleType]->iType)
				continue;
			if (! fnCheckDateRange (szDate1,expense [iCycle]->fnGetDate (),szDate2))
				continue;
			dSum += expense [iCycle]->fnGetSum ();
		}
		// подсчитываем общую сумму
		dSumTotal += dSum;
		// формируем строку таблицы
		s = "<tr><td>";
		s += ini4 [iCycleType]->szName;
		s += "</td><td align=right>";
		sprintf (szTmp,"%.2f",dSum);
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td></tr>";
		query->dst->fnAddLine (s.c_str ());
	}
	query->dst->fnAddLine ("</table>");

	s = "<table border=0 width=\"100%\"><tr><td align=right>Итого: <b>";
	sprintf (szTmp,"%.2f",dSumTotal);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</b></td></tr></table></p>";
	query->dst->fnAddLine (s.c_str ());

	fnReportEnd (query);
} // end of fnAppReportExpensesForm ()

// ****************************************************************************
// *                                                                          *
// *                         ОТЧЁТЫ МОДУЛЯ КОНТРОЛЯ                           *
// *                                                                          *
// ****************************************************************************

// ******************************************************
// * отчёт МК2 о предоставленных единовременных скидках *
// ******************************************************
void fnAppReportControl2_Form (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	string s;
	char szTmp [20];
	int iCycle;
	int iClient;
	char szClientFIO [100]; // для вывода FIO

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}

	s = "МК2: Отчёт о предоставленных единовременных скидках более ";
	sprintf (szTmp,"%i",config.iCheck2Max);
	s += szTmp;
	s += "% за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	fnReportTitle (query,s.c_str ());

	query->dst->fnAddLine (
"<table width=\"100%\" border=1><tr>\
<td align=center>Дата</td>\
<td align=center>Время</td>\
<td align=center>Клиент</td>\
<td align=center>Услуга</td>\
<td align=center>Цена</td>\
<td align=center>Кол-во</td>\
<td align=center>Сумма к оплате</td>\
<td align=center>Исходная цена</td>\
<td align=center>Скидка, %</td>\
<td align=center>Префикс</td>\
<td align=center>Примечания</td></tr>");

	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		// если дата платежа не входит в период
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetPaymentDate (),szDate2))
			continue;
		if (visit [iCycle]->fnGetDiscountType () != 1)
			continue;
		if (visit [iCycle]->fnGetDiscountPercent () <= (double) config.iCheck2Max)
			continue;

		// дата внутри комментария в формате ГГГГ/ММ/ДД для сортировки
		sprintf (szTmp,"<!-- %4u/%02u/%02u -->",
			fnGetYear (visit [iCycle]->fnGetPaymentDate ()),
			fnGetMonth (visit [iCycle]->fnGetPaymentDate ()),
			fnGetDay (visit [iCycle]->fnGetPaymentDate ()));
		s = szTmp;
		s += "<tr><td>";
		s += visit [iCycle]->fnGetPaymentDate (); // дата платежа
		s += "</td><td>";
		s += visit [iCycle]->fnGetPaymentTime (); // время
		s += "</td><td>";
		// клиент
		iClient = fnClientSearchByNum (visit [iCycle]->fnGetClientNum ());
		if (iClient == -1)
			continue;
		sprintf (szClientFIO,"%s %s %s",
			client [iClient]->fnGetFamily (),
			client [iClient]->fnGetName (),
			client [iClient]->fnGetName2 ());
		s += szClientFIO;
		s += "</td><td>";
		// услуга
		s += fnGetServiceName (visit [iCycle]->fnGetType ());
		s += "</td><td>";
		// цена
		sprintf (szTmp,"%.2f",visit [iCycle]->fnGetPrice ());
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td><td>";
		// кол-во
		sprintf (szTmp,"%.2f",visit [iCycle]->fnGetQty ());
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td><td>";
		// сумма к оплате
		sprintf (szTmp,"%.2f",visit [iCycle]->fnGetSum ());
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td><td>";
		// исходная цена
		sprintf (szTmp,"%.2f",visit [iCycle]->fnGetOriginalPrice ());
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td><td>";
		// скидка
		sprintf (szTmp,"%.2f %%",visit [iCycle]->fnGetDiscountPercent ());
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</td><td>";
		s += visit [iCycle]->fnGetPrefix (); // префикс
		s += "&nbsp;</td><td>";
		s += visit [iCycle]->fnGetComments (); // примечания
		s += "&nbsp;</td></tr>";
		query->dst->fnAddLine (s.c_str ());
	}
	query->dst->fnAddLine ("</table>");

	fnReportEnd (query);
} // end of fnAppReportControl2_Form ()

// *******************************
// * отчёт о созданных договорах *
// *******************************
void fnAppReportContractsForm (QUERY *query)
{
	std::auto_ptr<RING> contracts (new RING (1024 kb));
	string s;
	int iQty;
	int iCycle;
	EVENT_RECORD s_event;
	SYSTEMTIME lt;
	char szTmp [20];
	int iClient;
	char szClientFIO [100]; // для вывода FIO
	std::auto_ptr<A_ARRAY> contract_sum (new A_ARRAY (64 kb));
	// ключ ассоциативного массива в формате "номер договора_дата заключения"
	char szKey [20];
	double dContractSum;

	query->ws_ptr->fnGetEvents(contracts.get(),1);

	fnReportTitle(query,"Отчёт о созданных договорах");

	s = "<table width=\"100%\" border=1 cellspacing=0><tr>\
<td>FILETIME</td>\
<td>Подтип</td>\
<td>Логин</td>\
<td>Событие</td>\
<td>№ и дата договора</td>\
<td>Клиент</td>\
<td>Сумма</td>\
<td>Страница</td></tr>";

	iQty = contracts->fnGetQty();
	for (iCycle = 0; iCycle < iQty; iCycle++)
	{
		contracts->fnPop((char *) &s_event);

		s += "<tr";
		// ключ ассоциативного массива - строка с номером и датой договора
		sprintf(szKey,"%i_%s",s_event.iValue1,s_event.szDate);
		if (contract_sum->fnGetValue(szTmp,szKey))
		{
			dContractSum = atof(szTmp);
			// если сумма договора уменьшилась
			if (s_event.dValue5 < dContractSum)
			{
				// окрашиваем строку таблицы в предупредительный цвет
				s += " bgcolor=\"";
				s += szColorOrange;
				s += "\"";
			}
			else
			{
				// если сумма договора увеличилась
				if (s_event.dValue5 > dContractSum)
				{
					sprintf(szTmp,"%.2f",s_event.dValue5);
					contract_sum->fnAdd(szKey,szTmp);
				}
			}
		}
		else
		{
			sprintf(szTmp,"%.2f",s_event.dValue5);
			contract_sum->fnAdd(szKey,szTmp);
		}
		s += ">";

		// FILETIME
		s += "<td>";
		FileTimeToSystemTime(&s_event.ft,&lt);
		sprintf (szTmp,"%02u/%02u/%4u %02u:%02u:%02u",
			lt.wDay,lt.wMonth,lt.wYear,lt.wHour,lt.wMinute,lt.wSecond);
		s += szTmp;
		s += "</td>";

		// подтип
		s += "<td>";
		sprintf (szTmp,"%i",s_event.iSubType);
		s += szTmp;
		s += "</td>";

		// логин
		s += "<td>";
		s += s_event.szOwner;
		s += "</td>";

		// событие
		s += "<td>";
		s += s_event.szDesc;
		s += "</td>";

		// номер и дата договора
		s += "<td>";
		sprintf(szTmp,"%i от ",s_event.iValue1);
		s += szTmp;
		s += s_event.szDate;
		s += "</td>";

		// клиент
		s += "<td>";
		iClient = fnClientSearchByNum(s_event.iValue2);
		if (iClient == -1)
			continue;
		sprintf(szClientFIO,"%s %s %s",
			client [iClient]->fnGetFamily(),
			client [iClient]->fnGetName(),
			client [iClient]->fnGetName2());
		s += szClientFIO;
		s += "</td>";

		// сумма
		s += "<td>";
		sprintf(szTmp,"%.2f",s_event.dValue5);
		s += szTmp;
		s += "</td>";

		// страница
		s += "<td>";
		if (s_event.iValue3)
		{
			sprintf(szTmp,"%i",s_event.iValue3);
			s += szTmp;
		}
		s += "&nbsp;</td></tr>";
	}

	s += "</table>";
	query->dst->fnAddLine(s.c_str ());

	fnReportEnd(query);
} // end of fnAppReportContractsForm()

// ******************************************************************
// * отчёт о редактировании прейскуранта в конструкторе видов услуг *
// ******************************************************************
void fnAppReportServicesEditForm (QUERY *query)
{
	std::auto_ptr<RING> services_edit (new RING (1024 kb));
	string s;
	int iQty;
	int iCycle;
	EVENT_RECORD s_event;
	SYSTEMTIME lt;
	char szTmp [20];

	query->ws_ptr->fnGetEvents(services_edit.get(),2);

	fnReportTitle(query,"Отчёт о редактировании прейскуранта в конструкторе видов услуг");

	s = "<table width=\"100%\" border=1 cellspacing=0><tr>\
<td>FILETIME</td>\
<td>Подтип</td>\
<td>Логин</td>\
<td>Событие</td>\
<td>№</td>\
<td>Наименование</td>\
<td>Прежнее значение</td>\
<td>Новое значение</td></tr>";

	iQty = services_edit->fnGetQty();
	for (iCycle = 0; iCycle < iQty; iCycle++)
	{
		services_edit->fnPop((char *) &s_event);

		s += "<tr>";

		// FILETIME
		s += "<td>";
		FileTimeToSystemTime(&s_event.ft,&lt);
		sprintf (szTmp,"%02u/%02u/%4u %02u:%02u:%02u",
			lt.wDay,lt.wMonth,lt.wYear,lt.wHour,lt.wMinute,lt.wSecond);
		s += szTmp;
		s += "</td>";

		// подтип
		s += "<td>";
		sprintf (szTmp,"%i",s_event.iSubType);
		s += szTmp;
		s += "</td>";

		// логин
		s += "<td>";
		s += s_event.szOwner;
		s += "</td>";

		// событие
		s += "<td>";
		s += s_event.szDesc;
		s += "</td>";

		// уникальный номер
		s += "<td>";
		sprintf(szTmp,"%i",s_event.iValue1);
		s += szTmp;
		s += "</td>";

		// наименование
		s += "<td>";
		s += s_event.szValue7;
		s += "</td>";

		// прежнее значение
		s += "<td>";
		switch (s_event.iSubType)
		{
			case 4:
			case 5:
			case 6:
			case 7:
			case 8:
			sprintf(szTmp,"%.2f",s_event.dValue5);
			s += szTmp;
		}
		s += "&nbsp;</td>";

		// новое значение
		s += "<td>";
		switch (s_event.iSubType)
		{
			case 4:
			case 5:
			case 6:
			case 7:
			case 8:
			sprintf(szTmp,"%.2f",s_event.dValue6);
			s += szTmp;
		}
		s += "&nbsp;</td>";

		s += "</tr>";
	}

	s += "</table>";
	query->dst->fnAddLine(s.c_str ());

	fnReportEnd(query);
} // end of fnAppReportServicesEditForm()

// ****************************************************************************
// *                                                                          *
// *                       ОТЧЁТЫ О РАБОТЕ СПЕЦИАЛИСТОВ                       *
// *                                                                          *
// ****************************************************************************

// **************************************
// * отчёт по ведению амбулаторных карт *
// **************************************
void fnAppReportMapKeepingForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	string s;
	char szTmp [20];
	int iCycleSpec,iCycle;
	int iQty;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}

	s = "Отчёт о работе специалистов за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	s += "<br>Ведение амбулаторных карт";
	fnReportTitle (query,s.c_str ());

	query->dst->fnAddLine (
"<table width=\"100%\" border=1><tr>\
<td align=center>Специалист</td>\
<td align=center>Кол-во новых амбулаторных карт</td></tr>");

	for (iCycleSpec = 0; iCycleSpec < iSpecsQty; iCycleSpec++)
	{
		// пропускаем консультантов
		if (fnGetSpecCons (fnGetSpecType (iCycleSpec)))
			continue;

		iQty = 0;
		for (iCycle = 0; iCycle < iMapsQty; iCycle++)
		{
			if (map [iCycle]->fnGetDelete ())
				continue;
			if (! fnCheckDateRange (szDate1,map [iCycle]->fnGetDate (),szDate2))
				continue;
			if (map [iCycle]->fnGetSpec () != fnGetSpecType (iCycleSpec))
				continue;
			iQty++;
		}
		// формируем строку таблицы
		s = "<tr><td>";
		s += fnGetSpecFIO (fnGetSpecType (iCycleSpec));
		s += "</td><td align=right>";
		sprintf (szTmp,"%i",iQty);
		s += szTmp;
		s += "</td></tr>";
		query->dst->fnAddLine (s.c_str ());
	}
	query->dst->fnAddLine ("</table>");

	fnReportEnd (query);
} // end of fnAppReportMapKeepingForm ()

// *****************************************
// * выполненные работы и заработная плата *
// *****************************************
void fnAppReportSalaryForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	char szGroupId [2 +1];
	char szVisitFlagId [2 +1];
	int iOrg = -1;

	int iGroupId;
	int iVisitFlagId;
	std::auto_ptr<RING> visits_found (new RING (64 kb));
	int iQty;
	int iVisit;
	string s;
	char szTmp [20];
	char szClientFIO [100];
	int iCycleSpec,iCycle;
//	int iClientNum;
	int iClient;
	double dSumTotal;
	double dSalary;
	std::auto_ptr<RING> table (new RING (10 kb));
	double dSalaryTotal;
	int iSpecType;
	double dSumOverall = 0.0;
	double dSalaryOverall = 0.0;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);
	// флажок посещения
	if (! login_visitflag->fnGetValue (szVisitFlagId,query->szLogin))
	{
		strcpy (szVisitFlagId,"-1");
		login_visitflag->fnAdd (query->szLogin,szVisitFlagId);
	}
	iVisitFlagId = atoi (szVisitFlagId);
	// организация-плательщик
	if (login_org->fnGetValue (szTmp,query->szLogin))
		iOrg = atoi (szTmp);
	else
		login_org->fnAdd (query->szLogin,"-1");

	s = "Выполненные работы и заработная плата за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	if (iOrg != -1)
	{
		char szOrgName [WS_MAX_DESC_LEN +1];

		s += ", плательщик: ";
		s += fnGetOrgName (szOrgName,iOrg);
	}
	fnReportTitle (query,s.c_str ());

	// выбираем актуальные посещения
	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetDate (),szDate2))
			continue;
		if (visit [iCycle]->fnGetPreEntry ())
			continue;
		// организация-плательщик
		if (iOrg != -1)
			if (visit [iCycle]->fnGetOrg () != iOrg)
				continue;
		// флажок посещения
		switch (iVisitFlagId)
		{
			case 11:
			if (visit [iCycle]->fnGetFlag1 () == false)
				continue;
			break;

			case 10:
			if (visit [iCycle]->fnGetFlag1 () == true)
				continue;
			break;

			case 21:
			if (visit [iCycle]->fnGetFlag2 () == false)
				continue;
			break;

			case 20:
			if (visit [iCycle]->fnGetFlag2 () == true)
				continue;
			break;

			case 31:
			if (visit [iCycle]->fnGetFlag3 () == false)
				continue;
			break;

			case 30:
			if (visit [iCycle]->fnGetFlag3 () == true)
				continue;
			break;

			case 41:
			if (visit [iCycle]->fnGetFlag4 () == false)
				continue;
			break;

			case 40:
			if (visit [iCycle]->fnGetFlag4 () == true)
				continue;
		}
		// группа
		if (iGroupId >= 0)
			if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
				continue;
		if (visit [iCycle]->fnGetAbsence ())
			continue;
		if (visit [iCycle]->fnGetType () < 0)
			continue;
		// размещаем номер записи в кольцо visits_found
		visits_found->fnPush ((char *) &iCycle,sizeof (iCycle));
	}
	iQty = visits_found->fnGetQty ();

	// цикл по специалистам
	for (iCycleSpec = 0; iCycleSpec < iSpecsQty; iCycleSpec++)
	{
		iSpecType = fnGetSpecType (iCycleSpec);
		// пропускаем консультантов
		if (fnGetSpecCons (iSpecType))
			continue;
		dSumTotal = 0.0;
		dSalaryTotal = 0.0;

		for (iCycle = 0; iCycle < iQty; iCycle++)
		{
			// выбираем записи для текущего специалиста
			visits_found->fnPop ((char *) &iVisit,iCycle);
			if (visit [iVisit]->fnGetSpec () != iSpecType)
				continue;

			dSumTotal += visit [iVisit]->fnGetSum ();
			dSalary = visit [iVisit]->fnGetSpecPayment ();
			dSalaryTotal += dSalary;

			// формируем строку таблицы
//			iClientNum = visit [iCycle]->fnGetClientNum ();
//			iClient = fnClientSearchByNum (iClientNum);
			iClient = visit [iVisit]->fnGetClientIndex ();
			if (iClient == -1)
				continue;
			// дата внутри комментария в формате ГГГГ/ММ/ДД для сортировки
			sprintf (szTmp,"<!-- %4u/%02u/%02u -->",
				fnGetYear (visit [iVisit]->fnGetDate ()),
				fnGetMonth (visit [iVisit]->fnGetDate ()),
				fnGetDay (visit [iVisit]->fnGetDate ()));
			s = szTmp;
			s += "<tr><td>";
			s += visit [iVisit]->fnGetDate ();
			s += "</td><td>";
			sprintf (szClientFIO,"%s %s %s",
				client [iClient]->fnGetFamily (),
				client [iClient]->fnGetName (),
				client [iClient]->fnGetName2 ());
			s += szClientFIO;
			s += "</td><td>";
			s += fnGetServiceName (visit [iVisit]->fnGetType ());
			s += "</td><td align=right>";
			sprintf (szTmp,"%.2f",visit [iVisit]->fnGetSum ());
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</td><td align=right>";
			sprintf (szTmp,"%.2f",visit [iVisit]->fnGetConsPayment ());
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</td><td align=right>";
			sprintf (szTmp,"%.2f",dSalary);
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</td></tr>";
			table->fnPushStr (s.c_str ());
		}
		if (table->fnGetQty ())
		{
			char *sz;

			table->fnSort (0); // сортировка в кольце

			s = "Таблица \"Выполненные работы (используется дата посещения): ";
			s += fnGetSpecFIO (iSpecType);
			if (*fnGetSpecProfession (iSpecType))
			{
				s += " - ";
				s += fnGetSpecProfession (iSpecType);
			}
			s += "\".";
			query->dst->fnAddLine (s.c_str ());

			query->dst->fnAddLine (
"<table width=\"100%\" border=1 style=\"font-family: arial, sans-serif; font-size: 9pt;\"><tr>\
<td width=\"10%\" align=center>Дата</td>\
<td width=\"20%\" align=center>ФИО клиента</td>\
<td width=\"40%\" align=center>Вид услуг</td>\
<td width=\"10%\" align=center>Сумма</td>\
<td width=\"10%\" align=center>Консультанту</td>\
<td width=\"10%\" align=center>Заработная плата</td></tr>");

			while (table->fnGetQty ())
			{
				sz = new char [table->fnGetLen ()];
				table->fnPop (sz);
				query->dst->fnAddLine (sz);
				delete [] sz;
			}
			query->dst->fnAddLine ("</table>");

			s = "<table border=0 width=\"100%\"><tr><td align=right>Итого выполнено работ на сумму: <b>";
			sprintf (szTmp,"%.2f",dSumTotal);
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</b><br>Итого заработная плата: <b>";
			sprintf (szTmp,"%.2f",dSalaryTotal);
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</b></td></tr></table>";
			query->dst->fnAddLine (s.c_str ());
		}
		dSumOverall += dSumTotal;
		dSalaryOverall += dSalaryTotal;
	}

	s = "<p>Таблица \"Итоги\".";
	s += "<table width=\"100%\" border=1 style=\"font-family: arial, sans-serif; font-size: 9pt;\">\
<tr><td width=\"50%\" align=center>Итого выполнено работ на сумму:</td><td align=center>Итого заработная плата:</td></tr>";
	s += "<tr><td align=right>";
	sprintf (szTmp,"%.2f",dSumOverall);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</td><td align=right>";
	sprintf (szTmp,"%.2f",dSalaryOverall);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</td></tr></table></p>";
	query->dst->fnAddLine (s.c_str ());

	fnReportEnd (query);
} // end of fnAppReportSalaryForm ()

// ****************************
// * заработная плата (итоги) *
// ****************************
void fnAppReportSalaryShortForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	char szGroupId [2 +1];
	char szVisitFlagId [2 +1];
	int iOrg = -1;

	int iGroupId;
	int iVisitFlagId;
	std::auto_ptr<RING> visits_found (new RING (64 kb));
	int iQty;
	int iVisit;
	string s;
	char szTmp [20];
	int iCycleSpec,iCycle;
	double dSumTotal;
	double dSalary;
	double dSalaryTotal;
	int iSpecType;
	double dSumOverall = 0.0;
	double dSalaryOverall = 0.0;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);
	// флажок посещения
	if (! login_visitflag->fnGetValue (szVisitFlagId,query->szLogin))
	{
		strcpy (szVisitFlagId,"-1");
		login_visitflag->fnAdd (query->szLogin,szVisitFlagId);
	}
	iVisitFlagId = atoi (szVisitFlagId);
	// организация-плательщик
	if (login_org->fnGetValue (szTmp,query->szLogin))
		iOrg = atoi (szTmp);
	else
		login_org->fnAdd (query->szLogin,"-1");

	s = "Заработная плата (итоги) за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	if (iOrg != -1)
	{
		char szOrgName [WS_MAX_DESC_LEN +1];

		s += ", плательщик: ";
		s += fnGetOrgName (szOrgName,iOrg);
	}
	fnReportTitle (query,s.c_str ());

	// выбираем актуальные посещения
	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetDate (),szDate2))
			continue;
		if (visit [iCycle]->fnGetPreEntry ())
			continue;
		// организация-плательщик
		if (iOrg != -1)
			if (visit [iCycle]->fnGetOrg () != iOrg)
				continue;
		// флажок посещения
		switch (iVisitFlagId)
		{
			case 11:
			if (visit [iCycle]->fnGetFlag1 () == false)
				continue;
			break;

			case 10:
			if (visit [iCycle]->fnGetFlag1 () == true)
				continue;
			break;

			case 21:
			if (visit [iCycle]->fnGetFlag2 () == false)
				continue;
			break;

			case 20:
			if (visit [iCycle]->fnGetFlag2 () == true)
				continue;
			break;

			case 31:
			if (visit [iCycle]->fnGetFlag3 () == false)
				continue;
			break;

			case 30:
			if (visit [iCycle]->fnGetFlag3 () == true)
				continue;
			break;

			case 41:
			if (visit [iCycle]->fnGetFlag4 () == false)
				continue;
			break;

			case 40:
			if (visit [iCycle]->fnGetFlag4 () == true)
				continue;
		}
		// группа
		if (iGroupId >= 0)
			if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
				continue;
		if (visit [iCycle]->fnGetAbsence ())
			continue;
		if (visit [iCycle]->fnGetType () < 0)
			continue;
		// размещаем номер записи в кольцо visits_found
		visits_found->fnPush ((char *) &iCycle,sizeof (iCycle));
	}
	iQty = visits_found->fnGetQty ();

	// цикл по специалистам
	for (iCycleSpec = 0; iCycleSpec < iSpecsQty; iCycleSpec++)
	{
		iSpecType = fnGetSpecType (iCycleSpec);
		// пропускаем консультантов
		if (fnGetSpecCons (iSpecType))
			continue;
		dSumTotal = 0.0;
		dSalaryTotal = 0.0;

		for (iCycle = 0; iCycle < iQty; iCycle++)
		{
			// выбираем записи для текущего специалиста
			visits_found->fnPop ((char *) &iVisit,iCycle);
			if (visit [iVisit]->fnGetSpec () != iSpecType)
				continue;

			dSumTotal += visit [iVisit]->fnGetSum ();
			dSalary = visit [iVisit]->fnGetSpecPayment ();
			dSalaryTotal += dSalary;
		}
		if (dSumTotal != 0)
		{
			s = "<p>Таблица \"Заработная плата (используется дата посещения): ";
			s += fnGetSpecFIO (iSpecType);
			if (*fnGetSpecProfession (iSpecType))
			{
				s += " - ";
				s += fnGetSpecProfession (iSpecType);
			}
			s += "\".";
			query->dst->fnAddLine (s.c_str ());

			s = "<table width=\"100%\" border=1 style=\"font-family: arial, sans-serif; font-size: 9pt;\">\
<tr><td width=\"50%\" align=center>Выполнены работы на сумму</td><td align=center>Заработная плата</td></tr>";
			s += "<tr><td align=right>";
			sprintf (szTmp,"%.2f",dSumTotal);
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</td><td align=right>";
			sprintf (szTmp,"%.2f",dSalaryTotal);
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</td></tr></table></p>";
			query->dst->fnAddLine (s.c_str ());
		}
		dSumOverall += dSumTotal;
		dSalaryOverall += dSalaryTotal;
	}

	s = "<p>Таблица \"Итоги\".";
	s += "<table width=\"100%\" border=1 style=\"font-family: arial, sans-serif; font-size: 9pt;\">\
<tr><td width=\"50%\" align=center>Итого выполнено работ на сумму:</td><td align=center>Итого заработная плата:</td></tr>";
	s += "<tr><td align=right>";
	sprintf (szTmp,"%.2f",dSumOverall);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</td><td align=right>";
	sprintf (szTmp,"%.2f",dSalaryOverall);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</td></tr></table></p>";
	query->dst->fnAddLine (s.c_str ());

	fnReportEnd (query);
} // end of fnAppReportSalaryShortForm ()

// *************************************
// * история посещений по специалистам *
// *************************************
void fnAppReportSpecsHistoryForm (QUERY *query)
{
	RING *args = query->args;
	char sz [INI_MAX_LEXEM_LEN +1];
	bool bPrimary = false;

	char szDate1 [11];
	char szDate2 [11];
	char szGroupId [2 +1];

	int iGroupId;
	int iCycle;
	char szTmp [20];
	string s;
	std::auto_ptr<RING> visits_found (new RING (512 kb));
	A_KEY_INT *client_nums;
	int iQty;
	int iClientNum;
	int iClient;
	char szClientFIO [100]; // для вывода FIO
	int iCycle2;
	int iVisit;
	bool bPrev;
	double dSum;
	std::auto_ptr<RING> table (new RING (512 kb));
	double dSumTotal = 0.0;
	int iCounter;
	char *szBuf;
	std::auto_ptr<A_KEY_SZ> client_visits_dates (new A_KEY_SZ);
	int iCycleSpec;
	int iSpecType;
	double dTmp;
	char szRegDate [11];
	double dSumOverall = 0.0;

	while (args->fnGetQty ())
	{
		args->fnPop (sz);
		if (! strcmp (sz,"primary"))
		{
			args->fnPop (sz);
			bPrimary = true;
			continue;
		}
	}

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);

	if (bPrimary)
		s = "История первичных посещений по специалистам за период с ";
	else
		s = "История посещений по специалистам за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	fnReportTitle (query,s.c_str ());

	// выбираем актуальные посещения
	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetDate (),szDate2))
			continue;
		if (visit [iCycle]->fnGetPreEntry ())
			continue;
		if (visit [iCycle]->fnGetType () < 0)
			continue;
		// группа
		if (iGroupId >= 0)
			if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
				continue;

		if (bPrimary)
		{
			iClient = visit [iCycle]->fnGetClientIndex();
			if (iClient == -1)
				continue;

			if (iClient == 0) // Анонимный
				continue;
			client [iClient]->fnCreationDate ()->fnGetDate (szRegDate);
			if (! fnCheckDateRange (szDate1,szRegDate,szDate2))
				continue;
		}

		// размещаем номер записи в кольцо visits_found
		visits_found->fnPush ((char *) &iCycle,sizeof (iCycle));
	}

	client_nums = new A_KEY_INT ();
	iQty = visits_found->fnGetQty ();
	// цикл по специалистам
	for (iCycleSpec = 0; iCycleSpec < iSpecsQty; iCycleSpec++)
	{
		iSpecType = fnGetSpecType (iCycleSpec);
		// пропускаем консультантов
		if (fnGetSpecCons (iSpecType))
			continue;

		client_nums->fnClear();
		iCounter = 1;
		dSumTotal = 0.0;
		for (iCycle = 0; iCycle < iQty; iCycle++)
		{
			// выбираем записи для текущего специалиста
			visits_found->fnPop ((char *) &iVisit,iCycle);
			if (visit [iVisit]->fnGetSpec () != iSpecType)
				continue;

			iClientNum = visit [iVisit]->fnGetClientNum ();
			iClient = visit [iVisit]->fnGetClientIndex ();
			if (iClient == -1)
				continue;

			// если номера клиента в массиве нет
			if (! client_nums->fnCheck (iClientNum))
			{
				client_nums->fnAdd (iClientNum);

				client_visits_dates->fnClear();
				dSum = 0.0;

				// начало строки не заполняем! ("<tr><td>№</td>")

				// ФИО клиента, дата рождения
				s = "<td>";
				sprintf (szClientFIO,"%s %s %s",
					client [iClient]->fnGetFamily (),
					client [iClient]->fnGetName (),
					client [iClient]->fnGetName2 ());
				s += szClientFIO;
				s += ", ";
				s += client [iClient]->fnGetBirthday ();
				s += "</td>";

				// номер амбулаторной карты
				if (ini1.bSpecMedical)
				{
					s += "<td>";
					if (client [iClient]->fnGetMapOrderNum())
					{
						sprintf (szTmp,"%i",client [iClient]->fnGetMapOrderNum());
						s += szTmp;
					}
					s += "&nbsp;</td>";
				}

				// даты посещений
				s += "<td>";
				bPrev = false;
				for (iCycle2 = iCycle; iCycle2 < iQty; iCycle2++)
				{
					visits_found->fnPop ((char *) &iVisit,iCycle2);

					if (visit [iVisit]->fnGetClientNum () != iClientNum)
						continue;
					if (visit [iVisit]->fnGetSpec () != iSpecType)
						continue;

					// подсчитываем количество посещений (разных дат)
					if (! client_visits_dates->fnCheck (visit [iVisit]->fnGetDate ()))
					{
						if (bPrev)
							s += ", "; // разделитель
						s += visit [iVisit]->fnGetDate ();
						bPrev = true;

						client_visits_dates->fnAdd (visit [iVisit]->fnGetDate ());
					}

					// подсчитываем сумму
					dTmp = visit [iVisit]->fnGetSum();
					dSum += dTmp;
					dSumTotal += dTmp;
				}
				s += "</td>";

				// количество посещений
				s += "<td>";
				sprintf (szTmp,"%i",client_visits_dates->fnGetQty ());
				s += szTmp;
				s += "</td>";

				// на сумму
				s += "<td align=right>";
				sprintf (szTmp,"%.2f",dSum);
				if (config.bReportSepComma)
					fnCharToComma (szTmp,'.');
				s += szTmp;
				s += "</td></tr>";

				table->fnPushStr (s.c_str ());
			}
		}
		if (table->fnGetQty ())
		{
			table->fnSort (0); // сортировка в кольце

			s = "Таблица \"";
			s += fnGetSpecFIO (iSpecType);
			if (*fnGetSpecProfession (iSpecType))
			{
				s += " - ";
				s += fnGetSpecProfession (iSpecType);
			}
			s += "\".";

			s += "<table width=\"100%\" border=1><tr>";
			s += "<td align=center width=\"5%\">№</td>";
			s += "<td align=center width=\"35%\">ФИО</td>";
			if (ini1.bSpecMedical)
				s += "<td align=center width=\"10%\">№ амб. карты</td>";
			s += "<td align=center width=\"30%\">Даты посещений</td>";
			s += "<td align=center width=\"10%\">Кол-во посещений</td>";
			s += "<td align=center width=\"10%\">Сумма</td></tr>";
			query->dst->fnAddLine (s.c_str ());

			while (table->fnGetQty ())
			{
				s = "<tr><td>";
				sprintf (szTmp,"%i",iCounter++);
				s += szTmp;
				s += "</td>";
				szBuf = new char [table->fnGetLen ()];
				table->fnPop (szBuf);
				s += szBuf;
				delete [] szBuf;
				query->dst->fnAddLine (s.c_str ());
			}
			query->dst->fnAddLine ("</table></p>");

			s = "<p align=right>";
			sprintf (szTmp,"Итого: %.2f",dSumTotal);
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</p>";
			query->dst->fnAddLine (s.c_str ());

			dSumOverall += dSumTotal;
		}
	}
	delete client_nums;

	s = "<p>Таблица \"Итоги\".";
	s += "<table width=\"100%\" border=1>";
	s += "<tr><td width=\"50%\" align=center>Общая сумма:</td><td align=right>";
	sprintf (szTmp,"%.2f",dSumOverall);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</td></tr>";
	s += "</table></p>";
	query->dst->fnAddLine (s.c_str ());

	fnReportEnd (query);
} // end of fnAppReportSpecsHistoryForm()

// ****************************
// * начисления консультантам *
// ****************************
void fnAppReportConsPaymentsForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	char szGroupId [2 +1];
	char szVisitFlagId [2 +1];

	int iGroupId;
	int iVisitFlagId;
	string s;
	char szTmp [20];
	char szClientFIO [100];
	int iCycleSpec,iCycle;
	int iClientNum;
	int iClient;
	double dSalary;
	std::auto_ptr<RING> table (new RING (10 kb));
	double dSalaryTotal;
	double dAllPayments = 0.0;
	double dSum;
	double dSumTotal;
	double dAllSums = 0.0;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);
	// флажок посещения
	if (! login_visitflag->fnGetValue (szVisitFlagId,query->szLogin))
	{
		strcpy (szVisitFlagId,"-1");
		login_visitflag->fnAdd (query->szLogin,szVisitFlagId);
	}
	iVisitFlagId = atoi (szVisitFlagId);

	s = "Начисления консультантам за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	fnReportTitle (query,s.c_str ());

	for (iCycleSpec = 0; iCycleSpec < iSpecsQty; iCycleSpec++)
	{
		// пропускаем специалистов
		if (! fnGetSpecCons (fnGetSpecType (iCycleSpec)))
			continue;

		dSalaryTotal = 0.0;
		dSumTotal = 0.0;
		for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
		{
			if (visit [iCycle]->fnGetDelete ())
				continue;
			if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetPaymentDate (),szDate2))
				continue;
			if (visit [iCycle]->fnGetPreEntry ())
				continue;
			// флажок посещения
			switch (iVisitFlagId)
			{
				case 11:
				if (visit [iCycle]->fnGetFlag1 () == false)
					continue;
				break;

				case 10:
				if (visit [iCycle]->fnGetFlag1 () == true)
					continue;
				break;

				case 21:
				if (visit [iCycle]->fnGetFlag2 () == false)
					continue;
				break;

				case 20:
				if (visit [iCycle]->fnGetFlag2 () == true)
					continue;
				break;

				case 31:
				if (visit [iCycle]->fnGetFlag3 () == false)
					continue;
				break;

				case 30:
				if (visit [iCycle]->fnGetFlag3 () == true)
					continue;
				break;

				case 41:
				if (visit [iCycle]->fnGetFlag4 () == false)
					continue;
				break;

				case 40:
				if (visit [iCycle]->fnGetFlag4 () == true)
					continue;
			}
			// группа
			if (iGroupId >= 0)
				if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
					continue;
			if (visit [iCycle]->fnGetCons () != fnGetSpecType (iCycleSpec))
				continue;
			if (visit [iCycle]->fnGetAbsence ())
				continue;
			dSalary = visit [iCycle]->fnGetConsPayment ();
			if (dSalary == 0.0)
				continue;
			dSalaryTotal += dSalary;
			dAllPayments += dSalary;
			dSum = visit [iCycle]->fnGetSum ();
			dSumTotal += dSum;
			dAllSums += dSum;

			// формируем строку таблицы
			iClientNum = visit [iCycle]->fnGetClientNum ();
			iClient = fnClientSearchByNum (iClientNum);
			if (iClient == -1)
				continue;
			// дата внутри комментария в формате ГГГГ/ММ/ДД для сортировки
			sprintf (szTmp,"<!-- %4u/%02u/%02u -->",
				fnGetYear (visit [iCycle]->fnGetDate ()),
				fnGetMonth (visit [iCycle]->fnGetDate ()),
				fnGetDay (visit [iCycle]->fnGetDate ()));
			s = szTmp;
			s += "<tr><td>";
			s += visit [iCycle]->fnGetDate ();
			s += "</td><td>";
			sprintf (szClientFIO,"%s %s %s",
				client [iClient]->fnGetFamily (),
				client [iClient]->fnGetName (),
				client [iClient]->fnGetName2 ());
			s += szClientFIO;
			s += "</td><td>";
			s += fnGetServiceName (visit [iCycle]->fnGetType ());
			s += "</td><td align=right>";
			sprintf (szTmp,"%.2f",visit [iCycle]->fnGetSum ());
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</td><td align=right>";
			sprintf (szTmp,"%.2f",dSalary);
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</td></tr>";
			table->fnPushStr (s.c_str ());
		}
		if (table->fnGetQty ())
		{
			char szOrgName [WS_MAX_DESC_LEN +1];
			char *sz;

			table->fnSort (0); // сортировка в кольце

			s = "Таблица \"Направления: ";
			s += fnGetSpecFIO (fnGetSpecType (iCycleSpec));
			*szOrgName = 0;
			fnGetConsOrgName (szOrgName,fnGetSpecType (iCycleSpec));
			if (*szOrgName)
			{
				s += " &mdash; ";
				s += szOrgName;
			}
			s += "\".";
			query->dst->fnAddLine (s.c_str ());

			query->dst->fnAddLine (
"<table width=\"100%\" border=1 style=\"font-family: arial, sans-serif; font-size: 9pt;\"><tr>\
<td width=\"10%\" align=center>Дата</td>\
<td width=\"20%\" align=center>ФИО клиента</td>\
<td width=\"40%\" align=center>Вид услуг</td>\
<td width=\"15%\" align=center>Сумма</td>\
<td width=\"15%\" align=center>Начислено</td></tr>");

			while (table->fnGetQty ())
			{
				sz = new char [table->fnGetLen ()];
				table->fnPop (sz);
				query->dst->fnAddLine (sz);
				delete [] sz;
			}
			query->dst->fnAddLine ("</table>");

			s = "<table border=0 width=\"100%\"><tr><td align=right>Итого сумма: <b>";
			sprintf (szTmp,"%.2f",dSumTotal);
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</b>, к выплате: <b>";
			sprintf (szTmp,"%.2f",dSalaryTotal);
			if (config.bReportSepComma)
				fnCharToComma (szTmp,'.');
			s += szTmp;
			s += "</b></td></tr></table>";
			query->dst->fnAddLine (s.c_str ());
		}
	}
	s = "<p align=center>Общая сумма: <b>";
	sprintf (szTmp,"%.2f",dAllSums);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</b>, сумма всех начислений: <b>";
	sprintf (szTmp,"%.2f",dAllPayments);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</b></p>";
	query->dst->fnAddLine (s.c_str ());
	fnReportEnd (query);
} // end of fnAppReportConsPaymentsForm ()

// ********************************************
// * начисления консультантам по организациям *
// ********************************************
void fnAppReportOrgsPaymentsForm (QUERY *query)
{
	char szDate1 [11];
	char szDate2 [11];
	char szGroupId [2 +1];
	char szVisitFlagId [2 +1];

	int iGroupId;
	int iVisitFlagId;
	string s;
	int iOrgsQty;
	int iCycleOrg;
	ORG s_org;
	int iCycleSpec;
	int iCycle;
	double dSalaryTotal;
	double dOrgTotal;
	char szTmp [20];
	double dAllPayments = 0.0;

	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}
	// группа
	if (! login_group->fnGetValue (szGroupId,query->szLogin))
	{
		strcpy (szGroupId,"-1");
		login_group->fnAdd (query->szLogin,szGroupId);
	}
	iGroupId = atoi (szGroupId);
	// флажок посещения
	if (! login_visitflag->fnGetValue (szVisitFlagId,query->szLogin))
	{
		strcpy (szVisitFlagId,"-1");
		login_visitflag->fnAdd (query->szLogin,szVisitFlagId);
	}
	iVisitFlagId = atoi (szVisitFlagId);

	s = "Начисления консультантам по организациям за период с ";
	s += szDate1;
	s += " по ";
	s += szDate2;
	if (iGroupId >= 0)
	{
		SERVICES_GROUP s_group;

		groups->fnPop ((char *) &s_group,iGroupId);
		s += ", группа: ";
		s += s_group.szName;
	}
	fnReportTitle (query,s.c_str ());

	iOrgsQty = orgs->fnGetQty ();
	for (iCycleOrg = 0; iCycleOrg < iOrgsQty; iCycleOrg++)
	{
		dOrgTotal = 0.0;
		orgs->fnPop ((char *) &s_org,iCycleOrg); // s_org.iKey
		// таблица "организация"
		s = "<p><table border=0><tr><td>Наименование:</td><td><b>";
		s += s_org.szName;
		s += "</b></td></tr><tr><td>Адрес:</td><td>";
		s += s_org.szAddress;
		s += "&nbsp;</td></tr><tr><td>Телефоны:</td><td>";
		s += s_org.szPhones;
		s += "&nbsp;</td></tr><tr><td>Менеджер:</td><td>";
		s += s_org.szManager;
		s += "&nbsp;</td></tr></table>";
		// заголовок таблицы "к оплате"
		s += "<table border=1 width=\"100%\"><tr>\
<td width=\"50%\" align=center>Консультант</td>\
<td width=\"50%\" align=center>Начислено</td></tr>";

		for (iCycleSpec = 0; iCycleSpec < iSpecsQty; iCycleSpec++)
		{
			// пропускаем специалистов
			if (! fnGetSpecCons (fnGetSpecType (iCycleSpec)))
				continue;
			// пропускаем консультантов из других организаций
			if (fnGetConsOrg (fnGetSpecType (iCycleSpec)) != s_org.iKey)
				continue;
			// рассчитываем начисления консультанту
			dSalaryTotal = 0.0;
			for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
			{
				if (visit [iCycle]->fnGetDelete ())
					continue;
				if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetPaymentDate (),szDate2))
					continue;
				if (visit [iCycle]->fnGetPreEntry ())
					continue;
				// флажок посещения
				switch (iVisitFlagId)
				{
					case 11:
					if (visit [iCycle]->fnGetFlag1 () == false)
						continue;
					break;

					case 10:
					if (visit [iCycle]->fnGetFlag1 () == true)
						continue;
					break;

					case 21:
					if (visit [iCycle]->fnGetFlag2 () == false)
						continue;
					break;

					case 20:
					if (visit [iCycle]->fnGetFlag2 () == true)
						continue;
					break;

					case 31:
					if (visit [iCycle]->fnGetFlag3 () == false)
						continue;
					break;

					case 30:
					if (visit [iCycle]->fnGetFlag3 () == true)
						continue;
					break;

					case 41:
					if (visit [iCycle]->fnGetFlag4 () == false)
						continue;
					break;

					case 40:
					if (visit [iCycle]->fnGetFlag4 () == true)
						continue;
				}
				// группа
				if (iGroupId >= 0)
					if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),iGroupId))
						continue;
				if (visit [iCycle]->fnGetCons () != fnGetSpecType (iCycleSpec))
					continue;
				if (visit [iCycle]->fnGetAbsence ())
					continue;
				dSalaryTotal += visit [iCycle]->fnGetConsPayment ();
			}
			if (dSalaryTotal)
			{
				dOrgTotal += dSalaryTotal;
				dAllPayments += dSalaryTotal;
				// формируем строку таблицы
				s += "<tr><td>";
				s += fnGetSpecFIO (fnGetSpecType (iCycleSpec));
				s += "</td><td align=right>";
				sprintf (szTmp,"%.2f",dSalaryTotal);
				if (config.bReportSepComma)
					fnCharToComma (szTmp,'.');
				s += szTmp;
				s += "</td></tr>";
			}
		}
		s += "<table width=\"100%\"><tr><td align=right>Итого: <b>";
		sprintf (szTmp,"%.2f",dOrgTotal);
		if (config.bReportSepComma)
			fnCharToComma (szTmp,'.');
		s += szTmp;
		s += "</b></td></tr></table></p>";
		query->dst->fnAddLine (s.c_str ());
	}
	s = "<p align=center>Общая сумма всех начислений: <b>";
	sprintf (szTmp,"%.2f",dAllPayments);
	if (config.bReportSepComma)
		fnCharToComma (szTmp,'.');
	s += szTmp;
	s += "</b></p>";
	query->dst->fnAddLine (s.c_str ());

	fnReportEnd (query);
} // end of fnAppReportOrgsPaymentsForm ()

// ****************************************************************************
// *                                                                          *
// *                            ШАБЛОННЫЕ ОТЧЁТЫ                              *
// *                                                                          *
// ****************************************************************************

void fnAppReportTemplateForm (QUERY *query)
{
	RING *args = query->args;
	char sz [INI_MAX_LEXEM_LEN +1];
	int iTemplate = 0;
	int iCycle,iCycle2;
	double dSumTotal [52]; // a..z, A..Z
	double dQtyTotal [52];
	char szDate1 [11];
	char szDate2 [11];
	double dSum;
	double dQty;
//	int iServiceNum;
	VDL_TEXT *tpl;
	const char *psz;

	while (args->fnGetQty ())
	{
		args->fnPop (sz);
		if (! strcmp (sz,"num"))
		{
			args->fnPop (sz);
			iTemplate = atoi (sz);
			continue;
		}
	}
	// инициализация
	for (iCycle = 0; iCycle < 52; iCycle++)
	{
		dSumTotal [iCycle] = 0.0;
		dQtyTotal [iCycle] = 0.0;
	}
	// загружаем даты из ассоциативных массивов
	if (! login_date1->fnGetValue (szDate1,query->szLogin))
	{
		fnGetToday (szDate1);
		login_date1->fnAdd (query->szLogin,szDate1);
	}
	if (! login_date2->fnGetValue (szDate2,query->szLogin))
	{
		fnGetToday (szDate2);
		login_date2->fnAdd (query->szLogin,szDate2);
	}

	for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
	{
		if (visit [iCycle]->fnGetDelete ())
			continue;
		if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetDate (),szDate2))
			continue;
		dSum = visit [iCycle]->fnGetSum ();
		dQty = visit [iCycle]->fnGetQty ();

		for (iCycle2 = 0; iCycle2 < 52; iCycle2++)
		{
			if (strstr (fnGetServiceGroups (visit [iCycle]->fnGetType ()),
				fnServicesGroupsGetSymbol (iCycle2)))
			{
				dSumTotal [iCycle2] += dSum;
				dQtyTotal [iCycle2] += dQty;
			}
		}
	}

	strcpy (sz,ini0.szBaseDir);
	// имя файла шаблона
	strcat (sz,rep_template [iTemplate]->szFile);
	tpl = new VDL_TEXT;
	tpl->fnLoad (sz); // загрузка шаблона
	for (iCycle = 0; iCycle < (int) tpl->fnGetLinesQty (); iCycle++)
	{
		psz = tpl->fnGetLine (iCycle);
		if (! strcmp (psz,"{org_name}"))
		{
			query->dst->fnAddLine (fnGetFilialName(query->szPrefix));
			continue;
		}
		if (! strcmp (psz,"{date1}"))
		{
			query->dst->fnAddLine (szDate1);
			continue;
		}
		if (! strcmp (psz,"{date2}"))
		{
			query->dst->fnAddLine (szDate2);
			continue;
		}
		if (! strncmp (psz,"{sum}",5))
		{
			dSum = 0.0;
			for (iCycle2 = 0; iCycle2 < 52; iCycle2++)
			{
				if (strstr (psz+5,fnServicesGroupsGetSymbol (iCycle2)))
					dSum += dSumTotal [iCycle2];
			}
			sprintf (sz,"%.2f",dSum);
			if (config.bReportSepComma)
				fnCharToComma (sz,'.');
			query->dst->fnAddLine (sz);
			continue;
		}
		if (! strncmp (psz,"{qty}",5))
		{
			dQty = 0.0;
			for (iCycle2 = 0; iCycle2 < 52; iCycle2++)
			{
				if (strstr (psz+5,fnServicesGroupsGetSymbol (iCycle2)))
					dQty += dQtyTotal [iCycle2];
			}
			sprintf (sz,"%.2f",dQty);
			if (config.bReportSepComma)
				fnCharToComma (sz,'.');
			query->dst->fnAddLine (sz);
			continue;
		}
		query->dst->fnAddLine (psz);
	}
	delete tpl;
} // end of fnAppReportTemplateForm ()

На главную © Д.С.Кузьмин