1С: Еще раз о создании файла DOCX по шаблону без Word на сервере

Подобная статья уже была где-то на сайте, но вот еще одна, но решил актуализировать.

Итак, задача: при нажатии кнопки «В Word», сформировать на сервере файл по шаблону, сохранить его на клиент и открыть любым зарегистрированным приложением. Работать должно кроссплатформенно Linux/Windows

Создадим docx файл вида:

Решение:

{v8 Область.Тушка}

какойто текст, текст, текст. Бла-бла-бла..

{v8 АрбитражныйСудНаименование}

{/v8 Область.Тушка}

Загрузим его в макет как бинарные данные.

Далее код кнопки:


&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)	
	ПоказатьОповещениеПользователя("Формирую документ", "", "Формируем документ. Это может занять некоторое время", БиблиотекаКартинок.БизнесПроцесс);	
	Для Каждого ДокументСсылка Из ПараметрКоманды Цикл
		БинарныеДанные = СформироватьДокументНаСервере(ДокументСсылка);
		врмф = ПолучитьИмяВременногоФайла(".docx");
		БинарныеДанные.Записать(врмф);
		
		Оповещение = Новый ОписаниеОповещения("ЗапускПриложения", ЭтотОбъект);
		НачатьЗапускПриложения(Оповещение, врмф, , Ложь);
	 	ПоказатьОповещениеПользователя("Документ сформирован", "", "Дождитесь открытия приложения для работы с документом", БиблиотекаКартинок.БизнесПроцесс);
	КонецЦикла;		
КонецПроцедуры

&НаКлиенте
Процедура ЗапускПриложения(КодВозврата, ДополнительныйПараметр) Экспорт

КонецПроцедуры



&НаСервере
Функция СформироватьДокументНаСервере(ДокументСсылка);
	Возврат Документы.СК_КалькуляторИндексации.СгенерироватьДокумент(ДокументСсылка,"ЗаявлениеОбИндексации");
КонецФункции

Код формирования файла на сервере:

Процедура ДобавитьОписаниеОбласти(НаборОбластей, знач ИмяОбласти, знач ТипОбласти) Экспорт
	НоваяОбласть = Новый Структура;	
	НоваяОбласть.Вставить("ИмяОбласти", ИмяОбласти);
	НоваяОбласть.Вставить("ТипОбласти", ТипОбласти);	
	НаборОбластей.Вставить(ИмяОбласти, НоваяОбласть);	
КонецПроцедуры

Функция ПолучениеОписанияОбластей() Экспорт
	ОписаниеОбластей = Новый Структура;	
	ДобавитьОписаниеОбласти(ОписаниеОбластей, "Тушка", "Общая");
	ДобавитьОписаниеОбласти(ОписаниеОбластей, "Подвал", "Общая");
	ДобавитьОписаниеОбласти(ОписаниеОбластей, "ВерхнийКолонтитул", "ВерхнийКолонтитул");
	ДобавитьОписаниеОбласти(ОписаниеОбластей, "НижнийКолонтитул", "НижнийКолонтитул");
	ДобавитьОписаниеОбласти(ОписаниеОбластей, "НижнийТитульныйКолонтитул", "НижнийТитульныйКолонтитул");		
	Возврат ОписаниеОбластей;		
КонецФункции		


функция ПолучитьДанныеМакета(Знач ИмяМакета)
	
	ОписаниеОбластей = Новый Соответствие;
	ДвоичныеДанныеМакетов = Новый Соответствие;
	ТипыМакетов = Новый Соответствие; 	
	ДвоичныеДанныеМакетов.Вставить(ИмяМакета, ПолучитьМакет(ИмяМакета)); 	
	ОписаниеОбластей.Вставить(ИмяМакета, ПолучениеОписанияОбластей());
	
	Макет = Новый Структура;
	Макет.Вставить("ОписаниеОбластей", ОписаниеОбластей);
	Макет.Вставить("ДвоичныеДанныеМакетов", ДвоичныеДанныеМакетов);
	Макет.Вставить("ТипыМакетов", ТипыМакетов);
	Макет.Вставить("ЛокальныйКаталогФайловПечати", Неопределено); 
	Если НЕ Макет.Свойство("ТипыМакетов") Тогда
		Макет.Макеты.Вставить("ТипыМакетов", Новый Соответствие); 
	КонецЕсли;
	
	
	Возврат Макет;                               
	
