1c 7.7 Выборка всех элементов справочника без группировки

1С 7.7 не умеет выбирать все элементы справочника в запросе без группировки по какому то реквизиту. Обычно группируют по Коду. А что делать, если какой-то талантливый программист, решил что поле Код в справочнике например может быть не уникальным? Тогда будем группировать по текущему элементу справочника. Например:

	ТекстЗапроса=
	"//{{ЗАПРОС(СформироватьСЧТ)
	|ОбрабатыватьДокументы все;
	|Обрабатывать НеПомеченныеНаУдаление;
	|Владелец = Справочник.Счетчики.Владелец;
	|Наименование = Справочник.Счетчики.Наименование;
	|ТекущийЭлемент = Справочник.Счетчики.ТекущийЭлемент;
	|Группировка ТекущийЭлемент  Без Групп;
	|"//}}ЗАПРОС
	;             
            
		Запрос = СоздатьОбъект("Запрос");		
		Запрос.Выполнить(ТекстЗапроса);		 
		Пока Запрос.Группировка() = 1 Цикл
...
...

Драйвер принтера TCS-210 Linux

Ну не хотят еще до сих пор разработчики драйверов под Linux писать их нормально. Ну как можно сделать драйвера, без возможности добавить свои размеры бумаги? Только хардкор, только ручная правка файла ppd для CUPS.

В ниже представленном драйвере, добавлен размер бумаги 58х28мм, один из распространённых размеров для печати этикеток.

OTP авторизация

Суть в чём: для каждого пользователя хранится некий OTP ключ (соль), на основании которого генерируется некий код, который в один момент времени (плюс-минус 30 секунд) будет одинаковый с ключём сгенерированным сторонним приложением. Естественно этому стороннему приложению сначала необходимо передать ключ.

Соответственно если код сгенерированный при проверке одинаков с ключем сгенерированным приложением, можно считать что идентификация успешно пройдена.

OTP авторизация обычно используется как «дополнительная», т.е. в качестве реализации двухфакторной авторизации.

Соберём класс для генерации кода на основании токена:

class TOTP {

 const keyRegeneration  = 30; // Время действия ключа
 const otpLength  = 6; // длина кода OTP

 private static $lut = array( 
  "A" => 0, "B" => 1,"C" => 2, "D" => 3,"E" => 4, "F" => 5,"G" => 6, "H" => 7,"I" => 8, "J" => 9,"K" => 10, "L" => 11,
  "M" => 12, "N" => 13,"O" => 14, "P" => 15,"Q" => 16, "R" => 17,"S" => 18, "T" => 19,"U" => 20, "V" => 21,"W" => 22, "X" => 23,
  "Y" => 24, "Z" => 25,"2" => 26, "3" => 27,"4" => 28, "5" => 29,"6" => 30, "7" => 31
 );


 /**
 * Возвратим текущее время Unix Timestamp округлённое до времени действия ключа
 * @return integer
 **/
 public static function get_timestamp() {
  return floor( (microtime(true) + 10) /self::keyRegeneration);
 }

 /**
 * Перекодируем строку base32 в бинарный вид
 **/
 public static function base32_decode($b32) {
  $b32  = strtoupper($b32);
  if (!preg_match('/^[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]+$/', $b32, $match))
   throw new Exception('Используются не верные символы в ключе.');
  $l  = strlen($b32);
  $n = 0;
  $j = 0;
  $binary = "";
  for ($i = 0; $i < $l; $i++) {
   $n = $n << 5;     // Move buffer left by 5 to make room
   $n = $n + self::$lut[$b32[$i]];  // Add value into buffer
   $j = $j + 5;    // Keep track of number of bits in buffer
   if ($j >= 8) {
    $j = $j - 8;
    $binary .= chr(($n & (0xFF << $j)) >> $j);
   }
  }
  return $binary;
 }

 /**
 * Вернём текущий код
 * @param binary $key - бинарный ключ
 * @param integer $counter - Timestamp
 * @return string
 **/
 public static function oath_hotp($key, $counter){
    if (strlen($key) < 8)
      throw new Exception('Секретный ключ слишком мал.Он должен быть больше 16 символов');
    $bin_counter = pack('N*', 0) . pack('N*', $counter);  
    $hash  = hash_hmac ('sha1', $bin_counter, $key, true);
    return str_pad(self::oath_truncate($hash), self::otpLength, '0', STR_PAD_LEFT);
 }

