// Скрипт автоматизации работой с фискальными регистраторами под управлением драйвера АТОЛ (версия ФФД от 1.2) 
// Copyright (C)

// Печать чека. Если программа не находит данной процедуры, то выполняет просто скрипт. Оставлено для совместимости со старыми скриптами
// При успешном завершении переменная Result должна вернуть 0. Иначе - код ошибки ККМ и ResultDescription - текст ошибки
// procedure Cash_Execute(NeedConnect :boolean = true) :boolean;  

// процедура вернет серийный номер кассы
// procedure Cash_GetNumbers(NeedConnect :boolean = true);

// процедура вернет номер сессии
// procedure Cash_GetSessionNumber(NeedConnect :boolean = true) :string;

// процедура проверяет и, если необходимо - инициализирует драйвер устройства (OLЕ-объект). В случае ошибки вызовет exception 
// procedure Cash_CheckDevice;

// процедура устанавливает связь с сервером. В случае ошибки вернет false, а также установит ResultCode и Result_Description 
// procedure Cash_Connect :boolean;

// процедура разрывает связь с сервером 
// procedure Cash_Disconnect;

// процедура отрезки чека
// procedure Cash_Cut(NeedConnect :boolean = true);

// процедура отмены зависшего чека
// procedure Cash_CancelCheck(NeedConnect :boolean = true);

// процедура "продолжить печать"
// procedure Cash_RepeatCheck(NeedConnect :boolean = true);

// процедура показа параметров устройства
// procedure Cash_ShowProperties;

// процедура вносить сумму в кассу
// procedure Cash_DoSummaryIn(NeedConnect :boolean = true);
// процедура изымает суммы из кассы
// procedure Cash_DoSummaryOut(NeedConnect :boolean = true);

 
// процедура открывает ящик
//procedure Cash_OpenDrawer(NeedConnect :boolean = true);

// Отчет с гашением
// procedure Cash_ZReport(NeedConnect :boolean = true);
// Отчет с без гашения
// procedure Cash_XReport(NeedConnect :boolean = true);
// Отчет по секциям
// procedure Cash_SectionReport(NeedConnect :boolean = true);
// Отчет по кассирам
// procedure Cash_UsersReport(NeedConnect :boolean = true);

// Отчет по регистрам (общий отчет)
// procedure Cash_RegistersReport(NeedConnect :boolean = true);

// все нижеперечисленные переменные могут быть определены в параметрах работы программы и проверяются перед выполнением на их наличие там.
// если в параметрах не найдено, то используются настройки по-умолчанию 


// поднять любую настройку из кассы (по её номеру, см. в приложении к АТОЛ "Настройки ККТ"). Требуется подключение к кассе.
// function Cash_GetSettingValue(SettingNumber :integer) :string; 

// поднять из нашей локальной инишки настройки драйвера 
// (основные настройки, отображающиеся на первой странице в настройках драйвера),
// не хранятся в кассе, требуется их восстановление и сохранение, 
// подключение к кассе не требуется.
// procedure cash_RestoreSettings;  

// сохранить настройки подключения для драйвера в нашей локальной инишке
// подключение к кассе не требуется, эти настройки в кассе не хранятся
// procedure Сash_SaveSettings;

// Проверить состояние смены и открыть смены 
// procedure Cash_CheckShiftState(NeedConnect :boolean = true; ShowResult :boolean = false);

var
  // Округление при обрезании цен и сумм
  DefRoundParam :  integer  = rpDown; // было rpTruncate // (rpDown = -1, rpNearest = 0, rpUp = 1, rpTruncate = 2,rpDEFAULT = 100);


var 
      CASH_DeviceName :string =  'AddIn.Fptr10';
      CASH_KKMSYSPASSWORD :string = ''; 
      CASH_STDUSERPASSWORD  :string = ''; // пароль кассира. Если не указан, то берется пароль пользователя программы. ДОлжен состоять только из цифр. Системный же пароль вбивается в настройках программы на закладке розницы.
      CASH_DEFAULT_USERNAME :string = ''; // кассир по-умолчанию. Если он не определен, то используется пользователь программы
      CASH_DEFAULT_USERINN :string = '';  // ИНН кассира по-умолчанию
      CASH_DiscountType :integer = 0; // 0 - скидка не отображается, 1 - детальная скидка, 2  - скидка на весь чек
      CASH_PrintStringDiscountSummary :boolean = true; // печатать строку с размером скидки  
      CASH_PrintStringPriceOut :boolean = true; // печатать строку со строкой без скидки
      CASH_PrintStringDiscountOnCheck :boolean = true; // печатать строку со скидкой на чек  

      CASH_NameBadCharList :string = '';  // символы в наименовании на замену
      CASH_NameReplaceCharList :string = ''; // символы в наименовании, которыми надо заменить плохие.   

      CASH_TypeCloseNal :integer = 0; // LIBFPTR_PT_CASH
      CASH_TypeCloseBN :integer = 1; // LIBFPTR_PT_ELECTRONICALLY подмена стандартных типов оплаты данными
      CASH_TypeCloseKredit :integer = 1;
      CASH_TypeCloseSert :integer = 2; // LIBFPTR_PT_PREPAID = 2, LIBFPTR_PT_CREDIT = 3, LIBFPTR_PT_OTHER = 4 ....
     
      CASH_CutType :integer = 0;  //0- не отрезать (не контролировать); 1-полная отрезка; 2-неполная отрезка
      
      CASH_OPENDRAWER_NAL :boolean = false; // открывать ли ящик в нале

      CASH_TrimNameGoods :boolean = false; // Обрезать ли наименование товара по длине строки
      
      // Длина строки. 0 - без обрезания и учета длины 
      // <0 - взять автоматически средствами драйвера      
      CASH_StringLength :integer = -1;
      
      //Cash_Protocol3 :boolean = true;
      
      CASH_SHOWNDS :boolean = true; // отображать ли НДС
      CASH_SHOWNDSSUMMARY :boolean = false;//посылать сумму НДС на аппарат (поддерживается не всеми аппаратами, теми, что не поддерживают, игнорируется, похоже)
      CASH_NDS0TYPE :integer = 6; //LIBFPTR_TAX_VAT0 // тип НДС0
	    CASH_NDS5TYPE :integer = 9; //LIBFPTR_TAX_VAT5
	    CASH_NDS7TYPE :integer = 10; //LIBFPTR_TAX_VAT7
      CASH_NDS10TYPE :integer = 2; //LIBFPTR_TAX_VAT10
      CASH_NDS18TYPE :integer = 7; //LIBFPTR_TAX_VAT18
      CASH_NDS20TYPE :integer = 7; //LIBFPTR_TAX_VAT20
      CASH_CANDIVIDEDIVNUM :boolean = true; // можно ли делить количество и цену для фасованных товаров (приводить к фасованным единицам и ценам)
      CASH_CANFLOATQUANTITY :boolean = false; // допустимо ли дробное количество (не касается товаров, помеченных как весовые)
      
      //CASH_SESSIONREGISTER :integer = 53; // 21 или 27, или 28, или 53 // раньше использовал 21, но потом стал давать 0

      CASH_SHOWADVANCEDERRORTEXT :boolean = true; // выводить ли в cash_checkerror дополнительный хинт с ошибкой
      CASH_PRINTCLIENT :boolean = false; // выводить ли имя и инн покупателя (атрибуты 1227 и 1228)
      CASH_SAVEMARKS :integer = 1;  // сохранять ли марку в кассе
      CASH_CHECKDATEENDFN :boolean = true; // проверять ли срок действия ФН
      CASH_CHECKDATETIME  :boolean = true; // проверять ли дату-время ККМ
      
      CASH_MAXMINUTESDIFF :integer = 10; // максимальное расхождение в минутах между временем ПК и временем кассы, после превышения которого будет выдано предупрежденеие

      Cash_Logging :boolean = true; // Сохранять лог операции своими средствами (для тестирования)
    
      CASH_NODISCONNECT :boolean = true; // Производить ли дисконнект по требованию
      CASH_PRINTM :boolean = false; // печатать ли символ [М] в наименовании
      
      CASH_CHECKMARKS :boolean = true; // Производить ли проверку марок перед их отправкой?
      //CASH_SAVEUNITS :boolean = true; // Отправлять ли единицы измерения в кассу?
      //CASH_REGFRAC :boolean = true; // Отправлять ли FRACTIONAL в кассу при регистрации? не влияет на проверку марки

      CASH_SAVE2108 :boolean = true; // Отправлять ли тег 2108

      CASH_CHECKMARK_SLEEPMS :integer = 200; // интервал ожидания в мс между запросами ожидания ответа от кассы при проверке марки
      CASH_CHECKMARK_WAIT :integer = 0; // максимальный интервал ожидания в мс марки. В случае превышения таймаута - выход и действия в соответствии с CASH_CHECKMARK_EXIT
                                        // если 0, то проверять бесконечно. если -1, то ожидания нет, флаг LIBFPTR_PARAM_MARKING_WAIT_FOR_VALIDATION_RESULT выставляется в FALSE
      CASH_CHECKMARK_EXIT :integer = 2; // реакция на ошибки проверок или ошибки по таймауту: 0 - остановить пробитие чека, 1 - запросить диалог пользователя, 2 - продолжаем пробитие чека в любом случае
      CASH_CHECKMARK_ONLY_FN :boolean = true; // проверять ли марки только средствами FN. параметр LIBFPTR_SETTING_VALIDATE_MARK_WITH_FNM_ONLY

      // про возможность отключения печати чека тут: http://forum.atol.ru/index.php?showtopic=33053. там есть и про отключение печати отчетов, см. Fptr.setParam(Fptr.LIBFPTR_PARAM_REPORT_ELECTRONICALLY, 1); 
      CASH_PRINT_RECEIPT :boolean = true; // печатать ли чек на бумаге. отключить возможно, если пользователь указал телефон или емейл, или если указан емейл для отправки по дефолту
      CASH_NOPRINT_EMAIL :string = ''; // емейл для отправки чека, если пользователь не указал ни телефона, ни емейла, и если указано, что не нужна печать чека
      
      CASH_CURRENT_SECTION :integer = 0; // секция для всего товара
  
      TaxType :integer = 0; //Применяемая система налогообложения (СНО) Определяется программой согласно её настройке "Тип налога в кассовом чеке по-умолчанию" на закладке/ветке "Розница" 
  


const       
      FNN = 'NN';       
      FName = 'name';
      FMARKS_BARCODES = 'MARKS_BARCODES';
      FQuantity = 'kol';
      FPrice = 'cena';
      FPriceOut = 'prodcena';
      FPriceOut1 = 'rs_cena';
      FSection = 'section';
      FNDS = 'NDS';
      FSUMMARY = 'SUMMA';
      FFloatBarcode = 'FloatBarcode';
      FDivNum = 'DivNum';

{

var
    CardsPrintCutLineLength :integer; // сколько надо пропустить, чтобы линия отреза была там, где надо
    CardsPrintCutLine :boolean; // Надо ли резать (некоторые аппараты не поддерживают. по-умолчанию - true
    CardsPrintCutLineSleep :integer; // на месте отреза сделать слип, в секундах
}    


var
  IsInvoice :boolean = false; // true - идет печать из накладной
  DATASET :TDataset = nil; // датасет с товарами. Набор полей смотрите в чеке розницы
  DatasetMarks :tDataset = nil;
  Summary :Currency = 0; // сумма по чеку
  PaySummary :Currency = 0; // Внесено денег
  DiscountSummary :currency = 0; // сумма надбавки/скидки
  Discount   :double = 0; // процент надбавки/скидки
  DiscountIsLiveneed   :double = 0; // процент надбавки/скидки для ЖНВЛС
  DiscountMG   :double = 0; // процент надбавки/скидки от наценки
  DiscountIsLiveneedMG   :double = 0; // процент надбавки/скидки от наценки для ЖНВЛС
  DiscountSummary :double = 0; // сумма надбавки/скидки
  ClientName :string = ''; // имя контрагента
  ClientID :integer = 0; // код контрагента
  AddInfo :string = ''; // доп. инфо к контрагенту
  Doc_Reason :string = ''; // код основания в чеке
  Doc_Reason_Name :string = ''; // наименование основания в чеке
  Doc_Reason_FILTERED :string = ''; // код основания, по которому отфильтрован чек
  Doc_Reason_FILTERED_Name :string = ''; // наименование отфильтрованного основания в чеке
  DOC_TYPE_CLOSE :integer = 0; //
  SummaNotNullField :double = 0; // Сумма строк с ненулевым полем, установленным согласно настройкам
  EMAIL :string = ''; // телефон или емейл покупателя, для онлайн-касс
  user_name :string = ''; // имя кассира
  user_id :integer = 0; // ID кассира  
  IsReturn :boolean = false; // Это чек возврата, используется при пробитии чека
  Number_DOC :integer = 0; // Номер документа
  
  Storage_ID :integer = 0; // Номер склада

  VarActionNal :boolean = false;
  VarActionBN :boolean = false;
  VarActionKredit :boolean = false;
  VarActionSert :boolean = false;

  VarActionDiskont :boolean = false;
  VarActionDiskont1 :boolean = false;
  VarActionPension :boolean = false;
  VarActionVIP :boolean  = false;
  VarActionInsurance :boolean  = false;
  

  VarDevice :Variant = null; // устройство печати. Если не указано, то определять самостоятельно. Может быть использовано приложением для получения от этого скрипта и передачи другим скриптам

  ResultSerialNumber :string = '';   // серийный номер, возвращаемый процедурой Cash_GetSerialNumber и Cash_execute (если этого требуют настройки программы)  
  ResultSessionNumber :string = '';  // номер сессии, возвращаемый процедурой Cash_GetSessionNumber и Cash_execute (если этого требуют настройки программы)
  ResultDocumentNumber :integer = 0; // номер  документа  

  ResultRegisterListNames :TStrings = nil; 
  ResultRegisterListValues :TSTrings = nil;  
  
  VarReceptSeria: string = '';
  VarReceptNumber: string = '';
  VarReceptDate: TDateTime = 0;

  MeasurementValue :Variant;
  
  //GISMT_REQID: string;
  //GISMT_REQTIMESTAMP: string;
  
 
var
  // Возвращаемые параметры, могут быть использованы вызывающим скриптом или программой  
  ResultCode : integer =0; // результат, код ошибки, если не 0
  // Переменная ResultDescription возвращает текст кода Result
  ResultDescription :string = '';
  ResultCodeExtended :integer = 0; // расширенная ошибка согласно стандарту OPOS

procedure Cash_SaveLog(StrValue :string; LogAlways :boolean = false);
begin
  if Cash_Logging or LogAlways then
  with TLogFile.create('cashatol.log') do
  try
    AddStr(StrValue);
  finally
    Free;
  end;
end;

function Cash_CheckError(FuncName :string; NeedExcept :boolean = true) :boolean; // Проверка ошибки драйвера. Вылетаем на exception, если была ошибка
var strval :string;
begin
  ResultCode := VarDevice.ErrorCode;
  ResultCodeExtended := 0;
  ResultDescription := VarDevice.ErrorDescription;
  result := resultcode=0;
  if CASH_SHOWADVANCEDERRORTEXT then
  begin
    if (ResultCode in [1,2,4]) then  CreateHintW('Проверьте, включена ли касса','Рекомендации по ошибке ('+inttostr(resultcode)+': '+resultdescription+')')
    else if (resultcode = 82) then createhintw('Чек открыт: Попробуйте провести операцию отмены зависшего чека');
  end;
  
  if (ResultCode<>0) then
  begin
    strval := FuncName+': ошибка: ' + inttostr(resultcode) + ': ' + resultDescription; 
    cash_savelog(strval,true);
    if needexcept then raiseException(strval);
  end;
end;
  
  
function CASH_GET_DATETIME {(NeedConnect :boolean = true)}:tdatetime;  
begin
  //if NeedConnect then  Cash_Connect;
  try
    VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_DATE_TIME); 
    VarDevice.queryData; cash_checkerror('CASH_GET_DATETIME:QueryData');
    Result := VarDevice.getParamDateTime(VarDevice.LIBFPTR_PARAM_DATE_TIME); cash_checkerror('CASH_GET_DATETIME:1');
  finally
    //if NeedConnect then Cash_disconnect;
  end;
end;

function CASH_GET_FN_LAST_DATETIME {(NeedConnect :boolean = true)}:tdatetime;  
begin
  //if NeedConnect then  Cash_Connect;
  try
    VarDevice.setParam(VarDevice.LIBFPTR_PARAM_FN_DATA_TYPE, VarDevice.LIBFPTR_FNDT_VALIDITY);
    VarDevice.fnqueryData; cash_checkerror('CASH_GET_FN_LAST_DATETIME:fnQueryData'); 
    Result := asfloat(VarDevice.getparamdatetime(VarDevice.LIBFPTR_PARAM_DATE_TIME)); cash_checkerror('CASH_GET_FN_LAST_DATETIME:1');
  finally
    //if NeedConnect then Cash_disconnect;
  end;  
