Для приготовления CRUD нам понадобится 1C, Python и ... PostgreSQL. Сначала нужно включить REST OData в 1C.

Поиск будем осуществлять следующей функцией на Python

import requests # импортируем библиотеку
def filter( # определяем функцию
    entity, # имя сущности
    filter=None, # фильтр для поиска сущности
    select=None, # выбор только заданных полей сущности
):
    url = f'http(s)://1c.host.name/api/odata/standard.odata/{entity}' # конструируем адрес
    headers = dict(Accept='application/json') # задаём тип ответа
    params = dict() # объявляем параметры
    if filter is not None: params['$filter'] = filter # если задан фильтр, то задаём его
    if select is not None: params['$select'] = select # если задан выбор полей, то задаём его
    response = requests.get(url, headers=headers, params=params) # выполняем запрос
    try: json = response.json() # получаем результат и пытаемся преобразовать его в json
    except: raise Exception(response.text) # а в случае неудачи поднимаем исключение
    if 'odata.error' in json: raise Exception(json['odata.error']['message']['value']) # если в результате ошибка, то поднимаем исключение
    return json['value'] # возвращаем массив сущностей

и на ... PL/pgSQL с помощью расширения pg_curl

create or replace function filter( -- создаём или меняем функцию
    entity text, -- имя сущности
    filter text default null, -- фильтр для поиска сущности
    "select" text default null -- выбор только заданных полей сущности
) returns jsonb language plpgsql as $body$ declare -- возвращающую json на языке PL/pgSQL
    url text default format($$http(s)://1c.host.name/api/odata/standard.odata/%s?$$, curl_easy_escape(entity)); -- объявляем и конструируем адрес
    jsonb jsonb; -- объявляем возвращаемую переменную
    text text; -- и вспомогательную переменную
begin
    perform curl_easy_setopt_url(url); -- задаём адрес
    perform curl_header_append('Accept', 'application/json'); -- задаём тип ответа
    if filter is not null then perform curl_url_append('$filter', filter); end if; -- если задан фильтр, то задаём его
    if "select" is not null then perform curl_url_append('$select', "select"); end if; -- если задан выбор полей, то задаём его
    perform curl_easy_perform(); -- выполняем запрос
    text = convert_from(curl_easy_getinfo_data_in(), 'utf-8'); -- получаем результат
    begin jsonb = text; exception when invalid_text_representation then raise exception '%', text; end; -- пытаемся преобразовать результат в json, а в случае неудачи поднимаем исключение
    if jsonb->'odata.error' is not null then raise exception '%', jsonb->'odata.error'->'message'->>'value'; end if; -- если в результате ошибка, то поднимаем исключение
    return nullif(jsonb->'value', '[]'); -- возвращаем непустой массив сущностей или ничего
end;$body$;    

Чтение будем осуществлять следующей функцией на Python

import requests # импортируем библиотеку
def read( # определяем функцию
    entity, # имя сущности
    guid, # идентификатор сущности
    select=None, # выбор только заданных полей сущности
):
    url = f'''http(s)://1c.host.name/api/odata/standard.odata/{entity}(guid'{guid}')''' # конструируем адрес
    headers = dict(Accept='application/json') # задаём тип ответа
    params = dict() # объявляем параметры
    if select is not None: params['$select'] = select # если задан выбор полей, то задаём его
    response = requests.get(url, headers=headers, params=params) # выполняем запрос
    try: json = response.json() # получаем результат и пытаемся преобразовать его в json
    except: raise Exception(response.text) # а в случае неудачи поднимаем исключение
    if 'odata.error' in json: raise Exception(json['odata.error']['message']['value']) # если в результате ошибка, то поднимаем исключение
    return json # возвращаем сущность

и на ... PL/pgSQL

create or replace function read( -- создаём или меняем функцию
    entity text, -- имя сущности
    guid uuid, -- идентификатор сущности
    "select" text default null -- выбор только заданных полей сущности
) returns jsonb language plpgsql as $body$ declare -- возвращающую json на языке PL/pgSQL
    url text default format($$http(s)://1c.host.name/api/odata/standard.odata/%s(guid'%s')?$$, curl_easy_escape(entity), curl_easy_escape(guid::text)); -- объявляем и конструируем адрес
    jsonb jsonb; -- объявляем возвращаемую переменную
    text text; -- и вспомогательную переменную
begin
    perform curl_easy_setopt_url(url); -- задаём адрес
    perform curl_header_append('Accept', 'application/json'); -- задаём тип ответа
    if "select" is not null then perform curl_url_append('$select', "select"); end if; -- если задан выбор полей, то задаём его
    perform curl_easy_perform(); -- выполняем запрос
    text = convert_from(curl_easy_getinfo_data_in(), 'utf-8'); -- получаем результат
    begin jsonb = text; exception when invalid_text_representation then raise exception '%', text; end; -- пытаемся преобразовать результат в json, а в случае неудачи поднимаем исключение
    if jsonb->'odata.error' is not null then raise exception '%', jsonb->'odata.error'->'message'->>'value'; end if; -- если в результате ошибка, то поднимаем исключение
    return jsonb; -- возвращаем сущность
end;$body$;

Создание будем осуществлять следующей функцией на Python

import requests # импортируем библиотеку
def create( # определяем функцию
    entity, # имя сущности
    data, # тело сущности
    select=None, # выбор только заданных полей сущности
):
    url = f'http(s)://1c.host.name/api/odata/standard.odata/{entity}' # конструируем адрес
    headers = dict(Accept='application/json') # задаём тип ответа
    response = requests.post(url, headers=headers, data=data) # выполняем запрос
    try: json = response.json() # получаем результат и пытаемся преобразовать его в json
    except: raise Exception(response.text) # а в случае неудачи поднимаем исключение
    if 'odata.error' in json: raise Exception(json['odata.error']['message']['value']) # если в результате ошибка, то поднимаем исключение
    if select is not None: return read(entity, json['Ref_Key'], select) # если задан выбор полей, то заново читаем и возвращаем сущность
    return json # иначе просто возвращаем сущность

и на ... PL/pgSQL

create or replace function "create"( -- создаём или меняем функцию
    entity text, -- имя сущности
    jsonb jsonb, -- тело сущности
    "select" text default null -- выбор только заданных полей сущности
) returns jsonb language plpgsql as $body$ declare -- возвращающую json на языке PL/pgSQL
    url text default format($$http(s)://1c.host.name/api/odata/standard.odata/%s?$$, curl_easy_escape(entity)); -- объявляем и конструируем адрес
    text text; -- объявляем вспомогательную переменную
begin
    perform curl_easy_setopt_postfields(convert_to(jsonb::text, 'utf-8')); -- задаём тело
    perform curl_easy_setopt_url(url); -- задаём адрес
    perform curl_header_append('Accept', 'application/json'); -- задаём тип ответа
    perform curl_easy_perform(); -- выполняем запрос
    text = convert_from(curl_easy_getinfo_data_in(), 'utf-8'); -- получаем результат
    begin jsonb = text; exception when invalid_text_representation then raise exception '%', text; end; -- пытаемся преобразовать результат в json, а в случае неудачи поднимаем исключение
    if jsonb->'odata.error' is not null then raise exception '%', jsonb->'odata.error'->'message'->>'value'; end if; -- если в результате ошибка, то поднимаем исключение
    if "select" is not null then return read(entity, (jsonb->>'Ref_Key')::uuid, "select"); end if; -- если задан выбор полей, то заново читаем и возвращаем сущность
    return jsonb; -- иначе просто возвращаем сущность
end;$body$;

Удаление будем осуществлять следующей функцией на Python

import requests # импортируем библиотеку
def delete( # определяем функцию
    entity, # имя сущности
    guid, # идентификатор сущности
):
    url = f'''http(s)://1c.host.name/api/odata/standard.odata/{entity}(guid'{guid}')''' # конструируем адрес
    headers = dict(Accept='application/json') # задаём тип ответа
    response = requests.delete(url, headers=headers) # выполняем запрос
    try: json = response.json() # получаем результат и пытаемся преобразовать его в json
    except: raise Exception(response.text) # а в случае неудачи поднимаем исключение
    if 'odata.error' in json: raise Exception(json['odata.error']['message']['value']) # если в результате ошибка, то поднимаем исключение

и на ... PL/pgSQL

create or replace function delete( -- создаём или меняем функцию
    entity text, -- имя сущности
    guid uuid -- идентификатор сущности
) returns void language plpgsql as $body$ declare -- ничего не возвращающую на языке PL/pgSQL
    url text default format($$http(s)://1c.host.name/api/odata/standard.odata/%s(guid'%s')?$$, curl_easy_escape(entity), curl_easy_escape(guid::text)); -- объявляем и конструируем адрес
    jsonb jsonb; -- объявляем вспомогательную переменную
    text text; -- и ещё одну
begin
    perform curl_easy_setopt_customrequest('DELETE'); -- задаём тип запроса
    perform curl_easy_setopt_url(url); -- задаём адрес
    perform curl_header_append('Accept', 'application/json'); -- задаём тип ответа
    perform curl_easy_perform(); -- выполняем запрос
    text = convert_from(curl_easy_getinfo_data_in(), 'utf-8'); -- получаем результат
    begin jsonb = text; exception when invalid_text_representation then raise exception '%', text; end; -- пытаемся преобразовать результат в json, а в случае неудачи поднимаем исключение
    if jsonb->'odata.error' is not null then raise exception '%', jsonb->'odata.error'->'message'->>'value'; end if; -- если в результате ошибка, то поднимаем исключение
end;$body$;

Обновление будем осуществлять следующей функцией на Python

import requests # импортируем библиотеку
def update( # определяем функцию
    entity, # имя сущности
    guid, # идентификатор сущности
    data, # тело сущности
    select=None, # выбор только заданных полей сущности
):
    url = f'''http(s)://1c.host.name/api/odata/standard.odata/{entity}(guid'{guid}')''' # конструируем адрес
    headers = dict(Accept='application/json') # задаём тип ответа
    response = requests.patch(url, headers=headers, data=data) # выполняем запрос
    try: json = response.json() # получаем результат и пытаемся преобразовать его в json
    except: raise Exception(response.text) # а в случае неудачи поднимаем исключение
    if 'odata.error' in json: raise Exception(json['odata.error']['message']['value']) # если в результате ошибка, то поднимаем исключение
    if select is not None: return read(entity, json['Ref_Key'], select) # если задан выбор полей, то заново читаем и возвращаем сущность
    return json # иначе просто возвращаем сущность

и на ... PL/pgSQL

create or replace function update( -- создаём или меняем функцию
    entity text, -- имя сущности
    guid uuid, -- идентификатор сущности
    jsonb jsonb, -- тело сущности
    "select" text default null -- выбор только заданных полей сущности
) returns jsonb language plpgsql as $body$ declare -- возвращающую json на языке PL/pgSQL
    url text default format($$http(s)://1c.host.name/api/odata/standard.odata/%s(guid'%s')?$$, curl_easy_escape(entity), curl_easy_escape(guid::text)); -- объявляем и конструируем адрес
    text text; -- объявляем вспомогательную переменную
begin
    perform curl_easy_setopt_customrequest('PATCH'); -- задаём тип запроса
    perform curl_easy_setopt_postfields(convert_to(jsonb::text, 'utf-8')); -- задаём тело
    perform curl_easy_setopt_url(url); -- задаём адрес
    perform curl_header_append('Accept', 'application/json'); -- задаём тип ответа
    perform curl_easy_perform(); -- выполняем запрос
    text = convert_from(curl_easy_getinfo_data_in(), 'utf-8'); -- получаем результат
    begin jsonb = text; exception when invalid_text_representation then raise exception '%', text; end; -- пытаемся преобразовать результат в json, а в случае неудачи поднимаем исключение
    if jsonb->'odata.error' is not null then raise exception '%', jsonb->'odata.error'->'message'->>'value'; end if; -- если в результате ошибка, то поднимаем исключение
    if "select" is not null then return read(entity, (jsonb->>'Ref_Key')::uuid, "select"); end if; -- если задан выбор полей, то заново читаем и возвращаем сущность
    return jsonb; -- иначе просто возвращаем сущность
end;$body$;

Можно ещё сделать кеширование при чтении и обновление только при изменении.

Комментарии (4)


  1. shibanovan
    18.05.2022 12:51
    +1

    Как то не тянет это на статью на хабре) Для подобного есть github

    Вы бы рассказали, с какой задачей столкнулись, рассказали бы что реализовали всем этим кодом

    Еще не понятно зачем тут PL/SQL?


    1. RekGRpth Автор
      18.05.2022 13:15

      загружаю в 1C из биллинга

      Контрагенты
      Номенклатура
      РеализацияТоваровУслуг
      СчетНаОплатуПокупателю
      СчетФактураВыданный

      PL/pgSQL потому, что в биллинге используется база PostgreSQL и проще было загрузку сделать асинхронно с помощью планировщика


      1. shibanovan
        18.05.2022 16:15

        А python, видимо, тоже пригодился?


  1. Deterok
    18.05.2022 13:13
    +1

    Хаатит уже уродовать так Python. Отвратительное вырвиглазное форматирвоание.