В статье описан процесс настройки системы для автоматического начисления и списания балов Спасибо при оплате заказа на кассовой станции.

Настройки в системе  

  1.  В группу Анализ чека (системы лояльности) добавьте скрипт:



    procedure ReceiptXMLAnalysis1001330(AXMLReceiptParameters: TXMLReceiptParameters);
    var
      p: integer;
      xml, PaymentTag, ExtInfo, CardInfo: string;
    begin
      xml := AXMLReceiptParameters.ReceiptXML;
      while xml <> '' do
      begin
        p := pos('<PAYMENT ', xml);
        if p = 0 then
          exit;
        xml := copy(xml, p, length(xml));
        p := pos('/>', xml);
        PaymentTag := copy(xml, 1, p + 1);
        xml := copy(xml, p + 2, length(xml));
        p := pos('exttransactioninfo="BANK:SBRF', PaymentTag);
        if p > 0 then
        begin
          ExtInfo := copy(PaymentTag, p + length('exttransactioninfo="'),
            length(PaymentTag));
          p := pos('"', ExtInfo);
          ExtInfo := copy(ExtInfo, 1, p - 1);
          p := pos('/PdsCard=', ExtInfo);
          if p = 0 then
          begin
            p := pos('PdsCard=', ExtInfo);
            if p = 1 then
              CardInfo := copy(ExtInfo, 1 + length('PdsCard='), length(ExtInfo))
            else
              CardInfo := '';
          end
          else
            CardInfo := copy(ExtInfo, p + length('/PdsCard='), length(ExtInfo));
          if CardInfo <> '' then
          begin
            p := pos(CardInfo, '/');
            if p > 0 then
              CardInfo := copy(CardInfo, 1, p - 1);
            AXMLReceiptParameters.CardCode := CardInfo;
            AXMLReceiptParameters.DoTransfer := true;
            AXMLReceiptParameters.SilentMode := true;
          end;
        end;
      end;
    end;

  2. Назначьте скрипт интерфейсу SBRF_Spasibo созданному ранее