end; 


  
procedure Cash_InitVars;
begin
   CASH_DeviceName :=  appinifile.readstring('advanced','CASH_DEVICENAME',dbinifile.readstring('advanced','CASH_DEVICENAME',CASH_DEVICENAME));

   CASH_KKMSYSPASSWORD := Appinifile.readstring('advanced','CASH_KKMSYSPASSWORD',DBINIFILE.readstring('advanced','CASH_KKMSYSPASSWORD',appinifile.readstring('common','KKMSYSPASSWORD',CASH_KKMSYSPASSWORD)));
   CASH_STDUSERPASSWORD := Appinifile.readstring('advanced','CASH_STDUSERPASSWORD',DBINIFILE.readstring('advanced','CASH_STDUSERPASSWORD',Appinifile.readstring('common','KKMUSERPASSWORD',CASH_STDUSERPASSWORD)));
   CASH_DEFAULT_USERNAME := Appinifile.readstring('advanced','CASH_DEFAULT_USERNAME',DBINIFILE.readstring('advanced','CASH_DEFAULT_USERNAME',CASH_DEFAULT_USERNAME));
   CASH_DEFAULT_USERINN := Appinifile.readstring('advanced','CASH_DEFAULT_USERINN',DBINIFILE.readstring('advanced','CASH_DEFAULT_USERINN',CASH_DEFAULT_USERINN));
   
   CASH_DiscountType  := appinifile.readinteger('advanced','CASH_DISCOUNTTYPE',dbinifile.readinteger('advanced','CASH_DISCOUNTTYPE',CASH_DiscountType));
   CASH_PrintStringDiscountSummary := appinifile.readbool('advanced','CASH_PrintStringDiscountSummary',dbinifile.readbool('advanced','CASH_PrintStringDiscountSummary',CASH_PrintStringDiscountSummary));   
   CASH_PrintStringPriceOut := appinifile.readbool('advanced','CASH_PrintStringPriceOut',dbinifile.readbool('advanced','CASH_PrintStringPriceOut',CASH_PrintStringPriceOut));
   CASH_PrintStringDiscountOnCheck := appinifile.readbool('advanced','CASH_PrintStringDiscountOnCheck',dbinifile.readbool('advanced','CASH_PrintStringDiscountOnCheck',CASH_PrintStringDiscountOnCheck));  
   CASH_NameBadCharList := appinifile.readstring('advanced','CASH_NameBadCharList',dbinifile.readstring('advanced','CASH_NameBadCharList',CASH_NameBadCharList));
   CASH_NameReplaceCharList  := appinifile.readstring('advanced','CASH_NameReplaceCharList',dbinifile.readstring('advanced','CASH_NameReplaceCharList',CASH_NameReplaceCharList));   
   CASH_TypeCloseNal := appinifile.readinteger('advanced','CASH_TypeCloseNal',dbinifile.readinteger('advanced','CASH_TypeCloseNal',CASH_TypeCloseNal));
   CASH_TypeCloseBN := appinifile.readinteger('advanced','CASH_TypeCloseBN',dbinifile.readinteger('advanced','CASH_TypeCloseBN',CASH_TypeCloseBN));
   CASH_TypeCloseKredit := appinifile.readinteger('advanced','CASH_TypeCloseKredit',dbinifile.readinteger('advanced','CASH_TypeCloseKredit',CASH_TypeCloseKredit));
   CASH_TypeCloseSert := appinifile.readinteger('advanced','CASH_TypeCloseSert',dbinifile.readinteger('advanced','CASH_TypeCloseSert',CASH_TypeCloseSert));
   CASH_CutType := appinifile.readinteger('advanced','CASH_CutType',dbinifile.readinteger('advanced','CASH_CutType',CASH_CutType));
   CASH_TrimNameGoods := appinifile.readbool('advanced','CASH_TrimNameGoods',dbinifile.readbool('advanced','CASH_TrimNameGoods',CASH_TrimNameGoods));
   CASH_StringLength := appinifile.readinteger('advanced','CASH_StringLength',dbinifile.readinteger('advanced','CASH_StringLength',CASH_StringLength));
   CASH_OPENDRAWER_NAL := appinifile.readbool('advanced','CASH_OPENDRAWER_NAL',dbinifile.readbool('advanced','CASH_OPENDRAWER_NAL',CASH_OPENDRAWER_NAL));
   //CASH_Protocol3 := appinifile.readbool('advanced','CASH_Protocol2',dbinifile.readbool('advanced','CASH_Protocol3',CASH_Protocol3));
   CASH_SHOWNDS := appinifile.readbool('advanced','CASH_SHOWNDS',dbinifile.readbool('advanced','CASH_SHOWNDS',CASH_SHOWNDS));
   CASH_SHOWNDSSUMMARY := appinifile.readbool('advanced','CASH_SHOWNDSSUMMARY',dbinifile.readbool('advanced','CASH_SHOWNDSSUMMARY',CASH_SHOWNDSSUMMARY));
   CASH_NDS0TYPE := appinifile.readinteger('advanced','CASH_NDS0TYPE',dbinifile.readinteger('advanced','CASH_NDS0TYPE',CASH_NDS0TYPE));
   CASH_NDS10TYPE := appinifile.readinteger('advanced','CASH_NDS10TYPE',dbinifile.readinteger('advanced','CASH_NDS10TYPE',CASH_NDS10TYPE));
   CASH_NDS18TYPE := appinifile.readinteger('advanced','CASH_NDS18TYPE',dbinifile.readinteger('advanced','CASH_NDS18TYPE',CASH_NDS18TYPE));
   CASH_NDS20TYPE := appinifile.readinteger('advanced','CASH_NDS20TYPE',dbinifile.readinteger('advanced','CASH_NDS20TYPE',CASH_NDS20TYPE));
   CASH_NDS5TYPE := appinifile.readinteger('advanced','CASH_NDS5TYPE',dbinifile.readinteger('advanced','CASH_NDS5TYPE',CASH_NDS5TYPE));
   CASH_NDS7TYPE := appinifile.readinteger('advanced','CASH_NDS7TYPE',dbinifile.readinteger('advanced','CASH_NDS7TYPE',CASH_NDS7TYPE));
   CASH_CANDIVIDEDIVNUM := appinifile.readbool('advanced','CASH_CANDIVIDEDIVNUM',dbinifile.readbool('advanced','CASH_CANDIVIDEDIVNUM',CASH_CANDIVIDEDIVNUM));
   CASH_CANFLOATQUANTITY := appinifile.readbool('advanced','CASH_CANFLOATQUANTITY',dbinifile.readbool('advanced','CASH_CANFLOATQUANTITY',CASH_CANFLOATQUANTITY));
   CASH_SHOWADVANCEDERRORTEXT := appinifile.readbool('advanced','CASH_SHOWADVANCEDERRORTEXT',dbinifile.readbool('advanced','CASH_SHOWADVANCEDERRORTEXT',CASH_SHOWADVANCEDERRORTEXT));
   CASH_PRINTCLIENT := appinifile.readbool('advanced','CASH_PRINTCLIENT',dbinifile.readbool('advanced','CASH_PRINTCLIENT',CASH_PRINTCLIENT));
   CASH_SAVEMARKS := appinifile.readinteger('advanced','CASH_SAVEMARKS',dbinifile.readinteger('advanced','CASH_SAVEMARKS',CASH_SAVEMARKS));
   CASH_CHECKDATEENDFN := appinifile.readbool('advanced','CASH_CHECKDATEENDFN',dbinifile.readbool('advanced','CASH_CHECKDATEENDFN',CASH_CHECKDATEENDFN));
   CASH_CHECKDATETIME := appinifile.readbool('advanced','CASH_CHECKDATETIME',dbinifile.readbool('advanced','CASH_CHECKDATETIME',CASH_CHECKDATETIME));
   CASH_MAXMINUTESDIFF := appinifile.readinteger('advanced','CASH_MAXMINUTESDIFF',dbinifile.readinteger('advanced','CASH_MAXMINUTESDIFF',CASH_MAXMINUTESDIFF));
   CASH_Logging := appinifile.readbool('advanced','CASH_LOGGING',dbinifile.readbool('advanced','CASH_LOGGING',CASH_LOGGING));
   CASH_NODISCONNECT := appinifile.readbool('advanced','CASH_NODISCONNECT',dbinifile.readbool('advanced','CASH_NODISCONNECT',CASH_NODISCONNECT));
   CASH_PRINTM := appinifile.readbool('advanced','CASH_PRINTM',dbinifile.readbool('advanced','CASH_PRINTM',CASH_PRINTM));
   CASH_CHECKMARKS := appinifile.readbool('advanced','CASH_CHECKMARKS',dbinifile.readbool('advanced','CASH_CHECKMARKS',CASH_CHECKMARKS));
   CASH_CHECKMARK_SLEEPMS := appinifile.readinteger('advanced','CASH_CHECKMARK_SLEEPMS',dbinifile.readinteger('advanced','CASH_CHECKMARK_SLEEPMS',CASH_CHECKMARK_SLEEPMS));
   CASH_CHECKMARK_WAIT := appinifile.readinteger('advanced','CASH_CHECKMARK_WAIT',dbinifile.readinteger('advanced','CASH_CHECKMARK_WAIT',CASH_CHECKMARK_WAIT));
   CASH_CHECKMARK_EXIT := appinifile.readinteger('advanced','CASH_CHECKMARK_EXIT',dbinifile.readinteger('advanced','CASH_CHECKMARK_EXIT',CASH_CHECKMARK_EXIT));
   CASH_CHECKMARK_ONLY_FN := appinifile.readbool('advanced','CASH_CHECKMARK_ONLY_FN',dbinifile.readbool('advanced','CASH_CHECKMARK_ONLY_FN',CASH_CHECKMARK_ONLY_FN));

   //CASH_SAVEUNITS := appinifile.readbool('advanced','CASH_SAVEUNITS',dbinifile.readbool('advanced','CASH_SAVEUNITS',CASH_SAVEUNITS));
   //CASH_REGFRAC := appinifile.readbool('advanced','CASH_REGFRAC',dbinifile.readbool('advanced','CASH_REGFRAC',CASH_REGFRAC));
   CASH_SAVE2108 := appinifile.readbool('advanced','CASH_SAVE2108',dbinifile.readbool('advanced','CASH_SAVE2108',CASH_SAVE2108));

   CASH_PRINT_RECEIPT := appinifile.readbool('advanced','CASH_PRINT_RECEIPT',dbinifile.readbool('advanced','CASH_PRINT_RECEIPT',CASH_PRINT_RECEIPT));
   CASH_NOPRINT_EMAIL := appinifile.readstring('advanced','CASH_NOPRINT_EMAIL',dbinifile.readstring('advanced','CASH_NOPRINT_EMAIL',CASH_NOPRINT_EMAIL));
   
   CASH_CURRENT_SECTION := appinifile.readinteger('advanced','CASH_CURRENT_SECTION',dbinifile.readinteger('advanced','CASH_CURRENT_SECTION',CASH_CURRENT_SECTION));

   // не надо дополнительных определений, это берется из программы
   //CASH_TaxType := appinifile.readinteger('advanced','CASH_TaxType',dbinifile.readinteger('advanced','CASH_TaxType',CASH_TaxType)); 
end;
                         


// поднять любую настройку из кассы (по её номеру, см. в приложении к АТОЛ "Настройки ККТ"). Требуется подключение к кассе.
function Cash_GetSettingValue(SettingNumber :integer) :string; 
begin
  VarDevice.setParam(VarDevice.LIBFPTR_PARAM_SETTING_ID, SettingNumber); cash_checkerror('Cash_GetSettingValue:1');
  VarDevice.readDeviceSetting; cash_checkerror('Cash_GetSettingValue:ReadDeviceSettings');
  result := VarDevice.GetParamString(VarDevice.LIBFPTR_PARAM_SETTING_VALUE); Cash_checkerror('Cash_GetSettingValue:2');
end; 

// поднять из нашей локальной инишки настройки драйвера 
// (основные настройки, отображающиеся на первой странице в настройках драйвера),
// не хранятся в кассе, требуется их восстановление и сохранение, 
// подключение к кассе не требуется.
procedure cash_RestoreSettings;  
var StrValue :string;
    FName :string;
begin
  cash_savelog('cash_restoresettings');
  //StrValue:= appinifile.ReadString('ATOL','SETTINGS','');
  FName := getappLocalDataFolder+'atol10.cfg';

  if fileexists(fName) then 
    StrValue := FileToString(FName) 
  else 
    StrVAlue := '';
  
  if strvalue>'' then
  begin
    //strvalue := stringreplace(strvalue,'<-CR->',#13,true,true);
    //strvalue := stringreplace(strvalue,'<-LF->',#10,true,true);
    VarDevice.SetSettings(StrValue); cash_checkerror('cash_RestoreSettings:SetSettings');
    cash_savelog('Файл настроек '+FName+' найден, применены его параметры');
  end
  else 
    cash_savelog('Файл настроек '+FName+' НЕ найден');
    
  if CASH_KKMSYSPASSWORD>'' then
  begin
    StrValue := VarDevice.getSingleSetting(VarDevice.LIBFPTR_SETTING_ACCESS_PASSWORD);
    if StrValue<>CASH_KKMSYSPASSWORD then VarDevice.setSingleSetting(VarDevice.LIBFPTR_SETTING_ACCESS_PASSWORD, CASH_KKMSYSPASSWORD);
    VarDevice.applySingleSettings;    
    cash_savelog('CASH_KKMSYSPASSWORD = '+CASH_KKMSYSPASSWORD);
    cash_checkerror('cash_RestoreSettings:LIBFPTR_SETTING_ACCESS_PASSWORD-KKM');
  end;
  if CASH_STDUSERPASSWORD>'' then
  begin
    StrValue := VarDevice.getSingleSetting(VarDevice.LIBFPTR_SETTING_USER_PASSWORD);
    if StrValue<>CASH_STDUSERPASSWORD then VarDevice.setSingleSetting(VarDevice.LIBFPTR_SETTING_USER_PASSWORD, CASH_STDUSERPASSWORD);
    VarDevice.applySingleSettings;    
    cash_savelog('CASH_STDUSERPASSWORD = '+CASH_STDUSERPASSWORD);
    cash_checkerror('cash_RestoreSettings:LIBFPTR_SETTING_USER_PASSWORD-STD');
  end;
  
  cash_savelog('CASH_CHECKMARK_ONLY_FN = '+asstring(CASH_CHECKMARK_ONLY_FN));
  VarDevice.SetSingleSetting(VarDevice.LIBFPTR_SETTING_VALIDATE_MARK_WITH_FNM_ONLY,ifthen_integer(CASH_CHECKMARK_ONLY_FN,1,0));
  VarDevice.applySingleSettings;
  cash_checkerror('CASH_CHECKMARK_ONLY_FN');
end;

// сохранить настройки подключения для драйвера в нашей локальной инишке
// подключение к кассе не требуется, эти настройки в кассе не хранятся
procedure cash_SaveSettings;
var StrValue :string;
begin
  StrValue := VarDevice.GetSettings;
  cash_checkerror('cash_savesettings:getsettings');
  StringToFile(getappLocalDataFolder+'atol10.cfg',StrValue);
  {
  strvalue := stringreplace(strvalue,#13,'<-CR->',true,true);
  strvalue := stringreplace(strvalue,#10,'<-LF->',true,true);
  appinifile.WriteString('ATOL','SETTINGS',strvalue);}
end;

procedure Cash_CheckDevice;
begin
  if varIsNull(VarDevice) then 
  begin
    VarDevice := CreateOleObject(CASH_DeviceName); 
    //VarDevice.ApplicationHandle := Application.Handle;
    Cash_RestoreSettings; 
  end;
end;

procedure Cash_Connect(NeedLogin :boolean = true);
var strvalue,StrValue1,strvalue2 :string;
    boolval :boolean;
    CashDefaultDevice :integer;
    dt :tdatetime;
    intval :int64;
begin
  cash_savelog('cash_connect');
  Cash_CheckDevice;
  
  //Boolval := VarDevice.isopened; cash_checkerror;
  //if not Boolval then 
  begin 
    VarDevice.open; Cash_CheckError('cash_connect:open');
  end;

  if NeedLogin then // если всегда прописывать юзера, то при зависшем чеке получим ошибку программирования параметра 1021
  begin
  
    if Cash_DEFAULT_USERNAME>'' then
    begin
      StrValue := CASH_DEFAULT_USERNAME;
      StrValue1 := CASH_DEFAULT_USERINN; 
    end
    else begin
      StrValue := UserProgram;
      StrValue1 := UserProgramINN;
    end; 
    
    //strvalue2 := VarDevice.GetParamString(1021); cash_checkerror; возвращается пустая строка, функция бесполезна 
    //showmessage(strvalue2);
    //if StrValue2<>StrValue then 
    begin  
      VarDevice.setParam(1021,StrVAlue); Cash_CheckError('cash_connect:1021');
    end;
  
    if StrValue1>'' then 
    begin
      //strvalue2 := VarDevice.GetParamString(1203); cash_checkerror;
      //showmessage(strvalue2);
      //if strvalue2<>StrVAlue1 then
      begin
        VarDevice.setParam(1203,StrVAlue1); Cash_CheckError('cash_connect:1203');
      end;
    end;
  
    VarDevice.OperatorLogin; Cash_CheckError('cash_connect:OperatorLogin');
  end;

  if CASH_CHECKDATEENDFN then 
  begin
    if  appinifile.readdate('Atol10','date_check_fn',0) <>date then
    try
      DT := CASH_GET_FN_LAST_DATETIME;
      if DT <=0 then bvmessageerror('Срок действия ФН закончился '+DateToStr(DT)+'. Сообщите в бухгалтерию!')
      else if DT-date <=30  then bvmessagewarning('ФН заканчивается '+DateToStr(DT)+', через '+inttostr(daysbetween(DT,date))+' дней'+'.','Сообщите в бухгалтерию!');

      Appinifile.writedate('Atol10','date_check_fn',date)
    except
      createhinte(exceptmessage,'Не могу проверить срок действия ФН на кассе');    
    end;
  end;

  if CASH_CHECKDATETIME then 
  begin
    if  appinifile.readdate('Atol10','date_check_dt',0)<>date then
    try
      dt := CASH_GET_DATETIME;
      intval := minutesbetween(dt,now);
      if intval>CASH_MAXMINUTESDIFF then CreatehintW ('Время в кассе и на компьтере сильно расходится: время компьютера: '+formatdatetime('dd/mm/yyyy hh:nn',now)+', время в кассе: '+formatdatetime('dd/mm/yyyy hh:nn',dt),'Надо исправить время в кассе.');

      Appinifile.writedate('Atol10','date_check_dt',date)
    except
      createhinte(exceptmessage,'Не могу проверить текущие дату и время на кассе');    
    end;
  end;
  
end;

procedure Cash_disconnect;
begin
  cash_savelog('cash_disconnect');
  if VarDevice.isopened  and not CASH_NODISCONNECT then 
  begin
    cash_savelog('disconnected');
    VarDevice.Close; cash_checkerror('cash_disconnect',false);
  end;
end;

procedure Cash_GetNumbers(NeedConnect :boolean = true);
begin
  cash_savelog('cash_getnumbers');
  if needConnect then Cash_Connect;
  try
    VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_STATUS); Cash_CheckError('cash_GetNumbers:1');
    VarDevice.queryData; Cash_CheckError('cash_GetNumbers:2');
  
    resultSerialNumber := VarDevice.GetParamString(VarDevice.LIBFPTR_PARAM_SERIAL_NUMBER); Cash_CheckError('cash_GetNumbers:3');
    ResultSessionNumber := VarDevice.GetParamString(VarDevice.LIBFPTR_PARAM_SHIFT_NUMBER); Cash_CheckError('cash_GetNumbers:4');
    ResultDocumentNumber := VarDevice.GetParamInt(VarDevice.LIBFPTR_PARAM_DOCUMENT_NUMBER { или VarDevice.LIBFPTR_PARAM_RECEIPT_NUMBER?}); Cash_CheckError('cash_GetNumbers:5'); 
  finally  
    if NeedConnect then Cash_disconnect;
  end;
end;

procedure Cash_Cut(NeedConnect :boolean = true);
begin
    if CASH_CutType=0 then exit; // нет отрезки
    
    if NeedConnect then Cash_Connect;
    try
      if CASH_CutType=1 then VarDevice.SetParam(VarDevice.LIBFPTR_PARAM_CUT_TYPE,VarDevice.LIBFPTR_CT_FUL) //VarDevice.LIBFPTR_PARAM_CUT_TYPE :=VarDevice.LIBFPTR_CT_FULL   //0- не отрезать (не контролировать); 1-полная отрезка; 2-неполная отрезка
      else VarDevice.SetParam(VarDevice.LIBFPTR_PARAM_CUT_TYPE,VarDevice.LIBFPTR_CT_PART);
      Cash_CheckError('cash_cut:1');
      
      VarDevice.cut; Cash_CheckError('cash_cut:2');
    finally
      if NeedConnect then Cash_disconnect;
    end;
end;

procedure Cash_OpenDrawer(NeedConnect :boolean = true);
begin
  if NeedConnect then Cash_Connect;
  try
    VarDevice.OpenDrawer; Cash_CheckError('cash_openDrawer');
  finally
    if NeedConnect then Cash_disconnect;
  end;
end;

procedure Cash_CheckShiftState(NeedConnect :boolean = true; ShowResult :boolean = false);
var IntVal :integer;
    ResultVal :string;
begin
  if NeedConnect then  Cash_Connect;
  try
    VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_SHIFT_STATE); Cash_CheckError('Cash_ShiftState.LIBFPTR_PARAM_DATA_TYPE'); 
    VarDevice.queryData; Cash_CheckError('Cash_ShiftState.QueryData');

    IntVal := VarDevice.GetParamInt(VarDevice.LIBFPTR_PARAM_SHIFT_STATE); Cash_CheckError('Cash_ShiftState.LIBFPTR_PARAM_SHIFT_STATE');

    if IntVal = VarDevice.LIBFPTR_SS_CLOSED then
    begin
       if ShowResult then CreateHint('Смена закрыта ('+inttostr(IntVal)+')','Проверка состояния смены');
       VarDevice.openShift; Cash_CheckError('Cash_ShiftState.OpenShift');
       if ShowResult then CreateHint('Открытие смены прошло успешно','Открытие смены');
    end      
    else if IntVal = VarDevice.LIBFPTR_SS_OPENED then 
    begin
      if ShowResult then CreateHint('Смена открыта ('+inttostr(IntVal)+')','Проверка состояния смены');
    end 
    else if IntVal = VarDevice.LIBFPTR_SS_EXPIRED then 
      raiseexception('Смена истекла (>24 часов) ('+inttostr(IntVal)+')')
    else raiseexception('Неизвестное значение при проверке состояния смены: '+inttostr(IntVal));
    
  finally
    if NeedConnect then Cash_disconnect;
  end;
