Тариф, учитывающий время проезда по маршруту и километраж — различия между версиями

Материал из TaxiMaster
Перейти к: навигация, поиск
 
Строка 88: Строка 88:
 
//          </param>
 
//          </param>
 
//          <param>
 
//          <param>
//            <code>CITY_MINUTE_INCLUDE</code>
+
//            <code>CITY_MINUTES_INCLUDED</code>
//            <type>integer</type>
+
//            <type>float</type>
//            <name>Сколько минут включено в поездку</name>
+
//            <name>Сколько минут включено в посадку</name>
 
//          </param>
 
//          </param>
 
//          <param>
 
//          <param>
 
//            <code>CITY_MINUTE_COST</code>
 
//            <code>CITY_MINUTE_COST</code>
 
//            <type>currency</type>
 
//            <type>currency</type>
//            <name>Стоимость минуты</name>
+
//            <name>Цена минуты далее</name>
 
//          </param>
 
//          </param>
 
//        </items>
 
//        </items>
Строка 134: Строка 134:
 
//          </param>
 
//          </param>
 
//          <param>
 
//          <param>
//            <code>COUNTRY_MINUTE_INCLUDE</code>
+
//            <code>COUNTRY_MINUTES_INCLUDED</code>
//            <type>integer</type>
+
//            <type>float</type>
//            <name>Сколько минут включено в поездку</name>
+
//            <name>Сколько минут включено в посадку</name>
 
//          </param>
 
//          </param>
 
//          <param>
 
//          <param>
 
//            <code>COUNTRY_MINUTE_COST</code>
 
//            <code>COUNTRY_MINUTE_COST</code>
 
//            <type>currency</type>
 
//            <type>currency</type>
//            <name>Стоимость минуты</name>
+
//            <name>Цена минуты далее</name>
 
//          </param>
 
//          </param>
 
//        </items>
 
//        </items>
Строка 661: Строка 661:
 
   CITY_KM_INCLUDED = 0;
 
   CITY_KM_INCLUDED = 0;
 
   CITY_KM_COST = 0;
 
   CITY_KM_COST = 0;
   CITY_MINUTE_INCLUDE = 0;
+
   CITY_MINUTES_INCLUDED = 0;
 
   CITY_MINUTE_COST = 0;
 
   CITY_MINUTE_COST = 0;
 
   BOARDING_COUNTRY = 0;
 
   BOARDING_COUNTRY = 0;
 
   COUNTRY_KM_INCLUDED = 0;
 
   COUNTRY_KM_INCLUDED = 0;
 
   COUNTRY_KM_COST = 0;
 
   COUNTRY_KM_COST = 0;
 +
  COUNTRY_MINUTES_INCLUDED = 0;
 
   COUNTRY_MINUTE_COST = 0;
 
   COUNTRY_MINUTE_COST = 0;
  COUNTRY_MINUTE_INCLUDE = 0;
 
 
   SOURCE_COUNTRY_KM_COST = 0;
 
   SOURCE_COUNTRY_KM_COST = 0;
 
   BOARDING_HOURLY = 0;
 
   BOARDING_HOURLY = 0;
Строка 1028: Строка 1028:
 
       if NeedPrintToBill then
 
       if NeedPrintToBill then
 
       begin
 
       begin
         WriteStr('Bill', 'Text', 'Скидка/наценка ''' +
+
        if F > 0 then
 +
          S := 'Наценка'
 +
        else
 +
          S := 'Скидка';
 +
         WriteStr('Bill', 'Text', S + ' ''' +
 
           ReadStr('DiscMarkupName', i) + '''');
 
           ReadStr('DiscMarkupName', i) + '''');
         WriteStr('Bill', 'Sum', FloatToStr(F, 2));
+
         WriteStr('Bill', 'Sum', FloatToStr(Abs(F), 2));
 
       end;
 
       end;
 
       // + это наценка, - это скидка.
 
       // + это наценка, - это скидка.
Строка 1040: Строка 1044:
 
       if NeedPrintToBill then
 
       if NeedPrintToBill then
 
       begin
 
       begin
         WriteStr('Bill', 'Text', 'Скидка/наценка ''' +
+
        if F > 0 then
 +
          S := 'Наценка'
 +
        else
 +
          S := 'Скидка';
 +
         WriteStr('Bill', 'Text', S + ' ''' +
 
           ReadStr('DiscMarkupName', i) + '''');
 
           ReadStr('DiscMarkupName', i) + '''');
         WriteStr('Bill', 'Sum', FloatToStr(F, 0) + '%');
+
         WriteStr('Bill', 'Sum', FloatToStr(Abs(F), 0) + '%');
 
       end;
 
       end;
 
       // + это наценка, - это скидка.
 
       // + это наценка, - это скидка.
Строка 1172: Строка 1180:
 
var
 
var
 
   Sum, F, CityDist, CountryDist, TotalDist, HourlyPayDist,
 
   Sum, F, CityDist, CountryDist, TotalDist, HourlyPayDist,
   ZonePathSum, TaxmZonesSum, MinuteSum: Single;
+
   ZonePathSum, TaxmZonesSum: Single;
 
   CityCost, CountryCost: Single;
 
   CityCost, CountryCost: Single;
   i, StopCount: Integer;
+
   i, StopCount, TripTime: Integer;
 
   NeedZoneOutCost: Boolean;
 
   NeedZoneOutCost: Boolean;
 +
  CityTripTime, CountryTripTime: Integer;
 
begin
 
begin
 
   Sum := 0;
 
   Sum := 0;
Строка 1215: Строка 1224:
 
     CountryDist := 0;
 
     CountryDist := 0;
 
   TotalDist := CityDist + CountryDist;
 
   TotalDist := CityDist + CountryDist;
 +
  TripTime := ReadInt('TripTime');
  
 +
  // Почасовой заказ.
 
   if ReadBool('IsHourly') then
 
   if ReadBool('IsHourly') then
 
   begin
 
   begin
 
     F := BOARDING_HOURLY;
 
     F := BOARDING_HOURLY;
     if ReadInt('TripTime') div 60 > HOURLY_MINUTES_INCLUDED then
+
     if TripTime div 60 > HOURLY_MINUTES_INCLUDED then
 
       if HOURLY_PERIOD = 0 then
 
       if HOURLY_PERIOD = 0 then
         F := F + (ReadInt('TripTime') div 60 - HOURLY_MINUTES_INCLUDED) *
+
         F := F + (TripTime div 60 - HOURLY_MINUTES_INCLUDED) *
 
           HOURLY_MINUTE_COST
 
           HOURLY_MINUTE_COST
 
       else
 
       else
         F := F + Ceil((ReadInt('TripTime') div 60 - HOURLY_MINUTES_INCLUDED) /
+
         F := F + Ceil((TripTime div 60 - HOURLY_MINUTES_INCLUDED) /
 
           HOURLY_PERIOD) * HOURLY_PERIOD * HOURLY_MINUTE_COST;
 
           HOURLY_PERIOD) * HOURLY_PERIOD * HOURLY_MINUTE_COST;
 
     if F <> 0 then
 
     if F <> 0 then
Строка 1231: Строка 1242:
 
       WriteStr('Bill', 'Text', 'Продолжительность');
 
       WriteStr('Bill', 'Text', 'Продолжительность');
 
       WriteStr('Bill', 'Value',
 
       WriteStr('Bill', 'Value',
         IntToStr(ReadInt('TripTime') div 60) + ' мин');
+
         IntToStr(TripTime div 60) + ' мин');
 
       WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
       WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
     end;
 
     end;
  
    F := 0;
+
     if HOURLY_KM_COST > 0 then
    HourlyPayDist := 0;
 
     if HOURLY_HOUR_KM_INCLUDED > 0 then
 
 
     begin
 
     begin
       HourlyPayDist := (TotalDist - HOURLY_HOUR_KM_INCLUDED *
+
       F := 0;
        Ceil(ReadInt('TripTime') / 60 / 60));
+
      HourlyPayDist := 0;
      F := HourlyPayDist * HOURLY_KM_COST;
+
      if HOURLY_HOUR_KM_INCLUDED > 0 then
    end
+
      begin
    else
+
        HourlyPayDist := (TotalDist - HOURLY_HOUR_KM_INCLUDED *
 +
          Ceil(TripTime / 60 / 60));
 +
        F := HourlyPayDist * HOURLY_KM_COST;
 +
      end
 +
      else
 
       if HOURLY_TRIP_KM_INCLUDED > 0 then
 
       if HOURLY_TRIP_KM_INCLUDED > 0 then
 
       begin
 
       begin
 
         HourlyPayDist := TotalDist - HOURLY_TRIP_KM_INCLUDED;
 
         HourlyPayDist := TotalDist - HOURLY_TRIP_KM_INCLUDED;
 
         F := HourlyPayDist * HOURLY_KM_COST;
 
         F := HourlyPayDist * HOURLY_KM_COST;
 +
      end
 +
      else
 +
      begin
 +
        HourlyPayDist := TotalDist;
 +
        F := TotalDist * HOURLY_KM_COST;
 +
      end;
 +
      if F > 0 then
 +
      begin
 +
        Sum := Sum + F;
 +
        WriteStr('Bill', 'Text', 'Платный километраж');
 +
        WriteStr('Bill', 'Value',
 +
          FloatToStr(HourlyPayDist, 2) + ' км');
 +
        WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
       end;
 
       end;
    if F > 0 then
 
    begin
 
      Sum := Sum + F;
 
      WriteStr('Bill', 'Text', 'Платный километраж');
 
      WriteStr('Bill', 'Value',
 
        FloatToStr(HourlyPayDist, 2) + ' км');
 
      WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
 
     end;
 
     end;
 
   end
 
   end
 
   else
 
   else
 
   begin
 
   begin
 +
    // Загородный заказ.
 
     if ReadBool('IsCountry') then
 
     if ReadBool('IsCountry') then
 
     begin
 
     begin
Строка 1281: Строка 1301:
 
       CountryCost := F - CityCost;
 
       CountryCost := F - CityCost;
  
      MinuteSum := (ReadInt('TripTime') / 60 - COUNTRY_MINUTE_INCLUDE) * COUNTRY_MINUTE_COST;
 
     
 
      if MinuteSum > 0 then
 
      begin
 
        Sum := Sum + MinuteSum;
 
        WriteStr('Bill', 'Text', 'Длительность');
 
        WriteStr('Bill', 'Value',
 
          FloatToStr((ReadInt('TripTime') / 60 - COUNTRY_MINUTE_INCLUDE), 2) + ' мин.');
 
        WriteStr('Bill', 'Sum', FloatToStr(MinuteSum, 2));
 
      end;
 
     
 
 
       if F <> 0 then
 
       if F <> 0 then
 
       begin
 
       begin
Строка 1299: Строка 1308:
 
           FloatToStr(TotalDist, 2) + ' км');
 
           FloatToStr(TotalDist, 2) + ' км');
 
         WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
         WriteStr('Bill', 'Sum', FloatToStr(F, 2));
       
 
 
         if ReadBool('BackFree') then
 
         if ReadBool('BackFree') then
 
         begin
 
         begin
Строка 1316: Строка 1324:
 
             WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
             WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
           end;
 
           end;
 +
        end;
 +
      end;
 +
 +
      if ((COUNTRY_MINUTE_COST > 0) or (CITY_MINUTE_COST > 0)) and
 +
        (TripTime > COUNTRY_MINUTES_INCLUDED * 60) and
 +
        (TotalDist > 0) then
 +
      begin
 +
        CountryTripTime := Floor(TripTime * (CountryDist / TotalDist));
 +
        CityTripTime := Floor(TripTime - CountryTripTime);
 +
 +
        if CityTripTime <= COUNTRY_MINUTES_INCLUDED * 60 then
 +
        begin
 +
          CityCost := 0;
 +
          CountryCost := (TripTime / 60 - COUNTRY_MINUTES_INCLUDED) * COUNTRY_MINUTE_COST
 +
        end
 +
        else
 +
        begin
 +
          CityCost := (CityTripTime / 60 - COUNTRY_MINUTES_INCLUDED) * CITY_MINUTE_COST;
 +
          CountryCost := CountryTripTime / 60 * COUNTRY_MINUTE_COST;
 +
        end;
 +
 +
        F := CityCost + CountryCost;
 +
        if F <> 0 then
 +
        begin
 +
          Sum := Sum + F;
 +
 +
          WriteStr('Bill', 'Text', 'Длительность по городу');
 +
          WriteStr('Bill', 'Value', TimeLenToStr(CityTripTime));
 +
          WriteStr('Bill', 'Sum', FloatToStr(CityCost, 2));
 +
 +
          WriteStr('Bill', 'Text', 'Длительность за городом');
 +
          WriteStr('Bill', 'Value', TimeLenToStr(CountryTripTime));
 +
          WriteStr('Bill', 'Sum', FloatToStr(CountryCost, 2));
 
         end;
 
         end;
 
       end;
 
       end;
 
     end
 
     end
 
     else
 
     else
 +
    // Городской заказ.
 
     begin
 
     begin
 
       F := BOARDING_CITY;
 
       F := BOARDING_CITY;
 
       if TotalDist > CITY_KM_INCLUDED then
 
       if TotalDist > CITY_KM_INCLUDED then
 
         F := F + (TotalDist - CITY_KM_INCLUDED) * CITY_KM_COST;
 
         F := F + (TotalDist - CITY_KM_INCLUDED) * CITY_KM_COST;
       
+
 
      MinuteSum := (ReadInt('TripTime') / 60 - CITY_MINUTE_INCLUDE) * CITY_MINUTE_COST;
 
     
 
      if MinuteSum > 0 then
 
      begin
 
        Sum := Sum + MinuteSum;
 
        WriteStr('Bill', 'Text', 'Длительность');
 
        WriteStr('Bill', 'Value',
 
          FloatToStr((ReadInt('TripTime') / 60 - CITY_MINUTE_INCLUDE), 2) + ' мин.');
 
        WriteStr('Bill', 'Sum', FloatToStr(MinuteSum, 2));
 
      end;
 
     
 
 
       if F <> 0 then
 
       if F <> 0 then
 
       begin
 
       begin
Строка 1343: Строка 1374:
 
           FloatToStr(TotalDist, 2) + ' км');
 
           FloatToStr(TotalDist, 2) + ' км');
 
         WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
         WriteStr('Bill', 'Sum', FloatToStr(F, 2));
       
 
 
         if ReadBool('BackFree') then
 
         if ReadBool('BackFree') then
 
           if (CITY_BACK_WAY_PERCENT <> 0) then
 
           if (CITY_BACK_WAY_PERCENT <> 0) then
Строка 1352: Строка 1382:
 
             WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
             WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
           end;
 
           end;
 +
      end;
 +
 +
      if (CITY_MINUTE_COST > 0) and
 +
        (TripTime > CITY_MINUTES_INCLUDED * 60) then
 +
      begin
 +
        F := (TripTime / 60 - CITY_MINUTES_INCLUDED) * CITY_MINUTE_COST;
 +
        if F <> 0 then
 +
        begin
 +
          Sum := Sum + F;
 +
          WriteStr('Bill', 'Text', 'Длительность по городу');
 +
          WriteStr('Bill', 'Value', TimeLenToStr(TripTime));
 +
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 +
        end;
 
       end;
 
       end;
 
     end;
 
     end;
Строка 1498: Строка 1541:
 
       WriteFloat('Sum', Sum);
 
       WriteFloat('Sum', Sum);
 
       WriteStr('SumStr', FloatToStrFixed(RoundSum(Sum)));
 
       WriteStr('SumStr', FloatToStrFixed(RoundSum(Sum)));
 +
      WriteFloat('CurrentSum', Sum);
 
     end;
 
     end;
  
Строка 1618: Строка 1662:
 
     WriteInt('Button', 'Enabled', 1);
 
     WriteInt('Button', 'Enabled', 1);
 
     WriteInt('Button', 'LongClick', 1);
 
     WriteInt('Button', 'LongClick', 1);
     WriteStr('Button', 'Text', ServiceName)
+
     WriteStr('Button', 'Text', ServiceName);
 
   end;
 
   end;
 
end;
 
end;
Строка 1796: Строка 1840:
 
   begin
 
   begin
 
     WriteStr('Bill', 'Code', 'DISC_SUM');
 
     WriteStr('Bill', 'Code', 'DISC_SUM');
     WriteStr('Bill', 'Text', 'Скидка');
+
     if DiscountSum < 0 then
     WriteStr('Bill', 'Sum', FloatToStr(DiscountSum, 2));
+
      WriteStr('Bill', 'Text', 'Наценка')
 +
    else
 +
      WriteStr('Bill', 'Text', 'Скидка');
 +
     WriteStr('Bill', 'Sum', FloatToStr(Abs(DiscountSum), 2));
 
   end;
 
   end;
  
Строка 1804: Строка 1851:
 
   begin
 
   begin
 
     WriteStr('Bill', 'Code', 'DISC_PERCENT');
 
     WriteStr('Bill', 'Code', 'DISC_PERCENT');
     WriteStr('Bill', 'Text', 'Скидка');
+
     if DiscountPercent < 0 then
     WriteStr('Bill', 'Sum', FloatToStr(DiscountPercent, 0) + '%');
+
      WriteStr('Bill', 'Text', 'Наценка')
 +
    else
 +
      WriteStr('Bill', 'Text', 'Скидка');
 +
     WriteStr('Bill', 'Sum', FloatToStr(Abs(DiscountPercent), 0) + '%');
 
   end;
 
   end;
  
Строка 1833: Строка 1883:
 
       (ReadFloat('TMRouteDistance') > 0) then
 
       (ReadFloat('TMRouteDistance') > 0) then
 
     begin
 
     begin
       if ReadFloat('TMRouteDistance') > ReadFloat('Temp', 'KMIncluded') then
+
       if ReadFloat('TMRouteDistance') > ReadFloat('Temp', 'KmIncluded') then
 
       begin
 
       begin
 
         if ReadFloat('TMRouteCountryDistance') = 0 then
 
         if ReadFloat('TMRouteCountryDistance') = 0 then
           DistanceSum := (ReadFloat('TMRouteDistance') - ReadFloat('Temp', 'KMIncluded')) * CITY_KM_COST
+
           DistanceSum := (ReadFloat('TMRouteDistance') - ReadFloat('Temp', 'KmIncluded')) * CITY_KM_COST
 
         else
 
         else
         if ReadFloat('TMRouteCityDistance') > ReadFloat('Temp', 'KMIncluded') then
+
         if ReadFloat('TMRouteCityDistance') > ReadFloat('Temp', 'KmIncluded') then
           DistanceSum := (ReadFloat('TMRouteCityDistance') - ReadFloat('Temp', 'KMIncluded')) * CITY_KM_COST +
+
           DistanceSum := (ReadFloat('TMRouteCityDistance') - ReadFloat('Temp', 'KmIncluded')) * CITY_KM_COST +
 
             ReadFloat('TMRouteCountryDistance') * COUNTRY_KM_COST
 
             ReadFloat('TMRouteCountryDistance') * COUNTRY_KM_COST
 
         else
 
         else
           DistanceSum := (ReadFloat('TMRouteDistance') - ReadFloat('Temp', 'KMIncluded')) * COUNTRY_KM_COST;
+
           DistanceSum := (ReadFloat('TMRouteDistance') - ReadFloat('Temp', 'KmIncluded')) * COUNTRY_KM_COST;
 
       end
 
       end
 
       else
 
       else
Строка 1858: Строка 1908:
 
     end;
 
     end;
 
   end;
 
   end;
 +
end;
  
end;
 
  
// Рассчитать полную стоимость поездки.
+
// Заполнить дополнительную информацию по тарифу в таксометре.
procedure TMD_CalcTaximeterSum;
+
procedure TMD_FillMoreInfo;
 
var
 
var
   Sum, DriverServicesSum: Single;
+
   BoardingMoreInfo, CityMoreInfo, CountryMoreInfo: String;
   DriverServicesPercent: Integer;
+
   HasKmCost, HasMinutesCost: Boolean;
  IsTripFinished: Boolean;
 
 
begin
 
begin
   Sum := 0;
+
   WriteStr('MoreInfo', 0, 'Тариф: ' + ReadStr('TariffName'));
  TMD_RecheckDriverServiceButtons;
 
  // Стоимость всех водительских услуг.
 
  TMD_GetDriverServicesSum(DriverServicesSum, DriverServicesPercent);
 
  
 
   if CALC_SUM_BY_TAXIMETER then
 
   if CALC_SUM_BY_TAXIMETER then
 
   begin
 
   begin
     IsTripFinished := ReadInt('Temp', 'TripFinished') = 1;
+
     if not ReadBool('IsHourly') then
 +
    begin
 +
      // Если задан хоть один параметр города или загорода, нужно будет выводить оба,
 +
      // даже если цена будет 0.
 +
      HasKmCost := (CITY_KM_COST <> 0) or (COUNTRY_KM_COST <> 0);
 +
      HasMinutesCost := (CITY_MINUTE_COST <> 0) or (COUNTRY_MINUTE_COST <> 0);
 +
 
 +
      // Выводим подробный текст в поле посадки, если есть включенные км или минуты,
 +
      // с учетом того, что есть соответствующие цены.
 +
      if ((ReadFloat('Temp', 'KmIncluded') <> 0) and HasKmCost) or
 +
        ((ReadFloat('Temp', 'MinutesIncluded') <> 0) and HasMinutesCost) then
 +
      begin
 +
        BoardingMoreInfo := 'Первые';
 +
        if HasKmCost then
 +
          BoardingMoreInfo := BoardingMoreInfo +
 +
            ' ' + FloatToStr(ReadFloat('Temp', 'KmIncluded')) + ' км';
 +
        if HasMinutesCost then
 +
          BoardingMoreInfo := BoardingMoreInfo +
 +
            ' ' + FloatToStr(ReadFloat('Temp', 'MinutesIncluded')) + ' мин';
 +
 
 +
        CityMoreInfo := 'Далее город:';
 +
        CountryMoreInfo := 'Далее загород:';
 +
      end
 +
      else
 +
      // Иначе выводим обычный текст.
 +
      begin
 +
        BoardingMoreInfo := 'Посадка';
 +
        CityMoreInfo := 'Город:';
 +
        CountryMoreInfo := 'Загород:';
 +
      end;
 +
 
 +
      // В конце строки посадки всегда пишем сумму посадки.
 +
      BoardingMoreInfo := BoardingMoreInfo +
 +
        ': ' + FloatToStrFixed(ReadFloat('Temp', 'BoardingSum')) + ' ' + VALUTA;
 +
 
 +
      // Если есть цена за км, либо вообще нет ни одной цены, то выводим цену за км.
 +
      if HasKmCost or not HasMinutesCost then
 +
      begin
 +
        CityMoreInfo := CityMoreInfo +
 +
          ' ' + FloatToStrFixed(CITY_KM_COST) + ' ' + VALUTA + '/км';
 +
        CountryMoreInfo := CountryMoreInfo +
 +
          ' ' + FloatToStrFixed(COUNTRY_KM_COST) + ' ' + VALUTA + '/км';
 +
      end;
  
    Sum := Sum + ReadFloat('Temp', 'PayWaitTimeSum') +
+
      // Если есть цена за минуты, то выводим ее.
      ReadFloat('Temp', 'PriorOrderCost') +
+
      // Если при этом была цена за км, то цена за минуты выводится дополнительно.
      ReadFloat('Temp', 'SourceDistCountrySum') +
+
      if HasMinutesCost then
      ReadFloat('Temp', 'BoardingSum');
+
      begin
 +
        CityMoreInfo := CityMoreInfo +  
 +
          ' ' + FloatToStrFixed(CITY_MINUTE_COST) + ' ' + VALUTA + '/мин';
 +
        CountryMoreInfo := CountryMoreInfo +  
 +
          ' ' + FloatToStrFixed(COUNTRY_MINUTE_COST) + ' ' + VALUTA + '/мин';
 +
      end;
  
    if ReadBool('IsHourly') then
+
      if IDLE_MINUTE_COST <> 0 then
      Sum := Sum + ReadFloat('Temp', 'TripTimeSum') +
