//---------------------------------------------------------------------------


#pragma hdrstop

#include "PrinterOPOS.h"
#include "OposFiscalPrinter_1_7_Lib_OCX.h"
//#include "OposFiscalPrinter_CCO_OCX.h"
#include "ud_Module.h"
#include <Registry.hpp>
#include <Math.h>
#include <DateUtils.hpp>
#include <Dialogs.hpp>
//---------------------------------------------------------------------------

#pragma package(smart_init)
//---------------------------------------------------------------------------
FiscalPrinter* g_printer;
//---------------------------------------------------------------------------
char * kkm_err_msg_ru[] = {
"OK",								//0
"ФП ID ошибка",						//1	FM ID Error
"Ошибка записи в ФП ",				//2	FM Rec Error
"Flash Chip не может быть очищен",	//3 Flash Chip cant clear
"ФП не пуста",						//4	FM not empty
"Данные в ФП разрушенны",			//5	FM Data destroyed
"Реж принтер игнорир кмд",			//6	Cmd ignor prn mode
"Нет кода оператора",				//7	Oper code is absent
"Нет типа документа",				//8	Doc type is absent
"Сер. номер ККМ",					//9 Ser num CR
"Ошибка пароля",					//10 Password error
"Ошибка дата/время",				//11 Data/Time error
"Завод. рег. ранее",				//12 Factory registration has already pass
"Сер ном ККМ разрушен",				//13 Ser num CR destroyed
"Фискализация ранее",				//14 Fiscalize has already pass
"ККМ не фиск режим",				//15 Not fisc mode CR
"Фискал ККМ разрушен",				//16 Fiscalize Data destroyed
"Перерег ККМ исчерпан",				//17 Rewrite is conclude
"Перерег ККМ разрушен",				//18 Rewrite is destroyed
"Смена открыта",					//19 Shift already open
"См не была открыта",				//20 Shift not opened
"Много товара в чеке",				//21 Many goods in receipt
"СМ в ФП разрушенна",				//22 EOD data in FM destroyed
"Формат документа",					//23 Document format error
"Перезапись текста",				//24 Text rewrite
"Много пар-ров док",				//25 Many parameters in document
"Ош параметр док-та",				//26 Document parameters error
"Ош значения пар-ра",				//27 Parameters value error
"Несуществующ объект",				//28 Object non-existent
"Док не был завершен",				//29 Document is not finished
"Товар/опер не полно",				//30 goods/operation description not enough
"Контрол сумма пакета",				//31 Check sum packet
"Принтер не готов",					//32 Prn not ready
"Вложенные прерывания",				//33 Nested interrupts
"Байт подтв прием данных",			//34 Check Sum Error
"Переполненние в ФП",				//35 Overflow if FM
"Неизвестная комманда",				//36 Unknown command
"CRC ОЗУ",							//37 CRC RAM
"CRC ФП",							//38 CRC FM
"Порт данных неисправ",				//39 Data port defective
"Порядок рекв чека",				//40 Receipts parameters sequence
"0xy для обязат рекв",				//41 0xy for required properties
"Длинна запроса",					//42 Length request
"Разрядность числа",				//43 number capacity
"Переполнение",						//44 Overflow
"Нет числа",						//45 Number is absent
"Нет ответа",						//46 Not response
"Ошибка передачи",					//47 Transmission error
"Мат. переполнение",				//48 Math overflow
"Нет бумаги...",					//49 Paper out...
"ККМ не готова!!!",					//50 CR not ready!!!
"Сбой памяти!!",					//51 Memory error!!
"Принтер выключен",					//52 Printer off
"Недостаточно памяти",				//53 Insufficient memory
"Длинна номера меньше",				//54 Lenght number less
"Нулевая длинна номера",			//55 Zero lenght number
"Длинна пароля меньше допустимой",	//56 Password lenght less permissible
"Нулевая длинна пароля",			//57 Zero lenght password
"Недопустимая величина",			//58 Impossible value
"Превышен тайм-аут",				//59 Time-out overdraw
"",
"Ош.ЭКЛЗ",
"Недопустимое состояние ЭКЛЗ",
"Данные учтены",
"","","","","","",//69
"","","","","","","","","","",//79
"","","","","","","","","","",//89
"","","","","","","","","","",//99
"","","","","","","","","","",//109
"","","","","","","","","","",//119
"","","","","","","","","","",//129
"","","","","","","","","","",//139
"","","","","","","","","","",//149
"","","","","","","","","","",//159

"","","","","","","","","","",//169
"","","","","","","","","","",//179
"","","","","","","","","","",//189
"","","","","","","","","","",//199
"","","","","","","","","","",//209
"","","","","","","","","","",//219
"","","","","","","","","","",//229
"","","","","","","","","","",//239
"Команды нет",//240									Cmd not init
"Ош. посылки команды",//241							Cmd write err
"Команда не отослана ККМ-неготов(DSR=0)",//242					Prn not ready (DSR=0)
"Команда отослана, но ответ что ККМ-неготов",//243		Cmd ok
"Превышено время ожидания ответа",//244					Cmd resp timeout
"Ошибка",//245										Prn error
"Пришло больше данных, чем ожидали",//246			Cmd resp large
"Пришло меньше данных, чем ожидали",//247			Cmd resp small
"Пришли некие данные",//248
"Порт закрыт",//249
"Порт закрыт во время выполнения",//250				Cmd break
"ККМ выключен или сломан",//251
"ККМ неготов",//252
"Ошибка в параметрах команды",//253
"Несуществующий номер команды",//254
"ККМ занят(предыдущая команда)!"//255			Previous cmd run
};
//------------------------------------------------------------------------------
bool FiscalPrinter::getNextCheckId(int &id)
{
	CheckId++; //Номер чека
	SaveSetup(); //сохраняем номер чека
        id=CheckId;
	return true;
}
//---------------------------------------------------------------------------
bool FiscalPrinter::SaveCheck(int CheckId) //Сохранение чека для последующей распечатки (суммы)
{
	if(dModule->UserType) //true - Юредическое лицо; false - физическое лицо
		dModule->SaveCheck(CheckId,dModule->UserId,0,getGoodsPrice());
	else
		dModule->SaveCheck(CheckId,0,dModule->UserId,getGoodsPrice());
	return true;
}
//---------------------------------------------------------------------------
bool FiscalPrinter::deleteCheck(int CheckId) //Удаление чека
{
	dModule->UpdateChek(CheckId);
	return true;
}
//---------------------------------------------------------------------------
int FiscalPrinter::getCOMPort()
{
	int n=-1;

	TRegistry* reg=new TRegistry;
	reg->RootKey = HKEY_LOCAL_MACHINE;
	if(reg->OpenKeyReadOnly("\\SOFTWARE\\OLEforRetail\\ServiceOPOS\\FiscalPrinter\\MbsFiscalPrinter"))
	{
		n = reg->ReadInteger("COM Num");
	}
	delete reg;
	return n;
}
//---------------------------------------------------------------------------
bool FiscalPrinter::setBaudRate(int val)
{
	bool result;
	TRegistry* reg=new TRegistry;
	reg->RootKey = HKEY_LOCAL_MACHINE;
	if(reg->OpenKey("\\SOFTWARE\\OLEforRetail\\ServiceOPOS\\FiscalPrinter\\MbsFiscalPrinter",true))
	{
		reg->WriteInteger("COM Speed",val);
		result = true;
	} else result = false;
	delete reg;
	return result;
}
//---------------------------------------------------------------------------
int FiscalPrinter::getBaudRate()
{
	int n=-1;
	TRegistry* reg=new TRegistry;
	reg->RootKey = HKEY_LOCAL_MACHINE;
	if(reg->OpenKeyReadOnly("\\SOFTWARE\\OLEforRetail\\ServiceOPOS\\FiscalPrinter\\MbsFiscalPrinter"))
	{
		n = reg->ReadInteger("COM Speed");
	}
	delete reg;
	return n;
}
//---------------------------------------------------------------------------
bool FiscalPrinter::setCOMPort(int n)
{
	bool result;
	TRegistry* reg=new TRegistry;
	reg->RootKey = HKEY_LOCAL_MACHINE;
	if(reg->OpenKey("\\SOFTWARE\\OLEforRetail\\ServiceOPOS\\FiscalPrinter\\MbsFiscalPrinter",true))
	{
		reg->WriteInteger("COM Num",n);
		result = true;
	} else result = false;
	delete reg;
	return result;
}
//---------------------------------------------------------------------------
void FiscalPrinter::LoadSetup()
{
	TIniFile* ini=new TIniFile(ExtractFilePath(ParamStr(0))+"\\Setup.ini");
//	cPort->port=ini->ReadString("Printer","Port","");
//	cPort->BaudRate=ini->ReadInteger("Printer","BaudRate",0);
	CheckId=ini->ReadInteger("Printer","CheckCount",0);
	TestMode=ini->ReadBool("Printer","TestMode",true);
	HeadLine=ini->ReadString("Printer","HeadLine","");
	GoodsName=ini->ReadString("Printer","GoodsName","");
	CasireName=ini->ReadString("Printer","CasireName","");
	AutoOpenShift=ini->ReadBool("Printer","AutoOpenShift",false);
	delete ini;
}
//---------------------------------------------------------------------------
void FiscalPrinter::SaveSetup()
{
	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",CheckId);
	ini->WriteBool("Printer","TestMode",TestMode);
	ini->WriteString("Printer","GoodsName",GoodsName);
	ini->WriteString("Printer","CasireName",CasireName);
	ini->WriteBool("Printer","AutoOpenShift",AutoOpenShift);
	delete ini;
}
//---------------------------------------------------------------------------
int FiscalPrinter::getGoodsPrice()
{
	int sum=0;
	for(int i=0;i<FListGoods->Count;i++)
		sum+=((Goods*)FListGoods->Items[i])->price;
	return sum;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
PrinterOPOS::PrinterOPOS(TComponent* AOwner):FiscalPrinter()
{
	Crashed=false;
	AutoOpenShift=false;
	fp=new TOPOSFiscalPrinter(AOwner);
	fp->DeviceEnabled = False;
	LoadSetup();
}
//---------------------------------------------------------------------------
PrinterOPOS::~PrinterOPOS()
{
	delete FListGoods;
	delete fp;
}
//---------------------------------------------------------------------------
//Соедениться по COM порту и проинициализировать принтер
bool PrinterOPOS::Start()
{
	if(fp->DeviceEnabled) return true;

	FState = fp->Open(L"MbsFiscalPrinter");
	if(FState!=0)
	{
		saveLog(1,AnsiString(FState)+"(PrinterOPOS::Start)"+GetStatusDescription(FState));
		return false;
	}
	FState = fp->ClaimDevice(1000);
	if(FState!=0)
	{
		saveLog(1,AnsiString(FState)+"(PrinterOPOS::Start)"+GetStatusDescription(FState));
		return false;
	}
	fp->DeviceEnabled = True;
	return true;
}
//---------------------------------------------------------------------------
void PrinterOPOS::setHeader(TStrings* Text)
{
	long err=0;
	try
	{
		if(Crashed) throw Exception("Драйвер принтера разрушен!");

		for(int i=0;i<Text->Count;i++)
		{
			WideString str=Text->Strings[i];
			err=fp->SetHeaderLine(i+1,str.c_bstr(),false);
			if(err) throw Exception(getLastError(&err));
		}
		err=fp->ResetPrinter();
		if(err)throw Exception(getLastError(&err));
	}catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(err,"(PrinterOPOS::setHeader)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::setHeader)"+exception.Message);
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::setHeader) Нет описания ошибки");
		dModule->SendError(1,"(PrinterOPOS::setHeader) Нет описания ошибки");
	}
}
//---------------------------------------------------------------------------
void PrinterOPOS::getHeader(TStrings* Text)
{
	TIniFile* ini=new TIniFile(ExtractFilePath(ParamStr(0))+"\\Setup.ini");
	Text->Add(ini->ReadString("Printer","HeadLine1",""));
	Text->Add(ini->ReadString("Printer","HeadLine2",""));
	Text->Add(ini->ReadString("Printer","HeadLine3",""));
	Text->Add(ini->ReadString("Printer","HeadLine4",""));
	Text->Add(ini->ReadString("Printer","HeadLine5",""));
	delete ini;

	for(int i=Text->Count-1;i>=0;i--)
		if(Text->Strings[i]=="")Text->Delete(i); else break;
}
//---------------------------------------------------------------------------
void PrinterOPOS::setTrailer(TStrings* Text)
{
	long err=0;
	try
	{	if(Crashed) throw Exception("Драйвер принтера разрушен!");
		for(int i=0;i<Text->Count;i++)
		{
			WideString str=Text->Strings[i];
			err=fp->SetTrailerLine(i+1,str.c_bstr(),false);
			if(err) throw Exception(getLastError(&err));
		}
		err=fp->ResetPrinter();
		if(err) throw Exception(getLastError(&err));
	}catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(err,"(PrinterOPOS::setTrailer)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::setTrailer)"+exception.Message);
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::setTrailer) Нет описания ошибки");
		dModule->SendError(1,"(PrinterOPOS::setTrailer) Нет описания ошибки");
	}
}
//---------------------------------------------------------------------------
void PrinterOPOS::getTrailer(TStrings* Text)
{
	TIniFile* ini=new TIniFile(ExtractFilePath(ParamStr(0))+"\\Setup.ini");
	Text->Add(ini->ReadString("Printer","TailLine1",""));
	Text->Add(ini->ReadString("Printer","TailLine2",""));
	Text->Add(ini->ReadString("Printer","TailLine3",""));
	Text->Add(ini->ReadString("Printer","TailLine4",""));
	Text->Add(ini->ReadString("Printer","TailLine5",""));
	delete ini;

	for(int i=Text->Count-1;i>=0;i--)
		if(Text->Strings[i]=="")Text->Delete(i); else break;
}
//---------------------------------------------------------------------------
bool PrinterOPOS::PrintLine(WideString line)
{
	//Не фискальная печать
	long err=0;
	try
	{	if(Crashed) throw Exception("Драйвер принтера разрушен!");
		err=fp->PrintNormal(2, WideString(WideString(WCHAR(0x1B)) + WideString(WCHAR(0x7C)) + line + L"\n").c_bstr());
		if(err) throw Exception(getLastError(&err));
	}catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(err,"(PrinterOPOS::PrintLine)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::PrintLine)"+exception.Message);
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::PrintLine) Нет описания ошибки");
		dModule->SendError(1,"(PrinterOPOS::PrintLine) Нет описания ошибки");
	}
	return err==0;
}
//---------------------------------------------------------------------------
//sales - true продажа, false - возврат
//check - номер чека если не задан =0 то генериться
//TODO Фича это фиксировать не распечатанные чеки потом печатать их
bool PrinterOPOS::PrintCheck(bool sales, int check, WideString headLine) //Тестовая печать
{
	long err=0;
	Currency cur=0;
	Currency cAllPrice=0;
	bool bOk=true;

	try
	{	if(Crashed) throw Exception("Драйвер принтера разрушен!");

		//Считаем сумму в чеке (заранее на случай ошибки)
		cAllPrice=getGoodsPrice();

		if(check==0) //если не задан номер чека то генерим сдесь
		{
			CheckId++; //Номер чека
			check=CheckId;
			SaveSetup(); //сохраняем номер чека
		}

		if(fp->RecEmpty) throw Exception("Нет бумаги!");
		if(!DayOpened()) throw Exception("Смена не открыта");

		Currency UnitPrice,AllPriceDrb,AllPrice;
		long Qnt,vat;
		BSTR* bstr;
		WideString sStr;
		BSTR sTmp=new OLECHAR[255];
		sTmp=L"";
		long MbsResponceCode;
		CURRENCY Amount1,Amount2;

		//Установка номера отдела
		//vat=11; sTmp=L"отдел";
		//err = fp->DirectIO(4, &vat, &sTmp);
		//if (err) goto ErrHandler;

		//Желателььно сделать в нутри чека TODO!!!
		if(headLine.Length()>0)
			PrintLine(headLine);


		if(sales) fp->FiscalReceiptType = FPTR_RT_SALES; //Чек продажи
		else fp->FiscalReceiptType=FPTR_RT_SERVICE; //Чек возврата

//setTrainingMode(true);

		//Фискальная печать (с заголовком или без)
		err = fp->BeginFiscalReceipt(true);
		if (err) throw Exception(getLastError(&err)); //251

		//Товары из списка в драйвер (TODO При печати чека не печатается услуга)
		for(int i=0;i<FListGoods->Count;i++)
		{
			Goods* goods=(Goods*)FListGoods->Items[i];
			VarCyFromR8(goods->price*100,&Amount1);
			Amount2.int64=0;
			WideString tmp=goods->name1+L"-/--/-0";
			err=fp->PrintRecItem(tmp.c_bstr(), Amount1, goods->count, goods->VatInfo, Amount2, L"Шт");
			if (err) throw Exception(getLastError(&err));
		}
		ClearGoods();

		//установка номера чека (Перед PrintRecTotal)
		err = fp->DirectIO(3, &CheckId, &sTmp);
		if (err) throw Exception(getLastError(&err));

		//Установка значений массива налоговых ставок
		//setNalog(1,12);

		//Формирования итога в чеке
		Amount2.int64=0;
		VarCyFromR8(cAllPrice*100,&Amount1);
		err=fp->PrintRecTotal(Amount1, Amount1, L"na");
		if (err) throw Exception(getLastError(&err));


		err = fp->EndFiscalReceipt(True); //Окончания печати, в нем происходит печать дополнительного трейлера (AdditionalTrailer) и обрезка бумаги
		if(err) throw Exception(getLastError(&err));
	}
	catch(Exception &exception)
	{
		ClearGoods();
		if(err==251) Crashed=true; //Кабздец
		saveLog(1,"Ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+CurrToStr(cAllPrice)+" Чек: "+AnsiString(CheckId)+". "+exception.Message);
		dModule->SendError(err,"Ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+IntToStr(cAllPrice)+" Чек: "+AnsiString(CheckId)+". "+exception.Message);
		bOk=false;
	}
	catch(...)
	{
		ClearGoods();
		if(err==251) Crashed=true; //Кабздец
		saveLog(1,"Не опознанная ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+IntToStr(cAllPrice)+" Чек: "+AnsiString(CheckId));
		dModule->SendError(1,"Не опознанная ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+IntToStr(cAllPrice)+" Чек: "+AnsiString(CheckId));
		bOk=false;
	}
	//сброс чека
	if(!bOk)
	{
		fp->PrintRecVoid(L"");
	}

	return bOk;
}
//---------------------------------------------------------------------------
bool PrinterOPOS::Cut() //Отрезать бумагу
{
	long err=0;
	try
	{
		if(Crashed) throw Exception("Драйвер принтера разрушен!");
		err=fp->PrintNormal(2, WideString(WideString(WCHAR(0x1B)) + WideString(WCHAR(0x7C)) + "75P").c_bstr());
		if(err) throw Exception(getLastError(&err));
	}catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(err,"(PrinterOPOS::Cut)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::Cut)"+exception.Message);
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::Cut) Нет описания ошибки");
		dModule->SendError(1,"(PrinterOPOS::Cut) Нет описания ошибки");
	}
}
//---------------------------------------------------------------------------
//Получить текущее состояние принтера (чтоб проверить готовность печати)
/*int PrinterOPOS::GetState()
{
	if(!fp->DeviceEnabled)FState=245;
	//if(FState!=0) return FState;
	//проверяем
	//Надо добавить лог
//	fp->ResultCodeExtended
	return 0;
} */
//---------------------------------------------------------------------------
//Проверка роботоспособности принтера
bool PrinterOPOS::isOk()
{
	long err=0;
	try
	{
		if(Crashed) throw Exception("Драйвер принтера разрушен!");
		if(fp->RecEmpty) throw "Нет бумаги!";
		err=fp->ResetPrinter();
		if(err) throw Exception(getLastError(&err)); //Очищает очередь с событиями

		AnsiString str;

		if(!dModule->getDayShift())throw Exception("Смена в базе не открыта!"); //Проверяем в базе открыта ли смен

		bool dOpen=DayOpened();
		if(!dOpen && AutoOpenShift && OpenShift()) dOpen=true;
		if(!dOpen) throw Exception("Смена не открыта!");

		if(DayOpened())
		{
			//Проверка на длину смены
			TDateTime dt=getDateOpenShift();
			str=getLastError(&err);
			if(err) throw Exception(getLastError(&err));

			dModule->getDate();
			if(HoursBetween(dt,dModule->date)>24) //Разница не более 24 часов
				throw Exception("[1]Смена не закрыта");
		} else throw Exception("Принтер не работает!");
		BSTR bstr=new OLECHAR[50];
		err=fp->GetDate(&bstr);
		if(err) throw Exception(getLastError(&err));
	}
	catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(1,"(PrinterOPOS::isOk)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::isOk)"+exception.Message);
		return false;
	}
	catch (...)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(1,"(PrinterOPOS::isOk)Неопознанная ошибка");
		dModule->SendError(1,"(PrinterOPOS::isOk)Неопознанная ошибка");
		return false;
	}
	return true;
}
//---------------------------------------------------------------------------
//Получить дату открытия смены
TDateTime PrinterOPOS::getDateOpenShift()
{
	long err=0;
	TDateTime date=0;
	try
	{
		if(Crashed) throw Exception("Драйвер принтера разрушен!");

		long iTmp;
		BSTR sTmp=new OLECHAR[50];
		err=fp->DirectIO(13, &iTmp, &sTmp);
		if(err) throw Exception(getLastError(&err));
		date=StrToDateTime(sTmp);
	}catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(err,"(PrinterOPOS::getDateOpenShift)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::getDateOpenShift)"+exception.Message);
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::getDateOpenShift) Нет описания ошибки");
		dModule->SendError(1,"(PrinterOPOS::getDateOpenShift) Нет описания ошибки");
	}
	return date;
}
//---------------------------------------------------------------------------
//Описание статуса
AnsiString PrinterOPOS::GetStatusDescription(long err)
{
	AnsiString str;
	try
	{
		if(err<256)
			str=kkm_err_msg_ru[err];
		if(str=="") str="Нет описания ошибки";
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::GetStatusDescription) Нет описания ошибки");
		return "Нет описания ошибки";
	}
	return str;
}
//---------------------------------------------------------------------------
//Получить код последней ошибки
AnsiString PrinterOPOS::getLastError(long* err)
{
	BSTR str=new OLECHAR[255];
	str=L"Нет описания ошибки!";
	try
	{
		fp->DirectIO(1, err, &str);
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::getLastError) Нет описания ошибки");
	}
	if(str==L"") return GetStatusDescription(*err);
	return str;
}
//---------------------------------------------------------------------------
AnsiString PrinterOPOS::getLastError()
{
	long err;
	return getLastError(&err);
}
//---------------------------------------------------------------------------
//Печать отчёта и закрытие смены
bool PrinterOPOS::PrintZReport()
{
	long err=0;
	try
	{
		if(Crashed) throw Exception("Драйвер принтера разрушен!");

		int sum=getDaySum();
		err=fp->PrintZReport();
		if(err) throw Exception(getLastError(&err));
		dModule->addZReport(sum);//Послать на сервер время снятия Z отчёта
		dModule->addPaper(-142*2);//Для подсчёта конца бумаги
	}catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(err,"(PrinterOPOS::PrintZReport)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::PrintZReport)"+exception.Message);
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::PrintZReport) Нет описания ошибки");
		dModule->SendError(1,"(PrinterOPOS::PrintZReport) Нет описания ошибки");
	}
	return err==0;
}
//---------------------------------------------------------------------------
//Печать суточного отчёта без закрытия смены
void PrinterOPOS::PrintXReport()
{
	long err=0;
	try
	{	if(Crashed) throw Exception("Драйвер принтера разрушен!");
		err=fp->PrintXReport();
		if(err) throw Exception(getLastError(&err));
	}catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(err,"(PrinterOPOS::PrintXReport)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::PrintXReport)"+exception.Message);
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::PrintXReport) Нет описания ошибки");
		dModule->SendError(1,"(PrinterOPOS::PrintXReport) Нет описания ошибки");
	}
}
//---------------------------------------------------------------------------
//Открытие смены
bool PrinterOPOS::OpenShift()
{
	long err;
	try
	{	if(Crashed) throw Exception("Драйвер принтера разрушен!");
		long n=1;
		//if(CasireName==NULL) CasireName=L" ";
		BSTR str=CasireName.c_bstr();
		err=fp->DirectIO (6,&n,&str);
		if(err) throw Exception(getLastError(&err)); //Передал номер и название кассира
		err=fp->SetVatValue(1,L"120");
		if(err) throw Exception(getLastError(&err));
	}catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(err,"(PrinterOPOS::OpenShift)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::OpenShift)"+exception.Message);
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::OpenShift) Нет описания ошибки");
		dModule->SendError(1,"(PrinterOPOS::OpenShift) Нет описания ошибки");
	}
	return err==0;
}
//---------------------------------------------------------------------------
bool PrinterOPOS::DayOpened()
{
	return fp->DayOpened;
}
//---------------------------------------------------------------------------
bool PrinterOPOS::setTrainingMode(bool val)
{
	long err;
	try
	{	if(Crashed) throw Exception("Драйвер принтера разрушен!");
		if(getTrainingMode()==val) return true;
		if(val) err=fp->BeginTraining(); else err=fp->EndTraining();
		if(err) throw Exception(getLastError(&err));
	}catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(err,"(PrinterOPOS::setTrainingMode)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::setTrainingMode)"+exception.Message);
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::setTrainingMode) Нет описания ошибки");
		dModule->SendError(1,"(PrinterOPOS::setTrainingMode) Нет описания ошибки");
	}
	return err==0;
}
//---------------------------------------------------------------------------
bool PrinterOPOS::getTrainingMode()
{
	return fp->TrainingModeActive;
}
//---------------------------------------------------------------------------
//Заполнение массива с суммами по налоговым ставкам
bool PrinterOPOS::setNalog(long n,float stavka)
{
	long err;
	try
	{	if(Crashed) throw Exception("Драйвер принтера разрушен!");
		long s=stavka*10;
		WideString str=AnsiString(s);
		err = fp->DirectIO(2, &n, &str);
		if(err) throw Exception(getLastError(&err));
	}catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(err,"(PrinterOPOS::setNalog)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::setNalog)"+exception.Message);
		return true;
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::setNalog) Нет описания ошибки");
		dModule->SendError(1,"(PrinterOPOS::setNalog) Нет описания ошибки");
		return true;
	}

	return err==0;
}
//---------------------------------------------------------------------------
//Дневной итог
int PrinterOPOS::getDaySum()
{
	long err;
	try
	{	if(Crashed) throw Exception("Драйвер принтера разрушен!");
		long n=1;
		BSTR str=new OLECHAR[20];
		err=fp->DirectIO (300,&n,&str);
		if(err) throw Exception(getLastError(&err));
		return StrToInt(str)/100.0;
	}catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(err,"(PrinterOPOS::getDaySum)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::getDaySum)"+exception.Message);
		return 0;
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::getDaySum) Нет описания ошибки");
		dModule->SendError(1,"(PrinterOPOS::getDaySum) Нет описания ошибки");
		return 0;
	}
}
//---------------------------------------------------------------------------
//Сумма  в кассе
int PrinterOPOS::getAllSum()
{
	long err=0;
	try
	{	if(Crashed) throw Exception("Драйвер принтера разрушен!");
		long n=2;
		BSTR str=new OLECHAR[20];
		err=fp->DirectIO (300,&n,&str);
		if(err)throw Exception(getLastError(&err));
		return StrToInt(str)/100.0;
	}catch(Exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		saveLog(err,"(PrinterOPOS::getAllSum)"+exception.Message);
		dModule->SendError(err,"(PrinterOPOS::getAllSum)"+exception.Message);
		return 0;
	}catch(...)
	{
		saveLog(1,"(PrinterOPOS::getAllSum) Нет описания ошибки");
		dModule->SendError(1,"(PrinterOPOS::getAllSum) Нет описания ошибки");
		return 0;
	}
}