end;

// вернуть единицу измерения для данного кода товара
function GetMeasurementValue(NN: string): Variant;
var 
  Ed: string;
begin
  Result := VarDevice.LIBFPTR_IU_PIECE; cash_checkerror('LIBFPTR_PARAM_MEASUREMENT_UNIT_VALUE');
  
  if NN = '' then Exit;

  Ed := '';
  with TTable.Create(nil) do
  try
    Databasename := 'dbkassa';
    TableName := 'tovar.db';
    Open;
    if FindKey([NN]) then
      Ed := trim(AnsiUpperCase(FieldByName('ed').AsString));
  finally
    Free
  end;

  if Ed = '' then Exit;
  while (Ed > '') and (Ed[Length(Ed)] = '.') do
    Ed := Copy(Ed,1,Length(Ed)-1);
  if Ed = '' then Exit;

  // допустимые значения искать здесь: https://integration.atol.ru/api/#proverka-km
  // все значения единиц измерения приведены предварительно к верхнему регистру, 
  // также удалены пробелы в начале и конце, также удалены точки в окончании
  if Ed in ['КГ'] then 
    Result := VarDevice.LIBFPTR_IU_KILOGRAM
  else if Ed in ['Г'] then 
    Result := VarDevice.LIBFPTR_IU_GRAM
  else if Ed in ['Т'] then 
    Result := VarDevice.LIBFPTR_IU_TON
  else if Ed in ['Л','ЛИТР'] then 
    Result := VarDevice.LIBFPTR_IU_LITER
  else if Ed in ['МЛ'] then 
    Result := VarDevice.LIBFPTR_IU_MILLILITER;
  
  cash_checkerror('LIBFPTR_PARAM_MEASUREMENT_UNIT_VALUE1');  
end;

procedure Cash_Execute(NeedConnect :boolean = true);
var i :integer;
    pSummaryCash,pSummaryDiscount :currency;
    pSummary,pSummaryOut :currency;
    pDiscount :currency;
    pPrice,pPriceOut :currency;
    pPriceOutDivNum :currency;
    pPriceDivNum :currency;
    pQuantity :Double;
    pQNTFrac :double;
    pQuantityDivNum :integer;
    pDivNum :integer;
    IsFloatBarcode :boolean;

    PNN :string;
    pName :string;
    pmarks_barcodes :string;
    DetailCash :integer;
    Index :integer;
    Summ2 :currency;
    StrValue,StrVAlue1,StrValue2 :string;
    EmailSeller :string;
    stringlength :integer;
    NDS :integer;
    thField :TField;
    IntValue :integer;
    INN :string;
    MARK_BC,MARK_NUM :string;
    MarkData :variant;
    ByteVal :byte;
    
    BATCH,EXPDATE :string;
    
    MDLP_STORAGE_ID :string;

    NEED_CHECK_KKM_COUNT: Integer; // количество марок, которые надо проверять в ККМ. Пока тут у нас все марки, которые не ЕГАИС
    MARKING_COUNT: Integer; // всего товаров с марками
    MDLP_COUNT :integer; // количество товаров с марками для МДЛП (лекарства)
    TOBACCO_COUNT :integer; // табак
    MILK_COUNT: Integer;  //молоко
    WATER_COUNT: Integer;  // вода
    ASEPT_COUNT: Integer; // антисептики
    MIZD_COUNT: Integer; // медизделия
    BAD_COUNT: Integer;  // бады
    VET_COUNT: Integer; // ветеринария
    PARFUM_COUNT: Integer; // парфюмерия, косметика, бытовая химия
    
    VarValue1084,VarIndustryInfo :variant;
    strQNT :string;
    BoolVal :boolean;
    //isMDLP :integer;
    Field :TField;
    
    //CDSMarksResults :TClientDataset;
    
    CDS :tclientdataset;
    
    WFCM :TMyWait;
    
    ik,ikc :integer;
    
    tc,tc1,tc2 :int64;
    IsFrac :boolean;
    ValidateResult :string;
    DoPrintReceipt :boolean;
    CurrValue: Currency;