+
        WriteStr('MoreInfo', 1, 'Простой: ' +
        ReadFloat('Temp', 'HourlyDistSum')
+
          FloatToStrFixed(IDLE_MINUTE_COST) + ' ' + VALUTA + '/мин');
 +
      if ReadFloat('Temp', 'MinSum') <> 0 then
 +
        WriteStr('MoreInfo', 2, 'Минимум: ' +
 +
          FloatToStrFixed(ReadFloat('Temp', 'MinSum')) + ' ' + VALUTA);
 +
      WriteStr('MoreInfo', 3, BoardingMoreInfo);
 +
      WriteStr('MoreInfo', 4, CityMoreInfo);
 +
      WriteStr('MoreInfo', 5, CountryMoreInfo);
 +
    end
 
     else
 
     else
 
     begin
 
     begin
       if not IsTripFinished and TMD_UseCalcTMRoute then
+
       if MIN_HOURLY <> 0 then
         TMD_RecalcDistSum;
+
         WriteStr('MoreInfo', 1, 'Минимум: ' +
 
+
          FloatToStrFixed(MIN_HOURLY) + ' ' + VALUTA);
       Sum := Sum + ReadFloat('Temp', 'DistanceSum') +
+
      if HOURLY_MINUTES_INCLUDED = 0 then
         ReadFloat('Temp', 'TripTimeSum') +
+
       begin
         ReadFloat('Temp', 'GPSLostDistSum') +
+
        WriteStr('MoreInfo', 3, 'Посадка: ' +
         ReadFloat('Temp', 'IdleTimeSum') +
+
          FloatToStrFixed(BOARDING_HOURLY) + ' ' + VALUTA);
         ReadFloat('Temp', 'StopsSum') +
+
         if HOURLY_PERIOD > 0 then
         ReadFloat('Temp', 'StopTimeSum');
+
          WriteStr('MoreInfo', 4, IntToStr(HOURLY_PERIOD) + ' мин: ' +
 +
            FloatToStrFixed(HOURLY_MINUTE_COST * HOURLY_PERIOD) + ' ' + VALUTA)
 +
         else
 +
          WriteStr('MoreInfo', 4, '1 час: ' +
 +
            FloatToStrFixed(HOURLY_MINUTE_COST * 60) + ' ' + VALUTA);
 +
      end
 +
      else
 +
      begin
 +
         WriteStr('MoreInfo', 3, 'Первые ' + IntToStr(HOURLY_MINUTES_INCLUDED) + ' мин: ' +
 +
          FloatToStrFixed(BOARDING_HOURLY) + ' ' + VALUTA);
 +
         if HOURLY_PERIOD > 0 then
 +
          WriteStr('MoreInfo', 4, 'Далее ' + IntToStr(HOURLY_PERIOD) + ' мин: ' +
 +
            FloatToStrFixed(HOURLY_MINUTE_COST * HOURLY_PERIOD) + ' ' + VALUTA)
 +
         else
 +
          WriteStr('MoreInfo', 4, 'Далее 1 час: ' +
 +
            FloatToStrFixed(HOURLY_MINUTE_COST * 60) + ' ' + VALUTA);
 +
      end;
 
     end;
 
     end;
 +
  end;
 +
end;
  
    if not USE_REAL_ZONES_IN_TAXM then
 
      Sum := Sum + ReadFloat('TaxmZonesSum')
 
    else
 
      Sum := Sum + ReadFloat('Temp', 'ZoneStopSum') +
 
        ReadFloat('Temp', 'ZonePathSum') +
 
        ReadFloat('Temp', 'ZoneInCost') +
 
        ReadFloat('Temp', 'ZoneOutCost');
 
  
    if not SERVICES_AFTER_MIN then
+
// Рассчитать полную стоимость поездки.
    begin
+
procedure TMD_CalcTaximeterSum;
      if IsTripFinished then
+
var
        TMD_AddServices;
+
  Sum, DriverServicesSum: Single;
      Sum := Sum + ReadFloat('ServicesSum') + DriverServicesSum +
+
  DriverServicesPercent: Integer;
        Sum * (DriverServicesPercent + ReadFloat('ServicesPercent')) / 100;
+
  IsTripFinished: Boolean;
    end;
+
begin
 +
  Sum := 0;
 +
  TMD_RecheckDriverServiceButtons;
 +
  // Стоимость всех водительских услуг.
 +
  TMD_GetDriverServicesSum(DriverServicesSum, DriverServicesPercent);
 +
 
 +
  if CALC_SUM_BY_TAXIMETER then
 +
  begin
 +
    IsTripFinished := ReadInt('Temp', 'TripFinished') = 1;
  
     // Сумма без скидки.
+
     Sum := Sum + ReadFloat('Temp', 'PayWaitTimeSum') +
    // Работает только для Android.
+
      ReadFloat('Temp', 'PriorOrderCost') +
    if ReadStr('Platform') = 'Android' then
+
      ReadFloat('Temp', 'SourceDistCountrySum') +
       WriteFloat('Sum', RoundSum(Sum));
+
       ReadFloat('Temp', 'BoardingSum');
  
     if not DISCOUNT_AFTER_MIN then
+
     if ReadBool('IsHourly') then
 +
      Sum := Sum + ReadFloat('Temp', 'TripTimeSum') +
 +
        ReadFloat('Temp', 'HourlyDistSum')
 +
    else
 
     begin
 
     begin
       WriteFloat('Temp', 'SumBeforeDiscount', Sum);
+
      if not IsTripFinished and TMD_UseCalcTMRoute then
       if IsTripFinished then
+
        TMD_RecalcDistSum;
 +
 
 +
      Sum := Sum + ReadFloat('Temp', 'DistanceSum') +
 +
        ReadFloat('Temp', 'CityTripTimeSum') +
 +
        ReadFloat('Temp', 'CountryTripTimeSum') +
 +
        ReadFloat('Temp', 'GPSLostDistSum') +
 +
        ReadFloat('Temp', 'IdleTimeSum') +
 +
        ReadFloat('Temp', 'StopsSum') +
 +
        ReadFloat('Temp', 'StopTimeSum');
 +
    end;
 +
 
 +
    if not USE_REAL_ZONES_IN_TAXM then
 +
      Sum := Sum + ReadFloat('TaxmZonesSum')
 +
    else
 +
      Sum := Sum + ReadFloat('Temp', 'ZoneStopSum') +
 +
        ReadFloat('Temp', 'ZonePathSum') +
 +
        ReadFloat('Temp', 'ZoneInCost') +
 +
        ReadFloat('Temp', 'ZoneOutCost');
 +
 
 +
    if not SERVICES_AFTER_MIN then
 +
    begin
 +
      if IsTripFinished then
 +
        TMD_AddServices;
 +
      Sum := Sum + ReadFloat('ServicesSum') + DriverServicesSum +
 +
        Sum * (DriverServicesPercent + ReadFloat('ServicesPercent')) / 100;
 +
    end;
 +
 
 +
    // Сумма без скидки.
 +
    // Работает только для Android.
 +
    if ReadStr('Platform') = 'Android' then
 +
      WriteFloat('Sum', RoundSum(Sum));
 +
 
 +
    if not DISCOUNT_AFTER_MIN then
 +
    begin
 +
       WriteFloat('Temp', 'SumBeforeDiscount', Sum);
 +
       if IsTripFinished then
 
         TMD_AddDiscounts;
 
         TMD_AddDiscounts;
 
       Sum := Sum - Sum * ReadFloat('TaxmTotalDiscPercent') / 100 -
 
       Sum := Sum - Sum * ReadFloat('TaxmTotalDiscPercent') / 100 -
Строка 1992: Строка 2149:
  
 
   WriteStr('SumStr', FloatToStrFixed(Sum));
 
   WriteStr('SumStr', FloatToStrFixed(Sum));
 +
  WriteFloat('CurrentSum', Sum);
 
end;
 
end;
  
Строка 2000: Строка 2158:
 
procedure InitCalc;
 
procedure InitCalc;
 
var
 
var
   F, MinSum, Boarding, KmMinutesIncluded: Single;
+
   F, MinSum, Boarding, KmIncluded, MinutesIncluded: Single;
 
begin
 
begin
 
   TMD_InitDriverServiceButtons;
 
   TMD_InitDriverServiceButtons;
Строка 2046: Строка 2204:
 
       begin
 
       begin
 
         Boarding := BOARDING_COUNTRY;
 
         Boarding := BOARDING_COUNTRY;
         KmMinutesIncluded := COUNTRY_KM_INCLUDED;
+
         KmIncluded := COUNTRY_KM_INCLUDED;
 +
        MinutesIncluded := COUNTRY_MINUTES_INCLUDED;
 
         MinSum := MIN_COUNTRY;
 
         MinSum := MIN_COUNTRY;
 
         WriteInt('Temp', 'WasOutCity', 1);
 
         WriteInt('Temp', 'WasOutCity', 1);
Строка 2053: Строка 2212:
 
       begin
 
       begin
 
         Boarding := BOARDING_CITY;
 
         Boarding := BOARDING_CITY;
         KmMinutesIncluded := CITY_KM_INCLUDED;
+
         KmIncluded := CITY_KM_INCLUDED;
 +
        MinutesIncluded := CITY_MINUTES_INCLUDED;
 
         MinSum := MIN_CITY;
 
         MinSum := MIN_CITY;
 
         WriteInt('Temp', 'WasOutCity', 0);
 
         WriteInt('Temp', 'WasOutCity', 0);
 
       end;
 
       end;
       WriteFloat('Temp', 'KMIncluded', KmMinutesIncluded);
+
       WriteFloat('Temp', 'KmIncluded', KmIncluded);
 +
      WriteFloat('Temp', 'MinutesIncluded', MinutesIncluded);
 
     end
 
     end
 
     else
 
     else
 
     begin
 
     begin
 
       Boarding := BOARDING_HOURLY;
 
       Boarding := BOARDING_HOURLY;
      KmMinutesIncluded := HOURLY_MINUTES_INCLUDED;
 
 
       MinSum := MIN_HOURLY;
 
       MinSum := MIN_HOURLY;
 
     end;
 
     end;
Строка 2093: Строка 2253:
 
   TMD_CalcTaximeterSum;
 
   TMD_CalcTaximeterSum;
  
   WriteStr('MoreInfo', 0, 'Тариф: ' + ReadStr('TariffName'));
+
   TMD_FillMoreInfo;
  
   if CALC_SUM_BY_TAXIMETER then
+
  WriteInt('Temp', 'AllStopTime', 0);
 +
  WriteFloat('Temp', 'StopTimeSum', 0);
 +
end;
 +
 
 +
 
 +
// Использовать восстановление километража при потере GPS.
 +
function TMD_UseGPSMissedDistanceRecovery: Boolean;
 +
begin
 +
  Result := USE_GPS_MISSED_DISTANCE_RECOVERY and
 +
    (ReadInt('SupportedScriptVersion') > 0);
 +
end;
 +
 
 +
 
 +
// Пересчитать параметры, связанные с координатами.
 +
procedure TMD_RecalcLostGPSParams;
 +
var
 +
  Lat, Lon, CurTotalDistance, KmCost, DistDelta: Single;
 +
begin
 +
  Lon := ReadFloat('Lon');
 +
  Lat := ReadFloat('Lat');
 +
 
 +
  // Посчитать километраж по прямой, если появились координаты.
 +
   if (ReadInt('Temp', 'IsLostGPS') = 1) and
 +
    ((ReadFloat('Temp', 'OldLat') > 0) or
 +
    (ReadFloat('Temp', 'OldLon') > 0)) and
 +
    ((Lat > 0) or (Lon > 0)) then
 
   begin
 
   begin
     if not ReadBool('IsHourly') then
+
     DistDelta := SegmentLength(ReadFloat('Temp', 'OldLon'),
    begin
+
       ReadFloat('Temp', 'OldLat'), Lon, Lat);
      WriteStr('MoreInfo', 1, 'Простой: ' +
 
        FloatToStrFixed(IDLE_MINUTE_COST) + ' ' + VALUTA + '/мин');
 
       WriteStr('MoreInfo', 2, 'Минимум: ' +
 
        FloatToStrFixed(MinSum) + ' ' + VALUTA);
 
  
      if KmMinutesIncluded = 0 then
+
    WriteFloat('Temp', 'GpsLostKmDist',
      begin
+
      ReadFloat('Temp', 'GpsLostKmDist') + DistDelta);
        WriteStr('MoreInfo', 3, 'Посадка: ' +
+
 
          FloatToStrFixed(Boarding) + ' ' + VALUTA);
+
    CurTotalDistance := ReadFloat('Temp', 'TotalDist') + DistDelta;
        WriteStr('MoreInfo', 4, 'Город: ' +
+
 
          FloatToStrFixed(CITY_KM_COST) + ' ' + VALUTA + '/км');
+
    // При восстанавлении координат не успевает правильно
        WriteStr('MoreInfo', 5, 'Загород: ' +
+
    // определиться флаг ReadBool('InCity').
          FloatToStrFixed(COUNTRY_KM_COST) + ' ' + VALUTA + '/км');
+
    if ReadInt('Temp', 'OldInCity') > 0 then
      end
+
    begin
      else
+
      WriteFloat('Temp', 'GpsLostDistCity',
      begin
+
         ReadFloat('Temp', 'GpsLostDistCity') + DistDelta);
        WriteStr('MoreInfo', 3, FloatToStrFixed(KmMinutesIncluded) + ' км: ' +
+
       KmCost := CITY_KM_COST;
          FloatToStrFixed(Boarding) + ' ' + VALUTA);
 
        WriteStr('MoreInfo', 4, 'Далее город: ' +
 
          FloatToStrFixed(CITY_KM_COST) + ' ' + VALUTA + '/км');
 
         WriteStr('MoreInfo', 5, 'Далее загород: ' +
 
          FloatToStrFixed(COUNTRY_KM_COST) + ' ' + VALUTA + '/км');
 
       end;
 
 
     end
 
     end
 
     else
 
     else
 
     begin
 
     begin
       WriteStr('MoreInfo', 1, 'Минимум: ' +
+
       WriteFloat('Temp', 'GpsLostDistCountry',
         FloatToStrFixed(MIN_HOURLY) + ' ' + VALUTA);
+
         ReadFloat('Temp', 'GpsLostDistCountry') + DistDelta);
       if HOURLY_MINUTES_INCLUDED = 0 then
+
       KmCost := COUNTRY_KM_COST;
      begin
+
    end;
        WriteStr('MoreInfo', 3, 'Посадка: ' +
+
 
          FloatToStrFixed(BOARDING_HOURLY) + ' ' + VALUTA);
+
    if CurTotalDistance > ReadFloat('Temp', 'KmIncluded') then
        if HOURLY_PERIOD > 0 then
+
    begin
          WriteStr('MoreInfo', 4, IntToStr(HOURLY_PERIOD) + ' мин: ' +
+
      // Если при восстановлении координат сразу закончился
            FloatToStrFixed(HOURLY_MINUTE_COST * HOURLY_PERIOD) + ' ' + VALUTA)
+
      // включенный киломтраж.
        else
+
      if ReadFloat('Temp', 'TotalDist') < ReadFloat('Temp', 'KmIncluded') then
          WriteStr('MoreInfo', 4, '1 час: ' +
+
        // Платный километраж.
            FloatToStrFixed(HOURLY_MINUTE_COST * 60) + ' ' + VALUTA);
+
         DistDelta := CurTotalDistance - ReadFloat('Temp', 'KmIncluded');
      end
+
 
      else
+
      WriteFloat('Temp', 'GPSLostDistSum',
      begin
+
         ReadFloat('Temp', 'GPSLostDistSum') + KmCost * DistDelta);
         WriteStr('MoreInfo', 3, IntToStr(HOURLY_MINUTES_INCLUDED) + ' мин: ' +
 
          FloatToStrFixed(BOARDING_HOURLY) + ' ' + VALUTA);
 
        if HOURLY_PERIOD > 0 then
 
          WriteStr('MoreInfo', 4, 'Далее ' + IntToStr(HOURLY_PERIOD) + ' мин: ' +
 
            FloatToStrFixed(HOURLY_MINUTE_COST * HOURLY_PERIOD) + ' ' + VALUTA)
 
         else
 
          WriteStr('MoreInfo', 4, 'Далее 1 час: ' +
 
            FloatToStrFixed(HOURLY_MINUTE_COST * 60) + ' ' + VALUTA);
 
      end;
 
 
     end;
 
     end;
 
   end;
 
   end;
  WriteInt('Temp', 'AllStopTime', 0);
 
  WriteFloat('Temp', 'StopTimeSum', 0);
 
end;
 
  
 
+
  // Пропал сигнал GPS.
// Использовать восстановление километража при потере GPS.
+
  if (Lat = 0) and (Lon = 0) then
function TMD_UseGPSMissedDistanceRecovery: Boolean;
+
    WriteInt('Temp', 'IsLostGPS', 1)
begin
+
  else
  Result := USE_GPS_MISSED_DISTANCE_RECOVERY and
+
  // Есть сигнал GPS.
     (ReadInt('SupportedScriptVersion') > 0);
+
  begin
 +
    WriteFloat('Temp', 'OldLat', Lat);
 +
    WriteFloat('Temp', 'OldLon', Lon);
 +
    if ReadBool('InCity') then
 +
      WriteInt('Temp', 'OldInCity', 1)
 +
     else
 +
      WriteInt('Temp', 'OldInCity', 0);
 +
    WriteInt('Temp', 'IsLostGPS', 0);
 +
  end;
 
end;
 
end;
  
  
// Пересчитать параметры, связанные с координатами.
+
// *******
procedure TMD_RecalcLostGPSParams;
+
// Расчёт.
 +
// *******
 +
procedure StepCalc;
 
var
 
var
   Lat, Lon, CurTotalDistance, KmCost, DistDelta: Single;
+
   F, DistDelta, TripDistance: Single;
 +
  City: String;
 +
  Seconds: Integer;
 
begin
 
begin
  Lon := ReadFloat('Lon');
+
   if CALC_SUM_BY_TAXIMETER then
  Lat := ReadFloat('Lat');
 
 
 
  // Посчитать километраж по прямой, если появились координаты.
 
   if (ReadInt('Temp', 'IsLostGPS') = 1) and
 
    ((ReadFloat('Temp', 'OldLat') > 0) or
 
    (ReadFloat('Temp', 'OldLon') > 0)) and
 
    ((Lat > 0) or (Lon > 0)) then
 
 
   begin
 
   begin
     DistDelta := SegmentLength(ReadFloat('Temp', 'OldLon'),
+
     if ReadBool('HasCities') then
      ReadFloat('Temp', 'OldLat'), Lon, Lat);
+
    begin
 +
      if ReadBool('InCity') then
 +
        City := ' [' + ReadStr('CityName') + ']'
 +
      else
 +
        City := ' [загород]';
 +
    end;
  
     WriteFloat('Temp', 'GpsLostKmDist',
+
     DistDelta := ReadFloat('DistDelta');
       ReadFloat('Temp', 'GpsLostKmDist') + DistDelta);
+
    if ReadBool('IsHourly') then
 +
    begin
 +
       WriteStr('Caption', 'ЧАС' + City);
  
    CurTotalDistance := ReadFloat('Temp', 'TotalDist') + DistDelta;
+
      if ReadInt('TripTime') > HOURLY_MINUTES_INCLUDED * 60 then
 +
      begin
 +
        if HOURLY_PERIOD = 0 then
 +
          F := HOURLY_MINUTE_COST / 60
 +
        else
 +
          if Floor((ReadInt('TripTime') - HOURLY_MINUTES_INCLUDED * 60 - 1) /
 +
            60 / HOURLY_PERIOD) * HOURLY_PERIOD * 60 =
 +
            ReadInt('TripTime') - HOURLY_MINUTES_INCLUDED * 60 - 1 then
 +
            F := HOURLY_PERIOD * HOURLY_MINUTE_COST
 +
          else
 +
            F := 0;
 +
        if F <> 0 then
 +
        begin
 +
          WriteFloat('Temp', 'TripTimeSum',
 +
            ReadFloat('Temp', 'TripTimeSum') + F);
 +
        end;
 +
      end;
 +
 
 +
      if HOURLY_KM_COST > 0 then
 +
      begin
 +
        F := 0;
 +
        if HOURLY_HOUR_KM_INCLUDED > 0 then
 +
        begin
 +
          // Ещё один час закончился.
 +
          if ReadInt('TripTime') mod (60 * 60) = 0 then
 +
            WriteFloat('Temp', 'DistHour', 0);
  
    // При восстанавлении координат не успевает правильно
+
          WriteFloat('Temp', 'DistHour',
    // определиться флаг ReadBool('InCity').
+
            ReadFloat('Temp', 'DistHour') + DistDelta);
    if ReadInt('Temp', 'OldInCity') > 0 then
 
    begin
 
      WriteFloat('Temp', 'GpsLostDistCity',
 
        ReadFloat('Temp', 'GpsLostDistCity') + DistDelta);
 
      KmCost := CITY_KM_COST;
 
    end
 
    else
 
    begin
 
      WriteFloat('Temp', 'GpsLostDistCountry',
 
        ReadFloat('Temp', 'GpsLostDistCountry') + DistDelta);
 
      KmCost := COUNTRY_KM_COST;
 
    end;
 
  
    if CurTotalDistance > ReadFloat('Temp', 'KMIncluded') then
+
          if ReadFloat('Temp', 'DistHour') > HOURLY_HOUR_KM_INCLUDED then
    begin
+
            F := DistDelta * HOURLY_KM_COST;
      // Если при восстановлении координат сразу закончился
+
        end
      // включенный киломтраж.
+
        else
      if ReadFloat('Temp', 'TotalDist') < ReadFloat('Temp', 'KMIncluded') then
+
        if HOURLY_TRIP_KM_INCLUDED > 0 then
         // Платный километраж.
+
        begin
         DistDelta := CurTotalDistance - ReadFloat('Temp', 'KMIncluded');
+
          if ReadFloat('TripDistance') > HOURLY_TRIP_KM_INCLUDED then
 +
            F := DistDelta * HOURLY_KM_COST;
 +
         end
 +
         else
 +
          F := DistDelta * HOURLY_KM_COST;
  
      WriteFloat('Temp', 'GPSLostDistSum',
+
        if F <> 0 then
        ReadFloat('Temp', 'GPSLostDistSum') + KmCost * DistDelta);
+
        begin
    end;
+
          WriteFloat('Temp', 'HourlyDist',
  end;
+
            ReadFloat('Temp', 'HourlyDist') + DistDelta);
 
+
          WriteFloat('Temp', 'HourlyDistSum',
  // Пропал сигнал GPS.
+
            ReadFloat('Temp', 'HourlyDistSum') + F);
  if (Lat = 0) and (Lon = 0) then
+
        end;
    WriteInt('Temp', 'IsLostGPS', 1)
+
      end;
  else
+
     end
  // Есть сигнал GPS.
 
  begin
 
    WriteFloat('Temp', 'OldLat', Lat);
 
    WriteFloat('Temp', 'OldLon', Lon);
 
     if ReadBool('InCity') then
 
      WriteInt('Temp', 'OldInCity', 1)
 
 
     else
 
     else
       WriteInt('Temp', 'OldInCity', 0);
+
    begin
    WriteInt('Temp', 'IsLostGPS', 0);
+
       WriteFloat('Temp', 'TotalDist',
  end;
+
        ReadFloat('Temp', 'TotalDist') + DistDelta);
end;
+
      // Если скорость достаточная, считать по километражу.
 +
      if ReadFloat('Speed') > SPEED_LIMIT then
 +
      begin
 +
        WriteStr('Caption', 'КМ' + City);
 +
        TripDistance := ReadFloat('Temp', 'TotalDist') + ReadFloat('Temp', 'GpsLostDistCountry') +
 +
          ReadFloat('Temp', 'GpsLostDistCity');
 +
        if not ReadBool('InCity') then
 +
        begin
 +
          WriteFloat('Temp', 'DistCountry',
 +
            ReadFloat('Temp', 'DistCountry') + DistDelta);
 +
          if TripDistance > ReadFloat('Temp', 'KmIncluded') then
 +
          begin
 +
            WriteFloat('Temp', 'DistanceSum',
 +
              ReadFloat('Temp', 'DistanceSum') + COUNTRY_KM_COST * DistDelta);
 +
          end;
 +
        end
 +
        else
 +
        begin
 +
          WriteFloat('Temp', 'DistCity',
 +
            ReadFloat('Temp', 'DistCity') + DistDelta);
 +
          if TripDistance > ReadFloat('Temp', 'KmIncluded') then
 +
          begin
 +
            WriteFloat('Temp', 'DistanceSum',
 +
              ReadFloat('Temp', 'DistanceSum') + CITY_KM_COST * DistDelta);
 +
          end;
 +
        end;
 +
      end;
  
 