Автоматическое списание Спасибо

  1. В настройках созданного ранее MCR-алгоритма проверьте активность типа устройства Скрипты.
  2. В свойствах драйвера измените значение параметра RemindLoyalty на WithPayPass
  3.   В настройках параметров самого терминала TlvEdit.exe измените значение параметра Возвращать промежуточный код ответа (DF7D) на По картам Сбербанка:

  4. В форме где будет использоваться функционал — здесь выбрана Редактирование заказа (быстрый чек) создайте копию предустановленного экземпляра формы, переименуйте ее и сохраните изменения

  5. Откройте редактор формы, выделите компонент CheckView в строке OnOrderVerify добавьте скрипт:

    if AVerifyType = vtAfterPay then
     CheckLoyaltyOnAuthorization;

  6. В самом начале обработчика событий и форм вставьте скрипт

    const minordersum = 250;
    const SpasiboCurrencyCode = 126;
    function ExtractPartFromExtTransactionInfo(ExtTransactionInfo:String;
    PartName:String):String;
    var i:Integer;
     s:string;
    begin
     i:=pos(PartName,ExtTransactionInfo);
     if i>1 then begin
     i:=pos('/'+PartName,ExtTransactionInfo);
     if i>0 then
     i:=i+1;
     end;
     if i=0 then
     s:=''
     else begin
     s:=copy(ExtTransactionInfo,i+length(PartName),65535);
     i:=pos('/',s);
     if i>0 then
     SetLength(s,i-1);
     end;
     Result:=s;
    end;
    procedure PerformLoyalyMCR(PayLine: TPayLine);
    var i: integer;
     CardCode: string;
     FirstNumbers:String;
     LastNumbers:String;
     BankName:String;
    begin
     CardCode := ExtractPartFromExtTransactionInfo(PayLine.ExtTransactionInfo, 'PdsCard=');
     i:=pos(';',CardCode);
     if i > 0 then begin
     LastNumbers:=copy(CardCode,i+1,255);
     SetLength(CardCode, i-1);
     end else
     LastNumbers:='';
     FirstNumbers:=PayLine.CardNum;
     i:=pos('*',PayLine.CardNum);
     if i>0 then
     SetLength(FirstNumbers, i-1);
     BankName:=ExtractPartFromExtTransactionInfo(PayLine.ExtTransactionInfo, 'BANK:');
     // Slide a spasibo card
    //RK7.PerformMcrAlgorithSilent('BANK:'+BankName+';'+FirstNumbers+';'+LastNumbers+';'+CardCode, 1);
     RK7.PerformMcrAlgorithSilent(BankName+':'+CardCode+';'+LastNumbers, 1);
    end;
    function SpasiboOnAuthorize(PayLine: TPayLine):Boolean;
    var i, k: integer;
     CardCode: string;
     it: TCheckItem;
     McrPay: TMcrPay;
     a: double;
     Editor: TNumEditor;
     SpasiboExists: boolean;
     BankName:String;
    begin
    //Exit; //Uncomment me to disable auto write-off SB SPASIBO
     // Looking for payment in tsAuthoring state
     Result:=False;
     a := 0;
     SpasiboExists := False;
     for i := 0 to RKCheck.CurrentOrder.Sessions.LinesCount - 1 do begin
     it := RKCheck.CurrentOrder.Sessions.Lines[i];
     if SYS.ObjectInheritsFrom(TObject(it), 'TPayLine') then begin
     if it.Code = trunc(SpasiboCurrencyCode) then
     SpasiboExists := True;
    if (it<>PayLine) and (it.State <> disClosed) and (it.State <> disDeleted) then
     a := a + TPayLine(it).BasicSum;
     end;
     end;
     if PayLine = Nil then Exit;
     BankName:=ExtractPartFromExtTransactionInfo(PayLine.ExtTransactionInfo, 'BANK:');
     if (PayLine.OriginalSum <= minordersum) or SpasiboExists or (BankName<>'SBRF') then
     Exit;
       
     // Spasibo card code: between "PdsCard=" and "/"
     CardCode := ExtractPartFromExtTransactionInfo(PayLine.ExtTransactionInfo, 'PdsCard=');
     if copy(CardCode,1,1)='H' then
     CardCode := Copy(CardCode, 2, 255);
     // Slide a spasibo card
     PerformLoyalyMCR(PayLine);
       
     Editor := TNumEditor(GUI.FindComponentByName('Editor'));
     for i := 0 to RKCheck.CurrentOrder.Sessions.McrPays.Count - 1 do begin
     McrPay := TMcrPay(RKCheck.CurrentOrder.Sessions.McrPays.Items[i]);
     // Checking mcr-payment for spasibo card
     if (McrPay.CardNum = CardCode) and (McrPay.Amount >= minordersum - 1) then begin
     k := GUI.MessageDlgEx('Предложите гостю оплатить заказ бонусами "Спасибо". ' +
     'К оплате бонусов: ' + FloatToStr(McrPay.Amount), mtInformation,
     mbYes + mbNo + mbCancel, 'Полностью;Частично;Не списывать');
     if k = ID_YES then begin // Maximum
     RKCheck.DeleteCheckItem(PayLine);
     if a = 0 then
     a := RKCheck.CurrentOrder.ToPaySum
     else a := RKCheck.CurrentOrder.ToPaySum - a;
     if a > McrPay.Amount then
     a := McrPay.Amount
     else a := a - 1;
     Editor.Text := FloatToStr(a);
     RKCheck.CreateCheckItem(rkrefCurrencies, IntToStr(McrPay.Code), McrPay.CardNum);
     Result:=True;
     end else if k = ID_NO then begin // Partially
     RKCheck.DeleteCheckItem(PayLine);
     Result:=True;
     end;
     Exit;
     end;
     end;
     // Mcr-pay not found, Result=False
    end;
    procedure CheckLoyaltyOnAuthorization;
    var i:integer;
     it: TCheckItem;
     PayLine: TPayLine;
    begin
     PayLine := Nil;
     for i := 0 to RKCheck.CurrentOrder.Sessions.LinesCount - 1 do begin
       it := RKCheck.CurrentOrder.Sessions.Lines[i];
          if SYS.ObjectInheritsFrom(TObject(it), 'TPayLine') then begin
              if TPayLine(it).TransactionStatus = tsAuthorizing then
     PayLine := TPayLine(it)
     end;
     end;
     if PayLine = Nil then Exit;
     if SpasiboOnAuthorize(PayLine) then exit;
     RK7.PerformOperation(rkoReAuhorizePay, 0);
    end;

    minordersum = 250 — минимальная сумма заказа при которой можно использовать оплату баллами "Спасибо", где:

    •  SpasiboCurrencyCode =126 — это код валюты, у которой в качестве интерфейса выбран интерфейс Спасибо. В данном случае, при настройке Extspasibo.ini выбрана валюта с кодом 12

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

      const minordersum = 2;
      const SpasiboCurrencyCode = 97;
      const RESERVE_VALUE = 1.0;
       
      function ExtractPartFromExtTransactionInfo(ExtTransactionInfo:String;
      PartName:String):String;
      var i:Integer;
       s:string;
      begin
        i:=pos(PartName,ExtTransactionInfo);
        if i>1 then begin
          i:=pos('/'+PartName,ExtTransactionInfo);
          if i>0 then
            i:=i+1;
        end;
        if i=0 then
          s:=''
        else begin
          s:=copy(ExtTransactionInfo,i+length(PartName),65535);
          i:=pos('/',s);
          if i>0 then
            SetLength(s,i-1);
        end;
        Result:=s;
      end;
       
      procedure PerformLoyalyMCR(PayLine: TPayLine);
      var i: integer;
        CardCode: string;
        FirstNumbers:String;
        LastNumbers:String;
        BankName:String;
      begin
        CardCode := ExtractPartFromExtTransactionInfo(PayLine.ExtTransactionInfo, 'PdsCard=');
        i:=pos(';',CardCode);
        if i > 0 then begin
          LastNumbers:=copy(CardCode,i+1,255);
          SetLength(CardCode, i-1);
        end else
          LastNumbers:='';
        FirstNumbers:=PayLine.CardNum;
        i:=pos('*',PayLine.CardNum);
        if i>0 then
          SetLength(FirstNumbers, i-1);
        BankName:=ExtractPartFromExtTransactionInfo(PayLine.ExtTransactionInfo, 'BANK:');
        // Slide a spasibo card
        //RK7.PerformMcrAlgorithSilent('BANK:'+BankName+';'+FirstNumbers+';'+LastNumbers+';'+CardCode, 1);
        RK7.PerformMcrAlgorithSilent(BankName+':'+CardCode+';'+LastNumbers, 1);
      end;
       
      function PartialSpasiboPay(PayLine: TPayLine; MCRPay: TMCRPay; prepaid: double; toPay: double): boolean;
      var
        sourceValue, a: double;
        peio: TPayExtraInfoObj;
        Editor: TNumEditor;
        CurrCode: integer
      begin
        Editor := TNumEditor(GUI.FindComponentByName('Editor'));
        peio := payLine.GetExtraInfoObj();
        sourceValue := payLine.BasicSum;
        CurrCode := PayLine.RefItem.Code;
        RKCheck.DeleteCheckItem(PayLine);
        Editor.Text := FloatToStr(toPay);
        RKCheck.CreateCheckItem(rkrefCurrencies, IntToStr(McrPay.Code), McrPay.CardNum);
        a := RKCheck.CurrentOrder.ToPaySum - prepaid - toPay;
        if a > sourceValue then
          a := sourceValue;
        Editor.Text := '';
        RKCheck.CreatePayLine(CurrCode, a, peio);
        Result := True;
      end;
       
      function SpasiboOnAuthorize(PayLine: TPayLine):Boolean;
      var i, k: integer;
        CardCode: string;
        it: TCheckItem;
        McrPay: TMcrPay;
        prepaid: double;
        SpasiboExists: boolean;
        BankName:String;
        toPay: double;
        newValStr: string;
        a: double;
      begin
        //Exit; //Uncomment me to disable auto write-off SB SPASIBO
        Result:=False;
        prepaid := 0;
        SpasiboExists := False;
        for i := 0 to RKCheck.CurrentOrder.Sessions.LinesCount - 1 do begin
          it := RKCheck.CurrentOrder.Sessions.Lines[i];
          if SYS.ObjectInheritsFrom(TObject(it), 'TPayLine') then begin
            if it.Code = trunc(SpasiboCurrencyCode) then
              SpasiboExists := True;
            if (it<>PayLine) and (it.State <> disClosed) and (it.State <> disDeleted) then
              prepaid := prepaid + TPayLine(it).BasicSum;
          end;
        end;
        if PayLine = Nil then Exit;
        BankName:=ExtractPartFromExtTransactionInfo(PayLine.ExtTransactionInfo, 'BANK:');
        //gui.showmessage('BankName: '+BankName+' paid='+floattostr(prepaid));
        if (PayLine.OriginalSum <= minordersum) or SpasiboExists or (BankName<>'SBRF') then
          Exit;
          
        // Spasibo card code: between "PdsCard=" and "/"
        CardCode := ExtractPartFromExtTransactionInfo(PayLine.ExtTransactionInfo, 'PdsCard=');
        if copy(CardCode,1,1)='H' then
          CardCode := Copy(CardCode, 2, 255);
        // Slide a spasibo card
        PerformLoyalyMCR(PayLine);
          
        //gui.showmessage('McrPays.Count= '+inttostr(RKCheck.CurrentOrder.Sessions.McrPays.Count));
        for i := 0 to RKCheck.CurrentOrder.Sessions.McrPays.Count - 1 do begin
          McrPay := TMcrPay(RKCheck.CurrentOrder.Sessions.McrPays.Items[i]);
          // Checking mcr-payment for spasibo card
          if (McrPay.CardNum = CardCode) and (McrPay.Amount >= minordersum - RESERVE_VALUE) then begin
            a := prepaid;
            if a < RESERVE_VALUE then
              a := RESERVE_VALUE;
            toPay := RKCheck.CurrentOrder.ToPaySum - a;
            if toPay > McrPay.Amount then
              toPay := McrPay.Amount;
            repeat
              k := GUI.MessageDlgEx('Предложите гостю оплатить заказ бонусами "Спасибо". ' +
                'Можно потратить бонусов: ' + FloatToStr(toPay), mtInformation,
                mbYes + mbNo + mbCancel, 'Полностью;Частично;Не списывать');     
              if k = ID_YES then
                Result := PartialSpasiboPay(PayLine, McrPay, prepaid, toPay)
              else
                if k = ID_NO then begin // Partially
                  newValStr := gui.InputBox('','Введите сумму баллов "Спасибо", которую надо потратить, не менее '+FloatToStr(minordersum - RESERVE_VALUE), floattostr(toPay), true);
                  a := StrToFloat(newValStr);
                  if a < minordersum - 1 then begin
                    gui.showMessage('Слишком маленькая сумма, нельзя тратить менее '+FloatToStr(minordersum - RESERVE_VALUE));
                  end else begin
                    if a > toPay then
                      a := toPay;
                    Result := PartialSpasiboPay(PayLine, McrPay, prepaid, a);
                    Exit;
                  end;
                end;
            until k <> ID_NO;
            Exit;
          end;
        end;
        // Mcr-pay not found, Result=False
      end;
       
      procedure CheckLoyaltyOnAuthorization;
      var i:integer;
        it: TCheckItem;
        PayLine: TPayLine;
      begin
        PayLine := Nil;
        // Looking for payment in tsAuthoring state
        for i := 0 to RKCheck.CurrentOrder.Sessions.LinesCount - 1 do begin
          it := RKCheck.CurrentOrder.Sessions.Lines[i];
          if SYS.ObjectInheritsFrom(TObject(it), 'TPayLine') then begin
            if TPayLine(it).TransactionStatus = tsAuthorizing then
              PayLine := TPayLine(it)
          end;
        end;
        if PayLine = Nil then Exit;
        if SpasiboOnAuthorize(PayLine) then exit;
        RK7.PerformOperation(rkoReAuhorizePay, 0);
      end;

  7. Сохраните изменения
  8. Модифицированную форму назначьте для схемы форм, которая будет применяться на станции