begin
   Cash_SaveLog('cash_execute');
   DetailCash := Appinifile.readinteger('common','DetailCash',dbinifile.readinteger('common','DetailCash',0));  //это стандартная настройка на закладке "розница"

   CDS := TClientDataset.Create(SelfScript);
   
   dataset.FieldDefs.update;
   for i := 0 to dataset.fieldcount-1 do
     cds.fielddefs.add(dataset.fields[i].fieldname,
                       dataset.fields[i].DataType,
                       dataset.fields[i].Size,
                       false);

   if dataset.findfield(fmarks_barcodes)=nil then
     cds.fielddefs.add(fmarks_barcodes,ftstring,1000,false);

   cds.FieldDefs.Add('tmp_ismarking',ftsmallint,0,False); // все марки не ЕГАИС
   cds.fielddefs.add('tmp_need_check_kkm',ftsmallint,0,false); // все проверяемые в ККМ
   cds.fielddefs.add('tmp_ismdlp',ftsmallint,0,false); // медикаменты
   cds.fielddefs.add('tmp_istobacco',ftsmallint,0,false);
   cds.fielddefs.add('tmp_ismilk',ftsmallint,0,false);
   cds.fielddefs.add('tmp_iswater',ftsmallint,0,false);
   cds.fielddefs.add('tmp_ismizd',ftsmallint,0,false);
   cds.fielddefs.add('tmp_isasept',ftsmallint,0,false);
   cds.fielddefs.add('tmp_isbad',ftsmallint,0,false);
   cds.fielddefs.add('tmp_isvet',ftsmallint,0,false);
   cds.fielddefs.add('tmp_isparfum',ftsmallint,0,false);
   cds.fielddefs.add('tmp_quantity_divnum',ftinteger,0,false);    
   cds.fielddefs.add('tmp_check_result',ftstring,1000,false);
   cds.createdataset;
   cds.LogChanges := false; 


   MARKING_COUNT := 0;
   NEED_CHECK_KKM_Count := 0;
   MDLP_COUNT := 0;
   TOBACCO_COUNT := 0;
   MILK_Count := 0;
   WATER_COUNT := 0;
   MIZD_COUNT := 0;
   VET_COUNT := 0;
   PARFUM_COUNT := 0;
   ASEPT_COUNT := 0;
   BAD_COUNT := 0;
   dataset.disablecontrols;
   try
     dataset.first;
     while not dataset.eof do
     begin

       cds.append;
       for i := 0 to dataset.fieldcount-1 do
         cds.fields[i].asvariant := dataset.fields[i].asvariant;

       cds.fieldbyname(fdivnum).asinteger := coalesce_integer(cds.fieldbyname(FDivNum).asinteger,1);    
       cds.fieldbyname('tmp_quantity_divnum').asinteger := round(cds.fieldbyname(fquantity).asfloat * cds.fieldbyname(fdivnum).asinteger);

       if (dataset.findfield(fmarks_barcodes)=nil) 
          and (DataSetMarks<>nil) 
          and  datasetmarks.locate('idprimary',dataset.fieldbyname('idprimary').asstring,0) 
       then 
         cds.fieldbyname(fmarks_barcodes).asstring := datasetmarks.fieldbyname('barcode').asstring;

       if (CASH_SAVEMARKS<>0) then
       begin
         if not NNInFilterEGAIS(dataset.fieldbyname(FNN).asstring) // егаисовские товары нас не интересуют 
            and not NNInFilterEGAISBEER(dataset.fieldbyname(FNN).asstring)
            and (cds.fieldbyname(fmarks_barcodes).asstring>'') then 
         begin
           inc(MARKING_COUNT);
           cds.fieldByName('tmp_ismarking').asInteger := 1;

           inc(NEED_CHECK_KKM_COUNT);
           cds.fieldbyname('tmp_need_check_kkm').asInteger := 1;
           
           if NNInFilterTobacco(dataset.fieldbyname(fnn).asstring) then
           begin 
             inc(TOBACCO_COUNT);
             cds.fieldbyname('tmp_istobacco').asinteger := 1;
           end
           else if NNInFilterMilk(dataset.fieldbyname(fnn).asstring) then
           begin 
             inc(MILK_COUNT);
             cds.fieldbyname('tmp_ismilk').asinteger := 1;
           end
           else if NNInFilterWater(dataset.fieldbyname(fnn).asstring) then
           begin 
             inc(WATER_COUNT);
             cds.fieldbyname('tmp_iswater').asinteger := 1;
           end
           else if NNInFilterMIZD(dataset.fieldbyname(fnn).asstring) then
           begin 
             inc(MIZD_COUNT);
             cds.fieldbyname('tmp_ismizd').asinteger := 1;
           end
           else if NNInFilterVET(dataset.fieldbyname(fnn).asstring) then
           begin 
             inc(VET_COUNT);
             cds.fieldbyname('tmp_isvet').asinteger := 1;
           end
           else if NNInFilterPARFUM(dataset.fieldbyname(fnn).asstring) then
           begin 
             inc(PARFUM_COUNT);
             cds.fieldbyname('tmp_isparfum').asinteger := 1;
           end
           else if NNInFilterASEPT(dataset.fieldbyname(fnn).asstring) then
           begin 
             inc(ASEPT_COUNT);
             cds.fieldbyname('tmp_isasept').asinteger := 1;
           end
           else if NNInFilterBAD(dataset.fieldbyname(fnn).asstring) then 
           begin
             inc(BAD_COUNT);
             cds.fieldbyname('tmp_isbad').asinteger := 1;
           end
           else if NNIsNotOtherMarks(Dataset.FieldByName(fnn).asString) then
           begin
             inc(MDLP_COUNT);
             cds.fieldbyname('tmp_ismdlp').asinteger := 1;
           end;
           
           if cds.fieldbyname('tmp_quantity_divnum').asinteger>cds.fieldbyname(FDIVNUM).asinteger then 
           begin
             Cash_SaveLog('Отмена чека: имеются товары с марками с количеством >1',true);
             raiseexception('Имеются товары с марками с количеством >1');
           end;
         end;
       end;
         
       cds.post;
       dataset.next;
     end;
     dataset.first;
   finally
     dataset.enablecontrols;
   end;
   
   MDLP_STORAGE_ID := asstring(BDEQueryValue('select mdlp_storage_id from agents where id = :id',[STORAGE_ID]));
   // если mdlp_storage_id пуст, то проверим сразу наличие товаров с марками и остановим скрипт, если имеются таковые
   if (CASH_SAVEMARKS<>0)  
      and (MDLP_COUNT>0)
      and (mdlp_storage_id='') then 
   begin  
     Cash_SaveLog('Отмена чека: имеются товары для МДЛП, но у склада не указан его код в МДЛП',true);
     raiseexception('Имеются товары для МДЛП, но у склада не указан его код в МДЛП');
   end;
   
   if needconnect then 
     Cash_Connect;
   try                       
       if CASH_CHECKMARKS and (NEED_CHECK_KKM_COUNT>0) then
       begin
         CASH_savelog('CASH_CHECKMARK_ONLY_FN='+asstring(CASH_CHECKMARK_ONLY_FN));

         tc := gettickcount;
         WFCM := TMyWait.create('Идет проверка марок в ККМ',selfscript,nil,true,false {,wpCenter});
         try
           WFCM.SHOW(true); // активация окна, чтобы можно было нажать ESC
           WFCM.StopKey := 27;
           wfcm.AdvancedText := 'Для прерывания поиска нажмите ESC';
           WFCM.progressbarmax := NEED_CHECK_KKM_COUNT;
           Cash_SaveLog('Проверка марок');
           Cash_CheckShiftState(false,false);
           VarDevice.CancelMarkingCodeValidation(); cash_checkerror('CancelMarkingCodeValidation');
           cds.first;
           while not cds.eof do
           begin
             if cds.fieldbyname('tmp_NEED_CHECK_KKM').asinteger>0 then
             begin
               Cash_SaveLog('Марка МДЛП: '+stringreplace(cds.fieldbyname(fmarks_barcodes).asstring,#29,'{SG}',true,true));
               tc1 := gettickcount;
          
               VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE_TYPE, VarDevice.LIBFPTR_MCT12_AUTO); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_TYPE');
               VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE, cds.fieldbyname(fmarks_barcodes).asstring); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE');

               isFrac := 
                  (cds.fieldbyname(fdivnum).asinteger>1)
                  and (cds.fieldbyname('tmp_quantity_divnum').asinteger>0) 
                  and (cds.fieldbyname('tmp_quantity_divnum').asinteger<cds.fieldbyname(fdivnum).asinteger);
               
               if true {IsFrac} then
               begin // почему-то это не работает в проверке, хотя для целых позиций нужно указывать именно так. Хотя в регистрации работает
                 VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE_STATUS, VarDevice.LIBFPTR_MES_DRY_FOR_SALE); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_STATUS')
               end
               else begin   
                 VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE_STATUS, VarDevice.LIBFPTR_MES_PIECE_SOLD); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_STATUS');
               end;
               
               VarDevice.setParam(VarDevice.LIBFPTR_PARAM_QUANTITY, 1);cash_checkerror('LIBFPTR_PARAM_QUANTITY');
               
               
               MeasurementValue := GetMeasurementValue(CDS.Fieldbyname('NN').AsString);
               Cash_SaveLog('MeasurementValue = '+asstring(MeasurementValue));
               VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MEASUREMENT_UNIT, MeasurementValue); cash_checkerror('LIBFPTR_PARAM_MEASUREMENT_UNIT');
               VarDevice.setParam(2108, MeasurementValue); cash_checkerror('2108');

               Boolval := CASH_CHECKMARK_WAIT<>-1;
               Cash_SaveLog('LIBFPTR_PARAM_MARKING_WAIT_FOR_VALIDATION_RESULT = '+asstring(boolval));
               VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_WAIT_FOR_VALIDATION_RESULT, Boolval); cash_checkerror('LIBFPTR_PARAM_MARKING_WAIT_FOR_VALIDATION_RESULT');

               VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_PROCESSING_MODE, 0);  cash_checkerror('LIBFPTR_PARAM_MARKING_PROCESSING_MODE');

               if IsFrac then  
                 VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_FRACTIONAL_QUANTITY, cds.fieldbyname('tmp_quantity_divnum').asstring+'/'+cds.fieldbyname(fdivnum).asstring); cash_checkerror('LIBFPTR_PARAM_MARKING_FRACTIONAL_QUANTITY');
                                
               VarDevice.beginMarkingCodeValidation(); cash_checkerror('beginMarkingCodeValidation');
               
               ValidateResult := '0';
            
                // Дожидаемся окончания проверки и запоминаем результат
               while true do
               begin
                 sleep(CASH_CHECKMARK_SLEEPMS);
  
                 if wfcm.checkstop then 
                   case CASH_CHECKMARK_EXIT of 
                     0: raiseexception('Проверка марок остановлена пользователем');
                     1: if GetConfirm('Ошибка проверки марок.','','Продолжить','Остановить')=mrOk then 
                        begin
                          Cash_SaveLog('Оператор продолжил сохранение чека');
                          //VarDevice.CancelMarkingCodeValidation(); cash_checkerror('CancelMarkingCodeValidation');
                          break
                        end
                        else raiseexception(StrValue);
                     else begin
                       Cash_SaveLog('Продолжено сохранение чека');
                       //VarDevice.CancelMarkingCodeValidation(); cash_checkerror('CancelMarkingCodeValidation');
                       break;
                     end
                   end;
                    
                 VarDevice.getMarkingCodeValidationStatus(); 
                 if not cash_checkerror('getMarkingCodeValidationStatus',false) then
                     case CASH_CHECKMARK_EXIT of 
                       0: raiseexception('Ошибка проверки марки: '+inttostr(resultcode)+': '+resultdescription);
                       1: if GetConfirm('Ошибка проверки марки: '+inttostr(resultcode)+': '+resultdescription,'','Продолжить','Остановить')=mrOk then 
                          begin
                            Cash_SaveLog('Оператор продолжил сохранение чека');
                            //VarDevice.CancelMarkingCodeValidation(); cash_checkerror('CancelMarkingCodeValidation');
                            break
                          end
                          else raiseexception('Ошибка проверки марки: '+inttostr(resultcode)+': '+resultdescription);
                       else begin
                         Cash_SaveLog('Продолжено сохранение чека');
                         //VarDevice.CancelMarkingCodeValidation(); cash_checkerror('CancelMarkingCodeValidation');
                         break;
                       end
                     end;
                 
                 BoolVal := VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_MARKING_CODE_VALIDATION_READY);   cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_VALIDATION_READY');
                 if BoolVal then  
                 begin
                   StrValue :=  asstring(VarDevice.getParamSTring(VarDevice.LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_ERROR));  cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_ERROR');
                   if (StrValue<>'0') and (StrVAlue<>'') then 
                   begin
                     StrValue := 'Ошибка проверки марок: '+StrValue+': '+asstring(VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_ERROR_DESCRIPTION)); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_ERROR_DESCRIPTION');
                     incstrCR(StrvAlue,'Наименование: '+cds.fieldbyname(fname).asstring);
                     incstrCR(StrvAlue,'Марка МДЛП: '+stringreplace(cds.fieldbyname(fmarks_barcodes).asstring,#29,'{SG}',true,true));
                     cash_savelog(StrValue,true);
                     
                     case CASH_CHECKMARK_EXIT of 
                       0: raiseexception(StrValue);
                       1: if GetConfirm('Ошибка проверки марок.','','Продолжить','Остановить')=mrOk then 
                          begin
                            Cash_SaveLog('Оператор продолжил сохранение чека');
                            break
                          end
                          else raiseexception(StrValue);
                       else begin
                         Cash_SaveLog('Продолжено сохранение чека');
                         break;
                       end
                     end
                   end
                   else 
                     ValidateResult := asstring(VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_RESULT)); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_RESULT');

                   break;
                 end 
                 else if (CASH_CHECKMARK_WAIT>0) and (gettickcount-tc1>CASH_CHECKMARK_WAIT) then
                 begin
                   StrValue := 'Ошибка проверки марок: '+StrValue+': превышение программного таймаута';
                   incstrCR(StrvAlue,'Наименование: '+cds.fieldbyname(fname).asstring);
                   incstrCR(StrvAlue,'Марка МДЛП: '+stringreplace(cds.fieldbyname(fmarks_barcodes).asstring,#29,'{SG}',true,true));
                   cash_savelog(StrValue,true);

                   case CASH_CHECKMARK_EXIT of 
                     0: raiseexception(StrValue);
                     1: if GetConfirm('Превышен интервал ожидания запроса статуса марки.','','Продолжить','Остановить')=mrOk 
                        then begin
                          Cash_SaveLog('Оператор продолжил сохранение чека');
                          break
                        end
                        else raiseexception(StrValue);
                     else begin
                       Cash_SaveLog('Продолжено сохранение чека');
                       break;
                     end
                   end
                 end
               end;
               
               cds.edit;
               cds.fieldbyname('tmp_check_result').asstring := ValidateResult;
               cds.post;
               Cash_SaveLog('Результат: '+ValidateResult);
             
               VarDevice.acceptMarkingCode();  cash_checkerror('AcceptMarkingCode');
               wfcm.incprogress;
               if WFCM.CheckStop then
               begin
                 Cash_SaveLog('Оператор остановил проверку марок');
                 raiseexception('Оператор остановил проверку марок');
               end;               

               tc2 := gettickcount;        
               with TLogFile.create('cashcheckmarktimes.log',false,1000000) do 
               try
                 AddStr(inttostr(tc2-tc1));
               finally
                 free
               end;
               cash_savelog('Время проверки марки: '+inttostr(tc2-tc1)+' мс.');
               tc1 := tc2;
             end;
             
             cds.next;
           end;
         finally
           FreeAndNil(WFCM)
         end;
         tc2 := gettickcount;               
         cash_savelog('Время проверки всех марок: '+inttostr(tc2-tc)+' мс.');
       end;
       
       Cash_GetNumbers(false);

       if CASH_stringlength <0 then 
       begin
         VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_RECEIPT_LINE_LENGTH); Cash_CheckError('Cash_Execute:LineLength1');
         VarDevice.queryData; cash_checkerror('Cash_Execute:LineLength2');
         StringLength  := VarDevice.getParamInt(VarDevice.LIBFPTR_PARAM_RECEIPT_LINE_LENGTH);
         Cash_CheckError('Cash_Execute:LineLength3');
       end;

       if (CASH_SAVEMARKS<>0) and (MDLP_COUNT>0) then
       begin // важно сформировать до PARAM_RECEIPT_TYPE, а заполнение самого тэга - после! иначе ошибки.
         cash_savelog('Заполнение тэга 1084 для МДЛП');
         VarDevice.SetParam(1085,'mdlp');  Cash_CheckError('Cash_Execute:1085');
         VarDevice.SetParam(1086,'sid'+mdlp_storage_id+'&');    Cash_CheckError('Cash_Execute:1086');
         VarDevice.utilFormTlv;  Cash_CheckError('Cash_Execute:1084:utilFormTlv');
         VarValue1084 := VarDevice.getParamByteArray(VarDevice.LIBFPTR_PARAM_TAG_VALUE);  Cash_CheckError('Cash_Execute:1084:LIBFPTR_PARAM_TAG_VALUE');
       
         cash_savelog('Отраслевые реквизиты для МДЛП');
         VarDevice.setParam(1262, '020'); Cash_CheckError('Cash_Execute:1262');
         VarDevice.setParam(1263, bvformatdatetime('dd/mm/yyyy',date(),'','.')); Cash_CheckError('Cash_Execute:1263');
         VarDevice.setParam(1264, inttostr(ResultDocumentNumber)); Cash_CheckError('Cash_Execute:1264');
         
         StrValue2 := 'tm=mdlp';
         
         if VarReceptSeria>'' then
           StrValue2 := StrValue2 + '&ps='+StringReplace(VarReceptSeria,'&','&&',True,True);
         if VarReceptNumber>'' then
           StrValue2 := StrValue2 + '&dn='+StringReplace(VarReceptNumber,'&','&&',True,True); //&&781 ??
         if VarReceptDate<>0 then
           StrValue2 := StrValue2 + '&dd='+FormatDateTime('yymmdd',VarReceptDate);
         
  
         StrValue2 := StrValue2 + '&sid='+mdlp_storage_id+'&';
          
         VarDevice.setParam(1265, StrValue2); Cash_CheckError('Cash_Execute:1265');                                    
         VarDevice.utilFormTlv;  Cash_CheckError('Cash_Execute:IndustryMDLPInfo:utilFormTlv');
         VarIndustryInfo := VarDevice.getParamByteArray(VarDevice.LIBFPTR_PARAM_TAG_VALUE); Cash_CheckError('Cash_Execute:IndustryMDLPInfo:LIBFPTR_PARAM_TAG_VALUE');
       end;
       
       if (CASH_SAVEMARKS = 0) and (MDLP_COUNT=0) and ((VarReceptSeria>'') or (VarReceptNumber>'') or (VarReceptDate<>0)) then
       begin
         Cash_SaveLog('Ошибка: Указан рецепт, но нет ни одного маркированного товара, либо не указана опция сохранения марок. Сохранение чека невозможно.');
         raiseexception('Ошибка: Указан рецепт, но нет ни одного маркированного товара, либо не указана опция сохранения марок. Сохранение чека невозможно.');
       end;
       
       if IsReturn then VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL_Return) 
       else VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL);
       Cash_CheckError('Cash_Execute:SetReceiptType');
       

       if (CASH_SAVEMARKS<>0) and (MDLP_COUNT>0) then // это должно быть после задания receipt_type
       begin
         VarDevice.setNonPrintableParam(1084, VarValue1084);  Cash_CheckError('Cash_Execute:1084');
         VarDevice.setParam(1261, VarIndustryInfo); Cash_CheckError('Cash_Execute:1261');
         //VarDevice.writeSalesNotice(); Cash_CheckError('Cash_Execute:WriteSalesNotice'); ошибка: 12: Не поддерживается в данном режиме
       end; 



       DoPrintReceipt := CASH_PRINT_RECEIPT;
       
       if not DoPrintReceipt then
       begin  
          if coalesce_string(EMail,CASH_NOPRINT_EMAIL)='' then begin
            DoPrintReceipt := true;
            CreateHintW('Выставлена опция "не печатать чек", но она будет проигнорирована, так как не указаны ни телефон, ни адрес покупателя, ни адрес для отправки по-умолчанию','Внимание!',5)
          end
          else begin  
           case getconfirm('Печатать чек на бумаге?','СТОП','Печатать','Не печатать') of 
             mrOk: DoPrintReceipt := true; 
             mrIgnore : raiseException('Печать чека отменена пользователем');
             else {mrCancel};
           end;
         end;
       end;

       if (Email>'') or Not DoPrintReceipt and (CASH_NOPRINT_EMAIL>'') then 
       begin
         VarDevice.setParam(1008, coalesce_string(EMail,CASH_NOPRINT_EMAIL)); 
         Cash_CheckError('Cash_Execute:1008'); 
       end;

       EmailSeller := appIniFile.readstring('cash','CashOnlineEmailSeller',DBIniFile.readstring('cash','CashOnlineEmailSeller',''));
       if EmailSEller<>'' then // адрес электронной почты отправителя чека 
       begin
          //Отправка данных о продавце
         VarDevice.setParam(1117, EMailSeller); 
         Cash_CheckError('Cash_Execute:1117'); 
       end;
       
       if CASH_PRINTCLIENT and (Clientid<>0) then
       begin
         StrValue := asstring(BDEQueryValue('select name from agents where id = :id',[Clientid]));
         if strvalue>'' then
         begin 
           //Отправка имени покупателя
           VarDevice.setParam(1227, StrVAlue); 
           Cash_CheckError('Cash_Execute:1227'); 
         end; 
         StrValue := asstring(BDEQueryValue('select inn from agents where id = :id',[Clientid]));
         if strvalue>'' then
         begin 
           //Отправка инн покупателя
           VarDevice.setParam(1228, StrValue); 
           Cash_CheckError('Cash_Execute:1228'); 
         end; 
       end;

       case DOC_TYPE_CLOSE of
         1 : Index := CASH_TypeCloseBN;
         2 : Index := CASH_TypeCloseKredit;
         3 : Index := CASH_TypeCloseSert;
         else  Index := 0;
       end;

       VarDevice.setParam(VarDevice.LIBFPTR_PARAM_PAYMENT_TYPE, Index); cash_checkerror('Cash_Execute:CAsh_typeClose');
       
       //fptr.setParam(fptr.LIBFPTR_PARAM_RECEIPT_ELECTRONICALLY, True);


       if TaxType>0 then 
       begin 
	     Cash_SaveLog('Cash_Execute:1055:TaxType='+inttostr(TaxType));
         //Cash_CheckError('Cash_Execute:1055:TaxType='+inttostr(TaxType));
         VarDevice.SetParam(1055,TaxType); //Применяемая система налогообложения (СНО)
         Cash_CheckError('Cash_Execute:1055');
       end;
   

       if not DoPrintReceipt then 
       begin
         VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_ELECTRONICALLY, True); Cash_CheckError('Cash_Execute:NOPRINT');
         //VarDevice.CheckMode := 0; Cash_CheckError('Cash_Execute:CheckMode');
       end;

       cash_savelog('OpenReceipt');
       VarDevice.openReceipt; Cash_CheckError('Cash_Execute:OpenReceipt');

       // печать чека
       //cds.savetofile('c:\temp\3.cds');

       cash_savelog('Товары');
       pSummaryCash := 0;
       pSummaryDiscount := 0;      // для варианта без детализации

       cds.First;
       while not cds.eof do
       begin

         if cds.fieldbyName('tmp_ismdlp').asInteger <> 0 then // какая-то из этих команд убивает все другие заполненные тэги, поэтому надо выполнять раньше их всех 
         begin
           cash_savelog('Формирование реквизита 1260 для МДЛП');
           VarDevice.setParam(1262, '020'); Cash_CheckError('Cash_Execute:1262');
           VarDevice.setParam(1263, bvformatdatetime('dd/mm/yyyy',date(),'','.')); Cash_CheckError('Cash_Execute:1263');
           VarDevice.setParam(1264, inttostr(ResultDocumentNumber)); Cash_CheckError('Cash_Execute:1264');
           
           StrValue2 := 'tm=mdlp';
           if VarReceptSeria>'' then
             StrValue2 := StrValue2 + '&ps='+StringReplace(VarReceptSeria,'&','&&',True,True);
           if VarReceptNumber>'' then
             StrValue2 := StrValue2 + '&dn='+StringReplace(VarReceptNumber,'&','&&',True,True); //&&781 ??
           if VarReceptDate<>0 then
             StrValue2 := StrValue2 + '&dd='+FormatDateTime('yymmdd',VarReceptDate);
           StrValue2 := StrValue2 + '&sid='+mdlp_storage_id+'&';
            
           VarDevice.setParam(1265, StrValue2); Cash_CheckError('Cash_Execute:1265');                                    
           VarDevice.utilFormTlv;  Cash_CheckError('Cash_Execute:IndustryMDLPInfo:utilFormTlv');
           VarIndustryInfo := VarDevice.getParamByteArray(VarDevice.LIBFPTR_PARAM_TAG_VALUE); Cash_CheckError('Cash_Execute:IndustryMDLPInfo:LIBFPTR_PARAM_TAG_VALUE');
           VarDevice.setParam(1260, VarIndustryInfo); Cash_CheckError('Cash_Execute:1260') 
         end
         else if {(GISMT_REQID>'') and (GISMT_REQTIMESTAMP>'')} (CDS.FindField('GISMT_CHECKED')<>nil) and (CDS.FieldByName('GISMT_CHECKED').asINteger<>0) then
         begin                                                         
           cash_savelog('Формирование реквизита 1260 для ГИС МТ');
           VarDevice.setParam(1262, '030'); Cash_CheckError('Cash_Execute:1262');
           VarDevice.setParam(1263, bvformatdatetime('dd/mm/yyyy',date(),'','.')); Cash_CheckError('Cash_Execute:1263');
           VarDevice.setParam(1264, inttostr(ResultDocumentNumber)); Cash_CheckError('Cash_Execute:1264');

           StrValue2 := 'UUID='+CDS.FieldByName('GISMT_REQID').asString+'&Time='+CDS.FieldByName('GISMT_REQTIMESTAMP').asString; //+'&';
           if CDS.FieldByName('GISMT_INST').asString>'' then
             StrValue2 := StrValue2 + '&Inst='+CDS.FieldByName('GISMT_INST').asString;
           if CDS.FieldByName('GISMT_VERSION').asString>'' then
             StrValue2 := StrValue2 + '&Ver='+CDS.FieldByName('GISMT_VERSION').asString;

           VarDevice.setParam(1265, StrValue2); Cash_CheckError('Cash_Execute:1265');                                    

           VarDevice.utilFormTlv;  Cash_CheckError('Cash_Execute:IndustryGISMTInfo:utilFormTlv');
           VarIndustryInfo := VarDevice.getParamByteArray(VarDevice.LIBFPTR_PARAM_TAG_VALUE); Cash_CheckError('Cash_Execute:IndustryGISMTInfo:LIBFPTR_PARAM_TAG_VALUE');
           VarDevice.setParam(1260, VarIndustryInfo); Cash_CheckError('Cash_Execute:1260')
         end;


         isFrac := 
            (cds.fieldbyname(fdivnum).asinteger>1)
            and (cds.fieldbyname('tmp_quantity_divnum').asinteger>0) 
            and (cds.fieldbyname('tmp_quantity_divnum').asinteger<cds.fieldbyname(fdivnum).asinteger);

         if isfrac and (cds.fieldbyname('tmp_ismarking').asinteger>0)  then 
         begin          
           ikc := cds.fieldbyname('tmp_quantity_divnum').asinteger;
           if ikc<1 then ikc := 1;
         end
         else ikc := 1;

         for ik := 1 to ikc do
         begin
           pQuantityDivNum := cds.fieldbyname('tmp_quantity_divnum').asinteger;
         
           pPrice := cds.fieldbyname(FPrice).asCurrency;
           cash_savelog('Цена:'+floattostr(pprice));
           thField := cds.findfield(fPriceOut);
           if thField=nil then thField := cds.findfield(fpriceout1);
           if thfield=nil then pPriceOut := 0 else  pPriceOut := thField.ascurrency;
  
           if pPriceOut < pPrice then  pPriceOut := pPrice;
           cash_savelog('Цена прод:'+floattostr(ppriceout));
  
           pQuantity := cds.fieldbyname(FQuantity).AsFloat;
           pQntFrac := bvroundto(frac(pQuantity),-6);
           pDivNum := coalesce_integer(cds.fieldbyname(FDivNum).asinteger,1);
           pPriceOutDivNum := bvroundto( pPriceOut / pDivNum,-4);
           pPriceDivNum := bvroundto( pPrice / pDivNum,-4);
           cash_savelog('Количество: '+floattostr(pQuantity)+' : '+floattostr(ppricedivnum));
           
  
           IsFloatBarcode := cds.fieldbyname(FFloatBarcode).asinteger<>0; 
  
           //cash_savelog('Параметры: '+asstring(DetailCash)+' : '+asstring(IsFloatBarcode)+' : '+asstring(pQNTFrac)+' : '+asstring(CASH_CANDIVIDEDIVNUM)+' : '+asstring(pdivnum)+' : '+asstring(pQuantityDivNUm)+' : '+asstring(pPriceOutDivNUm));
  
  
           if cds.fieldbyname('tmp_ismarking').asinteger>0 then
           begin
             if isFrac then 
             begin
               pPriceOut := pPriceOutDivNum;
               pPrice := pPriceDivNum;
               pQuantity := 1;
               pQuantityDivNum := 1;
               cash_savelog('МДЛП деленый товар: '+floattostr(pQuantity)+' : '+floattostr(pprice)+' : '+floattostr(ppriceout)); 
             end;
           end
           else if pQntFrac<>0 then // есть дробное количество
           begin
             if (DetailCash=0) // построчная детализация
                and CASH_CANDIVIDEDIVNUM // можно делить при печати фасованные товары 
                and not IsFloatBarcode // товар не является весовым 
                and (pDivNum<>1) // товар делится
             then begin // надо вывести целое количество фасованных единиц по цене фасованной единицы
               pPriceOut := pPriceOutDivNum;
               pPrice := pPriceDivNUm;
               pQuantity := pQuantityDivNum;
               cash_savelog('Фас.кол-во x цена за фасов.ед.: '+floattostr(pQuantity)+' : '+floattostr(pprice)+' : '+floattostr(ppriceout)); 
             end
             else if 
               (DetailCash<>0) // печать без детализации 
               or not CASH_CANFLOATQUANTITY // или нельзя дробные количества
               or IsFloatBarcode and (pQntFrac<>bvroundto(pQntFrac,-3)) // Для весовых - предохранимся от количеств, которые не понимает касса, оставляем 1xСумма
               //or (pQuantityDivNum<>bvroundto(pQuantityDivNum)) // число 2.999997 в фасовке еще допускается, но 2.999 - уже странно
               //or (pPriceOutDivNum <> bvRoundTo(pPriceOutDivNum,-2))
             then begin // необходимо распечатать 1 штуку по цене, равной полной сумме
               pPriceOut := pQuantity * pPriceOut;
               pPrice := pQuantity * pPrice;
               pQuantity := 1;
               cash_savelog('1 x Сумма: '+floattostr(pQuantity)+' : '+floattostr(pprice)+' : '+floattostr(ppriceout));
             end;
           end;
           
           pPrice := bvroundto(pPrice, -2,DefRoundParam);
           if pprice<>0 then  pPriceOut := bvroundto(pPriceOut, -2,DefRoundParam) else ppriceout := 0; // нулевая цена, значит и скидку нам не надо отображать
           
  
           pSummary := pQuantity * pPrice;
           pSummaryOut := pQuantity * pPriceOut;
  
           pSummaryCash := pSummaryCash + pSummary;
           pSummaryDiscount := pSummaryDiscount + (pSummaryOut - pSummary);
           pDiscount := bvRoundTo(pSummaryOut-pSummary,-2);
          
           cash_savelog('Суммы: '+floattostr(pSummary)+' : '+floattostr(pSummaryOut)+' : '+floattostr(pDiscount));
  
           if pquantity>0 //  (bvroundto(pSummary, -2) > 0) // возможна печать нулевых цен, поэтому проверку делаем только по количеству
           then begin
  
             pname := cds.fieldbyname(FName).asstring;
             if (stringlength>0) and cash_trimnamegoods then pname := copy(pname,1,stringlength);
             
             PNN := cds.fieldbyname(FNN).asstring;
  
             pMarks_barcodes := cds.fieldbyname(fmarks_barcodes).asstring;
             
             for i := 1 to min(length(CASH_NameBadCharList), length(CASH_NameReplaceCharList)) do 
               if pos(CASH_NameBadCharList[i], pname) > 0
                 then pname := stringreplace(pname, CASH_NameBadCharList[i], CASH_NameReplaceCharList[i],true,true);
  
             cash_savelog('Наименование1: '+pname);
  
             if detailcash <> 2
             then begin                 // детализация чека
               
               //cash_savelog(asstring(VarDevice.GetParamStr(1162))); cash_checkerror('Cash_Execute:1162-get');
               
               cash_savelog('параметры товара:');
  
               VarDevice.setParam(VarDevice.LIBFPTR_PARAM_COMMODITY_NAME, pName); Cash_CheckError('Cash_Execute:NAME');  

               //VarDevice.setParam(VarDevice.LIBFPTR_PARAM_QUANTITY, pQuantity); Cash_CheckError('Cash_Execute:Quantity');
               if 
                  (CASH_SAVEMARKS<>0) and (pmarks_barcodes>'') 
                  and (pQuantity<1) and (pdivnum>1) then 
               begin
                 strqnt := inttostr(round(pquantitydivnum))+'/'+inttostr(pdivnum);
                 cash_savelog('Количество FRAC: '+strQNT);
                 VarDevice.setParam(VarDevice.LIBFPTR_PARAM_QUANTITY, 1.000); Cash_CheckError('Cash_Execute:Quantity:1');
                 VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_FRACTIONAL_QUANTITY, strQNT); Cash_CheckError('Cash_Execute:FRAC_QUANTITY');
               end               
               else begin 
                 cash_savelog('Количество: '+floattostr(pQuantity));
                 VarDevice.setParam(VarDevice.LIBFPTR_PARAM_QUANTITY, pQuantity); Cash_CheckError('Cash_Execute:Quantity');
               end;
               
               
               //if CASH_SAVEUNITS then
               begin
                 //intvalue := VarDevice.LIBFPTR_IU_PIECE; cash_checkerror('LIBFPTR_IU_PIECE');
                 //cash_savelog('единицы измерения: '+inttostr(intvalue));
                 MeasurementValue := GetMeasurementValue(CDS.Fieldbyname('NN').AsString);
                 Cash_SaveLog('MeasurementValue1 = '+asstring(MeasurementValue));
                 
                 VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MEASUREMENT_UNIT, MeasurementValue); cash_checkerror('LIBFPTR_PARAM_MEASUREMENT_UNIT');
                   
                 if CASH_SAVE2108 then 
                 begin                
                   VarDevice.setParam(2108, MeasurementValue); cash_checkerror('2108');
                 end;
               end;
               
               VarDevice.setParam(VarDevice.LIBFPTR_PARAM_PRICE, ifthen_currency(CASH_DiscountType<>0,pPriceOut,pPrice)); Cash_CheckError('Cash_Execute:Price');
  
               thField := cds.findfield(fsection);
               if thfield<>nil then 
                 IntValue :=  coalesce_integer(thField.asinteger,CASH_CURRENT_SECTION,1) 
               else 
                 IntValue := CASH_CURRENT_SECTION;
               VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DEPARTMENT, IntValue); Cash_CheckError('Cash_Execute:Department');
  
               
               if Cash_ShowNDS then 
               begin
                 NDS := cds.fieldbyname(fnds).asinteger;
                 case NDS of 
                   20: IntValue := CASH_NDS20TYPE;
                   18: IntValue := CASH_NDS18TYPE;
                   10: IntVAlue := CASH_NDS10TYPE;
                   5:  IntValue := CASH_NDS5TYPE;
                   7:  IntValue := CASH_NDS7TYPE
                  else IntValue := CASH_NDS0TYPE; 
                 end;
                 cash_savelog('НДС: '+IntToStr(NDS)+', taxtype: '+ IntToStr(IntValue));

                 VarDevice.setParam(VarDevice.LIBFPTR_PARAM_TAX_TYPE, IntVAlue);
                 Cash_CheckError('Cash_Execute:NDS');
                 if cash_showNDSSUMMARY then 
                 begin
                   CurrValue := bvroundto(cds.fieldbyname(FSummary).asfloat *NDS/(100+NDS),-2);
                   cash_savelog('NDSSummary: '+FormatFloat(',0.00##',CurrValue));
                   VarDevice.SetParam(VArDevice.LIBFPTR_PARAM_TAX_SUM,CurrValue);                        
                   Cash_CheckError('Cash_Execute:NDSSummary');
                 end;
               end;
               
               cash_savelog('cash_discounttype:'+inttostr(cash_discounttype)+', '+floattostr(pdiscount));
               VarDevice.SetParam(VarDevice.LIBFPTR_PARAM_INFO_DISCOUNT_SUM,ifthen_currency(cash_DiscountType<>0,pDiscount,0));  Cash_CheckError('Cash_Execute:Discount');
  
               VarDevice.setParam(1212, 1); Cash_CheckError('Cash_Execute:1212'); //commodity - товар
               VarDevice.setParam(1214, 4); Cash_CheckError('Cash_Execute:1214'); //fullPayment - полный расчет
                                                 
  
               cash_savelog('cash_savemarks='+inttostr(cash_savemarks));
               
               if (CASH_SAVEMARKS<>0) and (pmarks_barcodes>'')
                  and not NNInFilterEGAIS(pNN) and not NNInFilterEGAISBEER(pNN) 
               then begin
                 //cash_savelog('mark='+pmarks_barcodes);
                 (*
                 if false {NNInFilterTOBACCO(pNN)} then
                 begin
                 
                    cash_savelog('mark_tobacco='+pmarks_barcodes);
                    Mark_BC := copy(pmarks_barcodes,1,14);
                    if (length(MARK_BC)<>14) or (StrToInt64Protected(MARK_BC)=0) then raiseexception('Неверный код марки для табачной продукции (штрихкод)');
                    cash_savelog('mark_bc_tobacco='+mark_bc);
                    
                    MARK_NUM := copy(pmarks_barcodes,15,7);
                    if length(mark_num)<>7 then raiseexception('Неверный код марки для табачной продукции (серия)');
                    cash_savelog('mark_num_tobacco='+mark_num);
  
                    if CASH_PRINTM then pName := '[M] '+pName; 
  
                    cash_savelog('mark_bc1='+mark_bc);
                    if cash_savemarks=1 then 
                    begin
                      
                      MarkData := VarArrayCreate([0,length(pmarks_barcodes)-1],VarByte);
                      for i := 1 to length(pmarks_barcodes) do VarArrayPut(MarkData, ord(pmarks_barcodes[i]), [i-1]); 
                      {begin
                        //ByteVal := ord(pmarks_barcodes[i]);  // HexToByte(strvalue); 
                        VarArrayPut(MarkData, ord(pmarks_barcodes[i]), [i-1]);
                      end;}
                      VarDevice.SetParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE,MarkData); cash_checkerror('Cash_Execute:LIBFPTR_PARAM_MARKING_CODE');
                      //VarDevice.SetParam(1162,MarkData); cash_checkerror('Cash_Execute:1162-3');
                      MarkData := unassigned;
                    end
                    else if CASH_SAVEMARKS=2 then // набираем сами, как в драйвере 8 (через строку), передаем как строку 
                    begin
                      Mark_BC := IntToHex(STrToInt64Protected(Mark_BC),6);
                      Mark_BC := StrPadLeft(Mark_BC,12,'0');
                      cash_savelog('mark_bc1='+mark_bc);
  
                      Mark_num:= stringtohex(Mark_NUM);
                      cash_savelog('mark_num1='+mark_num);
                    
                      StrVAlue := '0005'+Mark_BC+Mark_NUM;
                      cash_savelog('mark_hex1='+strvalue);
                      
                      for i := 1 to length(StrVAlue) div 2-1 do strvalue := copy(strvalue,1,i*2+i-1) + ' '+ copy(strvalue,i*2+i,length(strvalue)); // пробелы между знаками поставим
                      
                      VarDevice.SetParamStrHex(1162,StrValue); cash_checkerror('Cash_Execute:1162-2'); // или setNonPrintableParamStrHex()
                    end
                    else if CASH_SAVEMARKS=3 then // набираем сами, как в драйвере 8, передаем через массив, как в драйвере 10 
                    begin
                    
                      Mark_BC := IntToHex(STrToInt64Protected(Mark_BC),6);
                      Mark_BC := StrPadLeft(Mark_BC,12,'0');
                      cash_savelog('mark_bc2='+mark_bc);
  
                      Mark_num:= stringtohex(Mark_NUM);
                      cash_savelog('mark_num2='+mark_num);
                    
                      StrVAlue := '0005'+Mark_BC+Mark_NUM;
                      cash_savelog('mark_hex2='+strvalue);
                      
                      //for i := 1 to length(StrVAlue)-1 do strvalue := copy(strvalue,1,i*2+i-1) + ' '+ copy(strvalue,i*2+i,length(strvalue)); // пробелы между знаками поставим
  
                      MarkData := VarArrayCreate([0,14],VarByte); //2+6(бинар.формат штрихкода)+7 = 15 
                      for i := 0 to 14 do 
                      begin
                        ByteVal := HexToByte(strvalue); 
                        delete(StrVAlue,1,2);
                        VarArrayPut(MarkData, ByteVal, [i]);
                      end;
                      VarDevice.SetParam(1162,MarkData); cash_checkerror('Cash_Execute:1162-3');
                      MarkData := unassigned;
                    end
                    else  
                    begin // 4 
                      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_NOMENCLATURE_TYPE, VarDevice.LIBFPTR_NT_TOBACCO);
                      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_GTIN, MARK_BC);
                      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_SERIAL_NUMBER, MARK_NUM);
                      VarDevice.utilFormNomenclature;
                      MarkData := VarDevice.getParamByteArray(VarDevice.LIBFPTR_PARAM_TAG_VALUE);
                      //showmessage(asstring(vartype(MarkData))+':'+varTypeAsText(VarType(MarkData))+':'+asstring(VarArrayHighBound(MarkData,1)));
                      VarDevice.SetParam(1162,MarkData); cash_checkerror('Cash_Execute:1162-4');
                      MarkData := unassigned;
                    end;
                    //VarDevice.SetParam(1162,strValue); cash_checkerror; // должен быть массив байтов, а не строка. как передать массив? та же проблема в 8 версии
                 end
                 else 
                 *)
                 begin
                   cash_savelog('Ввод марки'); 
                   cash_savelog('Марка: '+stringreplace(pmarks_barcodes,#29,'{SG}',true,true)); 
                   VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE_TYPE, VarDevice.LIBFPTR_MCT12_AUTO); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_TYPE');
                   VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE, pmarks_barcodes); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE');
                   
                   if IsFrac then 
                   begin
                     cash_savelog('IsFrac = True');
                     VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE_STATUS, VarDevice.LIBFPTR_MES_DRY_FOR_SALE); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_STATUS');
                   end
                   else begin 
                     cash_savelog('IsFrac = False');
                     VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE_STATUS, VarDevice.LIBFPTR_MES_PIECE_SOLD); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_STATUS');
                   end;

                   
                   if cds.FieldByName('TMP_NEED_CHECK_KKM').asInteger<>0 then
                   begin
                       
                       if CASH_CHECKMARKS then 
                         IntValue := strtointprotected(cds.fieldbyname('tmp_check_result').asstring)
                       else  
                         IntValue := 0; //VarDevice.getParamInt(VarDevice.LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_RESULT); cash_checkerror('GET LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_RESULT');
                       
                       VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_RESULT, IntValue); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_RESULT');
                       VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_PROCESSING_MODE, 0);  cash_checkerror('LIBFPTR_PARAM_MARKING_PROCESSING_MODE');
                   end;

                   if  IsFrac then
                   begin 
                     //VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_FRACTIONAL_QUANTITY,  cds.fieldbyname('quantity_divnum').asstring + '/'+cds.fieldbyname(fdivnum).asstring); cash_checkerror('LIBFPTR_PARAM_MARKING_FRACTIONAL_QUANTITY');
                     VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_FRACTIONAL_QUANTITY,  IntToStr(pQuantityDivNum) + '/'+IntToStr(pDivNum)); cash_checkerror('LIBFPTR_PARAM_MARKING_FRACTIONAL_QUANTITY');
                   end;

                   (*  уже заполнены и введены раньше всех
                   if cds.fieldbyName('tmp_ismdlp').asInteger <> 0 then // если формировать прямо здесь, то поубиваем другие заполненные ранее тэги, поэтому делаем формирование раньше всех
                   begin
                     cash_savelog('Ввод реквизита 1260 для МДЛП');
                     VarDevice.setParam(1260, VarIndustryInfo); Cash_CheckError('Cash_Execute:1260')
                   end
                   else if (GISMT_REQID>'') and (GISMT_REQTIMESTAMP>'') and (CDS.FieldByName('GISMT_CHECKED').asINteger<>0) then
                   begin  
                     cash_savelog('Ввод реквизита 1260 для ГИС МТ');
                     VarDevice.setParam(1260, VarIndustryInfo); Cash_CheckError('Cash_Execute:1260')
                   end;

                   //VarDevice.writeSalesNotice(); Cash_CheckError('Cash_Execute:WriteSalesNotice'); //416: Нет маркированных позиций в чеке
                   *)
                 end; 
               end
               else begin
                 cash_savelog('tag1162?');
  
                 // проверим на tag1162 в справочнике товаров (Поле для заполнения тэга 1162 для медизделий (или других?) Постановление Правительства РФ от 16.04.2020 N 521 "О внесении изменений в постановление Правительства Российской Федерации от 21 февраля 2019 г. N 174")
                 strvalue := asstring(BDEQueryValue('select tag1162 from tovar where nn = :nn',[pNN]));
                 if strvalue>'' then 
                 begin
                   cash_savelog('nntag1162='+strvalue);
                   strvalue := IntToHex(STrToInt64Protected(strvalue),6);
                   strvalue := StrPadLeft(strvalue,12,'0');
                   StrVAlue := '450D'+StrValue;
                   cash_savelog('nntag1162_hex2='+strvalue);
  
                   if CASH_SAVEMARKS = 2 then
                   begin
                     for i := 1 to length(StrVAlue) div 2-1 do strvalue := copy(strvalue,1,i*2+i-1) + ' '+ copy(strvalue,i*2+i,length(strvalue)); // пробелы между знаками поставим
                     VarDevice.SetParamStrHex(1162,StrValue); cash_checkerror('Cash_Execute:nntag1162-2'); // или setNonPrintableParamStrHex()
                   end
                   else begin
                     MarkData := VarArrayCreate([0,7],VarByte); //2+6(бинар.формат штрихкода)
                     for i := 0 to 7 do 
                     begin
                       ByteVal := HexToByte(strvalue); 
                       delete(StrVAlue,1,2);
                       VarArrayPut(MarkData, ByteVal, [i]);
                     end;
                     VarDevice.SetParam(1162,MarkData); cash_checkerror('Cash_Execute:nntag1162-3');
                     MarkData := unassigned;
                   end;
                 end;
               end;
               
  
               cash_savelog('registration');
               VarDevice.Registration; Cash_CheckError('Cash_Execute:Registration');
               //raiseexception('test');
  
               if (pDiscount <> 0) and CASH_PrintStringDiscountSummary        
               then begin     
                 cash_savelog('pdiscount='+floattostr(pdiscount)); 
                 //VarDevice.Caption := 'В том числе скидка: '+bvCurrtostrF(pDiscount)+#13+'Цена без скидки: '+bvCurrToStrF(pPriceOut);
                 StrValue := 'Скидка: ';
                 strvalue1 := bvcurrtostrf(pdiscount);
                 if stringlength>0 then StrValue1 := StrPad(strvalue1,stringlength-length(strvalue),' ',true);
                 VarDevice.setParam(VarDevice.LIBFPTR_PARAM_TEXT, StrValue+StrValue1); cash_checkerror('Cash_Execute:TEXT');
                 VarDevice.printText; cash_checkerror('Cash_Execute:PrintText');
               end;
  
               if (pDiscount <> 0) and CASH_PrintStringPriceOut        
               then begin     
                 //VarDevice.Caption := 'В том числе скидка: '+bvCurrtostrF(pDiscount)+#13+'Цена без скидки: '+bvCurrToStrF(pPriceOut);
                 StrValue := 'Цена без скидки: ';
                 strvalue1 := bvcurrtostrf(pPriceOut);
                 cash_savelog('Цена без скидки: '+strvalue1);
                 if stringlength>0 then StrValue1 := StrPad(strvalue1,stringlength-length(strvalue),' ',true);
                 VarDevice.setParam(VarDevice.LIBFPTR_PARAM_TEXT, StrValue+StrValue1); cash_checkerror('Cash_Execute:TEXT1-1');
                 VarDevice.printText; cash_checkerror('Cash_Execute:PrintText1-1');
                 cash_savelog('-напечатано');
               end;
  
               {
               if Cash_ShowNDS
               then begin
                 VarDevice.Destination := 1; Cash_CheckError;
                 VarDevice.TaxTypeNumber := ifthen_integer(dataset.fieldbyname('nds').asinteger=18,CASH_NDS18TYPE,
                                          ifthen_integer(dataset.fieldbyname('nds').asinteger=10,CASH_NDS10TYPE,CASH_NDS0TYPE)); 
                 Cash_CheckError;
                 
               end;
               }
             end;
             Cash_CheckError('Cash_Execute:next');
           end;
         end;

         cash_savelog('Строка завершена');
         cds.next;
       end;
                                           
       if (DetailCash = 2) // Без детализации
       then begin
         cash_savelog('DetailCash = 2');
         if (pSummaryCash > 0) then
         begin
           VarDevice.setParam(VarDevice.LIBFPTR_PARAM_QUANTITY, 1); Cash_CheckError('Cash_Execute:QUANTITY2');
           
           thField := cds.findfield(fsection);
           if thfield<>nil then 
             IntValue :=  coalesce_integer(thField.asinteger,CASH_CURRENT_SECTION,1) 
           else 
             IntValue := CASH_CURRENT_SECTION;
           VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DEPARTMENT, IntValue); 
           Cash_CheckError('Cash_Execute:SECTION2');

           VarDevice.setParam(VarDevice.LIBFPTR_PARAM_PRICE, ifthen_currency(CASH_DiscountType<>0, bvroundto(pSummaryCash + pSummaryDiscount, -2,DefRoundParam), bvroundto(pSummaryCash, -2,defRoundParam))); 
           Cash_CheckError('Cash_Execute:Discount2');

           //VarDevice.SetParam(VarDevice.LIBFPTR_PARAM_INFO_DISCOUNT_SUM,ifthen_currency(cash_DiscountType<>0, bvRoundto(pSummaryDiscount,-2),0));  Cash_CheckError;
           //VarDevice.DiscountType := 0; Cash_CheckError;
           //VarDevice.DiscountValue := ifthen_currency(cash_DiscountType<>0, bvRoundto(pSummaryDiscount,-2),0);  Cash_CheckError;

           VarDevice.Registration; Cash_CheckError('Cash_Execute:Registration2'); 

           if (CASH_DiscountType=1)and ( bvroundto(pSummaryDiscount, -2) <> 0) then
           begin
             VarDevice.SetParam(VarDevice.LIBFPTR_PARAM_INFO_DISCOUNT_SUM,bvroundto(pSummaryDiscount, -2));  Cash_CheckError('Cash_Execute:DiscountSum2');
             //VArDevice.Summ :=  bvroundto(pSummaryDiscount, -2); Cash_CheckError;
             //VarDevice.Destination := 1; Cash_CheckError; // 0 - для всего чека, 1 - для последней операции
             //VarDevice.SummDiscount; Cash_CheckError;
           end;
           
           
           if (pSummaryDiscount <> 0) and CASH_PrintStringDiscountSummary then 
           begin     
             StrValue := 'Скидка: ';
             strvalue1 := bvcurrtostrf(pSummaryDiscount);
             if stringlength>0 then StrValue1 := StrPad(strvalue1,stringlength-length(strvalue),' ',true);
             VarDevice.setParam(VarDevice.LIBFPTR_PARAM_TEXT, StrValue+StrValue1); cash_checkerror('Cash_Execute:Text2');
             VarDevice.printText; cash_checkerror('Cash_Execute:PrintText2');
           end;

           if (pDiscount <> 0) and CASH_PrintStringPriceOut        
           then begin     
             //VarDevice.Caption := 'В том числе скидка: '+bvCurrtostrF(pDiscount)+#13+'Цена без скидки: '+bvCurrToStrF(pPriceOut);
             StrValue := 'Итого без скидки: ';
             strvalue1 := bvcurrtostrf(pSummaryCash);
             if stringlength>0 then StrValue1 := StrPad(strvalue1,stringlength-length(strvalue),' ',true);
             VarDevice.setParam(VarDevice.LIBFPTR_PARAM_TEXT, StrValue+StrValue1); cash_checkerror('Cash_Execute:Text2-2');
             VarDevice.printText; cash_checkerror('Cash_Execute:PrintText2-2');
           end;
           
         end;
       end;

       if (CASH_SAVEMARKS<>0) and (MARKING_COUNT>0) then // или только MDLP_COUNT?
       begin
         VarDevice.writeSalesNotice(); Cash_CheckError('Cash_Execute:WriteSalesNotice'); 
       end;

       if (CASH_DiscountType=2) and (bvroundto(pSummaryDiscount, -2) <> 0) then 
       begin
         cash_savelog('Cash_DiscountType=2, psummaryDiscount='+floattostr(pSummaryDiscount));
         VarDevice.SetParam(VarDevice.LIBFPTR_PARAM_INFO_DISCOUNT_SUM,bvroundto(pSummaryDiscount, -2));  Cash_CheckError('Cash_Execute:DiscountSum3');
         //VarDevice.Summ := bvroundto(pSummaryDiscount, -2); Cash_CheckError;
         //VarDevice.Destination := 0;
         //VarDevice.SummDiscount; Cash_CheckError;
       end;
       
       if (pSummaryDiscount <> 0) and CASH_PrintStringDiscountOnCheck then 
       begin     
         StrValue := 'Итого скидка по чеку: ';
         strvalue1 := bvcurrtostrf(pSummaryDiscount);
         cash_savelog(StrVAlue+strvalue1);
         
         if stringlength>0 then StrValue1 := StrPad(strvalue1,stringlength-length(strvalue),' ',true);
         VarDevice.setParam(VarDevice.LIBFPTR_PARAM_TEXT, StrValue+StrValue1); cash_checkerror('Cash_Execute:Text3');
         VarDevice.printText; cash_checkerror('Cash_Execute:PrintText3');
       end;
       cds.first;