//---------------------------------------------------------------------------
//sales - true продажа, false - возврат
//check - номер чека если не задан =0 то генериться
//Фича это фиксировать не распечатанные чеки потом печатать их
bool FiscalPrinterPort::PrintCheck(bool sales, int check, WideString headLine )
{
	//bool err=0;
	double cur=0;
	double cAllPrice=0;
	bool bOk=true;

	try
	{
		//Считаем сумму в чеке (заранее на случай ошибки)
		cAllPrice=getGoodsPrice();

		Currency UnitPrice,AllPriceDrb,AllPrice;
		long Qnt,vat;
		BSTR* bstr;
		WideString sStr;
		BSTR sTmp=new OLECHAR[255];
		sTmp=L"";
		long MbsResponceCode;
		CURRENCY Amount1,Amount2;

		//Фискальный чек или продажа
		if(sales) bOk = fp->OpenFiscalInv(1,"0000",1);
		else bOk = fp->OpenBackInv(1,"0000",1);
		if (!bOk) throw Exception(getLastError());

		if(headLine.Length()>0)
			PrintLine(headLine);

		//Товары из списка в драйвер
		for(int i=0;i<FListGoods->Count;i++)
		{
			Goods* goods=(Goods*)FListGoods->Items[i];
			bOk=fp->RegisterSale(goods->name1.c_bstr(),goods->name2.c_bstr(),0,"А",goods->price,goods->count,0,0); //Регистрация продажи (либо возврата)
			if (!bOk) throw Exception(getLastError());
		}
		ClearGoods();

		//Формирования итога в чеке (оплата)
		double Change;
		bOk=fp->Total("","","P",cAllPrice,Change);
		if (!bOk) throw Exception(getLastError());
		//Закрываем чек
		bOk = fp->CloseFiscalInv();
		if(!bOk) throw Exception(getLastError());
	}
	catch(Exception &exception)
	{
		ClearGoods();
		saveLog(1,"Ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+CurrToStr(cAllPrice)+" Чек: "+AnsiString(CheckId)+". "+exception.Message);
		dModule->SendError(bOk,"Ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+FloatToStr(cAllPrice)+" Чек: "+AnsiString(CheckId)+". "+exception.Message);
		bOk=false;
	}
	catch(...)
	{
		ClearGoods();
		saveLog(1,"Не опознанная ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+FloatToStr(cAllPrice)+" Чек: "+AnsiString(CheckId));
		dModule->SendError(1,"Не опознанная ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+FloatToStr(cAllPrice)+" Чек: "+AnsiString(CheckId));
		bOk=false;
	}
	//сброс чека
	if(!bOk)
	{
		fp->CancelFiscalInv();
	}
	return bOk;
}
//---------------------------------------------------------------------------
bool FiscalPrinterPort::PrintZReport()
{
	bool bOk;
	try
	{
		double Amount=0,CashSum=0,ServIn=0,ServOut=0;
		std::string Oper,Password,ExitCode="";
		bOk=fp->ParishOrConsumption(Oper,Password,Amount,ExitCode,CashSum,ServIn,ServOut);
		if(!bOk) throw Exception(getLastError());
		bOk=fp->PrintZReport();
		if(!bOk) throw Exception(getLastError());
		dModule->addZReport(CashSum);//Послать на сервер время снятия Z отчёта
	}
	catch(Exception &exception)
	{
		ClearGoods();
		saveLog(1,"Ошибка при печати Z отчёта "+exception.Message);
		dModule->SendError(bOk,"Ошибка при печати Z отчёта "+exception.Message);
		bOk=false;
	}
	catch(...)
	{
		ClearGoods();
		saveLog(1,"Не опознанная ошибка при печати Z отчёта.");
		dModule->SendError(1,"Не опознанная ошибка при печати Z отчёта.");
		bOk=false;
	}

	return bOk;
};
//---------------------------------------------------------------------------
bool FiscalPrinterPort::isOk()
{
	try
	{
		if (!fp->DiagnosticInfo()) throw Exception(getLastError());
		if(!dModule->getDayShift())throw Exception("Смена в базе не открыта!"); //Проверяем в базе открыта ли смен
	}
	catch(Exception &exception)
	{
		saveLog(1,"(PrinterOPOS::isOk)"+exception.Message);
		dModule->SendError(1,"(PrinterOPOS::isOk)"+exception.Message);
		return false;
	}
	catch (...)
	{
		saveLog(1,"(PrinterOPOS::isOk)Неопознанная ошибка");
		dModule->SendError(1,"(PrinterOPOS::isOk)Неопознанная ошибка");
		return false;
	}
	return true;
};
//---------------------------------------------------------------------------
