//! FP300KZ
/*!
Класс принтера FP300KZ
\author Иванов Игорь М.
\file FP300KZ.cpp
*/
//---------------------------------------------------------------------------
#pragma hdrstop

#include "stdafx.h"


#include "FP300KZ.h"
#include <stdTools.h>
#include <mathTools.h>
#include <sstream>

#include <iostream>
#include <fstream>
#include <locale>
//#include <string>
#include <vector>
#include <math.h>

#include <direct.h> //mkdir

//#include <unistd.h>
//#include <pthread.h>
//#include <stdlib.h>

#if defined( __WXMSW__ ) //Если кроссплатформкннное приложение 
	#include <wx/wx.h>
#endif // __WXMSW__
//---------------------------------------------------------------------------
//#pragma package(smart_init)
//---------------------------------------------------------------------------
//Добавил когда делал кросплатформеного кассирра
//typedef unsigned long       DWORD;
//---------------------------------------------------------------------------
//Сохранить лог в текстовый файл
bool saveLog(std::string FileName, std::string Text)
{
	try
	{
		for(uint4 i=0;i<Text.length();i++) 
		{	if(Text[i]=='\n') Text[i]=' '; //Чтоб в 1 строку было
		}
		Text="["+getDateTime()+"] "+Text; //Добавляем дату
		std::string path=getAppPathA()+std::string("logs\\"); //Путь к файлу

		_mkdir(path.c_str());
//#if defined( _VC )
//		CreateDirectoryA(path.c_str(), NULL); //Пробуем создать папку
//#endif
		path+=FileName+"_"+getStrDate()+".log";
#if defined( _BORLAND )
		std::ofstream file(path.c_str(),std::ios::app);
		file << Text.c_str() << std::endl;
		file.close();
#endif
#if defined( _VC )
		FILE* pfile = fopen ( path.c_str(), "a" ); //Для юникода _wfopen
		if(pfile!=NULL)
		{	fputs( Text.c_str() , pfile );
			fputs( "\n" , pfile );
			fclose( pfile );
		}
#endif
	}catch(...)
	{	return false;
	}
	return true;
}
//---------------------------------------------------------------------------
MyStatus::MyStatus()
{
	for(int i=0;i<8;i++)
		for(int j=0;j<6;j++) s[j][i]=false;
}
//---------------------------------------------------------------------------
void MyStatus::SetStatus(uint1* status)
{
	//переписываем статус в переменные для удобства
	//Байт 0: Общее предназначение
	s[0][7]=getBitVal(status[0],7); //0.7 Резерв.
	s[0][6]=getBitVal(status[0],6); //0.6 Открыт чек возврата.
	s[0][5]=getBitVal(status[0],5); //0.5 Признак ошибки (флаги, помеченные знаком # в байтах 0, 1, 2).
	s[0][4]=getBitVal(status[0],4); //0.4 # Печатающее устройство неисправно.
	s[0][3]=getBitVal(status[0],3); //0.3 Не подключен клиентский дисплей.
	s[0][2]=getBitVal(status[0],2); //0.2 Таймер не установлен.
	s[0][1]=getBitVal(status[0],1); //0.1 #	Неправильный код полученной команды.
	s[0][0]=getBitVal(status[0],0); //0.0 #	Синтаксическая ошибка в полученных данных.

	//Байт 1: Общее предназначение
	s[1][7]=getBitVal(status[1],7); //1.7 Резерв.
	s[1][6]=getBitVal(status[1],6); //1.6 Электронная контрольная лента напечатана.
	s[1][5]=getBitVal(status[1],5); //1.5 Крышка принтера открыта.
	s[1][4]=getBitVal(status[1],4); //1.4 # После включения принтера обнаружены нарушения данных в ОЗУ.
	s[1][3]=getBitVal(status[1],3); //1.3 # Батарея разряжена (Таймер реального времени в состоянии RESET).
	s[1][2]=getBitVal(status[1],2); //1.2 # ОЗУ обнулено.
	s[1][1]=getBitVal(status[1],1); //1.1 # Команда не может быть выполнена в данном фискальном режиме.
	s[1][0]=getBitVal(status[1],0); //1.0 Переполнение суммы. Статус 1.1 также будет установлен и команда не поменяет данные в принтере.

	//Байт 2: Общее предназначение
	s[2][7]=getBitVal(status[2],7); //2.7 Резерв.
	s[2][6]=getBitVal(status[2],6); //2.6 Электронная контрольная лента не пуста.
	s[2][5]=getBitVal(status[2],5); //2.5 Открыт служебный чек.
	s[2][4]=getBitVal(status[2],4); //2.4 Электронная контрольная лента заполнена на 90%.
	s[2][3]=getBitVal(status[2],3); //2.3 Открыт фискальный чек или чек возврата.
	s[2][2]=getBitVal(status[2],2); //2.2 Электронная контрольная лента заполнена.
	s[2][1]=getBitVal(status[2],1); //2.1 Недостаточно ленты.
	s[2][0]=getBitVal(status[2],0); //2.0 # Закончилась лента. Если флаг установлен во время выполнения команды печати, то выполнение команды будет остановлено и статус принтера не изменится.

	//Байт 3: Состояние конфигурационных переключателей
	s[3][7]=getBitVal(status[3],7); //3.7 Резерв.
	s[3][6]=getBitVal(status[3],6); //3.6 =1 Если переключатель Sw7 в положении ON. Скорость передачи данных в серийный порт.
	s[3][5]=getBitVal(status[3],5); //3.5 =1 Если переключатель Sw6 в положении ON. Скорость передачи данных в серийный порт.
	s[3][4]=getBitVal(status[3],4); //3.4 =1 Если переключатель Sw5 в положении ON. Не используется.
	s[3][3]=getBitVal(status[3],3); //3.3 =1 Если переключатель Sw4 в положении ON. Работа дисплея в кодовой таблице 1251 (Windows Cyrillic).
	s[3][2]=getBitVal(status[3],2); //3.2 =1 Если переключатель Sw3 в положении ON. Задает режим "прозрачный дисплей".
	s[3][1]=getBitVal(status[3],1); //3.1 =1 Если переключатель Sw2 в положении ON. Не используется.
	s[3][0]=getBitVal(status[3],0); //3.0 =1 Если переключатель Sw1 в положении ON. Разрешает автоматическую обрезку бумаги.

	//Байт 4: Фискальная память
	s[4][7]=getBitVal(status[4],7); //4.7 Резерв.
	s[4][6]=getBitVal(status[4],6); //4.6 Резерв.
	s[4][5]=getBitVal(status[4],5); //4.5 Признак ошибки (флаги, помеченные знаком * в байтах 4 и 5).
	s[4][4]=getBitVal(status[4],4); //4.4 * Фискальная память заполнена.
	s[4][3]=getBitVal(status[4],3); //4.3 В фискальной памяти осталось меньше 50 свободных полей.
	s[4][2]=getBitVal(status[4],2); //4.2 Запрограммирован заводской номер принтера.
	s[4][1]=getBitVal(status[4],1); //4.1 Запрограммированы налоговые номера.
	s[4][0]=getBitVal(status[4],0); //4.0 * Ошибка записи в фискальную память.

	//Байт 5: Фискальная память
	s[5][7]=getBitVal(status[5],7); //5.7 Резерв.
	s[5][6]=getBitVal(status[5],6); //5.6 Резерв.
	s[5][5]=getBitVal(status[5],5); //5.5 Не используется.
	s[5][4]=getBitVal(status[5],4); //5.4 Задана хотя бы одна налоговая ставка.
	s[5][3]=getBitVal(status[5],3); //5.3 Фискальный режим включен.
	s[5][2]=getBitVal(status[5],2); //5.2 * Последняя запись в фискальную память не успешна.
	s[5][1]=getBitVal(status[5],1); //5.1 Фискальная память отформатирована.
	s[5][0]=getBitVal(status[5],0); //5.0 * Фискальная память установлена в режим ТОЛЬКО ЧТЕНИЕ (заблокирована).
}
//---------------------------------------------------------------------------
//Получить статусы в виде строки
std::string MyStatus::getStatus()
{
	std::string str="";
	for(int i=0;i<8;i++)
		for(int j=0;j<6;j++)
			if(s[j][i]) str+="1"; else str+="0";
	return str;
}
//---------------------------------------------------------------------------
//Ошибки генерю сам по статусам
std::string FP300KZ::getErrorDesc(int ResultCode)
{
	std::string result="";
	switch( ResultCode )
	{
		//Ошибки взятые у штрихов
		case 0:   result="OK"; break;
		case 4:   result="Синтаксическая ошибка в полученных данных!"; break;
		case 5:   result="Нет запрошенных данных!"; break;
		case 78:  result="Смена превысила 24 часа!"; break;
		case 79:  result="Неверный пароль!"; break;
		case 103: result="Нет связи с ФП!"; break;
		case 192: result="Таймер не установлен!"; break;

		//Те ошибки которые я сам придумал
		case 500: result="Печатающее устройство неисправно!"; break;
		case 501: result="Неправильный код полученной команды!"; break;
		case 502: result="После включения принтера обнаружены нарушения данных в ОЗУ!"; break;
		case 503: result="Батарея разряжена (Таймер реального времени в состоянии RESET)!"; break;
		case 504: result="ОЗУ обнулено!"; break;
		case 505: result="Команда не может быть выполнена в данном фискальном режиме!"; break;
		case 506: result="Ошибка записи в фискальную память!"; break;
		case 507: result="Фискальная память заполнена!"; break;
		case 508: result="Закончилась лента!"; break;
		case 509: result="Уже открыт фискальный чек или чек возврата!"; break;
		case 510: result="Крышка принтера открыта!"; break;
		case 511: result="Не возможно закрыть чек доплатите денег!"; break;
		//При фискализации
		case 512: result="Не используется!"; break;
		case 513: result="Проведено максимальное количество перерегистраций!"; break;
		case 514: result="Не установлен заводской номер (фискализация) или не верный пароль налогового инспектора (перерегистрация)!"; break;
		case 515: result="Некорректный заводской номер!"; break;
		case 516: result="Открыт фискальный или нефискальный чек!"; break;
		case 517: result="Отпечатаны фискальные чеки после Z-отчета. Необходимо снять Z-отчет!"; break;
		case 518: result="Не установлены ставки НДС!"; break;
		case 519: result="Не включена ни одна группа НДС!"; break;
		case 520: result="Не установлены дата и время или фискальная память в режиме \"ТОЛЬКО ДЛЯ ЧТЕНИЯ\"!"; break;

		default:
			result="Нет описания ошибки!";
	}
	return result;
}
//---------------------------------------------------------------------------
std::string FP300KZ::getLastErrorDest()
{
	return getErrorDesc(ResultCode());
}
//---------------------------------------------------------------------------
//Генерим из статусов код ошибки в виде цифры
int FP300KZ::ResultCode()
{
	if(CommandName==fcCancelFiscalInv) return 0; //При отмене чека не выдавать ошибку хоть он и не был открыть

	if(CommandName==fcFiscalization)
	{
		if(m_ErrCode=="1") return 512; //'1' Не используется
		if(m_ErrCode=="2") return 513; //'2' Проведено максимальное количество перерегистраций.
		if(m_ErrCode=="3") return 514; //'3' Не установлен заводской номер (фискализация) или не верный пароль налогового инспектора (перерегистрация).
		if(m_ErrCode=="4") return 515; //'4' Некорректный заводской номер.
		if(m_ErrCode=="5") return 516; //'5' Открыт фискальный или нефискальный чек.
		if(m_ErrCode=="6") return 517; //'6' Отпечатаны фискальные чеки после Z-отчета. Необходимо снять Z-отчет.
		if(m_ErrCode=="7") return 518; //'7' Не установлены ставки НДС.
		if(m_ErrCode=="8") return 519; //'8' Не включена ни одна группа НДС.
		if(m_ErrCode=="9") return 520; //'9' Не установлены дата и время или фискальная память в режиме "ТОЛЬКО ДЛЯ ЧТЕНИЯ".
		m_ErrCode="";
	}

//1 1 Неисправен накопитель ФП 1, ФП 2 или часы
//2 2 Отсутствует ФП 1
//3 3 Отсутствует ФП 2
	if(Status->s[0][0]) return 4; //0x04 Некорректные параметры в команде обращения к ФП
/*5 5 Нет запрошенных данных
6 6 ФП в режиме вывода данных
7 7 Некорректные параметры в команде для данной реализации ФП
8 8 Команда не поддерживается в данной реализации ФП
9 9 Некорректная длина команды
0A 10 Формат данных не BCD
0B 11 Неисправна ячейка памяти ФП при записи итога
11 17 Не введена лицензия
12 18 Заводской номер уже введен
13 19 Текущая дата меньше даты последней записи в ФП
14 20 Область сменных итогов ФП переполнена
15 21 Смена уже открыта
16 22 Смена не открыта
17 23 Номер первой смены больше номера последней смены
18 24 Дата первой смены больше даты последней смены
19 25 Нет данных в ФП
1A 26 Область перерегистраций в ФП переполнена
1B 27 Заводской номер не введен
1C 28 В заданном диапазоне есть поврежденная запись
1D 29 Повреждена последняя запись сменных итогов
1F 31 Отсутствует память регистров
20 32 Переполнение денежного регистра при добавлении
21 33 Вычитаемая сумма больше содержимого денежного регистра
22 34 Неверная дата
23 35 Нет записи активизации
24 36 Область активизаций переполнена
25 37 Нет активизации с запрашиваемым номером
33 51 Некорректные параметры в команде
35 53 Некорректный параметр при данных настройках
36 54 Некорректные параметры в команде для данной реализации ФР
37 55 Команда не поддерживается в данной реализации ФР
38 56 Ошибка в ПЗУ +
39 57 Внутренняя ошибка ПО ФР
3A 58 Переполнение накопления по надбавкам в смене
3C 60 ЭКЛЗ: неверный регистрационный номер
3E 62 Переполнение накопления по секциям в смене
3F 63 Переполнение накопления по скидкам в смене
40 64 Переполнение диапазона скидок
41 65 Переполнение диапазона оплаты наличными
42 66 Переполнение диапазона оплаты типом 2
43 67 Переполнение диапазона оплаты типом 3
44 68 Переполнение диапазона оплаты типом 4
45 69 Cумма всех типов оплаты меньше итога чека
46 70 Не хватает наличности в кассе
47 71 Переполнение накопления по налогам в смене
48 72 Переполнение итога чека
4A 74 Открыт чек - операция невозможна
4B 75 Буфер чека переполнен
4C 76 Переполнение накопления по обороту налогов в смене
4D 77 Вносимая безналичной оплатой сумма больше суммы чека
4E 78 Смена превысила 24 часа
*/
	//if(CommandName==fcOpenFiscalInv && Password=="") return 79; //4F 79 Неверный пароль

/*50 80 Идет печать предыдущей команды
51 81 Переполнение накоплений наличными в смене
52 82 Переполнение накоплений по типу оплаты 2 в смене
53 83 Переполнение накоплений по типу оплаты 3 в смене
54 84 Переполнение накоплений по типу оплаты 4 в смене
56 86 Нет документа для повтора
57 87 ЭКЛЗ: количество закрытых смен не совпадает с ФП
58 88 Ожидание команды продолжения печати
59 89 Документ открыт другим оператором
5B 91 Переполнение диапазона надбавок
5C 92 Понижено напряжение 24В
5D 93 Таблица не определена
5E 94 Некорректная операция
5F 95 Отрицательный итог чека
60 96 Переполнение при умножении
61 97 Переполнение диапазона цены
62 98 Переполнение диапазона количества
63 99 Переполнение диапазона отдела
64 100 ФП отсутствует +
65 101 Не хватает денег в секции
66 102 Переполнение денег в секции*/
	if(!cPort->bOpen) return 103; //0x67 Ошибка связи с ФП +
/*68 104 Не хватает денег по обороту налогов
69 105 Переполнение денег по обороту налогов
6A 106 Ошибка питания в момент ответа по I2C
6B 107 Нет чековой ленты
6C 108 Нет контрольной ленты
6D 109 Не хватает денег по налогу
6E 110 Переполнение денег по налогу
6F 111 Переполнение по выплате в смене
70 112 Переполнение ФП
71 113 Ошибка отрезчика +
72 114 Команда не поддерживается в данном подрежиме
73 115 Команда не поддерживается в данном режиме
74 116 Ошибка ОЗУ
75 117 Ошибка питания +
76 118 Ошибка принтера: нет импульсов с тахогенератора +
77 119 Ошибка принтера: нет сигнала с датчиков +
78 120 Замена ПО
79 121 Замена ФП
7A 122 Поле не редактируется
7B 123 Ошибка оборудования
7C 124 Не совпадает дата
7D 125 Неверный формат даты
7E 126 Неверное значение в поле длины
7F 127 Переполнение диапазона итога чека
80 128 Ошибка связи с ФП +
81 129 Ошибка связи с ФП +
82 130 Ошибка связи с ФП +
83 131 Ошибка связи с ФП +
84 132 Переполнение наличности
85 133 Переполнение по продажам в смене
86 134 Переполнение по покупкам в смене
87 135 Переполнение по возвратам продаж в смене
88 136 Переполнение по возвратам покупок в смене
89 137 Переполнение по внесению в смене
8A 138 Переполнение по надбавкам в чеке
8B 139 Переполнение по скидкам в чеке
8C 140 Отрицательный итог надбавки в чеке
8D 141 Отрицательный итог скидки в чеке
8E 142 Нулевой итог чека
8F 143 Касса не фискализирована
90 144 Поле превышает размер, установленный в настройках
91 145 Выход за границу поля печати при данных настройках шрифта
92 146 Наложение полей
93 147 Восстановление ОЗУ прошло успешно
94 148 Исчерпан лимит операций в чеке
A0 160 Ошибка связи с ЭКЛЗ +
A1 161 ЭКЛЗ отсутствует +
A2 162 ЭКЛЗ: Некорректный формат или параметр команды
A3 163 Некорректное состояние ЭКЛЗ
A4 164 Авария ЭКЛЗ
A5 165 Авария КС в составе ЭКЛЗ
A6 166 Исчерпан временной ресурс ЭКЛЗ
A7 167 ЭКЛЗ переполнена
A8 168 ЗКЛЗ: Неверные дата и время
A9 169 ЭКЛЗ: Нет запрошенных данных
AA 170 Переполнение ЭКЛЗ (отрицательный итог документа)
B0 176 ЭКЛЗ: Переполнение в параметре количество
B1 177 ЭКЛЗ: Переполнение в параметре сумма
B2 178 ЭКЛЗ: Уже активизирована*/
	if(Status->s[0][2]) return 192; //0xC0 Контроль даты и времени (подтвердите дату и время)
/*C1 193 ЭКЛЗ: суточный отчёт с гашением прервать нельзя
C2 194 Превышение напряжения в блоке питания
C3 195 Несовпадение итогов чека и ЭКЛЗ
C4 196 Несовпадение номеров смен
С5 197 Буфер подкладного документа пуст
C6 198 Подкладной докуемнт отсутствует
C7 199 Поле не редактируется в данном режиме*/

	//Свои коды ошибок потому что немогу найти в списке выше этого значения
	if(Status->s[0][4]) return 500; //Печатающее устройство неисправно.
	if(Status->s[0][1]) return 501; //Неправильный код полученной команды.
	if(Status->s[1][4]) return 502; //После включения принтера обнаружены нарушения данных в ОЗУ.
	if(Status->s[1][3]) return 503; //Батарея разряжена (Таймер реального времени в состоянии RESET).
	if(Status->s[1][2]) return 504; //ОЗУ обнулено.
	if(Status->s[1][1])
	{
		if(CommandName==fcOpenFiscalInv && Status->s[2][3]) return 509; else //Уже открыт фискальный чек или чек возврата.
		if(CommandName==fcCloseFiscalInv)
		{
			bool Open; int Items; double Amount=0,Tender=0;
			FiscalTransactionsStatus(Open,Items,Amount,Tender);
			CommandName=fcCloseFiscalInv; //Чтоб при следующем вызове не обнолилось
			Status->s[1][1]=true; //Чтоб по прежнему была ошибка
			if(Open && Amount-(Tender+0.002)>0) return 511; //"Не возможно закрыть чек доплатите денег!"
		}else
		if(CommandName==fcOpenFiscalInv)
		{
			//Проверяем сколько времени прошло с начала смены
			m_SaveLog=false;
			int sec;
			if(SessionSec(sec) && sec>24*60*60)
			{
				Status->s[1][1]=true;
				CommandName=fcOpenFiscalInv; //Чтоб не изменилось
				return 78;
			}
			m_SaveLog=true;
		}
		return 505; //Команда не может быть выполнена в данном фискальном режиме.
	}
	if(Status->s[4][0]) return 506; //Ошибка записи в фискальную память.
	if(Status->s[4][4]) return 507; //Фискальная память заполнена.
	if(Status->s[2][0]) return 508; //Закончилась лента.
	//509 занят "Уже открыт фискальный чек или чек возврата."
	if(Status->s[1][5]) return 510; //Крышка принтера открыта!
	//511 занят "Не возможно закрыть чек доплатите денег!"
	//512 Не используется
	//513 Проведено максимальное количество перерегистраций.
	//514 Не установлен заводской номер (фискализация) или не верный пароль налогового инспектора (перерегистрация).
	//515 Некорректный заводской номер.
	//516 Открыт фискальный или нефискальный чек.
	//517 Отпечатаны фискальные чеки после Z-отчета. Необходимо снять Z-отчет.
	//518 Не установлены ставки НДС.
	//519 Не включена ни одна группа НДС.
	//520 Не установлены дата и время или фискальная память в режиме "ТОЛЬКО ДЛЯ ЧТЕНИЯ".


	return m_ErrorCode;
}
//---------------------------------------------------------------------------
FP300KZ::FP300KZ()
{
	cPort=new ComPort();
	Status=new MyStatus();
	CheckCount=0;
	for(int i=0;i<sizeof(ReadAr);i++) ReadAr[i]=0;
	FrameSeqNumber=0x20;

	PrinterName="none";
	m_Dots=0;
	m_ErrCode="this";
	m_SaveLog=true;
}
//---------------------------------------------------------------------------
FP300KZ::~FP300KZ()
{
	delete cPort;
}
//---------------------------------------------------------------------------
//Получить следующий порядковый номер запроса.
uint1 FP300KZ::getNextSeq()
{
	FrameSeqNumber++;
	if(FrameSeqNumber == 0x20 + 30) FrameSeqNumber = 0x20;
	if(FrameSeqNumber < 0x20) FrameSeqNumber = 0x20;
	return FrameSeqNumber;
}
//---------------------------------------------------------------------------
/*function FP_SendPMessage(var FP:TFP;cmd:TFiscalCommands;const Args:AnsiString;var ReceivedArguments:AnsiString;var ReceivedStatus:TReceivedStatus):integer;
var
  ReceivedMessage,
  packedCommand:AnsiString;
  i:integer;
begin
  Result:=FPE_NOTANSVER;
  FillChar(ReceivedStatus,sizeof(ReceivedStatus),$FF);
  ReceivedMessage:='';
  if FP_Serial_Open(FP) then
  begin
	FP.LastCommand:=FiscalCommands[cmd];
    for i := 0 to MSG_SEND_RETRIES-1 do
    begin
      packedCommand:=FP_PackMessage(FP,Args);
      if FP_Serial_WriteToComPort(FP,packedCommand[1], Length(packedCommand)) then
      begin
        if FP_ReceiveMessage(FP,ReceivedMessage) = FPE_NACK then
        begin
          // NACK or no answer received so wait a little untill the next retry
		  Sleep(MSG_SEND_RETRY_WAIT);
          continue;
        end;
        Result:=FP_UnpackMessage(FP,ReceivedMessage,ReceivedArguments,ReceivedStatus);
        break;
      end;
	end;
    FP_Serial_Close(FP);
  end;
end;*/
//---------------------------------------------------------------------------
/// Пакуем и отправляем сообщение на принтер потом ждём ответа
///\param msg Ссылка на первый символ массива символов
///\param size Размер массива
///\param answer Ответ в виде строки
///\Если результат true то всё ок
bool FP300KZ::SendPMessage(uint1* msg,uint1 size,std::string &answer)
{
	m_ErrorCode=0; //Обнуляем код ошибки перед выполнением команды
	if(!cPort->bOpen) { m_ErrorCode=103; return false; }

	CommandName=msg[3]; //Сохраняем номер последней команды
	for(int i=0;i<sizeof(ReadAr);i++) ReadAr[i]=0; //Очищаем буфер ответа.

	bool result=false; //Хоть чтото получили
	getNextSeq();//Увеличим на 1
	if(cPort->bOpen)
	{
		for(int i=0;i<5;i++) //Если после 5 попыток нет ответа то принтер неисправен...
		{
			//Отправляю запрос на принтер
			msg[1]=0x20+size-1; //Размер
			msg[2]=FrameSeqNumber;
			unsigned int crc=MakeCRC(msg,1,size);
			cPort->Write(msg,size); //Отправляем данные
			cPort->Write(&crc,4); //Контрольная сумма
			cPort->WriteChar(0x03); //Признак конца сообщения

			//Пытаюсь принять ответ от принтера
			bool isOk=true;
			int j=0;
			while(j<9) //9*60=540 в цикле чтоб ждать ответа не более 500ms по документации
			{
				uint1 start=0;
				unsigned long BytesRead=cPort->Read(&start,sizeof(start)); //читаемм байт (ответ должен прити в течении 60 ms хост должен ждать 500 ms)
				if(BytesRead==0) //Ничего не прочитал
				{	
					#ifdef __WXMSW__
						wxThread::Sleep(60);
					#endif // __WXMSW__
					#ifdef _BORLAND
						Sleep(60);
					#endif
					isOk=false;
					m_ErrorCode=103; //Код ошибки
					break;
				}else
				if(start==0x15) //NACK ошибка в контрольной сумме запрос заново отправить
				{
					#ifdef __WXMSW__
						wxThread::Sleep(60);
					#endif // __WXMSW__
					#ifdef _BORLAND
						Sleep(60);
					#endif
					isOk=false;
					break;
				}else
				if(start==0x16) //SYN комманда подождать данные посылается каждые 60ms
				{	
					#ifdef __WXMSW__
						wxThread::Sleep(60);
					#endif // __WXMSW__
					#ifdef _BORLAND
						Sleep(60);
					#endif
					j=0; //Начинаем ждать по новой (может зациклится)
				}else
				if(start==0x01) //Дочитываем
				{
					ReadAr[0]=start; //Для подсчёта CRC
					uint1 size=0;
					cPort->Read(&size,1); //Рзамер данных в байтах
					ReadAr[1]=size;
					size=ReadAr[1]-0x20 + 6; //Размер всего сообщения (+5 это 1 байт начало и CRC 4 байта и 1 байт конец)

					BytesRead=2; //Так как признак начала и размер уже прочитали
					for(int j=0;j<100;j++)
					{
						BytesRead+=cPort->Read(&ReadAr[BytesRead],size-BytesRead);
						if(BytesRead>=size)
							break;
					}

					//Проверяем ответ на CRC
					unsigned int crc0=MakeCRC(ReadAr,1,size-5);
					unsigned int crc1=*((unsigned int*)&ReadAr[size-5]);
					if(crc0!=crc1) isOk=false; //Ошибка в контрольной сумме ответа
					else
					{
						Status->SetStatus(&ReadAr[size-12]); //читаем статус
						answer.assign((char*)&ReadAr[4],size-17); //Добавляем ответ в результат
						result=true;
					}
					if(result) break;
				}
				j++;
			}
			if(!isOk) continue; //Ошибка повторяем запрос
			break; //всё в порядке
		}
	}

	if(!result) m_ErrorCode=5;
	return result;
}
//---------------------------------------------------------------------------
bool FP300KZ::OpenCOMPort(int ComNumber,int BaudRate)
{
	if(ComNumber>=0)
                cPort->ComNumber=ComNumber;
	if(BaudRate>=0)
                cPort->BaudRate=BaudRate;

	cPort->Close();
	
	if(cPort->Open(cPort->ComNumber))
	{
		if(!cPort->Setup(0))
			return false;
	}else return false;
	return true;
}
//---------------------------------------------------------------------------
void FP300KZ::LoadSetup()
{
/*
	std::wstring path=getCommonAppPathW()+L"\\NewTon\\Setup.ini";

	TIniFile* ini=new TIniFile(ExtractFilePath(ParamStr(0))+"\\Setup.ini");
	cPort->port=ini->ReadString("Printer","Port","");
	cPort->BaudRate=ini->ReadInteger("Printer","BaudRate",0);
	CheckCount=ini->ReadInteger("Printer","CheckCount",0);
	delete ini;
*/
}
//---------------------------------------------------------------------------
void FP300KZ::SaveSetup()
{
/*
	std::wstring path=getCommonAppPathW()+L"\\NewTon\\Setup.ini";

	TIniFile* ini=new TIniFile(ExtractFilePath(ParamStr(0))+"\\Setup.ini");
	ini->WriteString("Printer","Port",cPort->port);
	ini->WriteInteger("Printer","BaudRate",cPort->BaudRate);
	ini->WriteInteger("Printer","CheckCount",CheckCount);
	delete ini;
*/
}
//---------------------------------------------------------------------------
bool FP300KZ::Print()
{
	return false;
}
//---------------------------------------------------------------------------
void FP300KZ::NewLine()
{

}
//---------------------------------------------------------------------------
/*public byte[] ReturnBCC(byte[] bytePacketData)
        {
            // <BCC> Контролна сума (0000H-FFFFH)
            // дължина:    4 байта
			// стойност:   30H - 3FH
            // Сумата включва от <01> без него до <05> вкл.
            // Всяка цифра от двата байта се предава като и се прибави 30H.
            // Например сумата 1AE3H се представя като 31H,3AH,3EH,33H.

            // IN HEX
            //    01 25 50 4C 54 05 30

            // In decimal
            //     1 37 80 76 84 5 48

            Int64 triset_HEX = 0x30;

            byte[] bRes = new byte[4];
            int i = 48;
            int iRes = 0;
            // int i = 0;
            int iCountB = 0;
            string hexval1 = String.Empty;
            string hexval2 = String.Empty;
            StringBuilder sb = new StringBuilder();
			foreach (byte n in bytePacketData)
            {
                if (n != (byte)01)
                {
                    if (iCountB == 0)
                    {
                        sb.Append(n.ToString("X2"));
                        string hexString = sb.ToString();
                        triset_HEX = triset_HEX + Convert.ToInt64(hexString, 16);
                    }
                    iCountB++;
                    if (iCountB > 1)
                       iCountB = 0;
                }
                if (n == (byte)05)
                    break;
            }
            return this.ConvertHexToByteArr(Convert.ToString( triset_HEX ));
        }
*/
//---------------------------------------------------------------------------
///Постройка CRC специального для этого принтера
//BufStart - С какого байта начинать подсчёт
//BufEnd - По какой байт считать (не длина)
unsigned int MakeCRC(unsigned char* Buf, unsigned int BufStart,unsigned int BufEnd)
{
	unsigned int cs=0;
	for(unsigned int i=BufStart;i<BufEnd;i++)
		cs+=Buf[i];

	unsigned int result=0;
	unsigned char *mas=(unsigned char *)&result;
	mas[0]=((cs >> 0x0C) & 0x0F) + 0x30;
	mas[1]=((cs >> 0x08) & 0x0F) + 0x30;
	mas[2]=((cs >> 0x04) & 0x0F) + 0x30;
	mas[3]=((cs >> 0x00) & 0x0F) + 0x30;
	return result;
}
//---------------------------------------------------------------------------
//Инициализация переменных PrinterName PrinterVersion PrinterNumber PrinterDecimal
//Без которых принтер не может работать...
int FP300KZ::PrinterInit()
{
	int result;
	result = DiagnosticInfo();
	if(result == 0)
	{
		bool bA,bB,bC,bD;
		std::string Decimal,r,TaxA,TaxB,TaxC,TaxD;
		result = GetTaxRates(Decimal,r,bA,bB,bC,bD,TaxA,TaxB,TaxC,TaxD);
//		if(b) b=b && fp->GetStatusFP();
	}
	return result;
}
//---------------------------------------------------------------------------
///Получение байтов статуса принтера 4A
bool FP300KZ::GetStatusFP()
{
	unsigned char msg[5] = {0x01,0x24,0x20,fcGetStatusFP,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("GetStatusFP(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Аннуляция (сторно) фискального чека
bool FP300KZ::CancelFiscalInv()
{
	unsigned char msg[5] = {0x01,0x24,0x20,fcCancelFiscalInv,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("CancelFiscalInv(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Открытие фискального (клиентского) чека
///OpCode - Номер оператора 1..16
///OpPwd - Пароль оператора 4 - 6 цифр
///TillNmb - Номер кассового места целое число 1..99999
bool FP300KZ::OpenFiscalInv(int OpCode,std::string OpPwd,int TillNmb)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcOpenFiscalInv;
	msg+=IntToStdStr(OpCode)+","+OpPwd+","+IntToStdStr(TillNmb);
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	//if(b)
	//{	Password=OpPwd; //Сохраняем  пароль
	//}

	saveLog(PrinterName+"_"+PrinterNumber,std::string("OpenFiscalInv(OpCode="+IntToStdStr(OpCode)+",OpPwd=****,TillNmb="+IntToStdStr(TillNmb)+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Закрытие фискального чека
bool FP300KZ::CloseFiscalInv()
{
	unsigned char msg[5] = {0x01,0x24,0x20,fcCloseFiscalInv,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("CloseFiscalInv(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Открытие нефискального чека
bool FP300KZ::OpenServiceInv()
{
	unsigned char msg[5] = {0x01,0x24,0x20,fcOpenServiceInv,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("OpenServiceInv(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Закрытие нефискального чека
///TODO ответ: Количество всех напечатанных чеков (фискальных и служебных) с момента последнего закрытия смены до текущего момента /4 байта/.
bool FP300KZ::CloseServiceInv(int& count)
{
	count=0;
	unsigned char msg[5] = {0x01,0x24,0x20,fcCloseServiceInv,0x05};
	std::string str;
	bool b=SendPMessage(msg,sizeof(msg),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	if(b) count=fromString<int>(str);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("CloseServiceInv(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Открытие чека возврата
/**OpCode - Номер оператора 1..16
* OpPwd - 4 - 6 цифр
* TillNmb - Номер кассового места /целое число 1..99999/
*/
bool FP300KZ::OpenBackInv(int OpCode,std::string OpPwd,int TillNmb)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcOpenBackInv;
	msg+=IntToStdStr(OpCode)+','+OpPwd+','+IntToStdStr(TillNmb);
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("OpenBackInv(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Печать дубликата чека
bool FP300KZ::PrintDuplicateInv()
{
	unsigned char msg[6] = {0x01,0x25,0x20,fcPrintDuplicateInv,0x31,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("PrintDuplicateInv(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
/** Установка наименований дополнительных типов оплаты
Option - 1..4 номер типа оплаты
Name - Наименование типа оплаты (если name = '' то вернёт текущее)
*/
bool FP300KZ::SetAddTypesOfPayment(char Option, std::wstring& Text)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetAddTypesOfPayment;
	switch(Option)
	{
	case 1:
		msg+='I';
		break;
	case 2:
		msg+='J';
		break;
	case 3:
		msg+='K';
		break;
	case 4:
		msg+='L';
		break;
	}
	if(Text.length()!=0)
	{
		msg+=',';
		msg.append(ws2s(Text),0,31); //В документации макс 31 байт
	}
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b && Text.length()!=0 && answer!="P") b=b && false;
	if(b && Text.length()==0) Text=s2ws(answer);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("SetAddTypesOfPayment(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Печатать дневной отчёт с гашением
bool FP300KZ::PrintZReport()
{
	bool b=PrintEJ(); //печатаем контрольную ленту
	if(b) b=b && EJ("E"); //Отчищяяем контрольную ленту
	if(b) b=b && DailyFinancialReport('1'); //Сам Z отчёт
	return b;
}
//---------------------------------------------------------------------------
//Печатать дневной отчёт без гашения
bool FP300KZ::PrintXReport()
{
	return DailyFinancialReport('3');
}
//---------------------------------------------------------------------------
//Печатает строку текста (на служебном и на фискальном)
bool FP300KZ::PrintLine(std::wstring line)
{
	bool b=PrintFreeTextInFiscalInv(ws2s(line)); //TODO подправить на ru-ru.1251 роверить в интернете
	if(!b) b=PrintFreeTextInServiceInv(ws2s(line)); //Печать свободного текста в нефискальном чеке
	return b;

//	bool b=PrintFreeTextInFiscalInv(WStringToString(line, std::locale(""),'?')); //TODO подправить на ru-ru.1251 роверить в интернете
//	if(!b) b=PrintFreeTextInServiceInv(WStringToString(line, std::locale(""),'?')); //Печать свободного текста в нефискальном чеке
//	return b;
}
//---------------------------------------------------------------------------
///Дневной финансовый отчет
///'0' - Z отчёт без регистров
///'1' - Z отчёт с регистрами
///'2' - X отчёт без регистров
///'3' - X отчёт с содержанием регистров
bool FP300KZ::DailyFinancialReport(uint1 Option)
{
	//N на конце не сделал смотри документацию
	unsigned char msg[6] = {0x01,0x25,0x20,fcDailyFinancialReport,Option,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("DailyFinancialReport(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Отчет по налоговым ставкам и положению десятичной точки за период
///Start - Дата начала периода – DDMMYY /6 байт/
///End - Дата окончания периода – DDMMYY /6 байт/
bool FP300KZ::ReportOnTaxRates(std::string Start,std::string End) //Отчет по налоговым ставкам и положению десятичной точки за период
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcReportOnTaxRates;
	msg+=Start+','+End;
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	if(answer=="f") b=false; //Если не заданно налоговых ставок за период.
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("ReportOnTaxRates(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Полный фискальный отчет за период заданный датами
///Password - Пароль налогового инспектора от 4 до 6 цифр.
///Receipts - Не обязательный параметр: один байт со значением 'X'. Если он присутствует, то в отчете печатается количество фискальных чеков за день.
///Start - Начальная дата периода. 6 байт DDMMYY.
///End - Конечная дата периода. 6 байт DDMMYY.
///Если второй параметр отсутствует, команда генерирует месячный или годовой отчет. Синтаксис в этом случае:
///Start Месяц - 4 байта (MMYY) для месячного отчета.
///Start Год - 2 байта (YY) для годового отчета.
bool FP300KZ::FullFiscalReportByDate(std::string Password,std::string Receipts,std::string Start,std::string End)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFullFiscalReportByDate;

	msg+=Password+',';
	msg+=Receipts;
	msg+=Start+','+End;

	msg+=(char)0x05;

	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("FullFiscalReportByDate(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Сокращёный фискальный отчет за период заданный датами
///Password - Пароль налогового инспектора от 4 до 6 цифр.
///Receipts - Не обязательный параметр: один байт со значением 'X'. Если он присутствует, то в отчете печатается количество фискальных чеков за день.
///Start - Начальная дата периода. 6 байт DDMMYY.
///End - Конечная дата периода. 6 байт DDMMYY.
///Если второй параметр отсутствует, команда генерирует месячный или годовой отчет. Синтаксис в этом случае:
///Start Месяц - 4 байта (MMYY) для месячного отчета.
///Start Год - 2 байта (YY) для годового отчета.
bool FP300KZ::ReduceFiscalReportByDate(std::string Password,std::string Receipts,std::string Start,std::string End)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcReduceFiscalReportByDate;

	msg+=Password+',';
	msg+=Receipts;
	msg+=Start+','+End;

	msg+=(char)0x05;

	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("ReduceFiscalReportByDate(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Полный фискальный отчет за период заданный номерами смен
///Область данных:   <Password>, [[<Receipts>]<Start>,<End>]
///Password - Пароль налогового инспектора – от 4 до 6 цифр.
///Receipts - Не обязательный параметр: один байт со значением ‘X’. Если он присутствует, то в отчете печатается количество фискальных чеков за день.
///Start - Номер первой смены отчетного периода. 4 байта.
///End - Номер последней смены отчетного периода. 4 байта.
bool FP300KZ::FullFiscalReportByNumber(std::string Password,std::string Receipts,int Start,int End)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFullFiscalReportByNumber;

	msg+=Password+',';
	msg+=Receipts;
	msg+=IntToStdStr(Start)+','+IntToStdStr(End);

	msg+=(char)0x05;

	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("FullFiscalReportByNumber(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Сокращёный фискальный отчет за период заданный номерами смен
///Область данных:   <Password>, [[<Receipts>]<Start>,<End>]
///Password - Пароль налогового инспектора – от 4 до 6 цифр.
///Receipts - Не обязательный параметр: один байт со значением ‘X’. Если он присутствует, то в отчете печатается количество фискальных чеков за день.
///Start - Номер первой смены отчетного периода. 4 байта.
///End - Номер последней смены отчетного периода. 4 байта.
bool FP300KZ::ReduceFiscalReportByNumber(std::string Password,std::string Receipts,int Start,int End)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcReduceFiscalReportByNumber;

	msg+=Password+',';
	msg+=Receipts;
	msg+=IntToStdStr(Start)+','+IntToStdStr(End);

	msg+=(char)0x05;

	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("ReduceFiscalReportByNumber(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Дневной отчет по типам оплаты
bool FP300KZ::DailyReportByTypesOfPayment(std::string& Cash,std::string& Credit,std::string& Debit,std::string& Cheque,std::string& Pay1,std::string& Pay2,std::string& Pay3,std::string& Pay4,std::string& Closure,std::string& Receipt)
{
//
	unsigned char msg[5] = {0x01,0x24,0x20,fcDailyReportByTypesOfPayment,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		Cash=CutBeforeFirst(answer,',');
		Credit=CutBeforeFirst(answer,',');
		Debit=CutBeforeFirst(answer,',');
		Cheque=CutBeforeFirst(answer,',');
		Pay1=CutBeforeFirst(answer,',');
		Pay2=CutBeforeFirst(answer,',');
		Pay3=CutBeforeFirst(answer,',');
		Pay4=CutBeforeFirst(answer,',');
		Closure=CutBeforeFirst(answer,',');
		Receipt=CutBeforeFirst(answer,',');
	}
	saveLog(PrinterName+"_"+PrinterNumber,std::string("DailyReportByTypesOfPayment(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Отчет по артикулам
///'S' - Печатаются только данные артикулов по которым были продажи.
///'P' - Печатаются данные всех запрограммированных артикулов.
bool FP300KZ::ReportByArticle(std::string Option) //#define fcReportByArticle 0x6F //(111)Отчет по артикулам
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcReportByArticle; msg+=Option; msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("ReportByArticle(Option="+Option+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Отчет по операторам
bool FP300KZ::OperatorReport()
{
	unsigned char msg[5] = {0x01,0x24,0x20,fcOperatorReport,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("OperatorReport(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Протяжка ленты
///\param cnt Количество строк
bool FP300KZ::FeedPaper(int cnt)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFeedPaper;
	msg+=IntToStdStr(cnt);
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("FeedPaper(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Открытие денежного ящика
bool FP300KZ::OpenCashDrawer(int mSec)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcOpenCashDrawer;
	if(mSec>0) msg+=IntToStdStr(mSec);
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	saveLog(PrinterName+"_"+PrinterNumber,std::string("OpenCashDrawer(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//<Dept>,<Line1>[<LF><Line2>]
///Задать наименование департамента (Секции)
bool FP300KZ::SetDepartmentName(int dept,std::wstring line1,std::wstring line2)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetDepartmentName;
	msg+=IntToStdStr(dept);
	msg+=',';
	msg.append(ws2s(line1),0,36); //В документации макс 36 байт
	if(line2.length()>0)
	{
		msg+=(char)10;
		msg.append(ws2s(line2),0,46); //В документации макс 46 байт
	}
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("SetDepartmentName(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Получить информацию по секциям
bool FP300KZ::GetDepartmentInfo(int dept,int &RecSales,float &RecSum,int &TotSales,float &TotSum,std::wstring &Line1,std::wstring &Line2)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcGetDepartmentInfo;
	msg+=IntToStdStr(dept);
	msg+=(char)0x05;

	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	if(b)
	{
		if(CutBeforeFirst(str,',')=="P") //Секция запрограммированна
		{
			std::string nstr;
			nstr=CutBeforeFirst(str,',');
			RecSales=StdStrToInt(nstr);
			RecSum=fromString<float>(CutBeforeFirst(str,',')); //Натуральное число в текстовом виде с 2 десятичными знаками
			nstr=CutBeforeFirst(str,',');
			TotSales=StdStrToInt(nstr);
			TotSum=fromString<float>(CutBeforeFirst(str,',')); //Натуральное число в текстовом виде с 2 десятичными знаками
			Line1=s2ws(CutBeforeFirst(str,(char)10));
			Line2=s2ws(str);
		}else
		{
			RecSales=0;
			RecSum=0;
			TotSales=0;
			TotSum=0;
			Line1=L' ';
			Line2=L' ';
		}
	}
	saveLog(PrinterName+"_"+PrinterNumber,std::string("GetDepartmentInfo(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Обрезка ленты
bool FP300KZ::CutPaper()
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcCutPaper; msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("CutPaper(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Печать диагностической информации
bool FP300KZ::PrintDiagnostic()
{
	unsigned char msg[5] = {0x01,0x20,0x20,fcPrintDiagnostic,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("PrintDiagnostic(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
bool FP300KZ::SetManufacturersSerialNumber(std::string Serial)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetManufacturersSerialNumber;
	msg+=Serial;
	msg+=(char)0x05;

	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		b=b && BeforeFirst(answer,',')=="P";
		//Вторая часть ддолжна быть "KAZAKHSTAN"
	}
	saveLog(PrinterName+"_"+PrinterNumber,std::string("SetManufacturersSerialNumber(Serial="+Serial+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
std::string FP300KZ::GetStatusDescription(BYTE StatusCode)
{
	if (StatusCode == 0x00)
	{
		return "OK";
	}
	if (StatusCode == 0xFF)
	{
		return "Принтер недоступен!";
	}
	BYTE code = (BYTE)StatusCode & (BYTE)0x04;
	if (code > 0)
	{
		return "Бумага кончилась ";
	}
	code = (BYTE)StatusCode & (BYTE)0x01;
	if (code > 0)
	{
		return "Бумага скоро кончится ";
	}
	return "";
}
//---------------------------------------------------------------------------
///Чтение РНН и РНМ
bool FP300KZ::GetRNNAndRNM(std::string &RNN,std::string &RNM)
{
	unsigned char msg[5] = {0x01,0x24,0x20,fcGetRNNAndRNM,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	RNN=BeforeFirst(answer,',');
	RNM=AfterFirst(answer,',');

	saveLog(PrinterName+"_"+PrinterNumber,std::string("GetRNNAndRNM("+RNN+","+RNM+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Установка РНН и РНМ
bool FP300KZ::SetRNNAndRNM(std::string RNN,std::string RNM)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetRNNAndRNM;
	msg+=RNN+','+RNM;
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("SetRNNAndRNM(RNN="+RNN+",RNM="+RNM+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Установка пароля оператора
///\param OpCode Номер оператора
///\param OldPwd Старый пароль
///\param NewPwd Новый пароль
///\return Успех либо провал
bool FP300KZ::SetOperatorPassword(std::string OpCode,std::string OldPwd,std::string NewPwd)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetOperatorPassword;
	msg+=OpCode+','+OldPwd+','+NewPwd;
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("SetOperatorPassword(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Установка наименования оператора
///\param OpCode Номер оператора. От 1 до 16 строка.
///\param Pwd Пароль (4 до 8 цифр).
///\param OpName Наименование оператора (до 30 символов).
///\return Успех либо провал
bool FP300KZ::SetOperatorName(std::string OpCode,std::string Pwd,std::string OpName)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetOperatorName;
	msg+=OpCode+','+Pwd+','+OpName;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("SetOperatorName(OpCode="+OpCode+",OpName="+OpName+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Установка даты и времени
///\param date - Дата в формате "DD-MM-YY"
///\param time - врремя в формате "HH:MM[:SS]"
bool FP300KZ::SetDateTime(std::string date, std::string time) //#define fcSetDateTime 0x3D //(61)Установка даты и времени
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetDateTime;
	msg+=trim(date)+' '+trim(time);
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("SetDateTime(\"")+date+std::string("\", \"")+time+std::string("\"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Поолучение даты и времени
///\param date - Дата в формате "DD-MM-YY"
///\param time - врремя в формате "HH:MM:SS"
bool FP300KZ::GetDateTime(unsigned short& De,unsigned short& Me,unsigned short& Ye,unsigned short& Ho,unsigned short& Mi,unsigned short& Se)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcGetDateTime; msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	if(b)
	{
		De=fromString<int>(CutBeforeFirst(str,'-'));
		Me=fromString<int>(CutBeforeFirst(str,'-'));
		Ye=fromString<int>(CutBeforeFirst(str,' '));//+2000; закоментил чтоб было одинаково с тем что при установки времени

		Ho=fromString<int>(CutBeforeFirst(str,':'));
		Mi=fromString<int>(CutBeforeFirst(str,':'));
		Se=fromString<int>(str);
	}
	saveLog(PrinterName+"_"+PrinterNumber,std::string("GetDateTime(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Установка HEADER и FOOTER и опций печати
bool FP300KZ::PrintSetup(std::string Item, std::string Text, std::string& Answer)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcPrintSetup;
	msg+=Item+Text;
	msg+=(char)0x05;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),Answer);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("PrintSetup(Item="+Item+",Text="+Text+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
bool FP300KZ::PrintFreeTextInServiceInv(std::string Text) //Печать свободного текста в нефискальном чеке
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcPrintFreeTextInServiceInv;
	msg+=Text;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("PrintFreeTextInServiceInv(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Печать свободного текста в фискальном чеке
bool FP300KZ::PrintFreeTextInFiscalInv(std::string Text)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcPrintFreeTextInFiscalInv;
	msg+=Text;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("PrintFreeTextInFiscalInv(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Регистрация продажи
///[<L1>][<Lf><L2>]<Tab><TaxCd><[Sign]Price>[*<Qwan>][,Perc|;Abs]
///L1 - Первая строка описания продажи, до 36 байт текста
///L2 - Вторая строка описания продажи, до 36 байт текста
///dep - Департамент отдел (1..10)
///TaxCd - Один байт содержащий букву соответствующую налоговой группе (А, Б, В, Г, Д).
///Price - Цена единицы (до 8 значащих цифр).
///Qwan - Количество товара (Длина до 8 значащих цифр не более 3-х знаков после десятичной точки).
///Abs - абсолюбное ли значение в Perc иначе проценты
///Perc - Надбавка или скидка (в зависимости от знака) в процентах
bool FP300KZ::RegisterSale(std::wstring L1,std::wstring L2,int dep, std::string TaxCd,double Price,double Qwan,bool Abs,double Perc)
{
	L1=replaceStrings(L1,L"\n",L" "); //Избавляемся от переходов на новую строку
	L2=replaceStrings(L2,L"\n",L" "); //Избавляемся от переходов на новую строку

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcRegisterSale;
	msg.append(ws2s(L1),0,36); //В документации макс 36 байт
	if(L2.length()>0)
	{
		msg+=(char)0x0A;
		msg.append(ws2s(L2),0,36); //В документации макс 36 байт
	}
	msg+=(char)0x09;
	if(dep>0)
	{
		msg+=IntToStdStr(dep); //Параметр департамент отдел в документации в строке команды пропущен!!!!
		msg+=(char)0x09;
	}
	msg+=TaxCd; //налоговой группа 1 байт
	msg+=FloatToStdStr(Price,m_Dots); //Учитываем знаки после запятой
	msg+='*'+FloatToStdStr(Qwan,3);
	if(Perc!=0)
		if(Abs) msg+=';'+FloatToStdStr(Perc,m_Dots); //В абсолютном значении
		else msg+=','+FloatToStdStr(Perc,2); //Скидка или надбавка
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("RegisterSale(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Регистрация продажи с выводом на дисплей
///     [Line]]<Tab><TaxCd><[Sign]Price>[*Qwan][,Perc|;Abs]
///Line - Строка до 20 байта содержащая текст описывающий продажу.
///TaxCd - Один байт содержащий букву соответствующую налоговой группе (А, Б, В, Г, Д).
///Price - Цена единицы (до 8 значащих цифр).
bool FP300KZ::RegisterSaleDisp(std::string L1,int dep,std::string TaxCd,std::string Price)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcRegisterSaleDisp;

	msg+=L1;
	msg+=(char)0x09;
	if(dep>0)
	{
		msg+=IntToStdStr(dep); //Параметр департамент отдел в документации в строке команды пропущен!!!!
		msg+=(char)0x09;
	}
	msg+=TaxCd; //налоговой группа 1 байт
	msg+=Price;

	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("RegisterSaleDisp(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Подитог
//Print - Если ‘1’ – подитог печатается.
//Display - Если ‘1’ – сумма подитога выводится на дисплей.
//Abs - Абсолютное ли значчение false то Perc в процентах
//Perc - Скидка или надбавка в процентах (+-99.9) в зависимости от знака
//Sum - Сумма подитога в текущем фискальном чеке /до 10 байта/
bool FP300KZ::Subtotal(std::string Print,std::string Display, bool Abs, double Perc,double& Sum)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSubtotal;

	msg+=Print+Display;
	if(Perc!=0) //Скидка либо наценка
	{
		if(Abs) msg+=';'+FloatToStdStr(Perc,2);
		else msg+=','+FloatToStdStr(Perc,2);
	}

	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		Sum=fromString<double>(CutBeforeFirst(str,','))/M();
	}
	saveLog(PrinterName+"_"+PrinterNumber,std::string("Subtotal(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Оплата (итог)
//Line1 - Первая строка текста до 36 байт
//Line2 - Вторая строка текста до 36 байт
//PaidMode - Тип оплаты: 'P' – Оплата наличными; 'N' – Оплата в кредит; 'C' – Оплата чеком; 'D' – Оплата дебитной картой 'I' - Программируемый тип оплаты 1 'J' - Программируемый тип оплаты 2 'K' - Программируемый тип оплаты 3 'L' - Программируемый тип оплаты 4
//Один байт со значением ‘+’, указывающий знак Amount (суммы оплаты).
//Amount - Сумма оплаты /до 10 значащих цифр/.
//Change - Сдача
bool FP300KZ::Total(std::string Line1,std::string Line2,std::string PaidMode,double Amount, double& Change)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcTotal;
	msg+=Line1;
	msg+=(char)0x0A;
	msg+=Line2;
	msg+=(char)0x09; //<Tab>
	msg+=PaidMode; //Тип оплаты
	if(Amount>0) msg+='+';
	msg+=FloatToStdStr(Amount,m_Dots);

	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		if(str[0]=='F') b=false;
		std::string s="";
		s.append(str,1,str.length()-1);
		Change=fromString<double>(s)/M();
		if(str[0]=='D') Change=-fabs(Change);
	}

	saveLog(PrinterName+"_"+PrinterNumber,std::string("Total(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Служебный приход или расход
//Amount Сумма (до 10 значащих цифр). В зависимости от знака интерпретируется как приход или расход.
//strH - Заголовок  strF - последняя строка
//ExitCode ‘P’ Заявка исполнена. Если заявленная сумма  ненулевая, принтер печатает служебный чек  регистрирующий операцию. ‘F’   Заявка отклонена в случае если: Сумма наличности в кассе меньше суммы заявленного служебного расхода. Открыт фискальный или нефискальный чек.
//CashSum Сумма наличности в кассе. Сумма нарастающая после служебного прихода и после каждой оплаты наличными.
//ServIn Сумма всех команд  “Служебный приход”.
//ServOut Сумма всех команд  “Служебный расход”.
bool FP300KZ::ParishOrConsumption(std::string Oper,std::string Password,double Amount,std::wstring strH,std::wstring strF,std::string& ExitCode,double& CashSum,double& ServIn,double& ServOut)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcParishOrConsumption;

	if(PrinterName.find("FP600")!=std::string::npos)
	{
		if(Amount!=0)
		{	msg+=Oper+","; //Для Беларусов
			msg+=Password+","; //Для Беларусов
			msg+=FloatToStdStr(Amount,2);
		}
	}else
	{
		if(Amount!=0)
		{
			msg+=FloatToStdStr(Amount,2);
			while(strH.length()>0)
			{
				std::wstring str = CutBeforeWFirst(strH,L'\n');
				msg+='\t'; msg+='h'; msg.append(ws2s(str),0,48);
			}
			while(strF.length()>0)
			{
				std::wstring str = CutBeforeWFirst(strF,L'\n');
				msg+='\t'; msg+='f'; msg.append(ws2s(str),0,48);
			}
		}
	}

	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		ExitCode=CutBeforeFirst(str,',');
		CashSum=fromString<double>(CutBeforeFirst(str,','))/M();
		ServIn=fromString<double>(CutBeforeFirst(str,','))/M();
		ServOut=fromString<double>(str)/M();
	}

	saveLog(PrinterName+"_"+PrinterNumber,std::string("ParishOrConsumption(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Печать штрих-кода
///Type - Тип штрих кода от 1 до 5 (1-EAN8, 2-EAN13, 3-Code 128, 4-ITF, 5-ITF)
bool FP300KZ::PrintBarCode(int Type,std::string Data)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcPrintBarCode;
	msg+=IntToStdStr(Type);
	msg+=',';
	msg+=Data;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("PrintBarCode(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Звуковой сигнал
///\param Hz Частота звука
///\param mSec Милисекунд
MyError FP300KZ::Beep(int Hz,int mSec)
{
	MyError result;
	if(Hz==0) Hz=294;
	if(mSec==0) mSec=1000/8;

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcBeep;
	msg+=IntToStdStr(Hz);
	msg+=',';
	msg+=IntToStdStr(mSec);
	msg+=(char)0x05;
	std::string str="";
	SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	result.ErrorCode=ResultCode();
//	result.ErrorMessage=getErrorDesc(ResultCode());

	saveLog(PrinterName+"_"+PrinterNumber,std::string("Beep(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return result;
}
//---------------------------------------------------------------------------
//Количество логических мест для фискальных записей
///\Logical Количество логических мест для фискальных записей
bool FP300KZ::FreeFieldsByFiscalMemory(long& Logical)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFreeFieldsByFiscalMemory;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	if(b)
	{//	Logical=fromString<long>(CutBeforeFirst(str,','));
		Logical=fromString<int>(CutBeforeFirst(str,',')); //
	}
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("FreeFieldsByFiscalMemory(Logical); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Программирование конфигурационных ключей
///Если update=false то команда записывает из ОЗУ во флэш-память графический логотип, высоту печати штрих-кода, плотность печати и длину импульса открывания денежного ящика. После обнуления ОЗУ значения этих параметров восстанавливаются из флэш-памяти.
///\param update Если false то значения конфигуразионных ключей не изменяются, а данные настроек принтера записываются во флэш-память
bool FP300KZ::SwitchPrg(bool update)
{
	std::string msg,key="";
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSwitchPrg;
	if(update)
	{
		if(Sw8) key+='1'; else key+='0'; //Срокость
		if(Sw7) key+='1'; else key+='0'; //Срокость
		if(Sw6) key+='1'; else key+='0'; //Срокость
		if(Sw5) key+='1'; else key+='0'; //Не используется
		if(Sw4) key+='1'; else key+='0'; //Работа дисплея с кодовой таблицей Windows 1251
		if(Sw3) key+='1'; else key+='0'; //Режим прозрачного дисплея
		if(Sw2) key+='1'; else key+='0'; //Не используется
		if(Sw1) key+='1'; else key+='0'; //запись частичной информации на контрольную ленту(старое: Автоматическая обрезка ленты)
		msg+=key;
	}
	msg+=(char)0x05;
	std::string str="";

	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	saveLog(PrinterName+"_"+PrinterNumber,std::string("SwitchPrg("+key+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Для сохранение сокращённой информации в ЭКЛ
bool FP300KZ::getSmallEJ(bool& val)
{	//val=Sw1;
        val=Sw2;
	return true;//Всегда true потому что значение берётся не здесь.
}
//---------------------------------------------------------------------------
//Для сохранение сокращённой информации в ЭКЛ
bool FP300KZ::setSmallEJ(bool val)
{	//Sw1=val;
	Sw2=val;
	return SwitchPrg(true); //Сохраним переключатели
}
//---------------------------------------------------------------------------
//Режим прозрачного дисплея
bool FP300KZ::getDisplayTransparent(bool& val)
{	val=Sw3;
	return true;//Всегда true потому что значение берётся не здесь.
}
//---------------------------------------------------------------------------
//Режим прозрачного дисплея
bool FP300KZ::setDisplayTransparent(bool val)
{	Sw3=val;
	return SwitchPrg(true);
}
//---------------------------------------------------------------------------
///<Работа дисплея с кодовой таблицей Windows 1251
bool FP300KZ::getDisplayWin1251(bool& val)
{
	val=Sw4;
	return true;//Всегда true потому что значение берётся не здесь.
}
//---------------------------------------------------------------------------
///<Работа дисплея с кодовой таблицей Windows 1251
bool FP300KZ::setDisplayWin1251(bool val)
{	Sw4=val;
	return SwitchPrg(true);
}
//---------------------------------------------------------------------------
//Получить скорость порта из конфига "bps"
int FP300KZ::getComSpeed()
{
	int speed=0;
	if(!Sw6 && !Sw7 && !Sw8) speed=1200;
	if(!Sw6 && !Sw7 &&  Sw8) speed=2400;
	if(!Sw6 &&  Sw7 && !Sw8) speed=4800;
	if(!Sw6 &&  Sw7 &&  Sw8) speed=9600;
	if( Sw6 && !Sw7 && !Sw8) speed=19200;
	if( Sw6 && !Sw7 &&  Sw8) speed=38400;
	if( Sw6 &&  Sw7 && !Sw8) speed=57600;
	if( Sw6 &&  Sw7 &&  Sw8) speed=115200;
	return speed;
}
//---------------------------------------------------------------------------
//Установить скорость порта
bool FP300KZ::setComSpeed(int Speed)
{
	bool b=false;
	if(Speed==1200)   {Sw6=0; Sw7=0; Sw8=0; b=true;}
	if(Speed==2400)   {Sw6=0; Sw7=0; Sw8=1; b=true;}
	if(Speed==4800)   {Sw6=0; Sw7=1; Sw8=0; b=true;}
	if(Speed==9600)   {Sw6=0; Sw7=1; Sw8=1; b=true;}
	if(Speed==19200)  {Sw6=1; Sw7=0; Sw8=0; b=true;}
	if(Speed==38400)  {Sw6=1; Sw7=0; Sw8=1; b=true;}
	if(Speed==57600)  {Sw6=1; Sw7=1; Sw8=0; b=true;}
	if(Speed==115200) {Sw6=1; Sw7=1; Sw8=1; b=true;}

	if(b) b=SwitchPrg(true); //Запишем
	return b;
}
//---------------------------------------------------------------------------
///Команда очищает дисплей.
///Если открыт фискальный чек и Sw3 в положении OFF, очищается только нижняя строка.
bool FP300KZ::DisplayClear()
{
	unsigned char msg[5] = {0x01,0x24,0x20,fcDisplayClear,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("DisplayClear(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Вывод текста в нижнюю строку дисплея
//Text - До 20 символов текста
bool FP300KZ::DispalyLower(std::string Text)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcDispalyLower;
	msg+=Text;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("DispalyLower(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Вывод текста в верхнюю строку дисплея
///Text - До 20 символов текста
bool FP300KZ::DispalyUpper(std::string Text)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcDispalyUpper;
	msg+=Text;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("DispalyUpper(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Вывод на дисплей свободного текста
///Текст (до 40 символов), который выводится на дисплей. Если необходимо вывести символ ASCII меньше чем 20h (управляющие символы) то они увеличиваются на 40h и предваряются 10h.
bool FP300KZ::DispalyFree(std::string Text)
{
//Text=TransformCode(Text);

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcDispalyFree;
	msg+=Text;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("DispalyFree(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Чтение запрограммированных налоговых ставок
///\param Decimals Точек после  запятой 0,1 или 2
///\param bA,bB,bC,bD Означает разрешение налоговой группы
///\param TaxA Налоговая ставка А
///\param TaxB Налоговая ставка Б
///\param TaxC Налоговая ставка В
///\param TaxD Налоговая ставка Г
bool FP300KZ::GetTaxRates(std::string &Decimals,std::string &Rounding,bool& bA,bool& bB,bool& bC,bool& bD, std::string &TaxA, std::string &TaxB, std::string &TaxC, std::string &TaxD)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetTaxRates;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	if(b)
	{
		Decimals=CutBeforeFirst(str,',');
		m_Dots=fromString<int>(Decimals); //Заполняем глобальную переменную
		if(PrinterName.find("FP600")!=std::string::npos)
		{
			Rounding=CutBeforeFirst(str,','); //Для Беларусов округление
		}
		bA=str[0]=='1'; bB=str[1]=='1'; bC=str[2]=='1'; bD=str[3]=='1';
		CutBeforeFirst(str,',');
		TaxA=CutBeforeFirst(str,',');
		TaxB=CutBeforeFirst(str,',');
		TaxC=CutBeforeFirst(str,',');
		TaxD=str;
	}
	saveLog(PrinterName+"_"+PrinterNumber,std::string("GetTaxRates(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Установка положения десятичной точки и налоговых ставок
///\param Decimal 0,1 или 2 знака после запятой
bool FP300KZ::SetTaxRates(int Decimal,std::string Rounding,std::string TaxA, std::string TaxB, std::string TaxC, std::string TaxD)
{
	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetTaxRates;
	str+=IntToStdStr(Decimal)+","; //0,1,2 знака после запятой
	if(PrinterName.find("FP600")!=std::string::npos) //Для белорусов округление
	{
		str+=Rounding+',';
	}
	if(TaxA!="") str+='1'; else str+='0'; //Разрешена или нет
	if(TaxB!="") str+='1'; else str+='0'; //Разрешена или нет
	if(TaxC!="") str+='1'; else str+='0'; //Разрешена или нет
	if(TaxD!="") str+='1'; else str+='0'; //Разрешена или нет
	str+=",";
	str+=TaxA+',';
	str+=TaxB+',';
	str+=TaxC+',';
	str+=TaxD;
	msg+=str;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("SetTaxRates("+answer+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Статус фискальной транзакции
///\param Open Открыт фискальный или служебный чек
///\param Items Количество зарегистрированных продаж в текущем или последнем фискальном чеке.
///\param Amount Сумма последнего фискального чека
///\param Tender Сумма оплаты текущего или последнего чека.
bool FP300KZ::FiscalTransactionsStatus(bool& Open,int& Items,double& Amount,double& Tender)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFiscalTransactionsStatus;
	msg+='T';
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	Open=CutBeforeFirst(answer,',')=="1";
	Items=fromString<int>(CutBeforeFirst(answer,','));

	Amount=fromString<double>(CutBeforeFirst(answer,','))/M();
	Tender=fromString<double>(answer)/M();

	saveLog(PrinterName+"_"+PrinterNumber,std::string("FiscalTransactionsStatus(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Получить количество секунд с начала открытия смены
bool FP300KZ::SessionSec(int& sec)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)93;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	if(b)
		sec=fromString<int>(answer);
	if(m_SaveLog)
		saveLog(PrinterName+"_"+PrinterNumber,std::string("SessionSec(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Диагностическая информация
bool FP300KZ::DiagnosticInfo()
{
	unsigned char msg[5] = {0x01,0x20,0x20,fcDiagnosticInfo,0x05};
	std::string answer="";
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		//<Name><FwRev><Sp><FwDate><Sp><FwTime>,<Chk>,<Sw>,<ZNM>
		PrinterName=CutBeforeFirst(answer,',');
		PrinterVersion=CutBeforeFirst(answer,','); //Версия дата время
		CutBeforeFirst(answer,','); //Контрольная сумма
		std::string Sw18 = CutBeforeFirst(answer,',');//Положение конфигурационных переключателей Sw1 до Sw8. Строка 4 байта состоящая из‘0’ и‘1’
		Sw8=Sw18[0]=='1';
		Sw7=Sw18[1]=='1';
		Sw6=Sw18[2]=='1';
		Sw5=Sw18[3]=='1';
		Sw4=Sw18[4]=='1';
		Sw3=Sw18[5]=='1';
		Sw2=Sw18[6]=='1';
		Sw1=Sw18[7]=='1';
		PrinterNumber=answer; //Заводской номер - 12 байт.
	}

	saveLog(PrinterName+"_"+PrinterNumber,std::string("DiagnosticInfo(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Работа с электронной контрольной лентой
bool FP300KZ::EJ(std::string Cmd)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcEJ;
	msg+=Cmd;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("EJ("+Cmd+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Печать электронной контрольной ленты с начала (первая строка) нормальным шрифтом. Не Не печатаются служебные чеки, чеки служебного прихода и расхода и Х-отчет. Поле Data пустое.
bool FP300KZ::PrintEJ()
{
	return EJ("PL");
}
//---------------------------------------------------------------------------
///Сервисная очистка контрольной ленты
bool FP300KZ::ServiceClearEJ()
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcServiceClearEJ;
	msg+='F';
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	if(b)
	{
		if(answer!="P") b=false; //'P' (успешно) или 'F' (грешка)
	}
	saveLog(PrinterName+"_"+PrinterNumber,std::string("ServiceClearEJ(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
///Сервисное обнуление ОЗУ
bool FP300KZ::ServiceClearRAM()
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcServiceClearRAM;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	saveLog(PrinterName+"_"+PrinterNumber,std::string("ServiceClearRAM(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Печатается ли графический логотип
///\param Enable Разрешено либо запрещено печатать графический логотип.
///\param Height Высота графического логотипа
bool FP300KZ::getPrintLogo(bool& Enable,int& Height)
{
	std::string str;
	if(PrintSetup("I","L",str))
	{
		Enable = CutBeforeFirst(str,',')=="1";
		Height =fromString<int>(str);
		return true;
	}
	return false;
}
//---------------------------------------------------------------------------
//Печатать ли графический логотип
///\param Enable Разрешено либо запрещено печатать графический логотип.
///\param Height Высота графического логотипа
bool FP300KZ::setPrintLogo(bool Enable,int Height)
{
	std::string str="";
	if(Enable) str+="1,"; else str+="0,";
	str+=IntToStdStr(Height);

	std::string Answer="";
	return PrintSetup("L",str,Answer);
}
//---------------------------------------------------------------------------
//Программирование графического логотипа 576x96 точеек
//RowNum - номер линии
//Data - шестадцатеричная строка
bool FP300KZ::PrgGraphicLogo(int RowNum, std::string Data)
{
	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcPrgGraphicLogo;

	msg+=IntToStdStr(RowNum);
	msg+=',';
	msg+=Data;

	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	saveLog(PrinterName+"_"+PrinterNumber,std::string("PrgGraphicLogo("+IntToStdStr(RowNum)+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Программирование графического логотипа
///\param RowNum - Номер строки
///\param Data - Результат "01010101110"
bool FP300KZ::getGraphicLogo(int RowNum, std::string &Data)
{
	std::string msg,res;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcPrgGraphicLogo;
	msg+='R'+IntToStdStr(RowNum);
	msg+=(char)0x05;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),res);
	if(b)
	{
		Data="";
		for(uint4 i=0;i<res.size()/2;i++)
		{
			std::string sub=res.substr(i*2,2);
			int ch=0;
			#if defined( _VC )
				sscanf(sub.c_str(),"%X",&ch);
			#endif
			#if defined( _BORLAND )
				AnsiString str=sub.c_str();
				ch=StrToInt("0x"+str);
			#endif
			//Преобразуем в строку из 1 и 0
			if(getBitVal(ch,7)) Data+='0'; else Data+='1';
			if(getBitVal(ch,6)) Data+='0'; else Data+='1';
			if(getBitVal(ch,5)) Data+='0'; else Data+='1';
			if(getBitVal(ch,4)) Data+='0'; else Data+='1';
			if(getBitVal(ch,3)) Data+='0'; else Data+='1';
			if(getBitVal(ch,2)) Data+='0'; else Data+='1';
			if(getBitVal(ch,1)) Data+='0'; else Data+='1';
			if(getBitVal(ch,0)) Data+='0'; else Data+='1';
		}
	}

	saveLog(PrinterName+"_"+PrinterNumber,std::string("getGraphicLogo("+IntToStdStr(RowNum)+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Фискализация
//<Password>,<Serial>
bool FP300KZ::Fiscalization(std::string Password,std::string Serial,std::string& ErrCode)
{
	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFiscalization;
	msg+=Password+","+Serial;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	ErrCode=answer; //Код ошибки
	m_ErrCode=answer;

	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("Fiscalization("+Password+","+Serial+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Перерегистрация
//<OldPwd>,<Password>,<RNN>,<RNM>
bool FP300KZ::reFiscalization(std::string OldPwd,std::string Password,std::string RNN,std::string RNM,std::string& ErrCode)
{
	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFiscalization;
	msg+=Password+","+OldPwd+","+RNN+","+RNM; //Была ошибка в документации (старый и новый пароль поменял местами)
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	ErrCode=answer;
	m_ErrCode=answer;

	b=b && !Status->s[0][5]; //Признак ошибки

	saveLog(PrinterName+"_"+PrinterNumber,std::string("reFiscalization("+OldPwd+","+Password+","+RNN+","+RNM+"); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Информация о сумме накоплений за день
bool FP300KZ::AmountOfSavingsPerDay(double& TaxA,double& TaxB,double& TaxC,double& TaxD,double& TaxE)
{
	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcAmountOfSavingsPerDay;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		TaxA=fromString<double>(CutBeforeFirst(answer,','))/M();//TaxA
		TaxB=fromString<double>(CutBeforeFirst(answer,','))/M();//TaxB
		TaxC=fromString<double>(CutBeforeFirst(answer,','))/M();//TaxC
		TaxD=fromString<double>(CutBeforeFirst(answer,','))/M();//TaxD
		TaxE=fromString<double>(CutBeforeFirst(answer,','))/M();//TaxE
	}
	saveLog(PrinterName+"_"+PrinterNumber,std::string("AmountOfSavingsPerDay(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
bool FP300KZ::DepartmentReport()
{
	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcDepartmentReport;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	saveLog(PrinterName+"_"+PrinterNumber,std::string("DepartmentReport(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
bool FP300KZ::GetLastPrintedDocNumber(int& num)
{
	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcGetLastPrintedDocNumber;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		num=fromString<int>(answer);
	}else num=0;
	saveLog(PrinterName+"_"+PrinterNumber,std::string("GetLastPrintedDocNumber(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
//Информация о последней фискальной записи
///\param Clos Номер последней фискальной записи - 4 байта.
///\param Rec Количество фискальных чеков за день - 4 байта.
///\param Total Общая сумма продаж за день - 12  байт со знаком.
///\param VAT Общая сумма налогов за день - 12  байт со знаком.
///\param Date Дата последней фискальной записи - 6 байт /DDMMYY/.
bool FP300KZ::LatestFiscalRecord(std::string& Clos,int& Rec, float& Total,float& VAT,std::string& Date)
{
	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcLatestFiscalRecord;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		Clos=CutBeforeFirst(answer,',');
		if(PrinterName.find("FP600")==std::string::npos)
			Rec=fromString<int>(CutBeforeFirst(answer,','));
		else
			Rec=-1;
		Total=fromString<float>(CutBeforeFirst(answer,','));
		VAT=fromString<float>(CutBeforeFirst(answer,','));
		Date=answer;
	}
	saveLog(PrinterName+"_"+PrinterNumber,std::string("GetLastPrintedDocNumber(); //")+(b ? "OK=" : "ERROR=")+IntToStdStr(ResultCode())+" "+getErrorDesc(ResultCode()));
	return b;
}
//---------------------------------------------------------------------------