+
      if (COUNTRY_MINUTE_COST <> 0) or (CITY_MINUTE_COST <> 0) then
// *******
+
        if not ReadBool('InCity') then
// Расчёт.
+
        begin
// *******
+
          WriteInt('Temp', 'CountryTripTime',
procedure StepCalc;
+
            ReadInt('Temp', 'CountryTripTime') + 1);
var
+
          if ReadInt('TripTime') > ReadFloat('Temp', 'MinutesIncluded') * 60 then
  F, DistDelta, TripDistance: Single;
+
            WriteFloat('Temp', 'CountryTripTimeSum',  
  City: String;
+
              ReadFloat('Temp', 'CountryTripTimeSum') + COUNTRY_MINUTE_COST / 60);
  Seconds: Integer;
+
        end
begin
+
        else
  if CALC_SUM_BY_TAXIMETER then
+
        begin
  begin
+
          WriteInt('Temp', 'CityTripTime',
    if ReadBool('HasCities') then
+
            ReadInt('Temp', 'CityTripTime') + 1);
    begin
+
          if ReadInt('TripTime') > ReadFloat('Temp', 'MinutesIncluded') * 60 then
      if ReadBool('InCity') then
+
            WriteFloat('Temp', 'CityTripTimeSum',
        City := ' [' + ReadStr('CityName') + ']'
+
              ReadFloat('Temp', 'CityTripTimeSum') + CITY_MINUTE_COST / 60);
       else
+
        end;
         City := ' [загород]';
+
 
 +
       if TMD_UseGPSMissedDistanceRecovery then
 +
         TMD_RecalcLostGPSParams;
 
     end;
 
     end;
 +
  end;
  
     DistDelta := ReadFloat('DistDelta');
+
  if TMD_UseCalcStopsIdle then
     if ReadBool('IsHourly') then
+
  begin
 +
     if ReadFloat('Speed') > SPEED_LIMIT then
 +
      WriteInt('Temp', 'LastKMTime', ReadInt('TripTime'))
 +
    else
 +
     if ReadInt('TripTime') - ReadInt('Temp', 'LastKMTime') > FREE_IDLE_TIME then
 
     begin
 
     begin
       WriteStr('Caption', 'ЧАС' + City);
+
       WriteStr('Caption', 'Простой');
 
+
       WriteInt('Temp', 'IdleTime',
       if ReadInt('TripTime') > HOURLY_MINUTES_INCLUDED * 60 then
+
         ReadInt('Temp', 'IdleTime') + 1);
      begin
+
      WriteFloat('Temp', 'IdleTimeSum',
         if HOURLY_PERIOD = 0 then
+
        ReadFloat('Temp', 'IdleTimeSum') + IDLE_MINUTE_COST / 60);
          F := HOURLY_MINUTE_COST / 60
+
    end
        else
+
    else
          if Floor((ReadInt('TripTime') - HOURLY_MINUTES_INCLUDED * 60 - 1) /
+
    begin
            60 / HOURLY_PERIOD) * HOURLY_PERIOD * 60 =
+
      Seconds := FREE_IDLE_TIME -
            ReadInt('TripTime') - HOURLY_MINUTES_INCLUDED * 60 - 1 then
+
         (ReadInt('TripTime') - ReadInt('Temp', 'LastKMTime'));
            F := HOURLY_PERIOD * HOURLY_MINUTE_COST
+
      WriteStr('Caption', 'Ожидание (' + IntToStr(Seconds) + ')' + City);
          else
+
    end;
            F := 0;
+
  end;
         if F <> 0 then
 
        begin
 
          WriteFloat('Temp', 'TripTimeSum',
 
            ReadFloat('Temp', 'TripTimeSum') + F);
 
        end;
 
      end;
 
  
      F := 0;
+
  TMD_CalcTaximeterSum;
      if HOURLY_HOUR_KM_INCLUDED > 0 then
+
end;
      begin
 
        // Ещё один час закончился.
 
        if ReadInt('TripTime') mod (60 * 60) = 0 then
 
          WriteFloat('Temp', 'DistHour', 0);
 
  
        WriteFloat('Temp', 'DistHour',
 
          ReadFloat('Temp', 'DistHour') + DistDelta);
 
  
        if ReadFloat('Temp', 'DistHour') > HOURLY_HOUR_KM_INCLUDED then
+
// *****************
          F := DistDelta * HOURLY_KM_COST;
+
// Начало остановки.
      end
+
// *****************
      else
+
procedure StartStop;
        if HOURLY_TRIP_KM_INCLUDED > 0 then
+
var
          if ReadFloat('TripDistance') > HOURLY_TRIP_KM_INCLUDED then
+
  F: Single;
            F := DistDelta * HOURLY_KM_COST;
+
begin
      if F <> 0 then
+
  if CALC_SUM_BY_TAXIMETER then
      begin
+
  begin
        WriteFloat('Temp', 'HourlyDist',
+
    WriteStr('Caption', 'Остановка');
          ReadFloat('Temp', 'HourlyDist') + DistDelta);
+
    WriteInt('UseZonesPathGroupId', ZONES_PATH_GROUP_ID);
        WriteFloat('Temp', 'HourlyDistSum',
+
 
          ReadFloat('Temp', 'HourlyDistSum') + F);
+
     // Определяем район по фактическим координатам.
      end;
+
     if USE_REAL_ZONES_IN_TAXM then
     end
 
     else
 
 
     begin
 
     begin
       WriteFloat('Temp', 'TotalDist',
+
       if ReadInt('ZoneId') <> ReadInt('Temp', 'LastZoneId') then
         ReadFloat('Temp', 'TotalDist') + DistDelta);
+
        // Сохраняем признак, что покидали район посадки.
       // Если скорость достаточная, считать по километражу.
+
         WriteInt('Temp', 'NeedZoneOutCost', 1);
       if ReadFloat('Speed') > SPEED_LIMIT then
+
 
 +
       // Проезды между районами
 +
       if (USE_ZONE_PATH) and (ReadInt('ZoneId') > 0) then
 
       begin
 
       begin
         WriteStr('Caption', 'КМ' + City);
+
         F := ReadFloat('ZonePathCost',
        TripDistance := ReadFloat('Temp', 'TotalDist') + ReadFloat('Temp', 'GpsLostDistCountry') +
+
          ReadInt('Temp', 'LastZoneId'), ReadInt('ZoneId'));
          ReadFloat('Temp', 'GpsLostDistCity');
+
         if F <> 0 then
         if not ReadBool('InCity') then
 
 
         begin
 
         begin
           WriteFloat('Temp', 'DistCountry',
+
           WriteStr('Bill', 'Code', 'ZONES_PATH');
            ReadFloat('Temp', 'DistCountry') + DistDelta);
+
          WriteStr('Bill', 'Text', 'Проезд ' + '"' +
              
+
             ReadStr('ZoneName', ReadInt('Temp', 'LastZoneId')) +
          if ReadInt('TripTime') > COUNTRY_MINUTE_INCLUDE * 60 then
+
             '"-"' + ReadStr('ZoneName') + '"');
          begin
+
           WriteStr('Bill', 'Sum', FloatToStr(F, 2));
            if Floor((ReadInt('TripTime') - COUNTRY_MINUTE_INCLUDE * 60 - 1) /
+
 
              60 / 1) * 1 * 60 = ReadInt('TripTime') - COUNTRY_MINUTE_INCLUDE * 60 - 1 then
+
           WriteFloat('Temp', 'ZonePathSum',
              F := 1 * COUNTRY_MINUTE_COST
+
            ReadFloat('Temp', 'ZonePathSum') + F);
            else
+
        end;
              F := 0;
+
      end;
             
+
 
             if F > 0 then
+
      // Сохраняем текущий район.
              WriteFloat('Temp', 'TripTimeSum', ReadFloat('Temp', 'TripTimeSum') + F);
+
      WriteInt('Temp', 'LastZoneId', ReadInt('ZoneId'));
           end;
+
 
         
+
      // Остановка в районе.
          if TripDistance > ReadFloat('Temp', 'KMIncluded') then
+
      if USE_ZONE_COST then
           begin
+
      begin
            WriteFloat('Temp', 'DistanceSum',
+
        F := ReadFloat('ZoneStopCost', ReadInt('ZoneId'));
              ReadFloat('Temp', 'DistanceSum') + COUNTRY_KM_COST * DistDelta);
+
        if F <> 0 then
          end;
+
        begin
        end
+
          WriteStr('Bill', 'Code', 'ZONES_STOP');
        else
+
          WriteStr('Bill', 'Text', 'Остановка ' +
        begin
+
            '"' + ReadStr('ZoneName') + '"');
          WriteFloat('Temp', 'DistCity',
+
           WriteStr('Bill', 'Sum', FloatToStr(F, 2));
            ReadFloat('Temp', 'DistCity') + DistDelta);
+
 
           
+
           WriteFloat('Temp', 'ZoneStopSum',
          if ReadInt('TripTime') > CITY_MINUTE_INCLUDE * 60 then
+
            ReadFloat('Temp', 'ZoneStopSum') + F);
          begin
 
            if Floor((ReadInt('TripTime') - CITY_MINUTE_INCLUDE * 60 - 1) /
 
              60 / 1) * 1 * 60 = ReadInt('TripTime') - CITY_MINUTE_INCLUDE * 60 - 1 then
 
              F := 1 * CITY_MINUTE_COST
 
            else
 
              F := 0;
 
             
 
            if F > 0 then
 
              WriteFloat('Temp', 'TripTimeSum', ReadFloat('Temp', 'TripTimeSum') + F);
 
           end;
 
     
 
          if TripDistance > ReadFloat('Temp', 'KMIncluded') then
 
           begin
 
            WriteFloat('Temp', 'DistanceSum',
 
              ReadFloat('Temp', 'DistanceSum') + CITY_KM_COST * DistDelta);
 
          end;
 
 
         end;
 
         end;
 
       end;
 
       end;
     
 
      if TMD_UseGPSMissedDistanceRecovery then
 
        TMD_RecalcLostGPSParams;
 
 
     end;
 
     end;
 
   end;
 
   end;
Строка 2363: Строка 2550:
 
   if TMD_UseCalcStopsIdle then
 
   if TMD_UseCalcStopsIdle then
 
   begin
 
   begin
     if ReadFloat('Speed') > SPEED_LIMIT then
+
     WriteInt('Temp', 'StopTime', 0);
      WriteInt('Temp', 'LastKMTime', ReadInt('TripTime'))
+
     WriteInt('Temp', 'StopsCount',
     else
+
       ReadInt('Temp', 'StopsCount') + 1);
    if ReadInt('TripTime') - ReadInt('Temp', 'LastKMTime') > FREE_IDLE_TIME then
+
    WriteFloat('Temp', 'StopsSum',
    begin
+
      ReadFloat('Temp', 'StopsSum') + MIN_STOP_COST);
      WriteStr('Caption', 'Простой');
+
  end;
       WriteInt('Temp', 'IdleTime',
+
 
        ReadInt('Temp', 'IdleTime') + 1);
+
  TMD_CalcTaximeterSum;
      WriteFloat('Temp', 'IdleTimeSum',
+
end;
        ReadFloat('Temp', 'IdleTimeSum') + IDLE_MINUTE_COST / 60);
 
    end
 
    else
 
    begin
 
      Seconds := FREE_IDLE_TIME -
 
        (ReadInt('TripTime') - ReadInt('Temp', 'LastKMTime'));
 
      WriteStr('Caption', 'Ожидание (' + IntToStr(Seconds) + ')' + City);
 
    end;
 
  end;
 
  
  TMD_CalcTaximeterSum;
 
end;
 
  
 
+
// **********
// *****************
+
// Остановка.
// Начало остановки.
+
// **********
// *****************
+
procedure StepCalcStop;
procedure StartStop;
 
 
var
 
var
   F: Single;
+
   StopTime: Integer;
 +
  Sum: Single;
 
begin
 
begin
   if CALC_SUM_BY_TAXIMETER then
+
   if not TMD_UseCalcStopsIdle then
 +
    StepCalc
 +
  else
 
   begin
 
   begin
     WriteStr('Caption', 'Остановка');
+
     WriteFloat('Temp', 'TotalDist',
    WriteInt('UseZonesPathGroupId', ZONES_PATH_GROUP_ID);
+
      ReadFloat('Temp', 'TotalDist') + ReadFloat('DistDelta'));
 +
    if TMD_UseGPSMissedDistanceRecovery then
 +
      TMD_RecalcLostGPSParams;
  
    // Определяем район по фактическим координатам.
+
     if STOP_MINUTE_COST <> 0 then
     if USE_REAL_ZONES_IN_TAXM then
 
 
     begin
 
     begin
       if ReadInt('ZoneId') <> ReadInt('Temp', 'LastZoneId') then
+
       StopTime := ReadInt('Temp', 'StopTime') + 1;
        // Сохраняем признак, что покидали район посадки.
 
        WriteInt('Temp', 'NeedZoneOutCost', 1);
 
  
      // Проезды между районами
+
       if StopTime > (STOP_MINUTES_INCLUDED * 60) then
       if (USE_ZONE_PATH) and (ReadInt('ZoneId') > 0) then
 
 
       begin
 
       begin
         F := ReadFloat('ZonePathCost',
+
         WriteFloat('Temp', 'StopTimeSum',
          ReadInt('Temp', 'LastZoneId'), ReadInt('ZoneId'));
+
           ReadFloat('Temp', 'StopTimeSum') + STOP_MINUTE_COST / 60);
        if F <> 0 then
+
        TMD_CalcTaximeterSum;
        begin
+
      end;
           WriteStr('Bill', 'Code', 'ZONES_PATH');
 
          WriteStr('Bill', 'Text', 'Проезд ' + '"' +
 
            ReadStr('ZoneName', ReadInt('Temp', 'LastZoneId')) +
 
            '"-"' + ReadStr('ZoneName') + '"');
 
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
  
          WriteFloat('Temp', 'ZonePathSum',
+
      WriteInt('Temp', 'StopTime', StopTime);
            ReadFloat('Temp', 'ZonePathSum') + F);
+
      WriteInt('Temp', 'AllStopTime',
        end;
+
        ReadInt('Temp', 'AllStopTime') + 1);
      end;
+
    end;
 +
  end;
 +
end;
  
      // Сохраняем текущий район.
 
      WriteInt('Temp', 'LastZoneId', ReadInt('ZoneId'));
 
  
      // Остановка в районе.
+
// ****************
      if USE_ZONE_COST then
+
// Конец остановки.
      begin
+
// ****************
        F := ReadFloat('ZoneStopCost', ReadInt('ZoneId'));
+
procedure EndStop;
        if F <> 0 then
+
begin
        begin
+
  WriteStr('Caption', '');
          WriteStr('Bill', 'Code', 'ZONES_STOP');
 
          WriteStr('Bill', 'Text', 'Остановка ' +
 
            '"' + ReadStr('ZoneName') + '"');
 
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
 
 
          WriteFloat('Temp', 'ZoneStopSum',
 
            ReadFloat('Temp', 'ZoneStopSum') + F);
 
        end;
 
      end;
 
    end;
 
  end;
 
 
 
  if TMD_UseCalcStopsIdle then
 
  begin
 
    WriteInt('Temp', 'StopTime', 0);
 
    WriteInt('Temp', 'StopsCount',
 
      ReadInt('Temp', 'StopsCount') + 1);
 
    WriteFloat('Temp', 'StopsSum',
 
      ReadFloat('Temp', 'StopsSum') + MIN_STOP_COST);
 
  end;
 
 
 
  TMD_CalcTaximeterSum;
 
 
end;
 
end;
  
  
// **********
+
// ****************
// Остановка.
+
// Обработка дополнительных функциональных кнопок.
// **********
+
// ****************
procedure StepCalcStop;
+
procedure ButtonClick;
 
var
 
var
   StopTime: Integer;
+
   ButtonName, ServiceName: String;
   Sum: Single;
+
   Sum, ServiceSum, PercentSum: Single;
 +
  I, ServicePercent, ServiceId: Integer;
 +
  CanRepeatService: Boolean;
 
begin
 
begin
   if not TMD_UseCalcStopsIdle then
+
   ButtonName := ReadStr('Button', 'Clicked');
    StepCalc
+
  for I := 1 to TMD_GetDriverServicesCount do
  else
+
    if ButtonName = 'DriverServiceButton' + IntToStr(I) then
  begin
 
    WriteFloat('Temp', 'TotalDist',
 
      ReadFloat('Temp', 'TotalDist') + ReadFloat('DistDelta'));
 
    if TMD_UseGPSMissedDistanceRecovery then
 
      TMD_RecalcLostGPSParams;
 
 
 
    if STOP_MINUTE_COST <> 0 then
 
 
     begin
 
     begin
       StopTime := ReadInt('Temp', 'StopTime') + 1;
+
       TMD_GetServiceParamsByIndex(I, ServiceSum, ServicePercent, ServiceName,
 
+
        ServiceId, CanRepeatService);
       if StopTime > (STOP_MINUTES_INCLUDED * 60) then
+
      if CanRepeatService then
 +
        WriteInt('Temp', 'DriverServiceButton' + IntToStr(I),
 +
          ReadInt('Temp', 'DriverServiceButton' + IntToStr(I)) + 1)
 +
       else
 
       begin
 
       begin
         WriteFloat('Temp', 'StopTimeSum',
+
         WriteInt('Temp', 'DriverServiceButton' + IntToStr(I), 1);
          ReadFloat('Temp', 'StopTimeSum') + STOP_MINUTE_COST / 60);
+
        WriteStr('Button', 'Select', ButtonName);
         TMD_CalcTaximeterSum;
+
         WriteInt('Button', 'Visible', 0);
 
       end;
 
       end;
 +
    end;
  
      WriteInt('Temp', 'StopTime', StopTime);
+
   TMD_CalcTaximeterSum;
      WriteInt('Temp', 'AllStopTime',
 
        ReadInt('Temp', 'AllStopTime') + 1);
 
    end;
 
   end;
 
 
end;
 
end;
  
  
// ****************
+
// Добавить в чек стоимость за восстановленный километраж.
// Конец остановки.
+
procedure TMD_AddGPSParams;
// ****************
 
procedure EndStop;
 
 
begin
 
begin
   WriteStr('Caption', '');
+
   if TMD_UseGPSMissedDistanceRecovery and
end;
+
    (ReadFloat('Temp', 'GpsLostKmDist') > 0) then
 +
  begin
 +
    if ReadFloat('Temp', 'GPSLostDistCity') > 0 then
 +
    begin
 +
      WriteStr('Bill', 'Code', 'CITY_LOST_GPS_DIST');
 +
      WriteStr('Bill', 'Text', 'По городу при отсутствии GPS');
 +
      WriteStr('Bill', 'Value',
 +
        FloatToStr(ReadFloat('Temp', 'GPSLostDistCity'), 2) + ' км');
 +
    end;
  
 
+
    if ReadFloat('Temp', 'GPSLostDistCountry') > 0 then
// ****************
 
// Обработка дополнительных функциональных кнопок.
 
// ****************
 
procedure ButtonClick;
 
var
 
  ButtonName, ServiceName: String;
 
  Sum, ServiceSum, PercentSum: Single;
 
  I, ServicePercent, ServiceId: Integer;
 
  CanRepeatService: Boolean;
 
begin
 
  ButtonName := ReadStr('Button', 'Clicked');
 
  for I := 1 to TMD_GetDriverServicesCount do
 
    if ButtonName = 'DriverServiceButton' + IntToStr(I) then
 
 
     begin
 
     begin
       TMD_GetServiceParamsByIndex(I, ServiceSum, ServicePercent, ServiceName,
+
       WriteStr('Bill', 'Code', 'COUNTRY_LOST_GPS_DIST');
        ServiceId, CanRepeatService);
+
       WriteStr('Bill', 'Text', 'За городом при отсутствии GPS');
      if CanRepeatService then
+
      WriteStr('Bill', 'Value',
        WriteInt('Temp', 'DriverServiceButton' + IntToStr(I),
+
         FloatToStr(ReadFloat('Temp', 'GPSLostDistCountry'), 2) + ' км');
          ReadInt('Temp', 'DriverServiceButton' + IntToStr(I)) + 1)
 
       else
 
      begin
 
        WriteInt('Temp', 'DriverServiceButton' + IntToStr(I), 1);
 
        WriteStr('Button', 'Select', ButtonName);
 
         WriteInt('Button', 'Visible', 0);
 
      end;
 
 
     end;
 
     end;
 
+
   end;
   TMD_CalcTaximeterSum;
 
 
end;
 
end;
  
  
// Добавить в чек стоимость за восстановленный километраж.
+
// Добавить в чек стоимость за простой, ожидание, остановки.
procedure TMD_AddGPSParams;
+
procedure TMD_AddTimeParams;
 
begin
 
begin
  if TMD_UseGPSMissedDistanceRecovery and
+
   WriteStr('Bill', 'Code', 'IDLE_TIME');
    (ReadFloat('Temp', 'GpsLostKmDist') > 0) then
+
   WriteStr('Bill', 'Text', 'Простой');
  begin
 
    if ReadFloat('Temp', 'GPSLostDistCity') > 0 then
 
    begin
 
      WriteStr('Bill', 'Code', 'CITY_LOST_GPS_DIST');
 
      WriteStr('Bill', 'Text', 'По городу при отсутствии GPS');
 
      WriteStr('Bill', 'Value',
 
        FloatToStr(ReadFloat('Temp', 'GPSLostDistCity'), 2) + ' км');
 
    end;
 
 
 
    if ReadFloat('Temp', 'GPSLostDistCountry') > 0 then
 
    begin
 
      WriteStr('Bill', 'Code', 'COUNTRY_LOST_GPS_DIST');
 
      WriteStr('Bill', 'Text', 'За городом при отсутствии GPS');
 
      WriteStr('Bill', 'Value',
 
        FloatToStr(ReadFloat('Temp', 'GPSLostDistCountry'), 2) + ' км');
 
    end;
 
  end;
 
end;
 
 
 
 
 
// Добавить в чек стоимость за простой, ожидание, остановки.
 
procedure TMD_AddTimeParams;
 
begin
 
   WriteStr('Bill', 'Code', 'IDLE_TIME');
 
   WriteStr('Bill', 'Text', 'Простой');
 
 
   WriteStr('Bill', 'Value',
 
   WriteStr('Bill', 'Value',
 
     TimeLenToStr(ReadInt('Temp', 'IdleTime')));
 
     TimeLenToStr(ReadInt('Temp', 'IdleTime')));
Строка 2644: Строка 2748:
 
             '"' + ReadStr('ZoneName') + '"');
 
             '"' + ReadStr('ZoneName') + '"');
 
           WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
           WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 
+
 
           WriteFloat('Temp', 'ZoneOutCost', F);
+
           WriteFloat('Temp', 'ZoneOutCost', F);
         end;