Конецфункции                    

Функция СгенерироватьДокумент(ДокументСсылка,ИмяМакета) Экспорт
	
	ДанныеОбъекта = Новый Структура;
	ДанныеОбъекта.Вставить("АрбитражныйСуд", "Самый гуманный суд в мире!");
	
	ДанныеМакетов = ПолучитьДанныеМакета(ИмяМакета);	
	
	ТипМакета = ДанныеМакетов.ТипыМакетов[ИмяМакета];
	ДвоичныеДанныеМакета = ДанныеМакетов.ДвоичныеДанныеМакетов;
	Области = ДанныеМакетов.ОписаниеОбластей;
		
	
	Макет = УправлениеПечатью.ИнициализироватьМакетОфисногоДокумента(ДвоичныеДанныеМакета[ИмяМакета],ТипМакета,ИмяМакета);
	
	Если Макет = Неопределено Тогда
		Возврат "";
	КонецЕсли;
	
	ЗакрытьОкноПечатнойформы = Ложь;	
	

	ПечатнаяФорма = УправлениеПечатью.ИнициализироватьПечатнуюФорму(ТипМакета, Макет.НастройкиСтраницыМакета,Макет);
	АдресХранилищаПечатнойФормы = "";
		
	Если ПечатнаяФорма = Неопределено Тогда
		УправлениеПечатью.ОчиститьСсылки(Макет);
		Возврат "";
	КонецЕсли;	
	
	Область = УправлениеПечатью.ОбластьМакета(Макет, Области[ИмяМакета]["Тушка"]);
	УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, Область, ДанныеОбъекта);
		
	АдресХранилищаПечатнойФормы = УправлениеПечатью.СформироватьДокумент(ПечатнаяФорма);
			
	УправлениеПечатью.ОчиститьСсылки(ПечатнаяФорма, ЗакрытьОкноПечатнойФормы);
	УправлениеПечатью.ОчиститьСсылки(Макет);
	
	докбин = Новый ХранилищеЗначения(ПолучитьИзВременногоХранилища(АдресХранилищаПечатнойФормы));
	док = докбин.Получить();
	Возврат док;

		
КонецФункции	

Перенос работающего сайта WordPress с Mysql на PostgreeSQL

Задача: перенести рабочий, наполненный постами, сайт на движке WordPress с БД MySQL на PostgreeSQL

Инструментарий:

1) pgloader — утилита для переноса данных из баз данных MySQL в PostgreeSQL

Особенности о которые спотыкался:

  • для успешного переноса необходимо чтобы пользователь в терминале под которым осуществляется перенос имел максимальные права в БД и имел доступ «без пароля» для входа в консоль pgsql
  • при переносе создается схема с именем БД, а не заливается по умолчанию в схему public. Что в принципе для нашей ситуации даже будет плюсом.
  • Перед переносом, БД уже должна быть создана в PostgreeSQL

Синтаксис:

pgloader mysql://login:password@host/db_name pgsql:///db_name

2) Плагин PG4WP который на «лету» исправляет запросы к MySQL на PostgreeSQL

Особенности:

  • работает только при «чистой» установке. Т.е. WordPress должен быть штатно проинсталлирован с нуля
  • Инсталляция корректно работает только до версии WordPress 5.9
  • Плагин заброшен, последнее обновление — 3 года назад

Итак, общий алгоритм переноса рабочего WordPress получается такой:

  1. Переносим при помощи pgloader БД в отдельную схему
  2. Заново устанавливаем WordPress 5.9 с плагином PG4WP
  3. Удаляем из схемы public wp_posts (это если только статьи переносим) и переносим её из схемы созданной pgloader в public
  4. Пробуем обновить штатно WordPress

Точно понадобится:

-- перенос таблицы из отдной схемы в другую
ALTER TABLE wp_base.wp_users
SET SCHEMA public 

Удаление всех таблиц в схеме:

-- удаляем таблицы
DO $$ DECLARE
  r RECORD;
BEGIN
  FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP
    EXECUTE 'DROP TABLE ' || quote_ident(r.tablename) || ' CASCADE';
  END LOOP;
END $$;
-- удаляем последовательности
DO $$ DECLARE
    r RECORD;
BEGIN
    FOR r IN (SELECT relname FROM pg_class where relkind = 'S') LOOP
        EXECUTE 'DROP SEQUENCE IF EXISTS ' || quote_ident(r.relname) || ' CASCADE';
    END LOOP;