///////////////////////////////////////////////

       if VarActionNal then Summ2 := bvroundto(Paysummary, -2)  else Summ2 := 0; // bvroundto(pSummaryCash, -2 );

       cash_savelog('Summ2: '+floattostr(summ2));

       case DOC_TYPE_CLOSE of
         1 : Index := CASH_TypeCloseBN;
         2 : Index := CASH_TypeCloseKredit;
         3 : Index := CASH_TypeCloseSert;
         else  Index := 0;
       end;
       cash_savelog('PaymentType: '+inttostr(index));

       if Summ2<>0 then
       begin
         VarDevice.setParam(VarDevice.LIBFPTR_PARAM_PAYMENT_TYPE, Index); cash_checkerror('Cash_Execute:PaymentType');
         VarDevice.setParam(VarDevice.LIBFPTR_PARAM_PAYMENT_SUM, Summ2);  cash_checkerror('Cash_Execute:PaymentSum');
         VarDevice.payment; cash_checkerror('Cash_Execute:Payment');
       end;
    
       
       if (index=0) and CASH_OPENDRAWER_NAL   then 
       begin
         cash_savelog('OpenDrawer');
         Cash_OpenDrawer(false); 
       end;
       


       case DOC_TYPE_CLOSE of
         1 : Index := CASH_TypeCloseBN;
         2 : Index := CASH_TypeCloseKredit;
         3 : Index := CASH_TypeCloseSert;
         else  Index := 0;
       end;

       cash_savelog('PaymentType1: '+inttostr(index));
       VarDevice.setParam(VarDevice.LIBFPTR_PARAM_PAYMENT_TYPE, Index); cash_checkerror('Cash_Execute:PaymentType1');

       //raiseexception('тест');

       cash_savelog('CloseReceipt');
       VarDevice.CloseReceipt; //Cash_CheckError('Cash_Execute:CloseReceipt');
       cash_savelog('-');

       if VarDevice.checkDocumentClosed<>0 then
       While VarDevice.checkDocumentClosed <> 0 do
       begin
          cash_savelog('-not closed');
          Cash_CheckError('Cash_Execute:CheckDocumentClosed',false);
          if getConfirm('Сохранение чека ещё не завершено: '+#13+
                        'Ошибка: '+inttostr(ResultCode)+': '+ResultDescription,
                        '','Повторить/продолжить','Отменить')<>mrOk 
          then break;
       end
       else cash_savelog('-closed');
       
       if not VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_DOCUMENT_CLOSED) then // если чек не закрыт, то отменяем его.
       begin
         Cash_SaveLog('Отмена чека',true);
         VarDevice.CancelReceipt;
         cash_checkError('Cash_Execute:CancelReceipt');
         raiseexception('Чек отменен!');
       end;

       Cash_SaveLog('Проверка статуса печати');
       if not VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_DOCUMENT_PRINTED) then
       begin
         Cash_SaveLog('Ожидание окончания печати');
         while VarDevice.continuePrint<>0 do 
         begin
           cash_checkError('Cash_Execute:ContinuePrint',false);
           if getConfirm('Чек сохранён, но его печать не завершена:'+#13+
                        'Ошибка: '+inttostr(ResultCode)+': '+ResultDescription,
                        '','Продолжить печать','Выйти')<>mrOk 
           then break;
         end;
         Cash_SaveLog('- печать завершена');
       end;

       Cash_SaveLog('cash_cut');
       Cash_Cut(false); Cash_CheckError('Cash_Execute:Cash_Cut',false);
       Cash_SaveLog('-завершено');
     
       Cash_GetNumbers(false);
     
   finally
       if needconnect then cash_disconnect; 
   end;
   Cash_SaveLog('cash_execute:exit');