+
         end;
 +
      end;
 +
    end;
 +
 
 +
    if ReadBool('IsHourly') then
 +
    begin
 +
      WriteStr('Bill', 'Code', 'TRIP_TIME');
 +
      WriteStr('Bill', 'Text', 'Общее время');
 +
      WriteStr('Bill', 'Value',
 +
        TimeLenToStr(ReadInt('TripTime')));
 +
      WriteStr('Bill', 'Sum',
 +
        FloatToStr(ReadFloat('Temp', 'TripTimeSum') + ReadFloat('Temp', 'BoardingSum'), 2));
 +
 
 +
      WriteStr('Bill', 'Code', 'TRIP_DIST');
 +
      WriteStr('Bill', 'Text', 'Общее расстояние');
 +
      WriteStr('Bill', 'Value',
 +
        FloatToStr(ReadFloat('TripDistance'), 2) + ' км');
 +
 
 +
      F := ReadFloat('Temp', 'HourlyDistSum');
 +
      if F > 0 then
 +
      begin
 +
        WriteStr('Bill', 'Code', 'HOURLY_PAY_DIST');
 +
        WriteStr('Bill', 'Text', 'Платный километраж');
 +
        WriteStr('Bill', 'Value',
 +
          FloatToStr(ReadFloat('Temp', 'HourlyDist'), 2) + ' км');
 +
        WriteStr('Bill', 'Sum', FloatToStr(F, 2));
 +
      end;
 +
    end
 +
    else
 +
    begin
 +
      if TMD_UseCalcTMRoute then
 +
        TMD_RecalcDistSum;
 +
 
 +
      WriteStr('Bill', 'Code', 'TRIP_TIME');
 +
      WriteStr('Bill', 'Text', 'Общее время');
 +
      WriteStr('Bill', 'Value',
 +
        TimeLenToStr(ReadInt('TripTime')));
 +
 
 +
      if CITY_MINUTE_COST <> 0 then
 +
      begin
 +
        WriteStr('Bill', 'Code', 'CITY_TRIP_TIME');
 +
        WriteStr('Bill', 'Text', 'Время по городу');
 +
        WriteStr('Bill', 'Value',
 +
          TimeLenToStr(ReadInt('Temp', 'CityTripTime')));
 +
        WriteStr('Bill', 'Sum',
 +
          FloatToStr(ReadFloat('Temp', 'CityTripTimeSum'), 2));
 
       end;
 
       end;
    end;
 
 
    if ReadBool('IsHourly') then
 
    begin
 
      WriteStr('Bill', 'Code', 'TRIP_TIME');
 
      WriteStr('Bill', 'Text', 'Общее время');
 
      WriteStr('Bill', 'Value',
 
        TimeLenToStr(ReadInt('TripTime')));
 
      WriteStr('Bill', 'Sum',
 
        FloatToStr(ReadFloat('Temp', 'TripTimeSum') + ReadFloat('Temp', 'BoardingSum'), 2));
 
  
      WriteStr('Bill', 'Code', 'TRIP_DIST');
+
       if COUNTRY_MINUTE_COST <> 0 then
      WriteStr('Bill', 'Text', 'Общее расстояние');
 
      WriteStr('Bill', 'Value',
 
        FloatToStr(ReadFloat('TripDistance'), 2) + ' км');
 
 
 
      F := ReadFloat('Temp', 'HourlyDistSum');
 
       if F > 0 then
 
 
       begin
 
       begin
         WriteStr('Bill', 'Code', 'HOURLY_PAY_DIST');
+
         WriteStr('Bill', 'Code', 'COUNTRY_TRIP_TIME');
         WriteStr('Bill', 'Text', 'Платный километраж');
+
         WriteStr('Bill', 'Text', 'Время за городом');
 
         WriteStr('Bill', 'Value',
 
         WriteStr('Bill', 'Value',
           FloatToStr(ReadFloat('Temp', 'HourlyDist'), 2) + ' км');
+
           TimeLenToStr(ReadInt('Temp', 'CountryTripTime')));
         WriteStr('Bill', 'Sum', FloatToStr(F, 2));
+
         WriteStr('Bill', 'Sum',  
 +
          FloatToStr(ReadFloat('Temp', 'CountryTripTimeSum'), 2));
 
       end;
 
       end;
    end
 
    else
 
    begin
 
      if TMD_UseCalcTMRoute then
 
        TMD_RecalcDistSum;
 
 
      WriteStr('Bill', 'Code', 'TRIP_TIME');
 
      WriteStr('Bill', 'Text', 'Общее время');
 
      WriteStr('Bill', 'Value',
 
        TimeLenToStr(ReadInt('TripTime')));
 
      WriteStr('Bill', 'Sum',
 
        FloatToStr(ReadFloat('Temp', 'TripTimeSum'), 2));     
 
  
 
       WriteStr('Bill', 'Code', 'TRIP_DIST');
 
       WriteStr('Bill', 'Code', 'TRIP_DIST');
Строка 2893: Строка 3015:
 
         AddTextNotNullValue('По городу', ReadFloat('Temp', 'DistanceSum'));
 
         AddTextNotNullValue('По городу', ReadFloat('Temp', 'DistanceSum'));
 
         AddTextNotNullValue('За городом', ReadFloat('Temp', 'DistCountrySum'));
 
         AddTextNotNullValue('За городом', ReadFloat('Temp', 'DistCountrySum'));
 +
        if ReadFloat('Temp', 'CityTripTimeSum') <> 0 then
 +
          AddTextNotNullValue('Время по городу', ReadFloat('Temp', 'CityTripTimeSum'));
 +
        if ReadFloat('Temp', 'CountryTripTimeSum') <> 0 then
 +
          AddTextNotNullValue('Время за городом', ReadFloat('Temp', 'CountryTripTimeSum'));
 
         AddTextNotNullValue('Простой', ReadFloat('Temp', 'IdleTimeSum'));
 
         AddTextNotNullValue('Простой', ReadFloat('Temp', 'IdleTimeSum'));
 
         AddTextNotNullValue('Остановки', ReadFloat('Temp', 'StopsSum'));
 
         AddTextNotNullValue('Остановки', ReadFloat('Temp', 'StopsSum'));

Версия 10:43, 4 мая 2022

В тарифе существуют параметры, которые позволяют учитывать не только километраж маршрута, но и предварительно рассчитанное время проезда по этому маршруту, которое может зависеть от загруженности дорог.

Текст тарифа (Развернуть/Свернуть) →


//<?xml version="1.0" encoding="UTF-8"?>
//<xml_consts>
//  <param>
//    <code>PRIOR_ORDER_COST</code>
//    <type>currency</type>
//    <name>Наценка за предварительный заказ</name>
//  </param>

//  <group>
//    <name>Ожидание</name>
//    <items>
//      <param>
//        <code>WAITING_INCLUDED</code>
//        <type>boolean</type>
//        <name>Ожидание включено в минимальную стоимость</name>
//      </param>
//      <param>
//        <code>WAIT_MINUTE_COST</code>
//        <type>currency</type>
//        <name>Цена минуты ожидания</name>
//      </param>
//      <param>
//        <code>FREE_WAITING_TIME</code>
//        <type>integer</type>
//        <name>Бесплатное время ожидания, мин</name>
//      </param>
//      <param>
//        <code>PRIOR_FREE_WAITING_TIME</code>
//        <type>integer</type>
//        <name>Бесплатное время ожидания для предварительного заказа, мин</name>
//      </param>
//      <param>
//        <code>CLIENT_ABSENT_VISIBLE</code>
//        <type>boolean</type>
//        <name>Отображать кнопку "Не выходят"</name>
//      </param>
//      <param>
//        <code>CLIENT_ABSENT_ENABLED_TIME</code>
//        <type>integer</type>
//        <name>За сколько минут до начала платного ожидания делать доступной кнопку "Не выходят"</name>
//        <visible>
//          <code>CLIENT_ABSENT_VISIBLE</code>
//          <condition>equal</condition>
//          <value>true</value>
//        </visible>
//      </param>
//    </items>
//  </group>

//  <group>
//    <name>Обычный заказ (не почасовой)</name>
//    <items>
//      <group>
//        <name>По городу</name>
//        <items>
//          <param>
//            <code>MIN_CITY</code>
//            <type>currency</type>
//            <name>Минимальная стоимость</name>
//          </param>
//          <param>
//            <code>BOARDING_CITY</code>
//            <type>currency</type>
//            <name>Посадка</name>
//          </param>
//          <param>
//            <code>CITY_KM_INCLUDED</code>
//            <type>float</type>
//            <name>Сколько км включено в посадку</name>
//          </param>
//          <param>
//            <code>CITY_KM_COST</code>
//            <type>currency</type>
//            <name>Цена км далее</name>
//          </param>
//          <param>
//            <type>integer</type>
//            <name>На сколько % увеличивать сумму по городу при обратном пути в карте заказа</name>
//            <code>CITY_BACK_WAY_PERCENT</code>
//          </param>
//          <param>
//            <code>CITY_MINUTES_INCLUDED</code>
//            <type>float</type>
//            <name>Сколько минут включено в посадку</name>
//          </param>
//          <param>
//            <code>CITY_MINUTE_COST</code>
//            <type>currency</type>
//            <name>Цена минуты далее</name>
//          </param>
//        </items>
//      </group>

//      <group>
//        <name>За городом</name>
//        <items>
//          <param>
//            <code>MIN_COUNTRY</code>
//            <type>currency</type>
//            <name>Минимальная стоимость</name>
//          </param>
//          <param>
//            <code>BOARDING_COUNTRY</code>
//            <type>currency</type>
//            <name>Посадка</name>
//          </param>
//          <param>
//            <code>COUNTRY_KM_INCLUDED</code>
//            <type>float</type>
//            <name>Сколько км включено в посадку</name>
//          </param>
//          <param>
//            <code>COUNTRY_KM_COST</code>
//            <type>currency</type>
//            <name>Цена км далее</name>
//          </param>
//          <param>
//            <code>SOURCE_COUNTRY_KM_COST</code>
//            <type>currency</type>
//            <name>Цена км до адреса подачи за город</name>
//          </param>
//          <param>
//            <code>COUNTRY_BACK_WAY_PERCENT</code>
//            <type>integer</type>
//            <name>На сколько % увеличивать сумму за городом при обратном пути в карте заказа</name>
//          </param>
//          <param>
//            <code>COUNTRY_MINUTES_INCLUDED</code>
//            <type>float</type>
//            <name>Сколько минут включено в посадку</name>
//          </param>
//          <param>
//            <code>COUNTRY_MINUTE_COST</code>
//            <type>currency</type>
//            <name>Цена минуты далее</name>
//          </param>
//        </items>
//      </group>

//      <group>
//        <name>Простой</name>
//        <items>
//          <param>
//            <code>IDLE_MINUTE_COST</code>
//            <type>currency</type>
//            <name>Цена минуты простоя</name>
//          </param>
//          <param>
//            <code>FREE_IDLE_TIME</code>
//            <type>integer</type>
//            <name>Период между потерей скорости и началом простоя, сек</name>
//          </param>
//          <param>
//            <code>SPEED_LIMIT</code>
//            <type>integer</type>
//            <name>Скорость, ниже которой считается простой, км/ч</name>
//          </param>
//        </items>
//      </group>

//      <group>
//        <name>Остановки</name>
//        <items>
//          <param>
//            <code>MIN_STOP_COST</code>
//            <type>currency</type>
//            <name>Минимальная стоимость остановки</name>
//          </param>
//          <param>
//            <code>STOP_MINUTES_INCLUDED</code>
//            <type>integer</type>
//            <name>Сколько минут включено в минимальную стоимость остановки</name>
//          </param>
//          <param>
//            <code>STOP_MINUTE_COST</code>
//            <type>currency</type>
//            <name>Цена минуты остановки далее</name>
//          </param>
//        </items>
//      </group>

//      <group>
//        <name>Расчет километража для таксометра через ТМ</name>
//        <items>
//          <param>
//            <code>USE_CALC_TM_ROUTE</code>
//            <type>boolean</type>
//            <name>Использовать расчет километража для таксометра через ТМ</name>
//          </param>
//          <param>
//            <code>CALC_TM_ROUTE_PERIOD</code>
//            <type>integer</type>
//            <name>Через сколько секунд делать пересчет километража для таксометра через ТМ</name>
//          </param>
//        </items>
//      </group>

//    </items>
//  </group>

//  <group>
//    <name>Почасовой заказ</name>
//    <items>
//      <param>
//        <code>MIN_HOURLY</code>
//        <type>currency</type>
//        <name>Минимальная стоимость</name>
//      </param>
//      <param>
//        <code>BOARDING_HOURLY</code>
//        <type>currency</type>
//        <name>Посадка</name>
//      </param>
//      <param>
//        <code>HOURLY_MINUTES_INCLUDED</code>
//        <type>integer</type>
//        <name>Сколько минут включено в посадку</name>
//      </param>
//      <param>
//        <code>HOURLY_MINUTE_COST</code>
//        <type>currency</type>
//        <name>Цена минуты далее</name>
//      </param>
//      <param>
//        <code>HOURLY_PERIOD</code>
//        <type>integer</type>
//        <name>За сколько минут разом увеличивать сумму</name>
//      </param>
//      <param>
//        <code>HOURLY_TRIP_KM_INCLUDED</code>
//        <type>float</type>
//        <name>Количество км, включенных в поездку</name>
//        <visible>
//          <code>HOURLY_HOUR_KM_INCLUDED</code>
//          <condition>equal</condition>
//          <value>0</value>
//        </visible>
//      </param>
//      <param>
//        <code>HOURLY_HOUR_KM_INCLUDED</code>
//        <type>float</type>
//        <name>Количество км, включенных в час</name>
//        <visible>
//          <code>HOURLY_TRIP_KM_INCLUDED</code>
//          <condition>equal</condition>
//          <value>0</value>
//        </visible>
//      </param>
//      <param>
//        <code>HOURLY_KM_COST</code>
//        <type>currency</type>
//        <name>Цена км</name>
//      </param>
//    </items>
//  </group>

//  <group>
//    <name>Районы</name>
//    <items>
//      <param>
//        <code>USE_ZONE_COST</code>
//        <type>boolean</type>
//        <name>Учитывать посадку/высадку в районах</name>
//      </param>
//      <param>
//        <code>USE_ZONE_PATH</code>
//        <type>boolean</type>
//        <name>Учитывать проезды между районами</name>
//      </param>
//      <param>
//        <code>ZONES_PATH_GROUP_ID</code>
//        <type>zones_path_group</type>
//        <name>Группа проездов между районами</name>
//        <visible>
//          <code>USE_ZONE_PATH</code>
//          <condition>equal</condition>
//          <value>true</value>
//        </visible>
//      </param>
//      <param>
//        <code>ZONES_BACK_WAY_PERCENT</code>
//        <type>integer</type>
//        <name>На сколько % увеличивать сумму за проезды между районами при обратном пути в карте заказа</name>
//        <visible>
//          <code>USE_ZONE_PATH</code>
//          <condition>equal</condition>
//          <value>true</value>
//        </visible>
//      </param>
//      <param>
//        <code>USE_REAL_ZONES_IN_TAXM</code>
//        <type>boolean</type>
//        <name>Определять районы в таксометре по фактическому маршруту</name>
//      </param>
//    </items>
//  </group>

//  <group>
//    <name>Дополнительные параметры минимальной стоимости</name>
//    <items>
//      <param>
//        <code>DISCOUNT_AFTER_MIN</code>
//        <type>boolean</type>
//        <name>Считать скидки после минимальной стоимости</name>
//      </param>
//      <param>
//        <code>SERVICES_AFTER_MIN</code>
//        <type>boolean</type>
//        <name>Считать услуги после минимальной стоимости</name>
//      </param>
//      <param>
//        <code>MIN_SUM_AFTER_CALC</code>
//        <type>boolean</type>
//        <name>Применять минимальную стоимость после завершения расчета в таксометре</name>
//      </param>
//    </items>
//  </group>

//  <group>
//    <name>Округление</name>
//    <items>
//      <param>
//        <code>ROUNDING</code>
//        <type>currency</type>
//        <name>Округление</name>
//        <min>0</min>
//      </param>
//      <param>
//        <code>ROUND_UP</code>
//        <type>boolean</type>
//        <name>Округлять в большую сторону</name>
//      </param>
//    </items>
//  </group>

//  <group>
//    <name>Таксофон</name>
//    <items>
//      <param>
//        <code>TAXOPHONE_FIRST_DISCOUNT_SUM</code>
//        <type>currency</type>
//        <name>Скидка за первый заказ из TaxoPhone, руб</name>
//      </param>
//      <param>
//        <code>TAXOPHONE_FIRST_DISCOUNT_PERCENT</code>
//        <type>integer</type>
//        <name>Скидка за первый заказ из TaxoPhone, %</name>
//      </param>
//      <param>
//        <code>TAXOPHONE_CONSTANT_DISCOUNT_SUM</code>
//        <type>currency</type>
//        <name>Постоянная скидка для заказов из TaxoPhone, руб</name>
//      </param>
//      <param>
//        <code>TAXOPHONE_CONSTANT_DISCOUNT_PERCENT</code>
//        <type>integer</type>
//        <name>Постоянная скидка для заказов из TaxoPhone, %</name>
//      </param>
//      <param>
//        <code>TAXOPHONE_REGULAR_DISCOUNT_COUNT</code>
//        <type>integer</type>
//        <name>Через сколько заказов должна срабатывать регулярная скидка для заказов из TaxoPhone</name>
//      </param>
//      <param>
//        <code>TAXOPHONE_REGULAR_DISCOUNT_SUM</code>
//        <type>currency</type>
//        <name>Регулярная скидка для заказов из TaxoPhone, руб</name>
//      </param>
//      <param>
//        <code>TAXOPHONE_REGULAR_DISCOUNT_PERCENT</code>
//        <type>integer</type>
//        <name>Регулярная скидка для заказов из TaxoPhone, %</name>
//      </param>
//    </items>
//  </group>

//  <group>
//    <name>Услуги, доступные водителю в таксометре</name>
//    <items>
//      <param>
//        <code>SERVICES_BUTTON_COUNT</code>
//        <type>integer</type>
//        <name>Количество услуг</name>
//        <min>0</min>
//        <max>10</max>
//      </param>
//      <param>
//        <code>SERVICE_1</code>
//        <type>order_param</type>
//        <name>Услуга 1</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>1</value>
//        </visible>
//      </param>
//      <param>
//        <code>CAN_REPEAT_SERVICE_1</code>
//        <type>boolean</type>
//        <name>Услугу 1 можно использовать повторно</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>1</value>
//        </visible>
//      </param>
//      <param>
//        <code>SERVICE_2</code>
//        <type>order_param</type>
//        <name>Услуга 2</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>2</value>
//        </visible>
//      </param>
//      <param>
//        <code>CAN_REPEAT_SERVICE_2</code>
//        <type>boolean</type>
//        <name>Услугу 2 можно использовать повторно</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>2</value>
//        </visible>
//      </param>
//      <param>
//        <code>SERVICE_3</code>
//        <type>order_param</type>
//        <name>Услуга 3</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>3</value>
//        </visible>
//      </param>
//      <param>
//        <code>CAN_REPEAT_SERVICE_3</code>
//        <type>boolean</type>
//        <name>Услугу 3 можно использовать повторно</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>3</value>
//        </visible>
//      </param>
//      <param>
//        <code>SERVICE_4</code>
//        <type>order_param</type>
//        <name>Услуга 4</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>4</value>
//        </visible>
//      </param>
//      <param>
//        <code>CAN_REPEAT_SERVICE_4</code>
//        <type>boolean</type>
//        <name>Услугу 4 можно использовать повторно</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>4</value>
//        </visible>
//      </param>
//      <param>
//        <code>SERVICE_5</code>
//        <type>order_param</type>
//        <name>Услуга 5</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>5</value>
//        </visible>
//      </param>
//      <param>
//        <code>CAN_REPEAT_SERVICE_5</code>
//        <type>boolean</type>
//        <name>Услугу 5 можно использовать повторно</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>5</value>
//        </visible>
//      </param>
//      <param>
//        <code>SERVICE_6</code>
//        <type>order_param</type>
//        <name>Услуга 6</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>6</value>
//        </visible>
//      </param>
//      <param>
//        <code>CAN_REPEAT_SERVICE_6</code>
//        <type>boolean</type>
//        <name>Услугу 6 можно использовать повторно</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>6</value>
//        </visible>
//      </param>
//      <param>
//        <code>SERVICE_7</code>
//        <type>order_param</type>
//        <name>Услуга 7</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>7</value>
//        </visible>
//      </param>
//      <param>
//        <code>CAN_REPEAT_SERVICE_7</code>
//        <type>boolean</type>
//        <name>Услугу 7 можно использовать повторно</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>7</value>
//        </visible>
//      </param>
//      <param>
//        <code>SERVICE_8</code>
//        <type>order_param</type>
//        <name>Услуга 8</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>8</value>
//        </visible>
//      </param>
//      <param>
//        <code>CAN_REPEAT_SERVICE_8</code>
//        <type>boolean</type>
//        <name>Услугу 8 можно использовать повторно</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>8</value>
//        </visible>
//      </param>
//      <param>
//        <code>SERVICE_9</code>
//        <type>order_param</type>
//        <name>Услуга 9</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>9</value>
//        </visible>
//      </param>
//      <param>
//        <code>CAN_REPEAT_SERVICE_9</code>
//        <type>boolean</type>
//        <name>Услугу 9 можно использовать повторно</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>9</value>
//        </visible>
//      </param>
//      <param>
//        <code>SERVICE_10</code>
//        <type>order_param</type>
//        <name>Услуга 10</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>greater_or_equal</condition>
//          <value>10</value>
//        </visible>
//      </param>
//      <param>
//        <code>CAN_REPEAT_SERVICE_10</code>
//        <type>boolean</type>
//        <name>Услугу 10 можно использовать повторно</name>
//        <visible>
//          <code>SERVICES_BUTTON_COUNT</code>
//          <condition>equal</condition>
//          <value>10</value>
//        </visible>
//      </param>
//    </items>
//  </group>

//  <param>
//    <code>CALC_SUM_BY_TAXIMETER</code>
//    <type>boolean</type>
//    <name>Считать сумму по таксометру</name>
//  </param>
//  <param>
//    <code>USE_STOPS_WAITING_IDLE</code>
//    <type>boolean</type>
//    <name>Считать простой, ожидание и остановки независимо от настройки "Считать сумму по таксометру"</name>
//    <visible>
//      <code>CALC_SUM_BY_TAXIMETER</code>
//      <condition>equal</condition>
//      <value>false</value>
//    </visible>
//  </param>
//  <param>
//    <code>USE_GPS_MISSED_DISTANCE_RECOVERY</code>
//    <type>boolean</type>
//    <name>Использовать восстановление километража по прямой при потере координат</name>
//    <visible>
//      <code>CALC_SUM_BY_TAXIMETER</code>
//      <condition>equal</condition>
//      <value>true</value>
//    </visible>
//  </param>
//  <param>
//    <code>VALUTA</code>
//    <type>string</type>
//    <name>Валюта</name>
//  </param>

//  <group>
//    <name>Параметры для печати чека</name>
//    <items>
//      <param>
//        <code>NEED_DETAILS_IN_CHECK</code>
//        <type>boolean</type>
//        <name>Печатать детализацию поездки</name>
//      </param>
//      <param>
//        <code>TAXI_NAME</code>
//        <type>string</type>
//        <name>Название такси</name>
//      </param>
//      <param>
//        <code>TAXI_PHONE</code>
//        <type>string</type>
//        <name>Телефон такси</name>
//      </param>
//      <param>
//        <code>TAXI_INN</code>
//        <type>string</type>
//        <name>ИНН</name>
//      </param>
//    </items>
//  </group>
//</xml_consts>