 /**
 * Вычленяет OTP из SHA1 hash.
 * @param binary $hash
 * @return integer
 **/
 public static function oath_truncate($hash){
    $offset = ord($hash[19]) & 0xf;
    return (
        ((ord($hash[$offset+0]) & 0x7f) << 24 ) |
        ((ord($hash[$offset+1]) & 0xff) << 16 ) |
        ((ord($hash[$offset+2]) & 0xff) << 8 ) |
        (ord($hash[$offset+3]) & 0xff)
    ) % pow(10, self::otpLength);
 }
}

Использование:

$InitalizationKey = "QWERTYUIOPASDFGH";     // Начальный ключ

$TimeStamp  = TOTP::get_timestamp();
$secretkey   = TOTP::base32_decode($InitalizationKey); // Перекодируем в бинарную строку
$otp         = TOTP::oath_hotp($secretkey, $TimeStamp); // получим текщий токен

echo("Ключ: $InitalizationKey\n");
echo("Timestamp: $TimeStamp\n");
echo("Код OTP: $otp\n");

Для того чтобы руками не вводить в OTP приложение начальный токен, можно генерировать QR код, с текстом вида:

otpauth://totp/мой_сайт:логин?secret=токен&issuer=логин

1c 7.7 Получения последней даты занесения периодического реквизита

Задача: необходимо получить дату, когда было последний раз изменено значение периодического реквизита справочника.

Решение: используем следующую функцию:

Функция ПолучитьПоследнююДатуВводаПериодическогоРеквизита(ИмяРеквизита,спрЭлементСправочника)
	ДатаПерЗначения = ПолучитьПустоеЗначение("Дата");
	Пер = СоздатьОбъект("Периодический");
	Пер.ИспользоватьОбъект(ИмяРеквизита,спрЭлементСправочника);
	Пер.ОбратныйПорядок(1);
	Если Пер.ВыбратьЗначения() = 1 Тогда
		Если Пер.ПолучитьЗначение() = 1 Тогда
	   		ДатаПерЗначения = Пер.ДатаЗнач;
		КонецЕсли;
	КонецЕсли;
	Пер = 0;         
	//сообщить(ДатаПерЗначения);
	Возврат ДатаПерЗначения;
КонецФункции

Flutter: событие с параметрами при использовании BLOC

Зачастую нужно вызвать не просто событие, но и передать ему параметры. Делается это примерно так:

event.dart

abstract class MyStaticEvent {}

class InitEvent extends MyStaticEvent {}
class StartUpdateList extends MyStaticEvent {} // Запущен процесс обновления списка статистики
class UpdateList extends MyStaticEvent {} // Обновить список статистики пользователя
class UpdateListFull extends MyStaticEvent {
  final DateTime startDate;
  final DateTime endDate;
  final int car;
  UpdateListFull(this.startDate,this.endDate,this.car);
} // Обновить список статистики пользователя

В нужном месте дернем вызов UpdateListFull:

            actions: [
              IconButton(
                icon: SvgPicture.asset('lib/images/galka.svg'),
                onPressed: () {
                  print("Нажманули сохранение");
                  BlocProvider.of<MyStaticBloc>(context).add(StartUpdateList());
                  BlocProvider.of<MyStaticBloc>(context).add(UpdateListFull(startDate??DateTime.now(),endDate??DateTime.now(),globals.UserInfo["default_car"]));
                  Navigator.pop(context);
                },
              ),
            ],

Ну и сам bloc.dart:

    on<UpdateListFull>((event, emit) async {
      print("FullList: $event");
      MyStaticState res = MyStaticState();
      print("--обновляем список статистики ");
      TRequests req = new TRequests();
      http.Response response;
      await Future.delayed(Duration(seconds: 2), () async {
        try {
          response=await req.asyncRequest("rfqwrferf", jsonEncode({           
            "offset" : globals.time_offset.toString(),
            "dtfrom" : globals.HumanDateFormat2(event.startDate),
            "dtto"   : globals.HumanDateFormat2(event.endDate),
            "autoes" : "[${event.car.toString()}]"
          }));
          if (response.statusCode==200) {
            Map<String, dynamic> answer = jsonDecode(response.body);
            if (answer["error"]==true){
              EasyLoading.showToast(answer["errortxt"]);
            } else {
              res.StaticList = answer["result"];
              res.loading=true;
              print("--пришел список статистики заправки автомобилей: ${res.StaticList}");
            }
          } else {
            EasyLoading.showToast("Ошибка обращения к API");
          }
          emit(res);
        } catch (e) {
          EasyLoading.showToast("Ошибка обращения к API $e");
        };
        emit(res);
      });
    });
1 48 49 50 51 52 310