end;

procedure Cash_CancelCheck(NeedConnect :boolean = true);
begin
  if NeedConnect then Cash_Connect(false);
  try
    {
    VarDevice.GetStatus; Cash_CheckError;
    if (VarDevice.CheckState <> 0) then VarDevice.CancelCheck; 
    Cash_CheckError;
    }
    
    VarDevice.checkDocumentClosed; Cash_CheckError('Cash_CancelCheck:CheckDocumentClosed');
     
    if not VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_DOCUMENT_CLOSED) then // если чек не закрыт, то отменяем его.
    begin
       VarDevice.CancelReceipt;
       cash_checkError('Cash_CancelCheck:CheckDocumentClosed');
    end;
  finally
    if NeedConnect then  Cash_disconnect;
  end;
end;

procedure Cash_RepeatCheck(NeedConnect :boolean = true);
begin
  cash_savelog('Cash_RepeatCheck: функция не реализована для данного драйвера',true);
  raiseexception('Cash_RepeatCheck: функция не реализована для данного драйвера'); 
end;


procedure Cash_DoSummary(IsIn :boolean; NeedConnect :boolean = true);
var i :integer;
begin
  if needconnect then Cash_Connect;
  try
    VarDevice.SetParam(VarDevice.LIBFPTR_PARAM_SUM,Summary); cash_checkerror('Cash_DoSummary:Summary');
    if isIn then VarDevice.CashIncome else VarDevice.CashOutcome; Cash_CheckError('Cash_DoSummary:CashOutcome');
    Cash_Cut(false); Cash_CheckError('Cash_DoSummary:cash_cut');
  finally
    if needconnect then cash_disconnect;
  end;
end;

procedure Cash_DoSummaryIn(NeedConnect :boolean = true);
begin
  Cash_DoSummary(true,NeedConnect);
end;

procedure Cash_DoSummaryOut(NeedConnect :boolean = true);
begin
  Cash_DoSummary(false,NeedConnect);
end;


procedure Cash_XReport(NeedConnect :boolean = true);
begin
  if NeedConnect then Cash_Connect;
  try
    VarDevice.setParam(VarDevice.LIBFPTR_PARAM_REPORT_TYPE, VarDevice.LIBFPTR_RT_X);
    VarDevice.Report; Cash_CheckError('cash_xreport');
  finally
    if NeedConnect then Cash_disconnect;
  end;
end;

procedure Cash_ZReport(NeedConnect :boolean = true);
begin
  if NeedConnect then  Cash_Connect;
  try
    VarDevice.setParam(VarDevice.LIBFPTR_PARAM_REPORT_TYPE, VarDevice.LIBFPTR_RT_CLOSE_SHIFT);
    VarDevice.Report; Cash_CheckError('Cash_zreport');
  finally
    if NeedConnect then Cash_disconnect;
  end;
end;

procedure Cash_SectionReport(NeedConnect :boolean = true);
begin
  if NeedConnect then Cash_Connect;
  try
    VarDevice.setParam(VarDevice.LIBFPTR_PARAM_REPORT_TYPE, VarDevice.LIBFPTR_RT_DEPARTMENTS);
    VarDevice.Report; Cash_CheckError('Cash_SectionReport');
  finally
    if NeedConnect then Cash_disconnect;
  end;
end;

procedure Cash_UsersReport(NeedConnect :boolean = true);
begin
  if NeedConnect then  Cash_Connect;
  try
    VarDevice.setParam(VarDevice.LIBFPTR_PARAM_REPORT_TYPE, VarDevice.LIBFPTR_RT_OPERATORS);
    VarDevice.Report; Cash_CheckError('Cash_UsersReport');
  finally
    if NeedConnect then Cash_disconnect;
  end;
end;



procedure Cash_RegistersReport(NeedConnect :boolean = true);

var i :integer;
    List :Tstringlist;
    ResultVal :string; //,ResultVal1,ResultVal2,ResultVal3,ResultVal4,ResultVal5,ResultVal6 :string;
    FloatVal :double;
    IntVal :integer;
    DTVal :tdatetime;
    BoolVal :boolean;