const
  MIN_CITY = 0;
  MIN_COUNTRY = 0;
  MIN_HOURLY = 0;
  BOARDING_CITY = 0;
  CITY_KM_INCLUDED = 0;
  CITY_KM_COST = 0;
  CITY_MINUTES_INCLUDED = 0;
  CITY_MINUTE_COST = 0;
  BOARDING_COUNTRY = 0;
  COUNTRY_KM_INCLUDED = 0;
  COUNTRY_KM_COST = 0;
  COUNTRY_MINUTES_INCLUDED = 0;
  COUNTRY_MINUTE_COST = 0;
  SOURCE_COUNTRY_KM_COST = 0;
  BOARDING_HOURLY = 0;
  HOURLY_MINUTES_INCLUDED = 0;
  HOURLY_MINUTE_COST = 0;
  HOURLY_PERIOD = 0;
  HOURLY_TRIP_KM_INCLUDED = 0;
  HOURLY_HOUR_KM_INCLUDED = 0;
  HOURLY_KM_COST = 0;
  WAITING_INCLUDED = True;
  WAIT_MINUTE_COST = 0;
  FREE_WAITING_TIME = 0;
  PRIOR_FREE_WAITING_TIME = 0;
  CLIENT_ABSENT_VISIBLE = True;
  CLIENT_ABSENT_ENABLED_TIME = 0;
  IDLE_MINUTE_COST = 0;
  FREE_IDLE_TIME = 0;
  SPEED_LIMIT = 5;
  USE_ZONE_PATH = False;
  USE_ZONE_COST = False;
  ZONES_PATH_GROUP_ID = 0;
  USE_REAL_ZONES_IN_TAXM = False;
  MIN_STOP_COST = 0;
  STOP_MINUTES_INCLUDED = 0;
  STOP_MINUTE_COST = 0;
  PRIOR_ORDER_COST = 0;
  CITY_BACK_WAY_PERCENT = 0;
  COUNTRY_BACK_WAY_PERCENT = 0;
  ZONES_BACK_WAY_PERCENT = 0;
  ROUNDING = 1;
  ROUND_UP = False;
  MIN_SUM_AFTER_CALC = False;
  DISCOUNT_AFTER_MIN = False;
  SERVICES_AFTER_MIN = False;
  TAXOPHONE_FIRST_DISCOUNT_SUM = 0;
  TAXOPHONE_FIRST_DISCOUNT_PERCENT = 0;
  TAXOPHONE_CONSTANT_DISCOUNT_SUM = 0;
  TAXOPHONE_CONSTANT_DISCOUNT_PERCENT = 0;
  TAXOPHONE_REGULAR_DISCOUNT_COUNT = 0;
  TAXOPHONE_REGULAR_DISCOUNT_SUM = 0;
  TAXOPHONE_REGULAR_DISCOUNT_PERCENT = 0;
  CALC_SUM_BY_TAXIMETER = True;
  USE_STOPS_WAITING_IDLE = False;
  USE_GPS_MISSED_DISTANCE_RECOVERY = False;
  USE_CALC_TM_ROUTE = False;
  CALC_TM_ROUTE_PERIOD = 0;
  CALC_TM_ROUTE_FINISH_TIMEOUT = 15;
  VALUTA = 'р';
  NEED_DETAILS_IN_CHECK = False;
  TAXI_NAME = 'ООО "Название Такси"';
  TAXI_PHONE = '(495) 123-45-67';
  TAXI_INN = '123456789012';

  SERVICES_BUTTON_COUNT = 0;
  SERVICE_1 = 0;
  CAN_REPEAT_SERVICE_1 = False;
  SERVICE_2 = 0;
  CAN_REPEAT_SERVICE_2 = False;
  SERVICE_3 = 0;
  CAN_REPEAT_SERVICE_3 = False;
  SERVICE_4 = 0;
  CAN_REPEAT_SERVICE_4 = False;
  SERVICE_5 = 0;
  CAN_REPEAT_SERVICE_5 = False;
  SERVICE_6 = 0;
  CAN_REPEAT_SERVICE_6 = False;
  SERVICE_7 = 0;
  CAN_REPEAT_SERVICE_7 = False;
  SERVICE_8 = 0;
  CAN_REPEAT_SERVICE_8 = False;
  SERVICE_9 = 0;
  CAN_REPEAT_SERVICE_9 = False;
  SERVICE_10 = 0;
  CAN_REPEAT_SERVICE_10 = False;

// Округлить сумму.
function RoundSum(Sum: Single): Single;
var
  F, R: Single;
begin
  if ROUNDING = 0 then
    Result := Sum
  else
  begin
    R := 1 / ROUNDING;
    if ROUND_UP then
      Result := Ceil(Sum * R) / R
    else
    begin
      F := Trunc(Sum * R) / R;
      if Sum - F >= ROUNDING / 2 then
        F := F + ROUNDING;
      Result := F;
    end;
  end;
end;


function FloatToStrFixed(Value: Single): String;
var
  R, SymbolCount: Integer;
begin
  R := Floor(ROUNDING * 100);
  if R mod 100 = 0 then
    SymbolCount := 0
  else
  if R mod 10 = 0 then
    SymbolCount := 1
  else
    SymbolCount := 2;
  Result := FloatToStr(Round(Value, SymbolCount));
end;


procedure TM_AddZonesSum(var TaxmZonesSum: Single; var ZonePathSum: Single;
  NeedPrintToBill: Boolean);
var
  F: Single;
  s: String;
  NeedZoneOutCost: Boolean;
  StopCount, i: Integer;