END $$;

Поменять схему всех таблиц:

DO $$ DECLARE
  r RECORD;
BEGIN
  FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = 'старая_схема') LOOP
    EXECUTE 'ALTER TABLE старая_схема.' || quote_ident(r.tablename) || ' SET SCHEMA новая_схема ';
  END LOOP;
END $$;

В принципе пока вполне рабочая схема

Нарушена целостность структуры конфигурации 1С

Уже ранее была статья на эту тему, но в этом случае все советы не помогли. Помогли другие:

  1. Найти не битую cf этой версии конфигурации
  2. Зайти битую конфигурацию, снять её с поддержки
  3. Объединить битую конфигурацию с не битой cf. В время объединения 1С предложит снова поставить её на поддержку
  4. После этой манипуляции, битая становится не битой и позволяет далее нормально штатно обновлятся

Flutter: динамическое количество строк / колонок в виджетах

Для динамического построения виджетов удобно использовать List.generate, который в качестве параметра принимает количество элементов, а на вход функции-кэлбека — текущий элемент перебора. Использовать можно например как-то так:

List <Widget> MyBoardView(){
    int poz=0;
    return List<Widget>.generate(lh, (int index_h){
      return Row(
        children:
        List<Widget>.generate(lw, (int index_w){
          poz++;
          return
            Padding(
                padding: EdgeInsets.all(1),
                child:
                Container(
                    color: Colors.orange,
                    height: MediaQuery.of(context).size.height/lh-2 ,
                    width: MediaQuery.of(context).size.width/lw-2,
                    child: Text("$poz")
                )
            );
        }),
      );
    });
  }

Flutter: использование тем

Очень часто в коде тех, кто только начал свой путь в разработке на Flutter встречаются бесконечные однотипные портянки вроде:

child: Text(
                                                               FilteredListAutoes[index]["cars"][index2]["name"],                                                              style: TextStyle(fontFamily: 'Poppins', color: Colors.black, fontSize: 14.sp,)
....
....
final ButtonStyle raisedButtonStyleSuccess = ElevatedButton.styleFrom(
    onPrimary: Colors.black87,
    primary: Colors.orangeAccent,
    minimumSize: Size(120, 36),
    padding: EdgeInsets.symmetric(horizontal: 16),
    shape: const RoundedRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(10)),
    ),
  );

т.е. повторяющиеся во всём проекте прямые указания цвета, шрифта и т.п. А что если далее необходимо будет поменять эти самые шрифты и цвета? Менять руками всё довольно утомительно. К счастью в Flutter есть встроенный механизм, который помогает решить эту задачу: в виджете MaterialApp, возможно указать «Тему», как то так:

import 'package:me_flutter/inc/theme.dart' as me_theme;
MaterialApp(
  builder: EasyLoading.init(),
  title: 'Приколись!',
  debugShowCheckedModeBanner: false,
  theme: me_theme.createMeTheme(),
...

И оформим отдельный класс с «Темой»:

library me_flutter.theme;
import 'package:flutter/material.dart';

ThemeData createMeTheme() {
  return ThemeData(
    brightness: Brightness.light,
    //scaffoldBackgroundColor: Colors.grey[100],
    bottomAppBarColor : Colors.grey[100], // цвет фона панельки нижнего меню
    fontFamily : "Robotic",               // основной шрифт 
    primaryColor: Colors.black,           // основной цвет текста
    appBarTheme : AppBarTheme(
          backgroundColor: Colors.white   // фон панели сверху (Надпись Приколись! или название страницы)
    ),

  );
}
// зададим собственные названия свойств
extension CustomColorScheme on ColorScheme {
  Color get success => const Color(0xFF28a745);
  Color get info => const Color(0xFF17a2b8);
  Color get warning => const Color(0xFFffc107);
  Color get danger => const Color(0xFFdc3545);
  Color get TrayBackground => Colors.blue.shade900;  // полоска трея вверху
  Color get TrayFontColor => Colors.white;           // цвет текста в трее вверху
}

И далее во всех вложенных виджетах, автоматически будут применятся данные цвета. Так-же их можно указать принудительно, например так:

color: Theme.of(context).primaryColor
..
color: Theme.of(context).colorScheme.TrayFontColor //своё собственное свойство
1 48 49 50 51 52 311