begin
  if (ResultRegisterListNames=nil) or (ResultRegisterListValues=nil) 
  then raiseException('Ошибка в Cash_RegistersReport: Не проинициализированы контейнеры для результатов функции');

  if NeedConnect then  Cash_Connect;

  List := tstringlist.create;
  with TmyWait.create('Идет сбор данных по регистрам',selfscript) do  
  try

    //VarDevice.mode := 0; Cash_CheckError;
    //VarDevice.SetMode; Cash_CheckError;
    
    resultregisterlistnames.clear;
    resultregisterlistvalues.clear;       
    

    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_SHIFT_TOTALS); 
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:8',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM));
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма продаж (чеки продажи):');  ResultRegisterListValues.add(ResultVal);

    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_SHIFT_TOTALS); 
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL_RETURN);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:9',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM));
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма возвратов (чеки возврата продажи):');  ResultRegisterListValues.add(ResultVal);

    

    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_PAYMENT_SUM); 
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL);
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_PAYMENT_TYPE, VarDevice.LIBFPTR_PT_CASH);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:10',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма продаж (наличными):');  ResultRegisterListValues.add(ResultVal);


    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_PAYMENT_SUM); 
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL_RETURN);
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_PAYMENT_TYPE, VarDevice.LIBFPTR_PT_CASH);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:11',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма возвратов (наличными):');  ResultRegisterListValues.add(ResultVal);


    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_PAYMENT_SUM); 
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL);
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_PAYMENT_TYPE, VarDevice.LIBFPTR_PT_ELECTRONICALLY);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:12',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма продаж (безнал):');  ResultRegisterListValues.add(ResultVal);

   progressbarpos := 15;
   
    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_PAYMENT_SUM); 
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL_RETURN);
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_PAYMENT_TYPE, VarDevice.LIBFPTR_PT_ELECTRONICALLY);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:13',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма возвратов (безнал):');  ResultRegisterListValues.add(ResultVal);


    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_PAYMENT_SUM); 
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL);
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_PAYMENT_TYPE, VarDevice.LIBFPTR_PT_CREDIT);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:14',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма продаж (кредит):');  ResultRegisterListValues.add(ResultVal);


    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_PAYMENT_SUM); 
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL_RETURN);
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_PAYMENT_TYPE, VarDevice.LIBFPTR_PT_CREDIT);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:15',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма возвратов (кредит):');  ResultRegisterListValues.add(ResultVal);

    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_CANCELLATION_SUM ); 
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:16',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма отмененных чеков:');  ResultRegisterListValues.add(ResultVal);

    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_CANCELLATION_SUM ); 
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL_RETURN);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:17',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма отмененных возвратов:');  ResultRegisterListValues.add(ResultVal);



    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_CASHIN_SUM ); 
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:18',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма внесений:');  ResultRegisterListValues.add(ResultVal);

    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_CASHOUT_SUM ); 
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_RECEIPT_TYPE, VarDevice.LIBFPTR_RT_SELL_RETURN);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:19',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма выплат:');  ResultRegisterListValues.add(ResultVal);
    
    //////////////////

    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_CASH_SUM); 
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:20',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма наличности:');  ResultRegisterListValues.add(ResultVal);

    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_REVENUE); 
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:21',false) then ResultVal := ResultDescription 
      else ResultVal := bvcurrtostrf(VarDevice.getParamDouble(VarDevice.LIBFPTR_PARAM_SUM)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Сумма выручки:');  ResultRegisterListValues.add(ResultVal);
    
  progressbarpos := 30;
  
    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_DATE_TIME); 
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:22',false) then ResultVal := ResultDescription 
      else ResultVal := VarDevice.getParamDateTime(VarDevice.LIBFPTR_PARAM_DATE_TIME); //datetimetostr(VarDevice.getParamDateTime(VarDevice.LIBFPTR_PARAM_DATE_TIME)); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Текущие дата и время:');  ResultRegisterListValues.add(ResultVal);


    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_SHIFT_STATE); 
      VarDevice.queryData;
      
      if not cash_checkError('cash_registers_report:23',false) then raiseexception(ResultDescription) 
      else begin
        try
          IntVal := VarDevice.GetParamInt(VarDevice.LIBFPTR_PARAM_SHIFT_STATE);
          if IntVal = VarDevice.LIBFPTR_SS_CLOSED then ResultVal := 'Смена закрыта'
          else if IntVal = VarDevice.LIBFPTR_SS_OPENED then ResultVal := 'Смена Открыта' 
          else if IntVal = VarDevice.LIBFPTR_SS_EXPIRED then ResultVal := 'Смена истекла (>24 часов)'
          else ResultVal := 'Неизвестное значение: '+inttostr(IntVal);
        except
          resultval := ExceptionMessage
        end;
        ResultRegisterListNames.add('Состояние смены:');  ResultRegisterListValues.add(ResultVal);
        
        try
          resultval := VarDevice.GetParamString(VarDevice.LIBFPTR_PARAM_SHIFT_NUMBER);
        except
          resultval := ExceptionMessage
        end; 
        ResultRegisterListNames.add('Номер смены:');  ResultRegisterListValues.add(resultval);

        try
          resultval := VarDevice.getParamDateTime(VarDevice.LIBFPTR_PARAM_DATE_TIME);
        except
          resultval := ExceptionMessage
        end; 
        ResultRegisterListNames.add('Время истечения текущей смены:');  ResultRegisterListValues.add(resultval);
          
      end; 
    except
      ResultRegisterListNames.add('Ошибка запроса состояния смены:');  ResultRegisterListValues.add(ExceptionMessage);
    end; 
  
    
    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_STATUS); 
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:2_1',false) then raiseexception(resultDescription)
      else begin
        try
          ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_SERIAL_NUMBER); 
        except
          resultval := ExceptionMessage
        end; 
        ResultRegisterListNames.add('Заводской номер ККМ:');  ResultRegisterListValues.add(ResultVal);

        try
          ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_SHIFT_NUMBER); 
        except
          resultval := ExceptionMessage
        end; 
        ResultRegisterListNames.add('Текущий номер сессии:');  ResultRegisterListValues.add(ResultVal);
    
        try
          ResultVal := VarDevice.getParamstring(VarDevice.LIBFPTR_PARAM_DOCUMENT_NUMBER); 
        except
          resultval := ExceptionMessage
        end; 
        ResultRegisterListNames.add('Текущий номер документа:');  ResultRegisterListValues.add(ResultVal);
      end; 
    except
      ResultRegisterListNames.add('Запрос статуса ККМ - ошибка:');  ResultRegisterListValues.add(ExceptionMessage);
    end;
       

    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_MODEL_INFO);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:1',false) then raiseexception(ResultVal+':'+ResultDescription)
      else begin
          try
            ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_MODEL); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Номер модели ККМ:');  ResultRegisterListValues.add(ResultVal);

          try
            ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_MODEL_NAME); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Наименование ККМ:');  ResultRegisterListValues.add(ResultVal);

          try
            ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_UNIT_VERSION); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Версия ККМ:');  ResultRegisterListValues.add(ResultVal);
          
          
          try
            ResultVal := VarDevice.Version; 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Версия драйвера:');  ResultRegisterListValues.add(ResultVal);
          
      end; 
    except
      ResultRegisterListNames.add('Запрос модели ККМ:');  ResultRegisterListValues.add(ExceptMessage);
    end; 
    
    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_UNIT_VERSION);
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_UNIT_TYPE, VarDevice.LIBFPTR_UT_CONFIGURATION);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:2',false) then raiseexception(ResultDescription)
      else begin
          try
            ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_UNIT_VERSION ); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Версия прошивки:');  ResultRegisterListValues.add(ResultVal);
          try
            ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_UNIT_RELEASE_VERSION ); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Версия релиза:');  ResultRegisterListValues.add(ResultVal);
      end; 
    except
      ResultRegisterListNames.add('Запрос версии модуля:');  ResultRegisterListValues.add(ExceptMessage);
    end; 

    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_RECEIPT_LINE_LENGTH);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:3',false) then ResultVal := ResultDescription 
      else ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_RECEIPT_LINE_LENGTH); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Ширина ленты (симв.):');  ResultRegisterListValues.add(ResultVal);


    progressbarpos := 75;
    
    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_FN_DATA_TYPE, VarDevice.LIBFPTR_FNDT_OFD_EXCHANGE_STATUS);
      VarDevice.fnQueryData;
      Boolval := cash_checkError('cash_registers_report:4',false); 
      if not boolval then ResultVal := ResultDescription 
      else ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_OFD_EXCHANGE_STATUS); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Статус обмена с ОФД:');  ResultRegisterListValues.add(ResultVal);
    if boolval then
    begin
      try
        ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_DOCUMENTS_COUNT); 
      except
        resultval := ExceptionMessage
      end; 
      ResultRegisterListNames.add('Кол-во неотправленных документов в ОФД:');  ResultRegisterListValues.add(ResultVal);
      try
        //ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_DATE_TIME);  
        ResultVal := VarDevice.getParamDateTime(VarDevice.LIBFPTR_PARAM_DATE_TIME);
      except
        resultval := ExceptionMessage
      end; 
      ResultRegisterListNames.add('Дата и время первого не отправленного документа в ОФД:');  ResultRegisterListValues.add(ResultVal);
    end;
    
    
    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_DATA_TYPE, VarDevice.LIBFPTR_DT_LAST_SENT_OFD_DOCUMENT_DATE_TIME);
      VarDevice.queryData;
      if not cash_checkError('cash_registers_report:5_0',false) then ResultVal := ResultDescription  
      else ResultVal := VarDevice.getParamDateTime(VarDevice.LIBFPTR_PARAM_DATE_TIME) 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Дата и время последнего успешного обмена с ОФД:');  ResultRegisterListValues.add(ResultVal);
 
    //***********************************ИСМ***********************************************************************
    
    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_FN_DATA_TYPE, VarDevice.LIBFPTR_FNDT_ISM_EXCHANGE_STATUS);
      VarDevice.fnQueryData;
      Boolval := cash_checkError('cash_registers_report:4_0',false); 
      if not boolval then ResultVal := ResultDescription 
      else ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_FNDT_ISM_EXCHANGE_STATUS); 
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Статус информационного обмена с ИСМ:');  ResultRegisterListValues.add(ResultVal);
    if boolval then
    begin
      try
        ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_DOCUMENTS_COUNT); 
      except
        resultval := ExceptionMessage
      end; 
      ResultRegisterListNames.add('Кол-во непереданных уведомлений в ИСМ:');  ResultRegisterListValues.add(ResultVal);
      try
        ResultVal := VarDevice.getParamDateTime(VarDevice.LIBFPTR_PARAM_DATE_TIME);
      except
        resultval := ExceptionMessage
      end; 
      ResultRegisterListNames.add('Дата и время первого непереданного уведомления в ИСМ:');  ResultRegisterListValues.add(ResultVal);
    end;
           
    //****************************************************************************************************************
    
    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_FN_DATA_TYPE, VarDevice.LIBFPTR_FNDT_VALIDITY);
      VarDevice.fnqueryData;
      if not cash_checkError('cash_registers_report:5_1',false) then ResultVal := ResultDescription 
      else ResultVal := VarDevice.getParamDateTime(VarDevice.LIBFPTR_PARAM_DATE_TIME);
      
    
      
    //registrationsRemain := fptr.getParamInt(fptr.LIBFPTR_PARAM_REGISTRATIONS_REMAIN);
    //registrationsCount  := fptr.getParamInt(fptr.LIBFPTR_PARAM_REGISTRATIONS_COUNT);
    //dateTime:           := fptr.getParamDateTime(fptr.LIBFPTR_PARAM_DATE_TIME);    
       
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Срок действия ФН:');  ResultRegisterListValues.add(ResultVal);
    
    
    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_FN_DATA_TYPE, VarDevice.LIBFPTR_FNDT_FN_INFO); 
      VarDevice.fnQueryData;
      if not cash_checkError('cash_registers_report:5_2',false) then raiseexception(resultDescription)
      else begin
        try
          ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_SERIAL_NUMBER); 
        except
          resultval := ExceptionMessage
        end; 
        ResultRegisterListNames.add('Серийный номер ФН:');  ResultRegisterListValues.add(ResultVal);

        try
          ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_FN_VERSION); 
        except
          resultval := ExceptionMessage
        end; 
        ResultRegisterListNames.add('Версия ФН:');  ResultRegisterListValues.add(ResultVal);
    
        try
          IntVal := VarDevice.getParamInt(VarDevice.LIBFPTR_PARAM_FN_TYPE);
          
          if IntVal =  VarDevice.LIBFPTR_FNT_UNKNOWN then ResultVal := 'неизвестная (не удалось получить)'
          else if intVal = VarDevice.LIBFPTR_FNT_DEBUG then resultVal := 'отладочная версия'
          else if IntVal = VarDevice.LIBFPTR_FNT_RELEASE then ResultVal := 'боевая версия'
          else ResultVal := 'неизвестное значение: '+inttostr(intval);
           
        except
          resultval := ExceptionMessage
        end; 
        ResultRegisterListNames.add('Тип ФН:');  ResultRegisterListValues.add(ResultVal);
        


        try
          IntVal := VarDevice.getParamInt(VarDevice.LIBFPTR_PARAM_FN_STATE);

          if IntVal =  VarDevice.LIBFPTR_FNS_INITIAL then ResultVal := 'настройка ФН'
          else if intVal = VarDevice.LIBFPTR_FNS_CONFIGURED then resultVal := 'готовность к активации'
          else if IntVal = VarDevice.LIBFPTR_FNS_FISCAL_MODE then ResultVal := 'фискальный режим'
          else if IntVal = VarDevice.LIBFPTR_FNS_POSTFISCAL_MODE then ResultVal := 'постфискальный режим'
          else if IntVal = VarDevice.LIBFPTR_FNS_ACCESS_ARCHIVE then ResultVal := 'доступ к архиву'
          else ResultVal := 'неизвестное значение: '+inttostr(intval);
           
        except
          resultval := ExceptionMessage
        end; 
        ResultRegisterListNames.add('Состояние ФН:');  ResultRegisterListValues.add(ResultVal);

        ResultVal := '';
        try
          BoolVal := VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_FN_NEED_REPLACEMENT);
          if BoolVal then IncStr(ResultVal,'Требуется срочная замена ФН',', '); 

          BoolVal := VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_FN_RESOURCE_EXHAUSTED); 
          if BoolVal then IncStr(ResultVal,'Исчерпан ресурс ФН',', '); 

          BoolVal := VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_FN_OFD_TIMEOUT); 
          if BoolVal then IncStr(ResultVal,'Превышено время ожидания запроса от ОФД',', '); 

          BoolVal := VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_FN_MEMORY_OVERFLOW); 
          if BoolVal then IncStr(ResultVal,'Память ФН переполнена',', '); 

          BoolVal := VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_FN_CRITICAL_ERROR); 
          if BoolVal then IncStr(ResultVal,'Критическая ошибка ФН',', '); 

          BoolVal := VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_FN_MEMORY_OVERFLOW); 
          if BoolVal then IncStr(ResultVal,'Память ФН переполнена',', '); 

          BoolVal := VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_FN_MEMORY_OVERFLOW); 
          if BoolVal then IncStr(ResultVal,'Память ФН переполнена',', ');
          
          ResultRegisterListNames.add('Замечания по ФН:');  ResultRegisterListValues.add(ResultVal);
           
        except
          resultval := ExceptionMessage
        end; 
      end; 
    except
      ResultRegisterListNames.add('Запрос параметров ФН - ошибка:');  ResultRegisterListValues.add(ExceptionMessage);
    end;
    
    
    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_FN_DATA_TYPE, VarDevice.LIBFPTR_FNDT_FFD_VERSIONS);
      VarDevice.fnQueryData;
      if not cash_checkError('cash_registers_report:6',false) then ResultVal := ResultDescription 
      else ResultVal := VarDevice.getParamInt(VarDevice.LIBFPTR_PARAM_DEVICE_FFD_VERSION);    
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Версия ФФД ККТ:');  ResultRegisterListValues.add(ResultVal);
    
    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_FN_DATA_TYPE, VarDevice.LIBFPTR_FNDT_ERRORS);
      VarDevice.fnQueryData;
    
      if not cash_checkError('cash_registers_report:7',false) then ResultVal := ResultDescription 
      else begin
          try
            ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_NETWORK_ERROR ); 
          except
            resultval := ExceptionMessage
          end; 
      
          try
            incstr(resultval,asstring(VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_NETWORK_ERROR_TEXT )),': '); 
          except
            incstr(resultval,ExceptionMessage,': ');
          end; 
          ResultRegisterListNames.add('Ошибка сети:');  ResultRegisterListValues.add(ResultVal);
          
          try
            ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_OFD_ERROR ); 
          except
            resultval := ExceptionMessage
          end; 
          
          try
            incstr(ResultVal,asstring(VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_OFD_ERROR_TEXT )),': '); 
          except
            incstr(resultval,ExceptionMessage,': ');
          end; 
          ResultRegisterListNames.add('Текст ошибки ОФД:');  ResultRegisterListValues.add(ResultVal);
      end; 
    except
      ResultRegisterListNames.add('Ошибки сети:');  ResultRegisterListValues.add(ExceptMessage);
    end; 

    progressbarpos := 90;

    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_FN_DATA_TYPE, VarDevice.LIBFPTR_FNDT_REG_INFO);
      VarDevice.fnQueryData;
    
      if not cash_checkError('cash_registers_report:8',false) then ResultVal := ResultDescription 
      else begin
          try
            ResultVal := VarDevice.getParamString(1018); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('ИНН организации:');  ResultRegisterListValues.add(ResultVal);
    
          try
            ResultVal := VarDevice.getParamString(1048); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Название организации:');  ResultRegisterListValues.add(ResultVal);
    
          try
            ResultVal := VarDevice.getParamString(1117); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('EMAIL организации:');  ResultRegisterListValues.add(ResultVal);
    

          try
            ResultVal := VarDevice.getParamString(1187); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Адрес места расчетов:');  ResultRegisterListValues.add(ResultVal);

          try
            ResultVal := VarDevice.getParamString(1037); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Регистрационный номер устройства:');  ResultRegisterListValues.add(ResultVal);

          try
            ResultVal := VarDevice.getParamString(1017); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('ИНН ОФД:');  ResultRegisterListValues.add(ResultVal);
    
          try
            ResultVal := VarDevice.getParamString(1046); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Название ОФД:');  ResultRegisterListValues.add(ResultVal);

          try
            ResultVal := VarDevice.getParamString(1209); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Версия ФФД:');  ResultRegisterListValues.add(ResultVal);
 
          {          
          1060	Адрес сайта ФНС	string
          1009	Адрес расчетов	string
          1062	Системы налогообложения	int
          1057	Признак агента	int
          1001	Признак автоматического режима	bool
          1036	Номер автомата	string
          1002	Признак автономного режима	bool
          1056	Признак шифрования	bool
          1108	Признак ККТ для расчетов в сети Интернет	bool
          1109	Признак расчетов за услуги	bool
          1110	Признак АС БСО	bool
          1126	Признак проведения лотерей	bool
          1193	Признак проведения азартных игр	bool
          1207	Признак подакцизного товара	bool
          1221	Признак установки принтера в автомате	bool
          }

      end;
    except
      ResultRegisterListNames.add('Запрос реквизитов регистрации ККТ');  ResultRegisterListValues.add(ExceptMessage);
    end; 
    
    progressbarpos := 95;

    try
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_FN_DATA_TYPE, VarDevice.LIBFPTR_FNDT_LAST_RECEIPT);
      VarDevice.fnQueryData;
    
      if not cash_checkError('cash_registers_report:9',false) then ResultVal := ResultDescription 
      else begin
          try
            ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_DOCUMENT_NUMBER); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Последний документ в ФН: номер:');  ResultRegisterListValues.add(ResultVal);

          try
            ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_DATE_TIME); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Последний документ в ФН: дата-время:');  ResultRegisterListValues.add(ResultVal);
    
          try
            ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_RECEIPT_SUM); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Последний документ в ФН: сумма:');  ResultRegisterListValues.add(ResultVal);
    
          try
            ResultVal := VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_FISCAL_SIGN); 
          except
            resultval := ExceptionMessage
          end; 
          ResultRegisterListNames.add('Последний документ в ФН: фискальный признак:');  ResultRegisterListValues.add(ResultVal);
    
      end;
    except
      ResultRegisterListNames.add('Запрос данных последнего чека');  ResultRegisterListValues.add(ExceptMessage);
    end;
    
    try
      //VarDevice.setParam(VarDevice.LIBFPTR_PARAM_FN_DATA_TYPE, VarDevice.LIBFPTR_FNDT_FFD_VERSIONS);
      //VarDevice.fnQueryData;
      //ResultVal := asstring(VarDevice.getParamBool(VarDevice.LIBFPTR_SETTING_VALIDATE_MARK_WITH_FNM_ONLY));
      resultVal := asstring(VarDevice.getSingleSetting(VarDevice.LIBFPTR_SETTING_VALIDATE_MARK_WITH_FNM_ONLY));
      if not cash_checkError('cash_registers_report:LIBFPTR_SETTING_VALIDATE_MARK_WITH_FNM_ONLY',false) then ResultVal := ResultDescription; 
      //else ResultVal := VarDevice.getParamInt(VarDevice.LIBFPTR_PARAM_DEVICE_FFD_VERSION);
      
    except
      resultval := ExceptionMessage
    end; 
    ResultRegisterListNames.add('Проверка КМ средствами драйвера:');  ResultRegisterListValues.add(ResultVal);

    progressbarpos := 100;
  finally  
    if NeedConnect then Cash_disconnect;
    list.free;
    free
  end;
end;

procedure Cash_ShowProperties;
var StrVal :string;
    IntVal :integer;
begin
  Cash_CheckDevice;
  IntVal := VarDevice.ShowProperties(VarDevice.LIBFPTR_GUI_PARENT_NATIVE,0); cash_checkError('Cash_ShowProperties');
  if IntVal=0 then 
  begin
    Cash_SaveSettings; Cash_CheckError('Cash_ShowProperties:SaveSettings');
  end;
end;


procedure Cash_PrintText(Strings :tStrings;
                         NeedConnect :boolean = true;
                         RepeatPrint :integer =1; // число повторов слипа (если поступил одинарный слип, то повторим его печать)
                         CutAfter :boolean=false; // обрезать ли слип после печати
                         CutLine :boolean =false; // Надо ли резать (некоторые аппараты не поддерживают. по-умолчанию - true
                         CutLineText :string =''; // линия отреза содержит
                         CutLineLength :integer = 0; // сколько надо пропустить, чтобы линия отреза была там, где надо
                         CutLineSleep :integer = 0 // на месте отреза сделать слип, в секундах. Требуется, если аппарат не имеет отрезки, тогда эти секунды дадут возможность оторвать руками
                         );
var 
    i :integer;
    k :integer;
    incCutLine :integer;
    NeedCutLine :boolean; // Надо резать, после того, как IncCutLIne станет равной CardsPrintCutLineLength