begin
  // == Районы.
  if USE_ZONE_COST then
  begin
    // Посадка.
    F := ReadFloat('ZoneInCost', -1);
    if F <> 0 then
    begin
      s := ReadStr('ZoneName', -1);
      TaxmZonesSum := TaxmZonesSum + F;
      if NeedPrintToBill then
      begin
        WriteStr('Bill', 'Text', 'Посадка в ''' + s + '''');
        WriteStr('Bill', 'Sum', FloatToStr(F, 2));
      end;
    end;
    // Высадка.
    if ReadStr('ZoneName', -1) <> ReadStr('ZoneName', -2) then
      NeedZoneOutCost := True
    else
      if ReadInt('StopCount') > 0 then
      begin
        NeedZoneOutCost := False;
        for i := 0 to ReadInt('StopCount') - 1 do
          if ReadStr('ZoneName', i) <> ReadStr('ZoneName', -1) then
            NeedZoneOutCost := True;
      end
      else
        NeedZoneOutCost := False;
    if NeedZoneOutCost then
    begin
      F := ReadFloat('ZoneOutCost', -2);
      if F <> 0 then
      begin
        s := ReadStr('ZoneName', -2);
        TaxmZonesSum := TaxmZonesSum + F;
        if NeedPrintToBill then
        begin
          WriteStr('Bill', 'Text', 'Высадка в ''' + s + '''');
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));
        end;
      end;
    end;
    // Остановки.
    for i := 0 to ReadInt('StopCount') - 1 do
    begin
      F := ReadFloat('ZoneStopCost', i);
      if F <> 0 then
      begin
        s := ReadStr('ZoneName', i);
        TaxmZonesSum := TaxmZonesSum + F;
        if NeedPrintToBill then
        begin
          WriteStr('Bill', 'Text', 'Остановка в ''' + s + '''');
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));
        end;
      end;
    end;
  end;

  // Проезды.
  if USE_ZONE_PATH then
  begin
    StopCount := ReadInt('StopCount');
    if StopCount > 0 then
    begin
      F := ReadFloat('ZonePathCost', -1, 0);
      if F <> 0 then
      begin
        ZonePathSum := F;
        if NeedPrintToBill then
        begin
          WriteStr('Bill', 'Text', 'Проезд ''' +
            ReadStr('ZoneName', -1) + ''' -> ''' +
            ReadStr('ZoneName', 0) + '''');
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));
        end;
      end;
      for i := 0 to StopCount - 2 do
      begin
        F := ReadFloat('ZonePathCost', i, i + 1);
        if F <> 0 then
        begin
          ZonePathSum := ZonePathSum + F;
          if NeedPrintToBill then
          begin
            WriteStr('Bill', 'Text', 'Проезд ''' +
              ReadStr('ZoneName', i) + ''' -> ''' +
              ReadStr('ZoneName', i + 1) + '''');
            WriteStr('Bill', 'Sum', FloatToStr(F, 2));
          end;
        end;
      end;
      F := ReadFloat('ZonePathCost', StopCount - 1, -2);
      if F <> 0 then
      begin
        ZonePathSum := ZonePathSum + F;
        if NeedPrintToBill then
        begin
          WriteStr('Bill', 'Text', 'Проезд ''' +
            ReadStr('ZoneName', StopCount - 1) + ''' -> ''' +
            ReadStr('ZoneName', -2) + '''');
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));
        end;
      end;
    end
    else
    begin
      F := ReadFloat('ZonePathCost', -1, -2);
      if F <> 0 then
      begin
        ZonePathSum := F;
        if NeedPrintToBill then
        begin
          WriteStr('Bill', 'Text', 'Проезд ''' +
            ReadStr('ZoneName', -1) + ''' -> ''' +
            ReadStr('ZoneName', -2) + '''');
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));
        end;
      end;
    end;

    if ReadBool('BackFree') and (ZonePathSum <> 0) and
       (ZONES_BACK_WAY_PERCENT <> 0) then
    begin
      F := ZonePathSum * ZONES_BACK_WAY_PERCENT / 100;
      ZonePathSum := ZonePathSum + F;
      if NeedPrintToBill then
      begin
        WriteStr('Bill', 'Text', 'Обратный проезд между районами');
        WriteStr('Bill', 'Sum', FloatToStr(F, 2));
      end;
    end;
  end;
end;

// Заказ пришёл из TaxoPhone.
function TM_IsFromTaxophone: Boolean;
begin
  Result := (ReadInt('CreationWay') = 6) or
    (ReadInt('CreationWay') = 9) or
    (ReadInt('CreationWay') = 11);
end;


// Рассчитать стоимость за ожидание.
function TM_GetWaitingCost: Single;
var
  FreeWaitingTime: Integer;
begin
  if not ReadBool('IsPrior') then
    FreeWaitingTime := FREE_WAITING_TIME
  else
    FreeWaitingTime := PRIOR_FREE_WAITING_TIME;
  if ReadInt('WaitTime') div 60 > FreeWaitingTime then
    Result := WAIT_MINUTE_COST *
      (ReadInt('WaitTime') div 60 - FreeWaitingTime)
  else
    Result := 0;
end;


// Получить минималку.
function TM_GetMinSum: Single;
begin
  if ReadBool('IsHourly') then
    Result := MIN_HOURLY
  else
  if ReadBool('IsCountry') then
    Result := MIN_COUNTRY
  else
    Result := MIN_CITY;
end;


// Добавить услуги (атрибуты/параметры) к сумме.
procedure TM_AddServices(var Sum: Single; NeedPrintToBill: Boolean);
var
  F, ServicePercentSum, ServicesSum: Single;
  i: Integer;
begin
  // Услуги.
  ServicesSum := 0;
  for i := 0 to ReadInt('ServiceCount') - 1 do
  begin
    F := ReadFloat('ServiceSum', i);
    if F <> 0 then
    begin
      ServicesSum := ServicesSum + F;
      if NeedPrintToBill then
      begin
        WriteStr('Bill', 'Text',
          'Услуга ''' + ReadStr('ServiceName', i) + '''');
        WriteStr('Bill', 'Sum', FloatToStr(F, 2));
      end;
    end;
  end;

  ServicePercentSum := 0;
  for i := 0 to ReadInt('ServiceCount') - 1 do
  begin
    F := ReadFloat('ServicePercent', i);
    if F <> 0 then
    begin
      ServicePercentSum := ServicePercentSum + F;
      if NeedPrintToBill then
      begin
        WriteStr('Bill', 'Text',
          'Услуга ''' + ReadStr('ServiceName', i) + '''');
        WriteStr('Bill', 'Sum', FloatToStr(F, 0) + '%');
      end;
    end;
  end;

  Sum := Sum + Sum * ServicePercentSum / 100 + ServicesSum;
end;


// Рассчитать сумму со скидкой.
procedure TM_AddDiscounts(var Sum: Single;
  var TotalDiscSum: Single;
  var TotalDiscPercent: Single;
  NeedPrintToBill: Boolean);
var
  F: Single;
  i: Integer;
  S: String;
begin
  // == Скидки.

  TotalDiscSum := 0;
  TotalDiscPercent := 0;
  // Скидка/наценка.
  for i := 0 to ReadInt('DiscMarkupCount') - 1 do
  begin
    F := ReadFloat('DiscMarkupSum', i);
    if F <> 0 then
    begin
      if NeedPrintToBill then
      begin
        if F > 0 then
          S := 'Наценка'
        else
          S := 'Скидка';
        WriteStr('Bill', 'Text', S + ' ''' +
          ReadStr('DiscMarkupName', i) + '''');
        WriteStr('Bill', 'Sum', FloatToStr(Abs(F), 2));
      end;
      // + это наценка, - это скидка.
      TotalDiscSum := TotalDiscSum - F;
    end;
    F := ReadFloat('DiscMarkupPercent', i);
    if F <> 0 then
    begin
      if NeedPrintToBill then
      begin
        if F > 0 then
          S := 'Наценка'
        else
          S := 'Скидка';
        WriteStr('Bill', 'Text', S + ' ''' +
          ReadStr('DiscMarkupName', i) + '''');
        WriteStr('Bill', 'Sum', FloatToStr(Abs(F), 0) + '%');
      end;
      // + это наценка, - это скидка.
      TotalDiscPercent := TotalDiscPercent - F;
    end;
  end;

  if TM_IsFromTaxophone then
  begin
    // Постоянная скидка для заказов из TaxoPhone.
    TotalDiscSum := TotalDiscSum + TAXOPHONE_CONSTANT_DISCOUNT_SUM;
    TotalDiscPercent := TotalDiscPercent + TAXOPHONE_CONSTANT_DISCOUNT_PERCENT;
    if NeedPrintToBill then
    begin
      if TAXOPHONE_CONSTANT_DISCOUNT_SUM > 0 then
      begin
        WriteStr('Bill', 'Text', 'Постоянная скидка за заказ из TaxoPhone');
        WriteStr('Bill', 'Sum', FloatToStr(TAXOPHONE_CONSTANT_DISCOUNT_SUM, 2));
      end;
      if TAXOPHONE_CONSTANT_DISCOUNT_PERCENT > 0 then
      begin
        WriteStr('Bill', 'Text', 'Постоянная скидка за заказ из TaxoPhone');
        WriteStr('Bill', 'Sum', FloatToStr(TAXOPHONE_CONSTANT_DISCOUNT_PERCENT, 0) + '%');
      end;
    end;

    // Скидка за первый заказ из TaxoPhone.
    if ReadInt('ClientTaxoPhoneOrdersCount') = 0 then
    begin
      TotalDiscSum := TotalDiscSum + TAXOPHONE_FIRST_DISCOUNT_SUM;
      TotalDiscPercent := TotalDiscPercent + TAXOPHONE_FIRST_DISCOUNT_PERCENT;
      if NeedPrintToBill then
      begin
        if TAXOPHONE_FIRST_DISCOUNT_SUM > 0 then
        begin
          WriteStr('Bill', 'Text', 'Скидка за первый заказ из TaxoPhone');
          WriteStr('Bill', 'Sum', FloatToStr(TAXOPHONE_FIRST_DISCOUNT_SUM, 2));
        end;
        if TAXOPHONE_FIRST_DISCOUNT_PERCENT > 0 then
        begin
          WriteStr('Bill', 'Text', 'Скидка за первый заказ из TaxoPhone');
          WriteStr('Bill', 'Sum', FloatToStr(TAXOPHONE_FIRST_DISCOUNT_PERCENT, 0) + '%');
        end;
      end;
    end;

    // Регулярная скидка за заказ из TaxoPhone.
    if TAXOPHONE_REGULAR_DISCOUNT_COUNT > 0 then
      if (ReadInt('ClientTaxoPhoneOrdersCount') + 1) mod TAXOPHONE_REGULAR_DISCOUNT_COUNT = 0 then
      begin
        TotalDiscSum := TotalDiscSum + TAXOPHONE_REGULAR_DISCOUNT_SUM;
        TotalDiscPercent := TotalDiscPercent + TAXOPHONE_REGULAR_DISCOUNT_PERCENT;
        if NeedPrintToBill then
        begin
          if TAXOPHONE_REGULAR_DISCOUNT_SUM > 0 then
          begin
            WriteStr('Bill', 'Text', 'Регулярная скидка за каждый ' +
              IntToStr(TAXOPHONE_REGULAR_DISCOUNT_COUNT) + '-й заказ из TaxoPhone');
            WriteStr('Bill', 'Sum', FloatToStr(TAXOPHONE_REGULAR_DISCOUNT_SUM, 2));
          end;
          if TAXOPHONE_FIRST_DISCOUNT_PERCENT > 0 then
          begin
            WriteStr('Bill', 'Text', 'Регулярная скидка за каждый ' +
              IntToStr(TAXOPHONE_REGULAR_DISCOUNT_COUNT) + '-й заказ из TaxoPhone');
            WriteStr('Bill', 'Sum', FloatToStr(TAXOPHONE_REGULAR_DISCOUNT_PERCENT, 0) + '%');
          end;
        end;
      end;
  end;

  // Скидка.
  S := ReadStr('DiscountName');
  F := ReadFloat('DiscountSum');
  if F <> 0 then
  begin
    if NeedPrintToBill then
    begin
      WriteStr('Bill', 'Text', 'Скидка ''' + S + '''');
      WriteStr('Bill', 'Sum', FloatToStr(F, 2));
    end;
    TotalDiscSum := TotalDiscSum + F;
  end;
  F := ReadFloat('DiscountPercent');
  if F <> 0 then
  begin
    if NeedPrintToBill then
    begin
      WriteStr('Bill', 'Text', 'Скидка ''' + S + '''');
      WriteStr('Bill', 'Sum', FloatToStr(F, 0) + '%');
    end;
    TotalDiscPercent := TotalDiscPercent + F;
  end;
  // Скидка по диск. карте.
  S := ReadStr('DiscCardName');
  F := ReadFloat('DiscCardSum');
  if F <> 0 then
  begin
    if NeedPrintToBill then
    begin
      WriteStr('Bill', 'Text', 'Скидка по ДК ''' + S + '''');
      WriteStr('Bill', 'Sum', FloatToStr(F, 2));
    end;
    TotalDiscSum := TotalDiscSum + F;
  end;
  F := ReadFloat('DiscCardPercent');
  if F <> 0 then
  begin
    if NeedPrintToBill then
    begin
      WriteStr('Bill', 'Text', 'Скидка по ДК ''' + S + '''');
      WriteStr('Bill', 'Sum', FloatToStr(F, 0) + '%');
    end;
    TotalDiscPercent := TotalDiscPercent + F;
  end;

  Sum := Sum - Sum * TotalDiscPercent / 100 - TotalDiscSum;
  if NeedPrintToBill then
  begin
    WriteStr('Bill', 'Text', 'Сумма со скидкой');
    WriteStr('Bill', 'Sum', FloatToStr(Sum, 2));
  end;
end;


// *****************
// Вычисление суммы.
// *****************
procedure CalcSum;
var
  Sum, F, CityDist, CountryDist, TotalDist, HourlyPayDist,
  ZonePathSum, TaxmZonesSum: Single;
  CityCost, CountryCost: Single;
  i, StopCount, TripTime: Integer;
  NeedZoneOutCost: Boolean;
  CityTripTime, CountryTripTime: Integer;
begin
  Sum := 0;
  WriteInt('UseZonesPathGroupId', ZONES_PATH_GROUP_ID);

  if ReadBool('IsPrior') and (PRIOR_ORDER_COST <> 0) then
  begin
    Sum := Sum + PRIOR_ORDER_COST;
    WriteStr('Bill', 'Text', 'Предварительный заказ');
    WriteStr('Bill', 'Sum', FloatToStr(PRIOR_ORDER_COST, 2));
  end;

  F := TM_GetWaitingCost;
  if F <> 0 then
  begin
    Sum := Sum + F;
    WriteStr('Bill', 'Text',
      'Ожидание ' + FloatToStr(WAIT_MINUTE_COST, 2) + ' ' + VALUTA + '/мин');
    WriteStr('Bill', 'Value',
      IntToStr(ReadInt('WaitTime') div 60) + ' мин');
    WriteStr('Bill', 'Sum', FloatToStr(F, 2));
  end;

  F := SOURCE_COUNTRY_KM_COST * ReadFloat('SourceDistCountry');
  if F <> 0 then
  begin
    Sum := Sum + F;
    WriteStr('Bill', 'Text',
      'До подачи за город ' + FloatToStr(SOURCE_COUNTRY_KM_COST, 2) + ' ' + VALUTA + '/км');
    WriteStr('Bill', 'Value',
    FloatToStr(ReadFloat('SourceDistCountry'), 2) + ' км');
    WriteStr('Bill', 'Sum', FloatToStr(F, 2));
  end;

  CityDist := ReadFloat('Distance');
  if ReadBool('IsCountry') then
    CountryDist := ReadFloat('DistCountry')
  else
    CountryDist := 0;
  TotalDist := CityDist + CountryDist;
  TripTime := ReadInt('TripTime');

  // Почасовой заказ.
  if ReadBool('IsHourly') then
  begin
    F := BOARDING_HOURLY;
    if TripTime div 60 > HOURLY_MINUTES_INCLUDED then
      if HOURLY_PERIOD = 0 then
        F := F + (TripTime div 60 - HOURLY_MINUTES_INCLUDED) *
          HOURLY_MINUTE_COST
      else
        F := F + Ceil((TripTime div 60 - HOURLY_MINUTES_INCLUDED) /
          HOURLY_PERIOD) * HOURLY_PERIOD * HOURLY_MINUTE_COST;
    if F <> 0 then
    begin
      Sum := Sum + F;
      WriteStr('Bill', 'Text', 'Продолжительность');
      WriteStr('Bill', 'Value',
        IntToStr(TripTime div 60) + ' мин');
      WriteStr('Bill', 'Sum', FloatToStr(F, 2));
    end;

    if HOURLY_KM_COST > 0 then
    begin
      F := 0;
      HourlyPayDist := 0;
      if HOURLY_HOUR_KM_INCLUDED > 0 then
      begin
        HourlyPayDist := (TotalDist - HOURLY_HOUR_KM_INCLUDED *
          Ceil(TripTime / 60 / 60));
        F := HourlyPayDist * HOURLY_KM_COST;
      end
      else
      if HOURLY_TRIP_KM_INCLUDED > 0 then
      begin
        HourlyPayDist := TotalDist - HOURLY_TRIP_KM_INCLUDED;
        F := HourlyPayDist * HOURLY_KM_COST;
      end
      else
      begin
        HourlyPayDist := TotalDist;
        F := TotalDist * HOURLY_KM_COST;
      end;
      if F > 0 then
      begin
        Sum := Sum + F;
        WriteStr('Bill', 'Text', 'Платный километраж');
        WriteStr('Bill', 'Value',
          FloatToStr(HourlyPayDist, 2) + ' км');
        WriteStr('Bill', 'Sum', FloatToStr(F, 2));
      end;
    end;
  end
  else
  begin
    // Загородный заказ.
    if ReadBool('IsCountry') then
    begin
      F := BOARDING_COUNTRY;
      if TotalDist > COUNTRY_KM_INCLUDED then
        if CityDist <= COUNTRY_KM_INCLUDED then
          F := F + (TotalDist - COUNTRY_KM_INCLUDED) * COUNTRY_KM_COST
        else
          F := F + (CityDist - COUNTRY_KM_INCLUDED) * CITY_KM_COST +
            CountryDist * COUNTRY_KM_COST;

      CityCost := 0;
      if CityDist > COUNTRY_KM_INCLUDED then
        CityCost := BOARDING_COUNTRY + (CityDist - COUNTRY_KM_INCLUDED) * CITY_KM_COST
      else
        if (TotalDist > COUNTRY_KM_INCLUDED) and (COUNTRY_KM_INCLUDED > 0) then
          CityCost := BOARDING_COUNTRY * CityDist / COUNTRY_KM_INCLUDED
        else
          if TotalDist > 0 then
            CityCost := BOARDING_COUNTRY * CityDist / TotalDist;
      CountryCost := F - CityCost;

      if F <> 0 then
      begin
        Sum := Sum + F;
        WriteStr('Bill', 'Text', 'Путь');
        WriteStr('Bill', 'Value',
          FloatToStr(TotalDist, 2) + ' км');
        WriteStr('Bill', 'Sum', FloatToStr(F, 2));
        if ReadBool('BackFree') then
        begin
          if (CityCost <> 0) and (CITY_BACK_WAY_PERCENT <> 0) then
          begin
            F := CityCost * CITY_BACK_WAY_PERCENT / 100;
            Sum := Sum + F;
            WriteStr('Bill', 'Text', 'Обратно по городу');
            WriteStr('Bill', 'Sum', FloatToStr(F, 2));
          end;
          if (CountryCost <> 0) and (COUNTRY_BACK_WAY_PERCENT <> 0) then
          begin
            F := CountryCost * COUNTRY_BACK_WAY_PERCENT / 100;
            Sum := Sum + F;
            WriteStr('Bill', 'Text', 'Обратно за городом');
            WriteStr('Bill', 'Sum', FloatToStr(F, 2));
          end;
        end;
      end;

      if ((COUNTRY_MINUTE_COST > 0) or (CITY_MINUTE_COST > 0)) and 
         (TripTime > COUNTRY_MINUTES_INCLUDED * 60) and
         (TotalDist > 0) then
      begin
        CountryTripTime := Floor(TripTime * (CountryDist / TotalDist));
        CityTripTime := Floor(TripTime - CountryTripTime);

        if CityTripTime <= COUNTRY_MINUTES_INCLUDED * 60 then
        begin
          CityCost := 0;
          CountryCost := (TripTime / 60 - COUNTRY_MINUTES_INCLUDED) * COUNTRY_MINUTE_COST
        end
        else
        begin
          CityCost := (CityTripTime / 60 - COUNTRY_MINUTES_INCLUDED) * CITY_MINUTE_COST;
          CountryCost := CountryTripTime / 60 * COUNTRY_MINUTE_COST;
        end;

        F := CityCost + CountryCost;
        if F <> 0 then
        begin
          Sum := Sum + F;

          WriteStr('Bill', 'Text', 'Длительность по городу');
          WriteStr('Bill', 'Value', TimeLenToStr(CityTripTime));
          WriteStr('Bill', 'Sum', FloatToStr(CityCost, 2));

          WriteStr('Bill', 'Text', 'Длительность за городом');
          WriteStr('Bill', 'Value', TimeLenToStr(CountryTripTime));
          WriteStr('Bill', 'Sum', FloatToStr(CountryCost, 2));
        end;
      end;
    end
    else
    // Городской заказ.
    begin
      F := BOARDING_CITY;
      if TotalDist > CITY_KM_INCLUDED then
        F := F + (TotalDist - CITY_KM_INCLUDED) * CITY_KM_COST;

      if F <> 0 then
      begin
        Sum := Sum + F;
        WriteStr('Bill', 'Text', 'Путь');
        WriteStr('Bill', 'Value',
          FloatToStr(TotalDist, 2) + ' км');
        WriteStr('Bill', 'Sum', FloatToStr(F, 2));
        if ReadBool('BackFree') then
          if (CITY_BACK_WAY_PERCENT <> 0) then
          begin
            F := F * CITY_BACK_WAY_PERCENT / 100;
            Sum := Sum + F;
            WriteStr('Bill', 'Text', 'Обратно по городу');
            WriteStr('Bill', 'Sum', FloatToStr(F, 2));
          end;
      end;

      if (CITY_MINUTE_COST > 0) and 
         (TripTime > CITY_MINUTES_INCLUDED * 60) then
      begin
        F := (TripTime / 60 - CITY_MINUTES_INCLUDED) * CITY_MINUTE_COST;
        if F <> 0 then
        begin
          Sum := Sum + F;
          WriteStr('Bill', 'Text', 'Длительность по городу');
          WriteStr('Bill', 'Value', TimeLenToStr(TripTime));
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));
        end;
      end;
    end;
  end;

  // Остановки.
  if not ReadBool('IsHourly') then
  begin
    F := MIN_STOP_COST * ReadInt('StopCount');
    if F <> 0 then
    begin
      Sum := Sum + F;
      WriteStr('Bill', 'Text', 'Остановки');
      WriteStr('Bill', 'Value',
        IntToStr(ReadInt('StopCount')) + ' шт');
      WriteStr('Bill', 'Sum', FloatToStr(F, 2));
    end;
  end;

  TaxmZonesSum := 0;
  ZonePathSum := 0;
  TM_AddZonesSum(TaxmZonesSum, ZonePathSum, True);
  Sum := Sum + ZonePathSum + TaxmZonesSum;

  if not SERVICES_AFTER_MIN then
    TM_AddServices(Sum, True);

  WriteFloat('Sum', Sum);
end;


// ***********************************************
// Заполение полей райнов и скидок для таксометра.
// ***********************************************
procedure CalcTaxmSums;
var
  i, StopCount: Integer;
  TaxmZonesSum, TotalDiscPercent,
    TotalDiscSum, ZonePathSum, Sum: Single;
begin
  // == Районы.
  WriteInt('UseZonesPathGroupId', ZONES_PATH_GROUP_ID);
  TaxmZonesSum := 0;
  ZonePathSum := 0;
  TM_AddZonesSum(TaxmZonesSum, ZonePathSum, False);

  // Запись.
  WriteFloat('TaxmZonesSum', TaxmZonesSum + ZonePathSum);

  TotalDiscSum := 0;
  TotalDiscPercent := 0;
  TM_AddDiscounts(Sum, TotalDiscSum, TotalDiscPercent, False);

  // Запись.
  WriteFloat('TaxmTotalDiscSum', TotalDiscSum);
  WriteFloat('TaxmTotalDiscPercent', TotalDiscPercent);
end;


// ****************************
// Вычисление суммы со скидкой.
// ****************************
procedure CalcTotalSum;
var
  WaitingCost, F, MinSum, Sum: Single;
  i: Integer;
  TotalDiscSum, TotalDiscPercent: Single;
begin
  // Сумма без скидок.
  Sum := ReadFloat('Sum');

  TotalDiscSum := 0;
  TotalDiscPercent := 0;

  if not DISCOUNT_AFTER_MIN then
    TM_AddDiscounts(Sum, TotalDiscSum, TotalDiscPercent, True);

  MinSum := TM_GetMinSum;
  WriteStr('Bill', 'Text', 'Минимум');
  WriteStr('Bill', 'Sum', FloatToStr(MinSum, 2));

  WaitingCost := TM_GetWaitingCost;
  if WAITING_INCLUDED then
    Sum := Max(MinSum, Sum)
  else
    Sum := Max(MinSum + WaitingCost, Sum);

  if SERVICES_AFTER_MIN then
    TM_AddServices(Sum, True);

  if DISCOUNT_AFTER_MIN then
    TM_AddDiscounts(Sum, TotalDiscSum, TotalDiscPercent, True);

  Sum := RoundSum(Sum);

  WriteStr('Bill', 'Text', 'Итого');
  WriteStr('Bill', 'Sum', FloatToStr(Sum, 2) + ' ' + VALUTA);

  // Записать итоговую сумму.
  WriteFloat('TotalSum', Sum);
end;


// Использовать простой и остановки.
function TMD_UseCalcStopsIdle: Boolean;
begin
  Result := not ReadBool('IsHourly') and
    (CALC_SUM_BY_TAXIMETER or USE_STOPS_WAITING_IDLE)
end;


// **************
// Инициализация.
// **************
procedure ResetCalc;
begin
  if CLIENT_ABSENT_VISIBLE then
    WriteInt('ClientAbsentVisible', 1)
  else
    WriteInt('ClientAbsentVisible', 0);
end;


// *****************
// Ожидание клиента.
// *****************
procedure WaitCalc;
var
  Sum: Single;
  FreeWaitingTime, WaitTime: Integer;
begin
  if not ReadBool('IsPrior') then
    FreeWaitingTime := FREE_WAITING_TIME
  else
    FreeWaitingTime := PRIOR_FREE_WAITING_TIME;

  WaitTime := ReadInt('WaitTime');

  WriteInt('FreeWaitingTime', (FreeWaitingTime * 60 - WaitTime));

  if CALC_SUM_BY_TAXIMETER or USE_STOPS_WAITING_IDLE then
    if WaitTime > FreeWaitingTime * 60 then
    begin
      Sum := ReadFloat('Sum') + WAIT_MINUTE_COST / 60;
      WriteFloat('Temp', 'PayWaitTimeSum', Sum);
      WriteFloat('Sum', Sum);
      WriteStr('SumStr', FloatToStrFixed(RoundSum(Sum)));
      WriteFloat('CurrentSum', Sum);
    end;

  if CLIENT_ABSENT_VISIBLE and
     (WaitTime > (FreeWaitingTime - CLIENT_ABSENT_ENABLED_TIME) * 60) then
    WriteInt('ClientAbsentEnabled', 1)
  else
    WriteInt('ClientAbsentEnabled', 0);
end;


// Получить параметры услуги по ИД.
procedure TMD_GetServiceParams(ServiceId: Integer;
  var ServiceCost: Single;
  var ServicePercent: Integer;
  var ServiceName: String);
begin
  ServiceCost := ReadFloat('OrderParamSum', ServiceId);
  ServiceName := ReadStr('OrderParamName', ServiceId);
  ServicePercent := Trunc(ReadFloat('OrderParamPercent', ServiceId));
end;


// Получить параметры услуги по индексу.
procedure TMD_GetServiceParamsByIndex(Index: Integer;
  var ServiceCost: Single;
  var ServicePercent: Integer;
  var ServiceName: String;
  var ServiceId: Integer;
  var CanRepeatService: Boolean);
begin
  if Index = 1 then
  begin
    TMD_GetServiceParams(SERVICE_1, ServiceCost, ServicePercent, ServiceName);
    ServiceId := SERVICE_1;
    CanRepeatService := CAN_REPEAT_SERVICE_1;
  end
  else
  if Index = 2 then
  begin
    TMD_GetServiceParams(SERVICE_2, ServiceCost, ServicePercent, ServiceName);
    ServiceId := SERVICE_2;
    CanRepeatService := CAN_REPEAT_SERVICE_2;
  end
  else
  if Index = 3 then
  begin
    TMD_GetServiceParams(SERVICE_3, ServiceCost, ServicePercent, ServiceName);
    ServiceId := SERVICE_3;
    CanRepeatService := CAN_REPEAT_SERVICE_3;
  end
  else
  if Index = 4 then
  begin
    TMD_GetServiceParams(SERVICE_4, ServiceCost, ServicePercent, ServiceName);
    ServiceId := SERVICE_4;
    CanRepeatService := CAN_REPEAT_SERVICE_4;
  end
  else
  if Index = 5 then
  begin
    TMD_GetServiceParams(SERVICE_5, ServiceCost, ServicePercent, ServiceName);
    ServiceId := SERVICE_5;
    CanRepeatService := CAN_REPEAT_SERVICE_5;
  end
  else
  if Index = 6 then
  begin
    TMD_GetServiceParams(SERVICE_6, ServiceCost, ServicePercent, ServiceName);
    ServiceId := SERVICE_6;
    CanRepeatService := CAN_REPEAT_SERVICE_6;
  end
  else
  if Index = 7 then
  begin
    TMD_GetServiceParams(SERVICE_7, ServiceCost, ServicePercent, ServiceName);
    ServiceId := SERVICE_7;
    CanRepeatService := CAN_REPEAT_SERVICE_7;
  end
  else
  if Index = 8 then
  begin
    TMD_GetServiceParams(SERVICE_8, ServiceCost, ServicePercent, ServiceName);
    ServiceId := SERVICE_8;
    CanRepeatService := CAN_REPEAT_SERVICE_8;
  end
  else
  if Index = 9 then
  begin
    TMD_GetServiceParams(SERVICE_9, ServiceCost, ServicePercent, ServiceName);
    ServiceId := SERVICE_9;
    CanRepeatService := CAN_REPEAT_SERVICE_9;
  end
  else
  if Index = 10 then
  begin
    TMD_GetServiceParams(SERVICE_10, ServiceCost, ServicePercent, ServiceName);
    ServiceId := SERVICE_10;
    CanRepeatService := CAN_REPEAT_SERVICE_10;
  end;
end;


// Создать кнопку с услугой.
procedure TMD_CreateDriverServiceButton(Index: Integer; ButtonName: String);
var
  I, ServicePercent, ServiceId: Integer;
  ServiceCost: Single;
  ServiceName: String;
  CanRepeatService: Boolean;
begin
  TMD_GetServiceParamsByIndex(Index, ServiceCost, ServicePercent, ServiceName,
    ServiceId, CanRepeatService);
  if (ServiceId > 0) and
     ((ServiceCost <> 0) or (ServicePercent <> 0)) then
  begin
    WriteStr('Button', 'New', ButtonName);
    WriteStr('Button', 'Select', ButtonName);
    WriteInt('Button', 'Visible', 1);
    WriteInt('Button', 'Enabled', 1);
    WriteInt('Button', 'LongClick', 1);
    WriteStr('Button', 'Text', ServiceName);
  end;
end;


// Получить количество услуг, доступных водителю.
function TMD_GetDriverServicesCount: Integer;
begin
  if SERVICES_BUTTON_COUNT > 10 then
    Result := 10
  else
  if SERVICES_BUTTON_COUNT < 0 then
    Result := 0
  else
    Result := SERVICES_BUTTON_COUNT;
end;


// Инициализация доп. кнопок для водительских услуг.
procedure TMD_InitDriverServiceButtons;
var
  I: Integer;
  S: String;
begin
  for I := 1 to TMD_GetDriverServicesCount do
    TMD_CreateDriverServiceButton(I, 'DriverServiceButton' + IntToStr(I));
end;


// Перепроверить видимость услуг.
procedure TMD_RecheckDriverServiceButtons;
var
  I, J: Integer;
  ServicePercent, ServiceId: Integer;
  ServiceCost: Single;
  ServiceName: String;
  FoundService, CanRepeatService: Boolean;
  IsPressedUnrepeatableButton: Boolean;
begin
  for I := 1 to TMD_GetDriverServicesCount do
  begin
    TMD_GetServiceParamsByIndex(I, ServiceCost, ServicePercent, ServiceName,
      ServiceId, CanRepeatService);
    if ServiceId > 0 then
    begin
      WriteStr('Button', 'Select', 'DriverServiceButton' + IntToStr(I));
      // Кнопку нажали один раз, запрещено нажимать повторно.
      IsPressedUnrepeatableButton := not CanRepeatService and
        (ReadInt('Temp', 'DriverServiceButton' + IntToStr(I)) = 1);

      FoundService := False;
      for J := 0 to ReadInt('OrderParamsCount') - 1 do
        if ServiceId = ReadInt('OrderParamId', J) then
          FoundService := True;

      // В ТМ был добавлен атрибут с таким же ИД.
      // Нужно сделать соответствующую кнопку невидимой.
      if FoundService and
         ((ReadInt('Button', 'Visible') = 1) or IsPressedUnrepeatableButton) then
      begin
        WriteInt('Temp', 'DriverServiceButton' + IntToStr(I), 0);
        WriteInt('Button', 'Visible', 0);
      end
      else
      // В ТМ убрали атрибут.
      // Нужно вновь сделать кнопку видимой.
      if not FoundService and (ReadInt('Button', 'Visible') = 0) and
         not IsPressedUnrepeatableButton then
        WriteInt('Button', 'Visible', 1);
    end;
  end;
end;


// Взять сумму всех водительских услуг.
procedure TMD_GetDriverServicesSum(var DriverServicesSum: Single;
  var DriverServicesPercent: Integer);
var
  ServiceCost: Single;
  ServicePercent: Integer;
  ServiceName: String;
  ServiceId, I, ServicesCount: Integer;
  CanRepeatService: Boolean;
begin
  DriverServicesSum := 0;
  DriverServicesPercent := 0;
  for I := 1 to TMD_GetDriverServicesCount do
  begin
    ServicesCount := ReadInt('Temp', 'DriverServiceButton' + IntToStr(I));
    if ServicesCount > 0 then
    begin
      TMD_GetServiceParamsByIndex(I, ServiceCost, ServicePercent, ServiceName,
        ServiceId, CanRepeatService);
      DriverServicesSum := DriverServicesSum + ServicesCount * ServiceCost;
      DriverServicesPercent := DriverServicesPercent + ServicesCount * ServicePercent;
    end;
  end;
end;


// Добавить в чек стоимость за водительские услуги.
procedure TMD_AddDriverServices;
var
  ServiceName: String;
  ServiceCost: Single;
  I, ServicePercent, ServiceId, ServicesCount: Integer;
  CanRepeatService: Boolean;
begin
  for I := 1 to TMD_GetDriverServicesCount do
  begin
    ServicesCount := ReadInt('Temp', 'DriverServiceButton' + IntToStr(I));
    if ServicesCount > 0 then
    begin
      TMD_GetServiceParamsByIndex(I, ServiceCost, ServicePercent, ServiceName,
        ServiceId, CanRepeatService);

      if ServicePercent <> 0 then
      begin
        WriteStr('Bill', 'Code', 'DRIVER_SERVICE_PERCENT_' + IntToStr(I));
        WriteStr('Bill', 'Text', ServiceName);
        WriteStr('Bill', 'Value', IntToStr(ServicesCount));
        WriteStr('Bill', 'Sum', FloatToStr(ServicePercent * ServicesCount, 0) + '%');
      end;

      if ServiceCost <> 0 then
      begin
        WriteStr('Bill', 'Code', 'DRIVER_SERVICE_SUM_' + IntToStr(I));
        WriteStr('Bill', 'Text', ServiceName);
        WriteStr('Bill', 'Value', IntToStr(ServicesCount));
        WriteStr('Bill', 'Sum', FloatToStr(ServiceCost * ServicesCount, 2));
      end;
    end;
  end;
end;



// Добавить в чек стоимость за услуги (атрибуты/параметры).
procedure TMD_AddServices;
var
  F: Single;
begin
  F := ReadFloat('ServicesSum');
  if F <> 0 then
  begin
    WriteStr('Bill', 'Code', 'SERVICE_SUM');
    WriteStr('Bill', 'Text', 'Услуги');
    WriteStr('Bill', 'Value', ReadStr('ServicesName'));
    WriteStr('Bill', 'Sum', FloatToStr(F, 2));
  end;

  F := ReadFloat('ServicesPercent');
  if F <> 0 then
  begin
    WriteStr('Bill', 'Code', 'SERVICE_PERCENT');
    WriteStr('Bill', 'Text', 'Услуги');
    WriteStr('Bill', 'Value', ReadStr('ServicesName'));
    WriteStr('Bill', 'Sum', FloatToStr(F, 0) + '%');
  end;

  TMD_AddDriverServices;
end;


// Добавить в чек стоимость за скидки.
procedure TMD_AddDiscounts;
var
  Sum, DiscountSum, DiscountPercent: Single;
begin
  Sum := ReadFloat('Temp', 'SumBeforeDiscount');
  WriteStr('Bill', 'Code', 'BEFORE_DISC');
  WriteStr('Bill', 'Text', 'Сумма без скидки');
  WriteStr('Bill', 'Sum', FloatToStr(Sum, 2));

  DiscountSum := ReadFloat('TaxmTotalDiscSum');
  if DiscountSum <> 0 then
  begin
    WriteStr('Bill', 'Code', 'DISC_SUM');
    if DiscountSum < 0 then
      WriteStr('Bill', 'Text', 'Наценка')
    else
      WriteStr('Bill', 'Text', 'Скидка');
    WriteStr('Bill', 'Sum', FloatToStr(Abs(DiscountSum), 2));
  end;

  DiscountPercent := ReadFloat('TaxmTotalDiscPercent');
  if DiscountPercent <> 0 then
  begin
    WriteStr('Bill', 'Code', 'DISC_PERCENT');
    if DiscountPercent < 0 then
      WriteStr('Bill', 'Text', 'Наценка')
    else
      WriteStr('Bill', 'Text', 'Скидка');
    WriteStr('Bill', 'Sum', FloatToStr(Abs(DiscountPercent), 0) + '%');
  end;

  Sum := Sum - Sum * DiscountPercent / 100 - DiscountSum;

  WriteStr('Bill', 'Code', 'AFTER_DISC');
  WriteStr('Bill', 'Text', 'Сумма со скидкой');
  WriteStr('Bill', 'Sum', FloatToStr(Sum, 2));
end;


function TMD_UseCalcTMRoute: Boolean;
begin
  Result := USE_CALC_TM_ROUTE and (ReadInt('SupportedScriptVersion') >= 3);
end;


// Рассчитать стоимость за километраж с учётом маршрута из ТМ.
procedure TMD_RecalcDistSum;
var
  DistanceSum: Single;
begin
  if ReadInt('TMRouteReceiveTime') <> ReadInt('Temp', 'TMRouteReceiveTime') then
  begin
    WriteInt('Temp', 'TMRouteReceiveTime', ReadInt('TMRouteReceiveTime'));
    if (ReadInt('Now') - ReadInt('TMRouteSendTime') <= CALC_TM_ROUTE_FINISH_TIMEOUT) and
       (ReadFloat('TMRouteDistance') > 0) then
    begin
      if ReadFloat('TMRouteDistance') > ReadFloat('Temp', 'KmIncluded') then
      begin
        if ReadFloat('TMRouteCountryDistance') = 0 then
          DistanceSum := (ReadFloat('TMRouteDistance') - ReadFloat('Temp', 'KmIncluded')) * CITY_KM_COST
        else
        if ReadFloat('TMRouteCityDistance') > ReadFloat('Temp', 'KmIncluded') then
          DistanceSum := (ReadFloat('TMRouteCityDistance') - ReadFloat('Temp', 'KmIncluded')) * CITY_KM_COST +
            ReadFloat('TMRouteCountryDistance') * COUNTRY_KM_COST
        else
          DistanceSum := (ReadFloat('TMRouteDistance') - ReadFloat('Temp', 'KmIncluded')) * COUNTRY_KM_COST;
      end
      else
        DistanceSum := 0;

      // Перезаписать сумму и километраж.
      WriteFloat('Temp', 'DistanceSum', DistanceSum);
      WriteFloat('Temp', 'TotalDist', ReadFloat('TMRouteDistance'));
      WriteFloat('Temp', 'DistCity', ReadFloat('TMRouteCityDistance'));
      WriteFloat('Temp', 'DistCountry', ReadFloat('TMRouteCountryDistance'));
      WriteFloat('Temp', 'GPSLostDistSum', 0);
      WriteFloat('Temp', 'GpsLostDistCountry', 0);
      WriteFloat('Temp', 'GpsLostDistCity', 0);
      WriteFloat('Temp', 'GpsLostKmDist', 0);
    end;
  end;
end;


// Заполнить дополнительную информацию по тарифу в таксометре.
procedure TMD_FillMoreInfo;
var
  BoardingMoreInfo, CityMoreInfo, CountryMoreInfo: String;
  HasKmCost, HasMinutesCost: Boolean;
begin
  WriteStr('MoreInfo', 0, 'Тариф: ' + ReadStr('TariffName'));

  if CALC_SUM_BY_TAXIMETER then
  begin
    if not ReadBool('IsHourly') then
    begin
      // Если задан хоть один параметр города или загорода, нужно будет выводить оба, 
      // даже если цена будет 0.
      HasKmCost := (CITY_KM_COST <> 0) or (COUNTRY_KM_COST <> 0);
      HasMinutesCost := (CITY_MINUTE_COST <> 0) or (COUNTRY_MINUTE_COST <> 0);

      // Выводим подробный текст в поле посадки, если есть включенные км или минуты,
      // с учетом того, что есть соответствующие цены.
      if ((ReadFloat('Temp', 'KmIncluded') <> 0) and HasKmCost) or 
         ((ReadFloat('Temp', 'MinutesIncluded') <> 0) and HasMinutesCost) then
      begin
        BoardingMoreInfo := 'Первые';
        if HasKmCost then
          BoardingMoreInfo := BoardingMoreInfo + 
            ' ' + FloatToStr(ReadFloat('Temp', 'KmIncluded')) + ' км';
        if HasMinutesCost then
          BoardingMoreInfo := BoardingMoreInfo + 
            ' ' + FloatToStr(ReadFloat('Temp', 'MinutesIncluded')) + ' мин';

        CityMoreInfo := 'Далее город:';
        CountryMoreInfo := 'Далее загород:';
      end
      else
      // Иначе выводим обычный текст.
      begin
        BoardingMoreInfo := 'Посадка';
        CityMoreInfo := 'Город:';
        CountryMoreInfo := 'Загород:';
      end;

      // В конце строки посадки всегда пишем сумму посадки.
      BoardingMoreInfo := BoardingMoreInfo + 
        ': ' + FloatToStrFixed(ReadFloat('Temp', 'BoardingSum')) + ' ' + VALUTA;

      // Если есть цена за км, либо вообще нет ни одной цены, то выводим цену за км.
      if HasKmCost or not HasMinutesCost then
      begin
        CityMoreInfo := CityMoreInfo + 
          ' ' + FloatToStrFixed(CITY_KM_COST) + ' ' + VALUTA + '/км';
        CountryMoreInfo := CountryMoreInfo + 
          ' ' + FloatToStrFixed(COUNTRY_KM_COST) + ' ' + VALUTA + '/км';
      end;

      // Если есть цена за минуты, то выводим ее. 
      // Если при этом была цена за км, то цена за минуты выводится дополнительно.
      if HasMinutesCost then
      begin
        CityMoreInfo := CityMoreInfo + 
          ' ' + FloatToStrFixed(CITY_MINUTE_COST) + ' ' + VALUTA + '/мин';
        CountryMoreInfo := CountryMoreInfo + 
          ' ' + FloatToStrFixed(COUNTRY_MINUTE_COST) + ' ' + VALUTA + '/мин';
      end;

      if IDLE_MINUTE_COST <> 0 then
        WriteStr('MoreInfo', 1, 'Простой: ' +
          FloatToStrFixed(IDLE_MINUTE_COST) + ' ' + VALUTA + '/мин');
      if ReadFloat('Temp', 'MinSum') <> 0 then
        WriteStr('MoreInfo', 2, 'Минимум: ' +
          FloatToStrFixed(ReadFloat('Temp', 'MinSum')) + ' ' + VALUTA);
      WriteStr('MoreInfo', 3, BoardingMoreInfo);
      WriteStr('MoreInfo', 4, CityMoreInfo);
      WriteStr('MoreInfo', 5, CountryMoreInfo);
    end
    else
    begin
      if MIN_HOURLY <> 0 then
        WriteStr('MoreInfo', 1, 'Минимум: ' +
          FloatToStrFixed(MIN_HOURLY) + ' ' + VALUTA);
      if HOURLY_MINUTES_INCLUDED = 0 then
      begin
        WriteStr('MoreInfo', 3, 'Посадка: ' +
          FloatToStrFixed(BOARDING_HOURLY) + ' ' + VALUTA);
        if HOURLY_PERIOD > 0 then
          WriteStr('MoreInfo', 4, IntToStr(HOURLY_PERIOD) + ' мин: ' +
            FloatToStrFixed(HOURLY_MINUTE_COST * HOURLY_PERIOD) + ' ' + VALUTA)
        else
          WriteStr('MoreInfo', 4, '1 час: ' +
            FloatToStrFixed(HOURLY_MINUTE_COST * 60) + ' ' + VALUTA);
      end
      else
      begin
        WriteStr('MoreInfo', 3, 'Первые ' + IntToStr(HOURLY_MINUTES_INCLUDED) + ' мин: ' +
          FloatToStrFixed(BOARDING_HOURLY) + ' ' + VALUTA);
        if HOURLY_PERIOD > 0 then
          WriteStr('MoreInfo', 4, 'Далее ' + IntToStr(HOURLY_PERIOD) + ' мин: ' +
            FloatToStrFixed(HOURLY_MINUTE_COST * HOURLY_PERIOD) + ' ' + VALUTA)
        else
          WriteStr('MoreInfo', 4, 'Далее 1 час: ' +
            FloatToStrFixed(HOURLY_MINUTE_COST * 60) + ' ' + VALUTA);
      end;
    end;
  end;
end;


// Рассчитать полную стоимость поездки.
procedure TMD_CalcTaximeterSum;
var
  Sum, DriverServicesSum: Single;
  DriverServicesPercent: Integer;
  IsTripFinished: Boolean;
begin
  Sum := 0;
  TMD_RecheckDriverServiceButtons;
  // Стоимость всех водительских услуг.
  TMD_GetDriverServicesSum(DriverServicesSum, DriverServicesPercent);

  if CALC_SUM_BY_TAXIMETER then
  begin
    IsTripFinished := ReadInt('Temp', 'TripFinished') = 1;

    Sum := Sum + ReadFloat('Temp', 'PayWaitTimeSum') +
      ReadFloat('Temp', 'PriorOrderCost') +
      ReadFloat('Temp', 'SourceDistCountrySum') +
      ReadFloat('Temp', 'BoardingSum');

    if ReadBool('IsHourly') then
      Sum := Sum + ReadFloat('Temp', 'TripTimeSum') +
        ReadFloat('Temp', 'HourlyDistSum')
    else
    begin
      if not IsTripFinished and TMD_UseCalcTMRoute then
        TMD_RecalcDistSum;

      Sum := Sum + ReadFloat('Temp', 'DistanceSum') +
        ReadFloat('Temp', 'CityTripTimeSum') +
        ReadFloat('Temp', 'CountryTripTimeSum') +
        ReadFloat('Temp', 'GPSLostDistSum') +
        ReadFloat('Temp', 'IdleTimeSum') +
        ReadFloat('Temp', 'StopsSum') +
        ReadFloat('Temp', 'StopTimeSum');
    end;

    if not USE_REAL_ZONES_IN_TAXM then
      Sum := Sum + ReadFloat('TaxmZonesSum')
    else
      Sum := Sum + ReadFloat('Temp', 'ZoneStopSum') +
        ReadFloat('Temp', 'ZonePathSum') +
        ReadFloat('Temp', 'ZoneInCost') +
        ReadFloat('Temp', 'ZoneOutCost');

    if not SERVICES_AFTER_MIN then
    begin
      if IsTripFinished then
        TMD_AddServices;
      Sum := Sum + ReadFloat('ServicesSum') + DriverServicesSum +
        Sum * (DriverServicesPercent + ReadFloat('ServicesPercent')) / 100;
    end;

    // Сумма без скидки.
    // Работает только для Android.
    if ReadStr('Platform') = 'Android' then
      WriteFloat('Sum', RoundSum(Sum));

    if not DISCOUNT_AFTER_MIN then
    begin
      WriteFloat('Temp', 'SumBeforeDiscount', Sum);
      if IsTripFinished then
        TMD_AddDiscounts;
      Sum := Sum - Sum * ReadFloat('TaxmTotalDiscPercent') / 100 -
        ReadFloat('TaxmTotalDiscSum');
    end;

    if not ReadBool('IsHourly') and not ReadBool('IsCountry') then
      if (ReadInt('Temp', 'WasOutCity') = 0) and not ReadBool('InCity') then
      begin
        WriteInt('Temp', 'WasOutCity', 1);
        WriteFloat('Temp', 'MinSum', MIN_COUNTRY);
        WriteStr('MoreInfo', 2, 'Минимум: ' +
          FloatToStrFixed(MIN_COUNTRY) + ' ' + VALUTA);
      end;

    if IsTripFinished then
    begin
      WriteStr('Bill', 'Code', 'MINIMUM');
      WriteStr('Bill', 'Text', 'Минимум');
      WriteStr('Bill', 'Sum', FloatToStr(ReadFloat('Temp', 'MinSum'), 2));
    end;

    if (not MIN_SUM_AFTER_CALC) or (ReadInt('Temp', 'TripFinished') = 1) then
      if WAITING_INCLUDED then
        Sum := Max(ReadFloat('Temp', 'MinSum'), Sum)
      else
        Sum := Max(ReadFloat('Temp', 'MinSum') + ReadFloat('Temp', 'PayWaitTimeSum'), Sum);

    if SERVICES_AFTER_MIN then
    begin
      if IsTripFinished then
        TMD_AddServices;
      Sum := Sum + ReadFloat('ServicesSum') + DriverServicesSum +
        Sum * (DriverServicesPercent + ReadFloat('ServicesPercent')) / 100;
    end;

    if DISCOUNT_AFTER_MIN then
    begin
      WriteFloat('Temp', 'SumBeforeDiscount', Sum);
      if IsTripFinished then
        TMD_AddDiscounts;
      Sum := Sum - Sum * ReadFloat('TaxmTotalDiscPercent') / 100 -
        ReadFloat('TaxmTotalDiscSum');
    end;
  end
  else
  begin
    WriteStr('Caption', '');
    Sum := ReadFloat('OperSum');
    Sum := Sum + DriverServicesSum + Sum * DriverServicesPercent / 100;

    if USE_STOPS_WAITING_IDLE then
      Sum := Sum + ReadFloat('Temp', 'PayWaitTimeSum') +
        ReadFloat('Temp', 'IdleTimeSum') +
        ReadFloat('Temp', 'StopsSum') +
        ReadFloat('Temp', 'StopTimeSum');

    WriteFloat('Sum', RoundSum(Sum));
  end;

  Sum := RoundSum(Sum);

  // Итоговая сумма со скидкой.
  WriteFloat('TotalSum', Sum);

  // Для ios надо заполнить параметр Sum.
  if (ReadStr('Platform') <> 'Android') and CALC_SUM_BY_TAXIMETER then
    WriteFloat('Sum', Sum);

  WriteStr('SumStr', FloatToStrFixed(Sum));
  WriteFloat('CurrentSum', Sum);
end;


// ***************
// Начало расчета.
// ***************
procedure InitCalc;
var
  F, MinSum, Boarding, KmIncluded, MinutesIncluded: Single;
begin
  TMD_InitDriverServiceButtons;
  F := ReadFloat('Temp', 'PayWaitTimeSum');
  if F <> 0 then
  begin
    WriteStr('Bill', 'Code', 'WAITING_TIME');
    WriteStr('Bill', 'Text', 'Ожидание');
    WriteStr('Bill', 'Value',
      TimeLenToStr(ReadInt('WaitTime')));
    WriteStr('Bill', 'Sum', FloatToStr(F, 2));
  end;

  if CALC_SUM_BY_TAXIMETER then
  begin
    if ReadBool('IsPrior') and (PRIOR_ORDER_COST <> 0) then
    begin
      WriteStr('Bill', 'Code', 'PRIOR_ORDER');
      WriteStr('Bill', 'Text', 'Предварительный');
      WriteStr('Bill', 'Sum', FloatToStr(PRIOR_ORDER_COST, 2));
      WriteFloat('Temp', 'PriorOrderCost', PRIOR_ORDER_COST);
    end;

    F := ReadFloat('SourceDistCountry') * SOURCE_COUNTRY_KM_COST;
    if F <> 0 then
    begin
      WriteStr('Bill', 'Code', 'SOURCE_COUNTRY_DIST');
      WriteStr('Bill', 'Text', 'До подачи загород');
      WriteStr('Bill', 'Value',
        FloatToStr(ReadFloat('SourceDistCountry'), 2) + ' км');
      WriteStr('Bill', 'Sum', FloatToStr(F, 2));
      WriteFloat('Temp', 'SourceDistCountrySum', F);
    end;

    if not ReadBool('IsHourly') then
    begin
      if TMD_UseCalcTMRoute then
      begin
        WriteInt('UseCalcTMRoute', 1);
        WriteInt('CalcTMRoutePeriodSec', CALC_TM_ROUTE_PERIOD);
        ReadInt('Temp', 'TMRouteReceiveTime', 0);
      end;

      if ReadBool('IsCountry') or not ReadBool('InCity') then
      begin
        Boarding := BOARDING_COUNTRY;
        KmIncluded := COUNTRY_KM_INCLUDED;
        MinutesIncluded := COUNTRY_MINUTES_INCLUDED;
        MinSum := MIN_COUNTRY;
        WriteInt('Temp', 'WasOutCity', 1);
      end
      else
      begin
        Boarding := BOARDING_CITY;
        KmIncluded := CITY_KM_INCLUDED;
        MinutesIncluded := CITY_MINUTES_INCLUDED;
        MinSum := MIN_CITY;
        WriteInt('Temp', 'WasOutCity', 0);
      end;
      WriteFloat('Temp', 'KmIncluded', KmIncluded);
      WriteFloat('Temp', 'MinutesIncluded', MinutesIncluded);
    end
    else
    begin
      Boarding := BOARDING_HOURLY;
      MinSum := MIN_HOURLY;
    end;
    WriteFloat('Temp', 'BoardingSum', Boarding);
    WriteFloat('Temp', 'MinSum', MinSum);

    // Определяем район по фактическим координатам.
    if USE_REAL_ZONES_IN_TAXM then
    begin
      // Посадка в районе.
      if USE_ZONE_COST then
      begin
        F := ReadFloat('ZoneInCost', ReadInt('ZoneId'));
        if F <> 0 then
        begin
          WriteStr('Bill', 'Code', 'ZONE_IN');
          WriteStr('Bill', 'Text', 'Посадка ' +
            '"' + ReadStr('ZoneName') + '"');
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));

          WriteFloat('Temp', 'ZoneInCost', F);
        end;
      end;

      // Сохраняем текущий район.
      WriteInt('Temp', 'LastZoneId', ReadInt('ZoneId'));
    end;
  end;

  TMD_CalcTaximeterSum;

  TMD_FillMoreInfo;

  WriteInt('Temp', 'AllStopTime', 0);
  WriteFloat('Temp', 'StopTimeSum', 0);
end;


// Использовать восстановление километража при потере GPS.
function TMD_UseGPSMissedDistanceRecovery: Boolean;
begin
  Result := USE_GPS_MISSED_DISTANCE_RECOVERY and
    (ReadInt('SupportedScriptVersion') > 0);
end;


// Пересчитать параметры, связанные с координатами.
procedure TMD_RecalcLostGPSParams;
var
  Lat, Lon, CurTotalDistance, KmCost, DistDelta: Single;
begin
  Lon := ReadFloat('Lon');
  Lat := ReadFloat('Lat');

  // Посчитать километраж по прямой, если появились координаты.
  if (ReadInt('Temp', 'IsLostGPS') = 1) and
     ((ReadFloat('Temp', 'OldLat') > 0) or
     (ReadFloat('Temp', 'OldLon') > 0)) and
     ((Lat > 0) or (Lon > 0)) then
  begin
    DistDelta := SegmentLength(ReadFloat('Temp', 'OldLon'),
      ReadFloat('Temp', 'OldLat'), Lon, Lat);

    WriteFloat('Temp', 'GpsLostKmDist',
      ReadFloat('Temp', 'GpsLostKmDist') + DistDelta);

    CurTotalDistance := ReadFloat('Temp', 'TotalDist') + DistDelta;

    // При восстанавлении координат не успевает правильно
    // определиться флаг ReadBool('InCity').
    if ReadInt('Temp', 'OldInCity') > 0 then
    begin
      WriteFloat('Temp', 'GpsLostDistCity',
        ReadFloat('Temp', 'GpsLostDistCity') + DistDelta);
      KmCost := CITY_KM_COST;
    end
    else
    begin
      WriteFloat('Temp', 'GpsLostDistCountry',
        ReadFloat('Temp', 'GpsLostDistCountry') + DistDelta);
      KmCost := COUNTRY_KM_COST;
    end;

    if CurTotalDistance > ReadFloat('Temp', 'KmIncluded') then
    begin
      // Если при восстановлении координат сразу закончился
      // включенный киломтраж.
      if ReadFloat('Temp', 'TotalDist') < ReadFloat('Temp', 'KmIncluded') then
        // Платный километраж.
        DistDelta := CurTotalDistance - ReadFloat('Temp', 'KmIncluded');

      WriteFloat('Temp', 'GPSLostDistSum',
        ReadFloat('Temp', 'GPSLostDistSum') + KmCost * DistDelta);
    end;
  end;

  // Пропал сигнал GPS.
  if (Lat = 0) and (Lon = 0) then
    WriteInt('Temp', 'IsLostGPS', 1)
  else
  // Есть сигнал GPS.
  begin
    WriteFloat('Temp', 'OldLat', Lat);
    WriteFloat('Temp', 'OldLon', Lon);
    if ReadBool('InCity') then
      WriteInt('Temp', 'OldInCity', 1)
    else
      WriteInt('Temp', 'OldInCity', 0);
    WriteInt('Temp', 'IsLostGPS', 0);
  end;
end;


// *******
// Расчёт.
// *******
procedure StepCalc;
var
  F, DistDelta, TripDistance: Single;
  City: String;
  Seconds: Integer;
begin
  if CALC_SUM_BY_TAXIMETER then
  begin
    if ReadBool('HasCities') then
    begin
      if ReadBool('InCity') then
        City := ' [' + ReadStr('CityName') + ']'
      else
        City := ' [загород]';
    end;

    DistDelta := ReadFloat('DistDelta');
    if ReadBool('IsHourly') then
    begin
      WriteStr('Caption', 'ЧАС' + City);

      if ReadInt('TripTime') > HOURLY_MINUTES_INCLUDED * 60 then
      begin
        if HOURLY_PERIOD = 0 then
          F := HOURLY_MINUTE_COST / 60
        else
          if Floor((ReadInt('TripTime') - HOURLY_MINUTES_INCLUDED * 60 - 1) /
             60 / HOURLY_PERIOD) * HOURLY_PERIOD * 60 =
             ReadInt('TripTime') - HOURLY_MINUTES_INCLUDED * 60 - 1 then
            F := HOURLY_PERIOD * HOURLY_MINUTE_COST
          else
            F := 0;
        if F <> 0 then
        begin
          WriteFloat('Temp', 'TripTimeSum',
            ReadFloat('Temp', 'TripTimeSum') + F);
        end;
      end;

      if HOURLY_KM_COST > 0 then
      begin
        F := 0;
        if HOURLY_HOUR_KM_INCLUDED > 0 then
        begin
          // Ещё один час закончился.
          if ReadInt('TripTime') mod (60 * 60) = 0 then
            WriteFloat('Temp', 'DistHour', 0);

          WriteFloat('Temp', 'DistHour',
            ReadFloat('Temp', 'DistHour') + DistDelta);

          if ReadFloat('Temp', 'DistHour') > HOURLY_HOUR_KM_INCLUDED then
            F := DistDelta * HOURLY_KM_COST;
        end
        else
        if HOURLY_TRIP_KM_INCLUDED > 0 then
        begin
          if ReadFloat('TripDistance') > HOURLY_TRIP_KM_INCLUDED then
            F := DistDelta * HOURLY_KM_COST;
        end
        else
          F := DistDelta * HOURLY_KM_COST;

        if F <> 0 then
        begin
          WriteFloat('Temp', 'HourlyDist',
            ReadFloat('Temp', 'HourlyDist') + DistDelta);
          WriteFloat('Temp', 'HourlyDistSum',
            ReadFloat('Temp', 'HourlyDistSum') + F);
        end;
      end;
    end
    else
    begin
      WriteFloat('Temp', 'TotalDist',
        ReadFloat('Temp', 'TotalDist') + DistDelta);
      // Если скорость достаточная, считать по километражу.
      if ReadFloat('Speed') > SPEED_LIMIT then
      begin
        WriteStr('Caption', 'КМ' + City);
        TripDistance := ReadFloat('Temp', 'TotalDist') + ReadFloat('Temp', 'GpsLostDistCountry') +
          ReadFloat('Temp', 'GpsLostDistCity');
        if not ReadBool('InCity') then
        begin
          WriteFloat('Temp', 'DistCountry',
            ReadFloat('Temp', 'DistCountry') + DistDelta);
          if TripDistance > ReadFloat('Temp', 'KmIncluded') then
          begin
            WriteFloat('Temp', 'DistanceSum',
              ReadFloat('Temp', 'DistanceSum') + COUNTRY_KM_COST * DistDelta);
          end;
        end
        else
        begin
          WriteFloat('Temp', 'DistCity',
            ReadFloat('Temp', 'DistCity') + DistDelta);
          if TripDistance > ReadFloat('Temp', 'KmIncluded') then
          begin
            WriteFloat('Temp', 'DistanceSum',
              ReadFloat('Temp', 'DistanceSum') + CITY_KM_COST * DistDelta);
          end;
        end;
      end;

      if (COUNTRY_MINUTE_COST <> 0) or (CITY_MINUTE_COST <> 0) then
        if not ReadBool('InCity') then
        begin
          WriteInt('Temp', 'CountryTripTime', 
            ReadInt('Temp', 'CountryTripTime') + 1);
          if ReadInt('TripTime') > ReadFloat('Temp', 'MinutesIncluded') * 60 then
            WriteFloat('Temp', 'CountryTripTimeSum', 
              ReadFloat('Temp', 'CountryTripTimeSum') + COUNTRY_MINUTE_COST / 60);
        end
        else
        begin
          WriteInt('Temp', 'CityTripTime', 
            ReadInt('Temp', 'CityTripTime') + 1);
          if ReadInt('TripTime') > ReadFloat('Temp', 'MinutesIncluded') * 60 then
            WriteFloat('Temp', 'CityTripTimeSum', 
              ReadFloat('Temp', 'CityTripTimeSum') + CITY_MINUTE_COST / 60);
        end;

      if TMD_UseGPSMissedDistanceRecovery then
        TMD_RecalcLostGPSParams;
    end;
  end;

  if TMD_UseCalcStopsIdle then
  begin
    if ReadFloat('Speed') > SPEED_LIMIT then
      WriteInt('Temp', 'LastKMTime', ReadInt('TripTime'))
    else
    if ReadInt('TripTime') - ReadInt('Temp', 'LastKMTime') > FREE_IDLE_TIME then
    begin
      WriteStr('Caption', 'Простой');
      WriteInt('Temp', 'IdleTime',
        ReadInt('Temp', 'IdleTime') + 1);
      WriteFloat('Temp', 'IdleTimeSum',
        ReadFloat('Temp', 'IdleTimeSum') + IDLE_MINUTE_COST / 60);
    end
    else
    begin
      Seconds := FREE_IDLE_TIME -
        (ReadInt('TripTime') - ReadInt('Temp', 'LastKMTime'));
      WriteStr('Caption', 'Ожидание (' + IntToStr(Seconds) + ')' + City);
    end;
  end;

  TMD_CalcTaximeterSum;
end;


// *****************
// Начало остановки.
// *****************
procedure StartStop;
var
  F: Single;
begin
  if CALC_SUM_BY_TAXIMETER then
  begin
    WriteStr('Caption', 'Остановка');
    WriteInt('UseZonesPathGroupId', ZONES_PATH_GROUP_ID);

    // Определяем район по фактическим координатам.
    if USE_REAL_ZONES_IN_TAXM then
    begin
      if ReadInt('ZoneId') <> ReadInt('Temp', 'LastZoneId') then
        // Сохраняем признак, что покидали район посадки.
        WriteInt('Temp', 'NeedZoneOutCost', 1);

      // Проезды между районами
      if (USE_ZONE_PATH) and (ReadInt('ZoneId') > 0) then
      begin
        F := ReadFloat('ZonePathCost',
          ReadInt('Temp', 'LastZoneId'), ReadInt('ZoneId'));
        if F <> 0 then
        begin
          WriteStr('Bill', 'Code', 'ZONES_PATH');
          WriteStr('Bill', 'Text', 'Проезд ' + '"' +
            ReadStr('ZoneName', ReadInt('Temp', 'LastZoneId')) +
            '"-"' + ReadStr('ZoneName') + '"');
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));

          WriteFloat('Temp', 'ZonePathSum',
            ReadFloat('Temp', 'ZonePathSum') + F);
        end;
      end;

      // Сохраняем текущий район.
      WriteInt('Temp', 'LastZoneId', ReadInt('ZoneId'));

      // Остановка в районе.
      if USE_ZONE_COST then
      begin
        F := ReadFloat('ZoneStopCost', ReadInt('ZoneId'));
        if F <> 0 then
        begin
          WriteStr('Bill', 'Code', 'ZONES_STOP');
          WriteStr('Bill', 'Text', 'Остановка ' +
            '"' + ReadStr('ZoneName') + '"');
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));

          WriteFloat('Temp', 'ZoneStopSum',
            ReadFloat('Temp', 'ZoneStopSum') + F);
        end;
      end;
    end;
  end;

  if TMD_UseCalcStopsIdle then
  begin
    WriteInt('Temp', 'StopTime', 0);
    WriteInt('Temp', 'StopsCount',
      ReadInt('Temp', 'StopsCount') + 1);
    WriteFloat('Temp', 'StopsSum',
      ReadFloat('Temp', 'StopsSum') + MIN_STOP_COST);
  end;

  TMD_CalcTaximeterSum;
end;


// **********
// Остановка.
// **********
procedure StepCalcStop;
var
  StopTime: Integer;
  Sum: Single;
begin
  if not TMD_UseCalcStopsIdle then
    StepCalc
  else
  begin
    WriteFloat('Temp', 'TotalDist',
      ReadFloat('Temp', 'TotalDist') + ReadFloat('DistDelta'));
    if TMD_UseGPSMissedDistanceRecovery then
      TMD_RecalcLostGPSParams;

    if STOP_MINUTE_COST <> 0 then
    begin
      StopTime := ReadInt('Temp', 'StopTime') + 1;

      if StopTime > (STOP_MINUTES_INCLUDED * 60) then
      begin
        WriteFloat('Temp', 'StopTimeSum',
          ReadFloat('Temp', 'StopTimeSum') + STOP_MINUTE_COST / 60);
        TMD_CalcTaximeterSum;
      end;

      WriteInt('Temp', 'StopTime', StopTime);
      WriteInt('Temp', 'AllStopTime',
        ReadInt('Temp', 'AllStopTime') + 1);
    end;
  end;
end;


// ****************
// Конец остановки.
// ****************
procedure EndStop;
begin
  WriteStr('Caption', '');
end;


// ****************
// Обработка дополнительных функциональных кнопок.
// ****************
procedure ButtonClick;
var
  ButtonName, ServiceName: String;
  Sum, ServiceSum, PercentSum: Single;
  I, ServicePercent, ServiceId: Integer;
  CanRepeatService: Boolean;
begin
  ButtonName := ReadStr('Button', 'Clicked');
  for I := 1 to TMD_GetDriverServicesCount do
    if ButtonName = 'DriverServiceButton' + IntToStr(I) then
    begin
      TMD_GetServiceParamsByIndex(I, ServiceSum, ServicePercent, ServiceName,
        ServiceId, CanRepeatService);
      if CanRepeatService then
        WriteInt('Temp', 'DriverServiceButton' + IntToStr(I),
          ReadInt('Temp', 'DriverServiceButton' + IntToStr(I)) + 1)
      else
      begin
        WriteInt('Temp', 'DriverServiceButton' + IntToStr(I), 1);
        WriteStr('Button', 'Select', ButtonName);
        WriteInt('Button', 'Visible', 0);
      end;
    end;

  TMD_CalcTaximeterSum;
end;


// Добавить в чек стоимость за восстановленный километраж.
procedure TMD_AddGPSParams;
begin
  if TMD_UseGPSMissedDistanceRecovery and
     (ReadFloat('Temp', 'GpsLostKmDist') > 0) then
  begin
    if ReadFloat('Temp', 'GPSLostDistCity') > 0 then
    begin
      WriteStr('Bill', 'Code', 'CITY_LOST_GPS_DIST');
      WriteStr('Bill', 'Text', 'По городу при отсутствии GPS');
      WriteStr('Bill', 'Value',
        FloatToStr(ReadFloat('Temp', 'GPSLostDistCity'), 2) + ' км');
    end;

    if ReadFloat('Temp', 'GPSLostDistCountry') > 0 then
    begin
      WriteStr('Bill', 'Code', 'COUNTRY_LOST_GPS_DIST');
      WriteStr('Bill', 'Text', 'За городом при отсутствии GPS');
      WriteStr('Bill', 'Value',
        FloatToStr(ReadFloat('Temp', 'GPSLostDistCountry'), 2) + ' км');
    end;
  end;
end;


// Добавить в чек стоимость за простой, ожидание, остановки.
procedure TMD_AddTimeParams;
begin
  WriteStr('Bill', 'Code', 'IDLE_TIME');
  WriteStr('Bill', 'Text', 'Простой');
  WriteStr('Bill', 'Value',
    TimeLenToStr(ReadInt('Temp', 'IdleTime')));
  WriteStr('Bill', 'Sum',
    FloatToStr(ReadFloat('Temp', 'IdleTimeSum'), 2));

  if ReadInt('Temp', 'StopsCount') > 0 then
  begin
    WriteStr('Bill', 'Code', 'STOPS');
    WriteStr('Bill', 'Text', 'Остановки');
    WriteStr('Bill', 'Value',
      IntToStr(ReadInt('Temp', 'StopsCount')) + ' шт');
    WriteStr('Bill', 'Sum',
      FloatToStr(ReadFloat('Temp', 'StopsSum'), 2));

    if (STOP_MINUTE_COST <> 0) and (ReadFloat('Temp', 'StopTimeSum') <> 0) then
    begin
      WriteStr('Bill', 'Code', 'STOPS_TIME');
      WriteStr('Bill', 'Text', 'Длит. остановок');
      WriteStr('Bill', 'Value',
        TimeLenToStr(ReadInt('Temp', 'AllStopTime')));
      WriteStr('Bill', 'Sum',
        FloatToStr(ReadFloat('Temp', 'StopTimeSum'), 2));
    end;
  end;
end;


// *******************
// Завершение расчета.
// *******************
procedure TermCalc;
var
  F: Single;
begin
  WriteInt('Temp', 'TripFinished', 1);
  if CALC_SUM_BY_TAXIMETER then
  begin
    WriteInt('UseZonesPathGroupId', ZONES_PATH_GROUP_ID);

    if not USE_REAL_ZONES_IN_TAXM then
    begin
      F := ReadFloat('TaxmZonesSum');
      if F <> 0 then
      begin
        WriteStr('Bill', 'Code', 'ZONES');
        WriteStr('Bill', 'Text', 'Районы');
        WriteStr('Bill', 'Sum', FloatToStr(F, 2));
      end;
    end
    else
    begin
      // Перед высадкой проверяем проезды между районами
      if (USE_ZONE_PATH) and (ReadInt('ZoneId') > 0) then
      begin
        F := ReadFloat('ZonePathCost',
          ReadInt('Temp', 'LastZoneId'), ReadInt('ZoneId'));
        if F <> 0 then
        begin
          WriteStr('Bill', 'Code', 'ZONES_PATH');
          WriteStr('Bill', 'Text', 'Проезд ' + '"' +
            ReadStr('ZoneName', ReadInt('Temp', 'LastZoneId')) +
            '"-"' + ReadStr('ZoneName') + '"');
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));

          WriteFloat('Temp', 'ZonePathSum',
            ReadFloat('Temp', 'ZonePathSum') + F);
        end;
      end;

      // Высадка в районе.
      if USE_ZONE_COST and (ReadInt('ZoneId') > 0) and
         ((ReadInt('ZoneId') <> ReadInt('Temp', 'LastZoneId')) or
         (ReadInt('Temp', 'NeedZoneOutCost') = 1)) then
      begin
        F := ReadFloat('ZoneOutCost', ReadInt('ZoneId'));
        if F <> 0 then
        begin
          WriteStr('Bill', 'Code', 'ZONES_OUT');
          WriteStr('Bill', 'Text', 'Высадка ' +
            '"' + ReadStr('ZoneName') + '"');
          WriteStr('Bill', 'Sum', FloatToStr(F, 2));

          WriteFloat('Temp', 'ZoneOutCost', F);
        end;
      end;
    end;

    if ReadBool('IsHourly') then
    begin
      WriteStr('Bill', 'Code', 'TRIP_TIME');
      WriteStr('Bill', 'Text', 'Общее время');
      WriteStr('Bill', 'Value',
        TimeLenToStr(ReadInt('TripTime')));
      WriteStr('Bill', 'Sum',
        FloatToStr(ReadFloat('Temp', 'TripTimeSum') + ReadFloat('Temp', 'BoardingSum'), 2));

      WriteStr('Bill', 'Code', 'TRIP_DIST');
      WriteStr('Bill', 'Text', 'Общее расстояние');
      WriteStr('Bill', 'Value',
        FloatToStr(ReadFloat('TripDistance'), 2) + ' км');

      F := ReadFloat('Temp', 'HourlyDistSum');
      if F > 0 then
      begin
        WriteStr('Bill', 'Code', 'HOURLY_PAY_DIST');
        WriteStr('Bill', 'Text', 'Платный километраж');
        WriteStr('Bill', 'Value',
          FloatToStr(ReadFloat('Temp', 'HourlyDist'), 2) + ' км');
        WriteStr('Bill', 'Sum', FloatToStr(F, 2));
      end;
    end
    else
    begin
      if TMD_UseCalcTMRoute then
        TMD_RecalcDistSum;

      WriteStr('Bill', 'Code', 'TRIP_TIME');
      WriteStr('Bill', 'Text', 'Общее время');
      WriteStr('Bill', 'Value',
        TimeLenToStr(ReadInt('TripTime')));

      if CITY_MINUTE_COST <> 0 then
      begin
        WriteStr('Bill', 'Code', 'CITY_TRIP_TIME');
        WriteStr('Bill', 'Text', 'Время по городу');
        WriteStr('Bill', 'Value',
          TimeLenToStr(ReadInt('Temp', 'CityTripTime')));
        WriteStr('Bill', 'Sum', 
          FloatToStr(ReadFloat('Temp', 'CityTripTimeSum'), 2));
      end;

      if COUNTRY_MINUTE_COST <> 0 then
      begin
        WriteStr('Bill', 'Code', 'COUNTRY_TRIP_TIME');
        WriteStr('Bill', 'Text', 'Время за городом');
        WriteStr('Bill', 'Value',
          TimeLenToStr(ReadInt('Temp', 'CountryTripTime')));
        WriteStr('Bill', 'Sum', 
          FloatToStr(ReadFloat('Temp', 'CountryTripTimeSum'), 2));  
      end;

      WriteStr('Bill', 'Code', 'TRIP_DIST');
      WriteStr('Bill', 'Text', 'Общее расстояние');
      WriteStr('Bill', 'Value',
        FloatToStr(ReadFloat('Temp', 'TotalDist'), 2) + ' км');
      WriteStr('Bill', 'Sum',
        FloatToStr(ReadFloat('Temp', 'BoardingSum') + 
          ReadFloat('Temp', 'DistanceSum') + 
          ReadFloat('Temp', 'GPSLostDistSum'), 2));

      WriteStr('Bill', 'Code', 'CITY_DIST');
      WriteStr('Bill', 'Text', 'По городу');
      WriteStr('Bill', 'Value',
        FloatToStr(ReadFloat('Temp', 'DistCity'), 2) + ' км');

      WriteStr('Bill', 'Code', 'COUNTRY_DIST');
      WriteStr('Bill', 'Text', 'За городом');
      WriteStr('Bill', 'Value',
        FloatToStr(ReadFloat('Temp', 'DistCountry'), 2) + ' км');

      TMD_AddGPSParams;

      TMD_AddTimeParams;
    end;

    TMD_CalcTaximeterSum;
  end
  else
  begin
    WriteStr('Bill', 'Code', 'TRIP_TIME');
    WriteStr('Bill', 'Text', 'Общее время');
    WriteStr('Bill', 'Value',
      TimeLenToStr(ReadInt('TripTime')));

    WriteStr('Bill', 'Code', 'TRIP_DIST');
    WriteStr('Bill', 'Text', 'Общее расстояние');
    WriteStr('Bill', 'Value',
      FloatToStr(ReadFloat('TripDistance'), 2) + ' км');

    WriteStr('Bill', 'Code', 'OPER_SUM');
    WriteStr('Bill', 'Text', 'Сумма оператора');
    WriteStr('Bill', 'Sum', FloatToStr(ReadFloat('OperSum'), 2));

    if USE_STOPS_WAITING_IDLE then
      TMD_AddTimeParams;

    TMD_AddDriverServices;

    TMD_CalcTaximeterSum;

    WriteStr('Bill', 'Code', 'AFTER_DISC');
    WriteStr('Bill', 'Text', 'Сумма');
    if ReadStr('Platform') = 'Android' then
       WriteStr('Bill', 'Sum', FloatToStr(ReadFloat('TotalSum'), 2))
    else
       WriteStr('Bill', 'Sum', FloatToStr(ReadFloat('Sum'), 2));
  end;
end;

// *****************************************************************
// Добавить строку в чек. В конец строки вставляется перенос строки.
// *****************************************************************
procedure AddLine(Line: String);
begin
  WriteStr('PrintCheck', 'Text', Line);
end;

// ******************************************
// Добавить в чек строку типа текст/значение.
// ******************************************
procedure AddLineTextValue(Line: String; Value: String);
begin
  WriteStr('PrintCheck', 'Text', Line);
  WriteStr('PrintCheck', 'Value', Value);
end;

// ******************************************
// Добавить в чек строку типа текст/значение для стоимости.
// ******************************************
procedure AddTextCostValue(Line: String; Value: Single);
begin
  WriteStr('PrintCheck', 'Text', Line);
  WriteStr('PrintCheck', 'Value', '=' + FloatToStr(Value, 2));
end;

// ******************************************
// Добавить в чек строку типа текст/значение с проверкой на 0.
// ******************************************
procedure AddTextNotNullValue(Line: String; Value: Single);
begin
  if Value <> 0 then
    AddTextCostValue(Line, Value);
end;

// ******************************
// Добавить перенос строки в чек.
// ******************************
procedure AddLineBreak;
begin
  WriteStr('PrintCheck', 'BreakLine');
end;

// ******************************
// Получить текущую дату и время в виде строки.
// ******************************
function GetDateTimeStr(DT: Integer): String;
var
  TmpStr: String;
  D, M, Y, DW, H, S, I: Integer;
begin
  TmpStr := '';
  ExtractDate(DT, D, M, Y, DW);
  if D < 10 then
    TmpStr := TmpStr + '0';
  TmpStr := TmpStr + IntToStr(D) + '.';
  if M < 10 then
    TmpStr := TmpStr + '0';
  TmpStr := TmpStr + IntToStr(M) + '.';
  Y := Y mod 100;
  if Y < 10 then
    TmpStr := TmpStr + '0';
  TmpStr := TmpStr + IntToStr(y) + ' ';
  ExtractTime(ReadInt('Now'), H, M, S);
  if H < 10 then
    TmpStr := TmpStr + '0';
  TmpStr := TmpStr + IntToStr(H) + ':';
  if M < 10 then
    TmpStr := TmpStr + '0';
  TmpStr := TmpStr + IntToStr(M);

  Result := TmpStr;
end;

// ******************************
// Сформировать QR-код.
// ******************************
function GetQrCode: String;
var
  D, M, Y, DW, H, MM, S, I: Integer;
  QR: String;
begin
  ExtractDate(ReadInt('FiscalInfo', 'CompleteTime'), D, M, Y, DW);
  ExtractTime(ReadInt('FiscalInfo', 'CompleteTime'), H, MM, S);
  QR := 't=' +IntToStr(Y) + IntToStr(M) + IntToStr(D) + 'T' + IntToStr(H) +
    IntToStr(MM);
  QR := QR + '&s=' + FloatToStr(ReadFloat('BankCardSum') + ReadFloat('CashSum'), 2);
  QR := QR + '&fn=' + ReadStr('FiscalInfo', 'FiscalNumber');
  QR := QR + '&i=' + IntToStr(ReadInt('FiscalInfo', 'FiscalDocumentNumber'));
  QR := QR + '&fp=' + ReadStr('FiscalInfo', 'FiscalDocumentSign');
  QR := QR + '&n=1';
  Result := QR;
end;

// ************
// Печать чека.
// ************
procedure PrintCheck;
var
  I: Integer;
  TmpStr, PrinterModel, Encoding: String;
  ServicePercent, SumServicePercent, NdsSum, FiscalSum, DiscountSum: Single;
begin
  WriteStr('PrintCheck', 'Align', '0');
  AddLine(TAXI_NAME);
  AddLine('т. ' + TAXI_PHONE);
  AddLineBreak;
  AddLine('БЛАГОДАРИМ ВАС');
  AddLine('ЗА ОБРАЩЕНИЕ В НАШУ КОМПАНИЮ!');
  AddLineBreak;

  // Детализация поездки
  if NEED_DETAILS_IN_CHECK then
  begin
    if not ReadBool('IsBorder') then
      AddLine('Заказ #' + IntToStr(ReadInt('OrderId')))
    else
      AddLine('Бордюрный заказ');

    AddLine('Тариф: ' + ReadStr('TariffName'));
    if not ReadBool('IsBorder') then
      AddLine('Адрес: ' + ReadStr('SourceAddress'));
    AddLine('Водитель: ' + ReadStr('DriverName'));
    AddLine('Машина: ' + ReadStr('CarColor') + ' ' +
      ReadStr('CarMark') + ' ' + ReadStr('CarModel') + ' ' + ReadStr('CarGosnumber'));
    AddLineBreak;
    AddLine('Километраж: ' + FloatToStr(ReadFloat('TripDistance'), 2) + ' км');
    AddLine('Длительность: ' + TimeLenToStr(ReadInt('TripTime')));
    AddLineBreak;

    if CALC_SUM_BY_TAXIMETER then
    begin
      AddLine('Услуга                     Сумма');
      AddLine('--------------------------------');

      AddTextNotNullValue('Доезд до адреса подачи',
        ReadFloat('Temp', 'SourceDistCountrySum'));
      AddTextNotNullValue('Ожидание', ReadFloat('Temp', 'PayWaitTimeSum'));
      AddTextNotNullValue('Посадка', ReadFloat('Temp', 'BoardingSum'));
      AddTextNotNullValue('Районы', ReadFloat('TaxmZonesSum'));

      if ReadBool('IsHourly') then
      begin
        AddTextNotNullValue('Поездка', ReadFloat('Temp', 'TripTimeSum'));
      end
      else
      begin
        AddTextNotNullValue('По городу', ReadFloat('Temp', 'DistanceSum'));
        AddTextNotNullValue('За городом', ReadFloat('Temp', 'DistCountrySum'));
        if ReadFloat('Temp', 'CityTripTimeSum') <> 0 then
          AddTextNotNullValue('Время по городу', ReadFloat('Temp', 'CityTripTimeSum'));
        if ReadFloat('Temp', 'CountryTripTimeSum') <> 0 then
          AddTextNotNullValue('Время за городом', ReadFloat('Temp', 'CountryTripTimeSum'));
        AddTextNotNullValue('Простой', ReadFloat('Temp', 'IdleTimeSum'));
        AddTextNotNullValue('Остановки', ReadFloat('Temp', 'StopsSum'));
      end;

      if ReadFloat('ServicesSum') <> 0 then
      begin
        for I := 0 to ReadInt('ServiceCount') - 1 do
          AddTextNotNullValue(ReadStr('ServiceName', ReadInt('OrderServiceId', I)),
            ReadFloat('ServiceSum', ReadInt('OrderServiceId', I)));
      end;

      if ReadFloat('ServicesPercent') <> 0 then
      begin
        for I := 0 to ReadInt('ServiceCount') - 1 do
          if ReadFloat('ServicePercent', ReadInt('OrderServiceId', I)) <> 0 then
          begin
            ServicePercent := ReadFloat('ServicePercent', ReadInt('OrderServiceId', I));
            SumServicePercent := ServicePercent * ReadFloat('Temp', 'Check_SumBeforeServices') / 100;
            AddTextNotNullValue(
              ReadStr('ServiceName', ReadInt('OrderServiceId', I)) + ' ' + FloatToStr(ServicePercent, 0) + '%',
              SumServicePercent);
          end;
      end;
    end;

    AddLineTextValue('',
      '==' + FloatToStr(ReadFloat('Temp', 'SumBeforeDiscount'), 2));

    if ReadFloat('Temp', 'Check_DiscountSum') <> 0 then
    begin
      AddLine('--------------------------------');
      if ReadFloat('Temp', 'Check_DiscountSum') > 0 then
        AddTextCostValue('Скидка', ReadFloat('Temp', 'Check_DiscountSum'))
      else
        AddTextCostValue('Наценка', -ReadFloat('Temp', 'Check_DiscountSum'));

      AddTextCostValue('', ReadFloat('Temp', 'Check_SumAfterDiscount'));
    end;
  end;

  AddLine( '================================');

  if CALC_SUM_BY_TAXIMETER and NEED_DETAILS_IN_CHECK then
    AddTextNotNullValue('Минимум', ReadFloat('Temp', 'MinSum'));

  if not NEED_DETAILS_IN_CHECK then
    AddLine('ПОЕЗДКА');
  AddLineTextValue('ИТОГО К ОПЛАТЕ',
    '==' + FloatToStr(ReadFloat('Temp', 'Check_TotalSum'), 2));
  AddLineTextValue('Наличными',
    '==' + FloatToStr(ReadFloat('CashSum'), 2));
  AddLineBreak;
  AddLine(GetDateTimeStr(ReadInt('Now')) + '  ИНН ' + TAXI_INN);
  AddLineBreak;
  AddLineBreak;

  // Чек с фискальными данными.
  if not ReadBool('PrintCheck', 'IsFiscal') and ReadBool('FiscalInfo', 'Success') then
  begin
    WriteStr('PrintCheck', 'Align', '0');
    AddLine('КАССОВЫЙ ЧЕК');

    WriteStr('PrintCheck', 'Align', '-1');
    AddLine('ПРИХОД');
    
    FiscalSum := ReadFloat('BankCardSum') + ReadFloat('CashSum');
    AddLineTextValue(ReadStr('FiscalInfo', 'CommodityName'),
      FloatToStr(FiscalSum, 2) + ' x 1 = ' + FloatToStr(FiscalSum, 2));
    AddTextNotNullValue('  ' + ReadStr('FiscalInfo', 'TaxRate'), ReadFloat('FiscalInfo', 'TaxSum'));
    
    DiscountSum := ReadFloat('TotalSum') - FiscalSum;
    if DiscountSum > 0 then
      AddTextCostValue('СКИДКА', DiscountSum);

    AddLine('УСЛУГА');
    if ReadStr('FiscalInfo', 'TaxRate') = 'без НДС' then
      NdsSum := FiscalSum
    else
      NdsSum := ReadFloat('FiscalInfo', 'TaxSum');
    WriteStr('PrintCheck', 'FontSize', '1');  
    AddTextCostValue('ИТОГ', FiscalSum);
    WriteStr('PrintCheck', 'FontSize', '0');
    
    AddTextNotNullValue('  Сумма ' + ReadStr('FiscalInfo', 'TaxRate'), NdsSum);
    AddTextNotNullValue('НАЛИЧНЫМИ', ReadFloat('CashSum'));
    AddTextNotNullValue('БАНК. КАРТОЙ', ReadFloat('BankCardSum'));

    AddTextCostValue('ПОЛУЧЕНО', FiscalSum);
    AddLineTextValue('СНО:', ReadStr('FiscalInfo', 'Taxation'));
    if ReadStr('FiscalInfo', 'ClientPhone') <> '' then
      AddLineTextValue('Тел.покупателя', ReadStr('FiscalInfo', 'ClientPhone'));
    if (ReadStr('FiscalInfo', 'ClientPhone') = '') and (ReadStr('FiscalInfo', 'ClientEmail') <> '') then
      AddLineTextValue('Эл.адр.покупателя', ReadStr('FiscalInfo', 'ClientEmail'));
    AddLineTextValue('Пользователь:', ReadStr('FiscalInfo', 'OrganizationName'));
    AddLineTextValue('Адрес:', ReadStr('FiscalInfo', 'OrganizationAddress'));
    AddLineTextValue('Место расчетов:', ReadStr('FiscalInfo', 'OrganizationAddress'));
    AddLineTextValue('Кассир:', ReadStr('FiscalInfo', 'OperatorName'));
    AddLineTextValue('Сайт ФНС:', ReadStr('FiscalInfo', 'FnsUrl'));
    AddLineTextValue('ЗН ККТ:', ReadStr('FiscalInfo', 'SerialNumber'));
    AddLineTextValue('Смена №', IntToStr(ReadInt('FiscalInfo', 'ShiftNumber')));
    AddLineTextValue('Чек №', IntToStr(ReadInt('FiscalInfo', 'CheckNumber')));
    AddLineTextValue('Дата Время', GetDateTimeStr(ReadInt('FiscalInfo', 'CompleteTime')));
    AddLineTextValue('ОФД:', ReadStr('FiscalInfo', 'OfdName'));
    AddLineTextValue('ИНН:', ReadStr('FiscalInfo', 'OfdVatin'));
    AddLineTextValue('РН ККТ:', ReadStr('FiscalInfo', 'RegistrationNumber'));
    AddLineTextValue('ФН №', ReadStr('FiscalInfo', 'FiscalNumber'));
    AddLineTextValue('ФД №', IntToStr(ReadInt('FiscalInfo', 'FiscalDocumentNumber')));
    AddLineTextValue('ФП:', ReadStr('FiscalInfo', 'FiscalDocumentSign'));

    WriteStr('PrintCheck','QR', GetQrCode);
    AddLineBreak;
    AddLineBreak;
  end;
end;

Параметры, которые позволяют учитывать время проезда по маршруту в тарифе (справочник "Тарифы"):

  • Обычный заказ - По городу - Стоимость минуты.
  • Обычный заказ - За городом - Стоимость минуты.
Тариф время плюс км.png

Расчет времени происходит через онлайн карты (в данном примере используется 2GIS).

Нужно выбрать карту как источник для расчета времени доезда экипажа («Файл - Настройки - Карта - Онлайн карты - Функционал - Расчет времени доезда экипажа до заказа в карточке заказа»).

Ветка Карта - онлайн карты - Функционал.png
Интересная информация

Обратите внимание, для использования онлайн карт 2GIS, Яндекс и Google нужен API-ключ, который указывается в «Файл - Настройки - Карта - Онлайн карты - Настройки - API-ключ для использования онлайн карт».

Пример расчета стоимости поездки с учетом времени проезда по маршруту и километража в разное время.

Пример расчета по тарифу время плюс км.png
Пример второй расчета по тарифу время плюс км.png