Настроенную схему форм добавьте в использование.  

Пользовательский сценарий работы на кассовой станции

В данном примере использован сценарий работы в быстром чеке.

  1. Наполните заказ позициями меню
    Если стоимость заказа меньше указанного в скрипте значение const minordersum = 250 — процесс расчета аналогичен классической оплате по банковской карте, при выборе формы чека с настроенной информацией о статусах в системе "Спасибо" можно наблюдать количество начисленных балов
  2. Нажмите кнопку Оплатить Рубли > Кредитные карты > Валюта VISA

  3. Будет получено сообщение о подтверждении операции

    Подтверждение можно исключить, если назначить валюте Автозаполнение в значение Вся сумма.
  4. Согласитесь с подтверждением, далее произойдет оплата:

  5. После настроек печати чека вы увидите начисление баллов Спасибо, при печати
  6. Сумма заказа превышает порог, назначенный переменной minordersum, в нашем случае это 250 рублей.
    После прохождения Оплатить Рубли > Кредитные карты > Валюта VISA будет получено сообщение, формируемое в скрипте:
  7. От выбора кнопки зависит дальнейший расчет:
    • Полностью — бонусами оплачивается вся сумма минус 1 рубль, его оплачиваем наличными или банковской картой


    • Частично — укажите сумму частичной оплаты балами и выберите валюту, указанную при настройке Extspasibo.ini  для оплаты балами Спасибо. В данном случае выбрана валюта с кодом 126

    • Остаток доплатите рублями


    • Не списывать — простая оплата картой, с начислением баллов по программе "Спасибо"