begin
  if needConnect then Cash_Connect;
  try
  { тест 
    ShowMessage(Strings.text+#13+
                'NeedConnect:'+asstring(NeedConnect)+#13+
                'RepeatPrint:'+asstring(RepeatPrint)+#13+
                'CutAfter:'+asstring(CutAfter)+#13+  
                'CutLine:'+asstring(CutLine)+#13+  
                'CutLineText:'+asstring(CutLineText)+#13+  
                'CutLineLength:'+asstring(CutLineLength)+#13+  
                'CutLineSleep:'+asstring(CutLineSleep));
    exit;
  }
  
  
  
    Cash_SaveLog('PrintTextAtol');
    //Cash_SaveLog(strings.text);
    if trim(strings.text) ='' then 
      Exit;
  
    Cash_SaveLog('PrintTextAtol:2');

    // скорректируем линию отреза: если что-то там еще есть в строке, содержащей эту линию, то разделим строку
    if CutLineText>'' then 
      for i := strings.count-1 downto 0 do
        if (pos(CutLineText,strings[i])=1) and (length(strings[i])>length(CutLineText)) then
        begin
          strings[i] := copy(strings[i],length(CutLineText)+1,10000); 
          strings.Insert(i,CutLineText);
        end;
        
    //strings.SaveToFile('c:\temp\1.txt');
  
    for k := 1 to ifthen_integer(repeatprint>1,repeatprint,1) do
    begin
      NeedCutLine := false;
      incCutLine := 0;
      Cash_SaveLog('PrintTextAtol:3');



      for i := 0 to strings.count-1 do
      begin
        Cash_SaveLog('PrintTextAtol:3.1.'+inttostr(i));
        VarDevice.setParam(VarDevice.LIBFPTR_PARAM_TEXT, Strings[i]); //VarDevice.Caption := List[i]; 
        cash_checkerror('Cash_PrintText');
        Cash_SaveLog('PrintTextAtol:3.2.'+inttostr(i));
        
          //Перенос LIBFPTR_PARAM_TEXT_WRAP может принимать следующие значения:
            //LIBFPTR_TW_NONE - не переносить. Текст будет обрезаться по ширине ленты
            //LIBFPTR_TW_WORDS - переносить по словам. Разделителями считаются символы:
               //пробел точка запятая точка с запятой тире знак вопроса восклицательный знак закрывающая скобка
              //закрывающая фигурная скобка            закрывающая квадратная скобка            
            //LIBFPTR_TW_CHARS - переносить по символам
    
        VarDevice.setParam(VarDevice.LIBFPTR_PARAM_TEXT_WRAP, VarDevice.LIBFPTR_TW_CHARS); {VarDevice.TextWrap := 1;} 
        cash_checkerror('Cash_PrintText:1');//Перенос текста по словам
    
            //LIBFPTR_ALIGNMENT_LEFT - по левому краю
            //LIBFPTR_ALIGNMENT_CENTER - по центру
            //LIBFPTR_ALIGNMENT_RIGHT - по правому краю    
    
        VarDevice.setParam(VarDevice.LIBFPTR_PARAM_ALIGNMENT, VarDevice.LIBFPTR_ALIGNMENT_LEFT); {VarDevice.Alignment := 0; } 
        cash_checkerror('Cash_PrintText:2'); // выравнивание текста в строке
        
        VarDevice.printText;  {VArDevice.PrintString;}   
        cash_checkerror('Cash_PrintText:3');
        
        if pos(CutLineText,strings[i])=1 then begin
          NeedCutLine := true;
          IncCutLine := 0;
        end;
        
        if NeedCutLIne then
        begin
          inc(IncCutLine);
          if IncCutLine>CutLineLength
          then begin
            if CutLine then
            begin
              Cash_SaveLog('PrintTextAtol:3.3.'+inttostr(i));
              
                    //Выравнивание LIBFPTR_PARAM_CUT_TYPE может принимать следующие значения:
                    //LIBFPTR_CT_FULL - полная отрезка
                    //LIBFPTR_CT_PART - частичная отрезка              

              {VarDevice.SetParam(VarDevice.LIBFPTR_PARAM_CUT_TYPE,VarDevice.LIBFPTR_CT_FULL); Cash_checkerror('Cash_PrintText:4');
              VarDevice.Cut; cash_checkerror('Cash_PrintText:5');// отрезка} //на слипе выдавал ошибку. на 5й платформе не работает Cut
			  
              VarDevice.PrintCliche;  cash_checkerror('Cash_PrintText:PrintCliche:1');
            end;
            if CutLineSleep>0 then Sleep(CutLineSleep*1000);
            NeedCutLine := false;
            IncCutLine := 0;
          end;
        end;
      end;
  
      Cash_SaveLog('PrintTextAtol:4');
      if CutAfter and NeedCutLine and (IncCutLine<CutLineLength)
      then begin
        //VarDevice.StringQuantity:=CardsPrintCutLineLength-IncCutLine; //пропустить строки
        //VarDevice.FeedDocument;
        for i := 1 to (CutLineLength-IncCutLine) do
        begin
          Cash_SaveLog('PrintTextAtol:4.1.'+inttostr(i));
          VarDevice.setParam(VarDevice.LIBFPTR_PARAM_TEXT, '');  //VarDevice.Caption := ''; 
          cash_checkerror('Cash_PrintText:6');
          
          Cash_SaveLog('PrintTextAtol:4.2.'+inttostr(i));
          VarDevice.printText; //VArDevice.PrintString;   
          cash_checkerror('Cash_PrintText:7');
        end;
        if CutLine then
        begin
          //VarDevice.CutType:=False; // false полная отрезка, true - неполная
          //VarDevice.CutCheck; // отрезка
          
          vardevice.printCliche; //VarDevice.PrintHeader;   
          cash_checkerror('Cash_PrintText:PrintCliche:2');
        end;
        if CutLineSleep>0 then Sleep(CutLineSleep*1000);
      end;
    end;
    Cash_SaveLog('PrintTextAtol:6');

    //vardevice.printCliche; //VarDevice.PrintHeader;   
    //cash_checkerror('Cash_PrintText:8');
    //Cash_SaveLog('PrintTextAtol:6');
    //if CutLine then
    //begin
    //  Cash_SaveLog('PrintTextAtol:6.1');
           //VarDevice.partialcut;   cash_checkerror;

      //VarDevice.SetParam(VarDevice.LIBFPTR_PARAM_CUT_TYPE,VarDevice.LIBFPTR_CT_PART); Cash_checkerror('Cash_PrintText:9'); //на 5й платформе не работает 
      //VarDevice.Cut; cash_checkerror('Cash_PrintText:10');// отрезка //на 5й платформе не работает Cut
    //end;

    if CutLineSleep>0 then Sleep(CutLineSleep*1000);

    Cash_SaveLog('PrintTextAtol:exit');
  finally  
    if NeedConnect then Cash_disconnect;
  end;
end;

procedure Cash_CheckMark(MARK :string {; ShowWait :boolean = false; pWF :TMyWait = nil});
var List :tstringlist;
    StrVal,StrVal1,strVAl2 :string;
    IntVal :integer;
    MyWF :tMyWait;
    BoolVal :boolean;
    i :integer; 
begin

  {if (pWF<>nil) then MyWF := pWF
  else if ShowWait then} 
    MyWF := TMyWait.create('Идет запрос проверки марки',selfscript,nil,true,false,wpCenter)
  //else MyWF := nil
  ;  
  
  if (Mywf<>nil) then Mywf.SHOW;
  try
    try
      cash_connect;
      Cash_CheckShiftState(false,true);
      
      VarDevice.CancelMarkingCodeValidation(); cash_checkerror('CancelMarkingCodeValidation');

      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE_TYPE, VarDevice.LIBFPTR_MCT12_AUTO); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_TYPE');
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE, MARK); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE');
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_CODE_STATUS, {VarDevice.LIBFPTR_MES_DRY_FOR_SALE} 2); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_STATUS');
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_QUANTITY, 1.000);cash_checkerror('LIBFPTR_PARAM_QUANTITY');
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MEASUREMENT_UNIT, 0); cash_checkerror('LIBFPTR_PARAM_MEASUREMENT_UNIT');
      VarDevice.setParam(2108, 0); cash_checkerror('2108');
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_WAIT_FOR_VALIDATION_RESULT, True); cash_checkerror('LIBFPTR_PARAM_MARKING_WAIT_FOR_VALIDATION_RESULT');
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_PROCESSING_MODE, 0);  cash_checkerror('LIBFPTR_PARAM_MARKING_PROCESSING_MODE');
      VarDevice.setParam(VarDevice.LIBFPTR_PARAM_MARKING_FRACTIONAL_QUANTITY, '1/2');
      VarDevice.beginMarkingCodeValidation(); cash_checkerror('beginMarkingCodeValidation');
  
      StrVAl := '?';
      // Дожидаемся окончания проверки и запоминаем результат
      while not mywf.checkstophint do
      begin
          sleep(CASH_CHECKMARK_SLEEPMS);
          
          VarDevice.getMarkingCodeValidationStatus(); cash_checkerror('getMarkingCodeValidationStatus');
          BoolVal := VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_MARKING_CODE_VALIDATION_READY);   cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_VALIDATION_READY');
          
          StrVAl := 'LIBFPTR_PARAM_MARKING_CODE_VALIDATION_READY = '+asstring(BoolVal); 
          incstrcr(StrVal,'LIBFPTR_PARAM_IS_REQUEST_SENT='+asstring(VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_IS_REQUEST_SENT))); cash_checkerror('LIBFPTR_PARAM_IS_REQUEST_SENT');
          incstrcr(StrVal,'LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_RESULT='+asstring(VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_RESULT))); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_RESULT');
          incstrcr(StrVal,'LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_ERROR='+asstring(VarDevice.getParamSTring(VarDevice.LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_ERROR)));  cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_ERROR');
          incstrcr(StrVal,'LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_ERROR_DESCRIPTION='+VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_ERROR_DESCRIPTION)); cash_checkerror('LIBFPTR_PARAM_MARKING_CODE_ONLINE_VALIDATION_ERROR_DESCRIPTION');
          strval2 := asstring(VarDevice.getParamSTring(VarDevice.LIBFPTR_PARAM_TLV_LIST));  cash_checkerror('LIBFPTR_PARAM_TLV_LIST');
          incstrcr(strval,'LIBFPTR_PARAM_TLV_LIST='+strval2);
          if StrVAl2>'' then
          begin       
            List := tstringlist.create;
            try
              StringToList(StrVAl2,List,';');
              for i := 0 to list.count-1 do 
              begin
                IncSTrcr(StrVal,List[i]+'='+VarDevice.GetParamString(List[i])+' ('+VarDevice.GetParamStringHEX(List[i])+')'); cash_checkerror(List[i]);
              end;
            finally
              FreeAndNil(List)
            end;
          end;
  
          strval2 := asstring(VarDevice.getParamSTring(2106));  cash_checkerror('TAG 2106');
          incstrcr(strval,'TAG2106='+strval2);

          if BoolVal then  
          begin
            mywf.hide;
            //createhint(StrVal,'Проверка марки',0);
            bvMessage(StrVal);                    
            break;
          end;
          CreateHint(StrVAl); Application.processmessages;
      end;
   
      // Подтверждаем реализацию товара с указанным КМ
      VarDevice.DeclineMarkingCode(); cash_checkerror('DeclineMarkingCode');
      //VarDevice.acceptMarkingCode();
      
   
    //VarDevice.setParam(VarDevice.LIBFPTR_PARAM_FN_DATA_TYPE, VarDevice.LIBFPTR_FNDT_FFD_VERSIONS);
    //VarDevice.fnQueryData;
    //bvMessage(asstring(VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_DEVICE_MAX_FFD_VERSION)));
   // bvMessage(Asstring(VarDevice.LIBFPTR_MES_DRY_FOR_SALE  ));
       
      cash_disconnect;  cash_checkerror('cash_disconnect');
    except
     createhinte(exceptmessage);
    end;
  finally
    //if (MyWF<>nil) and (MyWF<>pWF) then 
    begin
      FreeAndNil(Mywf);
    end;
  end;
end;


procedure CASH_PingMarkingServer;
var BoolVal :boolean;
    StrVal :string;
begin
  with tmywait.create('Идет проверка сервера ИСМ',selfscript,nil,true) do
  try
    try
      cash_connect; cash_checkerror('cash_connect');
      VarDevice.PingMarkingServer; cash_checkerror('PingMarkingServer');
      while not CheckStop do 
      begin
        VarDevice.getMarkingServerStatus(); cash_checkerror('GetMarkingServerStatus');
        BoolVal := VarDevice.getParamBool(VarDevice.LIBFPTR_PARAM_CHECK_MARKING_SERVER_READY); cash_checkerror('LIBFPTR_PARAM_CHECK_MARKING_SERVER_READY');
        if Boolval then break;
        sleep(1000);
      end;
      
      StrVal := 'ERROR_CODE='+asstring(VarDevice.getParamInt(VarDevice.LIBFPTR_PARAM_MARKING_SERVER_ERROR_CODE)); cash_checkerror('LIBFPTR_PARAM_MARKING_SERVER_ERROR_CODE');
      incstrcr(StrVal,'ERROR_DESCRIPTION= '+asstring(VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_MARKING_SERVER_ERROR_DESCRIPTION))); cash_checkerror('LIBFPTR_PARAM_MARKING_SERVER_ERROR_DESCRIPTION');
      IncStrCr(StrVal,'RESPONSE_TIME= '+asstring(VarDevice.getParamString(VarDevice.LIBFPTR_PARAM_MARKING_SERVER_RESPONSE_TIME))); cash_checkerror('LIBFPTR_PARAM_MARKING_SERVER_RESPONSE_TIME');
      CreateHint(StrVAl,'Пинг сервера ИСМ');      
      
      cash_disconnect; cash_checkerror('cash_disconnect');
    except
      createhinte(exceptmessage);
    end;
  finally
    free
  end;
end;

begin
  // инициализация модуля. выполняется перед выполнением каких-либо функций и для установки параметров по-умолчанию
  Cash_InitVars;
  cash_checkdevice;
  cash_checkerror('init');
  //bvmessage(asstring(vardevice.checkmode));
  // конец инициализации


//    showmessage(asstring(VarDevice.LIBFPTR_MES_PIECE_SOLD));
    //showmessage(asstring(VarDevice.LIBFPTR_MES_DRY_FOR_SALE));

  //showmessage(asstring(VarDevice.LIBFPTR_IU_PIECE));  
  //CASH_PingMarkingServer;
  
      //'014494550435306821QXYXSALGLMYQQ\u001D91EE06\u001D92YWCXbmK6SN8vvwoxZFk7WAY8WoJNMGGr6Cgtiuja04c=';
      //'014494550435306821QXYXSALGLMYQQ'+#29+'91EE06'+#29+'92YWCXbmK6SN8vvwoxZFk7WAY8WoJNMGGr6Cgtiuja04c=';
      //'0104601429000020213901B34BT89TT'+#29+'91EE06'+#29+'92l0xssmrPosm8EfOzDfmh5OfxOW+SVKf3oaXeCeR576E='
      //'0104601429000020213901B34BT89TT\u001D91EE06\u001D92l0xssmrPosm8EfOzDfmh5OfxOW+SVKf3oaXeCeR576E='
  //Cash_CheckMark('014494550435306821QXYXSALGLMYQQ'+#29+'91EE06'+#29+'92YWCXbmK6SN8vvwoxZFk7WAY8WoJNMGGr6Cgtiuja04c=');

  
  (*
  list := tstringlist.create;
  try
     list.loadfromfile('');
  
     Cash_PrintText(list, //Strings :tStrings;
                    true,//       NeedConnect :boolean = true;
                    1,//       RepeatPrint :integer =1; // число повторов слипа (если поступил одинарный слип, то повторим его печать)
                    true,//       CutAfter :boolean=false; // обрезать ли слип после печати
                    true,//       CutLine :boolean =false; // Надо ли резать (некоторые аппараты не поддерживают. по-умолчанию - true
                    '=====',//       CutLineText :string =''; // линия отреза содержит
                    0,//       CutLineLength :integer = 0; // сколько надо пропустить, чтобы линия отреза была там, где надо
                    0 //       CutLineSleep :integer = 0 // на месте отреза сделать слип, в секундах. Требуется, если аппарат не имеет отрезки, тогда эти секунды дадут возможность оторвать руками
                           );
  finally
    list.free;
  end;
  *)

  //cash_connect;
  //showmessage(datetimetostr(CASH_GET_DATETIME));
  //showmessage(datetimetostr(CASH_GET_FN_LAST_DATETIME));
  
  //showmessage(asstring(VarDevice.LIBFPTR_PT_ELECTRONICALLY));
  
  //cash_connect;

  //showmessage(vardevice.isopened);  
  //cash_xreport(true);
  
{  
   // тест
  //cash_getnumbers; 
  //CreateHint('Результат : '+inttostr(ResultCode)+': '+ResultDescription);
  //createhint(asstring(resultserialnumber));
  //createhint(asstring(resultsessionnumber));
  //createhint(asstring(resultdocumentnumber));
   
   Dataset := TClientDAtaset.create(selfscript);
   with tclientdataset(Dataset) do
   begin
     fielddefs.clear;
     fielddefs.add(FName,ftstring,100,false);
     fielddefs.add(FQuantity,ftfloat,0,false);
     fielddefs.add(FPrice,ftcurrency,0,false);
     fielddefs.add(FSUMMARY,ftfloat,0,false);
     fielddefs.add(FPriceOut,ftcurrency,0,false);
     fielddefs.add(FSection,ftinteger,0,false);
     fielddefs.add(FNDS,ftinteger,0,false);
     createdataset;
     logchanges := false;

     append;
     fieldbyname(FName).asstring := 'Товар1 Товар1 Товар1 Товар1 Товар1 Товар1 Товар1 Товар1 Товар1 Товар1 Товар1 Товар1 Товар1 Товар1';
     fieldbyname(FQuantity).asfloat := 2;
     fieldbyname(FPrice).asfloat := 1.30;
     fieldbyname(FPriceOut).asfloat := 1.50;
     fieldbyname(FSummary).asfloat := fieldbyname(fquantity).asfloat * fieldbyname(fprice).asfloat;
     fieldbyname(FNDS).asinteger := 0;
     post;
     append;
     fieldbyname(FName).asstring := 'Товар2';
     fieldbyname(FQuantity).asfloat := 2;
     fieldbyname(FPrice).asfloat := 0.90;
     fieldbyname(FPriceOut).asfloat := 1.00;
     fieldbyname(FSummary).asfloat := fieldbyname(fquantity).asfloat * fieldbyname(fprice).asfloat;
     fieldbyname(FNDS).asinteger := 10;
     post;
     
     append;
     fieldbyname(FName).asstring := 'Товар3';
     fieldbyname(FQuantity).asfloat := 2;
     fieldbyname(FPrice).asfloat := 1.10;
     fieldbyname(FPriceOut).asfloat := 1.20;
     fieldbyname(FSummary).asfloat := fieldbyname(fquantity).asfloat * fieldbyname(fprice).asfloat;
     fieldbyname(FNDS).asinteger := 18;
     post;
     
     
   end;

  CASH_SHOWNDS := true;
   
  PaySummary := 100;
  EMAIL := 'borzov@solr.ru';
  IsReturn := false; 
  //CASH_UserPassword := '30';
  //CASH_SysPassword := '30'; 

  VarActionNal := true;
  VarActionBN := false;
  VarActionKredit := false; 
  VarActionSert := false;

  VarActionDiskont := false;
  VarActionDiskont1 := false;
  VarActionPension := false;
  VarActionVIP := false;
  VarActionInsurance := false;
  
  cash_execute();
  CreateHint('Результат : '+inttostr(ResultCode)+': '+ResultDescription);
}

end.
