diff --git a/mirzaev/spetsresurs/google_sheets/parser/system/public/markets.php b/mirzaev/spetsresurs/google_sheets/parser/system/public/markets.php index 7d52a09..d1b496c 100644 --- a/mirzaev/spetsresurs/google_sheets/parser/system/public/markets.php +++ b/mirzaev/spetsresurs/google_sheets/parser/system/public/markets.php @@ -27,7 +27,7 @@ use Google\Client, require __DIR__ . '/../../../../../../vendor/autoload.php'; -$arangodb = new connection(require '../settings/arangodb.php'); +$arangodb = new connection(require __DIR__ . '/../settings/arangodb.php'); function generateLabel(string $name): string { @@ -77,9 +77,9 @@ function sync(Row &$row, string $city = 'Красноярск'): void else throw new exception('Не удалось инициализировать коллекцию'); } -$settings = json_decode(require('../settings/markets/google.php'), true); -$document = require('../settings/markets/document.php'); -$sheets = require('../settings/markets/sheets.php'); +$settings = json_decode(require(__DIR__ . '/../settings/markets/google.php'), true); +$document = require(__DIR__ . '/../settings/markets/document.php'); +$sheets = require(__DIR__ . '/../settings/markets/sheets.php'); $client = new Client(); $client->setScopes(Sheets::SPREADSHEETS); diff --git a/mirzaev/spetsresurs/google_sheets/parser/system/public/workers.php b/mirzaev/spetsresurs/google_sheets/parser/system/public/workers.php index 1b90aa9..751833e 100644 --- a/mirzaev/spetsresurs/google_sheets/parser/system/public/workers.php +++ b/mirzaev/spetsresurs/google_sheets/parser/system/public/workers.php @@ -27,7 +27,7 @@ use Google\Client, require __DIR__ . '/../../../../../../vendor/autoload.php'; -$arangodb = new connection(require '../settings/arangodb.php'); +$arangodb = new connection(require __DIR__ . '/../settings/arangodb.php'); function generateLabel(string $name): string { @@ -159,9 +159,9 @@ function sync(Row &$row, string $city = 'Красноярск'): void else throw new exception('Не удалось инициализировать коллекцию'); } -$settings = json_decode(require('../settings/workers/google.php'), true); -$document = require('../settings/workers/document.php'); -$sheets = require('../settings/workers/sheets.php'); +$settings = json_decode(require(__DIR__ . '/../settings/workers/google.php'), true); +$document = require(__DIR__ . '/../settings/workers/document.php'); +$sheets = require(__DIR__ . '/../settings/workers/sheets.php'); $client = new Client(); $client->setScopes(Sheets::SPREADSHEETS); diff --git a/mirzaev/spetsresurs/google_sheets/parser/system/public/works.php b/mirzaev/spetsresurs/google_sheets/parser/system/public/works.php index 7eca30f..72dc1bb 100644 --- a/mirzaev/spetsresurs/google_sheets/parser/system/public/works.php +++ b/mirzaev/spetsresurs/google_sheets/parser/system/public/works.php @@ -27,43 +27,67 @@ use Google\Client, require __DIR__ . '/../../../../../../vendor/autoload.php'; -$arangodb = new connection(require '../settings/arangodb.php'); +$arangodb = new connection(require __DIR__ . '/../settings/arangodb.php'); function generateLabel(string $name): string { return match ($name) { + 'imported_created_in_sheets', 'Отметка времени' => 'imported_created_in_sheets', + 'imported_date', 'Дата заявки' => 'imported_date', + 'imported_market', 'Ваш магазин' => 'imported_market', + 'imported_worker', 'Требуемый сотрудник' => 'imported_worker', + 'imported_work', 'Вид работы' => 'imported_work', + 'imported_start', 'Начало работы' => 'imported_start', + 'imported_end', 'Конец работы' => 'imported_end', + 'imported_hours', 'Часы работы' => 'imported_hours', 'created_in_sheets', 'Создано' => 'created_in_sheets', 'date', 'Дата' => 'date', 'market', 'Магазин' => 'market', + 'type', 'Тип' => 'type', + 'address', 'Адрес' => 'address', 'worker', 'Сотрудник' => 'worker', + 'name', 'ФИО' => 'name', 'work', 'Работа' => 'work', 'start', 'Начало' => 'start', 'end', 'Конец' => 'end', 'hours', 'Часы' => 'hours', + 'tax', 'ИНН' => 'tax', 'confirmed', 'Подтверждено' => 'confirmed', 'commentary', 'Комментарий' => 'commentary', 'response', 'Ответ' => 'response', '_id', 'ID' => '_id', - default => throw new exception("Неизвестный столбец: $name") + default => $name }; } function degenerateLabel(string $name): string { return match ($name) { + 'Отметка времени', 'imported_created_in_sheets' => 'Отметка времени', + 'Дата заявки', 'imported_date' => 'Дата заявки', + 'Ваш магазин', 'imported_market' => 'Ваш магазин', + 'Требуемый сотрудник', 'imported_worker' => 'Требуемый сотрудник', + 'Вид работы', 'imported_work' => 'Вид работы', + 'Начало работы', 'imported_start' => 'Начало работы', + 'Конец работы', 'imported_end' => 'Конец работы', + 'Часы работы', 'imported_hours' => 'Часы работы', 'Создано', 'created_in_sheets' => 'Создано', 'Дата', 'date' => 'Дата', 'Магазин', 'market' => 'Магазин', + 'Тип', 'type' => 'Тип', + 'Адрес', 'address' => 'Адрес', 'Сотрудник', 'worker' => 'Сотрудник', + 'ФИО', 'name' => 'ФИО', 'Работа', 'work' => 'Работа', 'Начало', 'start' => 'Начало', 'Конец', 'end' => 'Конец', 'Часы', 'hours' => 'Часы', + 'ИНН', 'tax' => 'ИНН', 'Подтверждено', 'confirmed' => 'Подтверждено', 'Комментарий', 'commentary' => 'Комментарий', 'Ответ', 'response' => 'Ответ', 'ID', '_id' => 'ID', - default => throw new exception("Неизвестный столбец: $name") + default => $name }; } @@ -77,60 +101,215 @@ function init(array $row, bool $reverse = false): array } -function sync(Row &$row): void +function sync(Row &$row, ?array $raw = null): void { global $arangodb; - $_row = init($row->entries()->toArray()['row']); + $_row = init($row->toArray()['row']); if (collection::init($arangodb->session, 'works')) if (!empty($_row['_id']) && $work = collection::search($arangodb->session, sprintf("FOR d IN works FILTER d._id == '%s' RETURN d", $_row['_id']))) { - // Найдена запись работы (строки) в базе данных + // Найдена запись работы (строки) в базе данных и включен режим перезаписи (приоритет - google sheets) - // Очистка перед записью в таблицу - $new = array_diff_key($work->getAll(), ['_key' => true, 'created' => true]) + ['_id' => $work->getId()]; - - $buffer = $new; + if ($work->transfer_to_sheets) { + // Запрошен форсированный перенос данных из базы данных в таблицу - // Инициализация выбранного сотрудника - if (collection::init($arangodb->session, 'readinesses', true) && collection::init($arangodb->session, 'workers')) - $new = array_splice($new, 0, 2) + ['worker' => collection::search( - $arangodb->session, - sprintf( - "FOR d IN workers LET e = (FOR e IN readinesses FILTER e._to == '%s' RETURN e._from)[0] FILTER d._id == e RETURN d", - $_row['_id'] - ) - )->id ?? ''] + array_slice($buffer, 2); - else throw new exception('Не удалось инициализировать коллекции'); + // Очистка перед записью в таблицу + $new = [ + 'imported_created_in_sheets' => $work->imported_created_in_sheets['converted'], + 'imported_date' => $work->imported_date['converted'], + 'imported_market' => $work->imported_market, + 'imported_worker' => $work->imported_worker, + 'imported_work' => $work->imported_work, + 'imported_start' => $work->imported_start['converted'], + 'imported_end' => $work->imported_end['converted'], + 'imported_hours' => $work->imported_hours, + 'created_in_sheets' => $work->created_in_sheets['converted'], + 'date' => $work->date['converted'], + 'market' => $work->market, + 'type' => $work->type, + 'address' => $work->address, + 'worker' => $work->worker, + 'name' => $work->name, + 'work' => $work->work, + 'start' => $work->start['converted'], + 'end' => $work->end['converted'], + 'hours' => $work->hours, + 'tax' => $work->tax, + 'confirmed' => $work->confirmed, + 'commentary' => $work->commentary, + 'response' => $work->response, + '_id' => $work->getId(), + ]; - $buffer = $new; + // Инициализация выбранного сотрудника + if (collection::init($arangodb->session, 'readinesses', true) && collection::init($arangodb->session, 'workers')) + $new['worker'] = collection::search( + $arangodb->session, + $worker = sprintf( + "FOR d IN workers LET e = (FOR e IN readinesses FILTER e._to == '%s' RETURN e._from)[0] FILTER d._id == e RETURN d", + $_row['_id'] + ) + )?->id; + else throw new exception('Не удалось инициализировать коллекции'); - // Инициализация магазина - if (collection::init($arangodb->session, 'requests', true) && collection::init($arangodb->session, 'markets')) - if ($market = collection::search( - $arangodb->session, - sprintf( - "FOR d IN markets LET e = (FOR e IN requests FILTER e._to == '%s' RETURN e._from)[0] FILTER d._id == e RETURN d", - $_row['_id'] - ) - )) $new = array_splice($new, 0, 2) + ['market' => $market->id] + array_splice($buffer, 2); - else throw new exception('Не удалось найти магазин'); - else throw new exception('Не удалось инициализировать коллекции'); + // Инициализация магазина + if (collection::init($arangodb->session, 'requests', true) && collection::init($arangodb->session, 'markets')) + if ($new['market'] = collection::search( + $arangodb->session, + sprintf( + "FOR d IN markets LET e = (FOR e IN requests FILTER e._to == '%s' RETURN e._from)[0] FILTER d._id == e RETURN d", + $_row['_id'] + ) + )?->id); + else throw new exception('Не удалось найти магазин'); + else throw new exception('Не удалось инициализировать коллекции'); - // Замена NULL на пустую строку - foreach ($new as $key => &$value) if ($value === null) $value = ''; + // Замена NULL на пустую строку + foreach ($new as $key => &$value) if ($value === null) $value = ''; - // Реинициализация строки с новыми данными по ссылке (приоритет из базы данных) - if ($_row !== $new) $row = $row->set((new Flow())->read(From::array([init($new, true)]))->fetch(1)[0]->get('row')); + // Реинициализация строки с новыми данными по ссылке (приоритет из базы данных) + if ($_row !== $new) $row = $row->set((new Flow())->read(From::array([init($new, true)]))->fetch(1)[0]->get('row')); + + // Деактивация форсированного трансфера + $work->transfer_to_sheets = false; + } else { + // Перенос изменений из Google Sheet в инстанцию документа в базе данных + + if ( + collection::init($arangodb->session, 'readinesses', true) && collection::init($arangodb->session, 'workers') + && ($worker = collection::search( + $arangodb->session, + sprintf( + "FOR d IN workers LET e = (FOR e IN readinesses FILTER e._to == '%s' RETURN e._from)[0] FILTER d._id == e RETURN d", + $_row['_id'] + ) + )) + && $_row['worker'] !== $work->worker + ) { + // Изменён сотрудник (подразумевается, что внутри google sheet) + + if ($readiness = collection::search( + $arangodb->session, + sprintf( + "FOR e IN readinesses FILTER e._from == '%s' && e._to == '%s' LIMIT 1 RETURN e", + $worker->getId(), + $_row['_id'] + ) + )) { + // Инициализировано ребро: worker => work + + if ($_worker = collection::search( + $arangodb->session, + sprintf( + "FOR d IN workers FILTER d.id == '%s' LIMIT 1 RETURN d", + $_row['worker'] + ) + )) { + // Инициализирована инстанция документа в базе данных нового работника + + // Реинициализация работника + $readiness->_from = $_worker->getId(); + + // Обновление в базе данных + document::update($arangodb->session, $readiness); + } + } + } + + + if ( + collection::init($arangodb->session, 'requests', true) && collection::init($arangodb->session, 'markets') + && ($market = collection::search( + $arangodb->session, + sprintf( + "FOR d IN markets LET e = (FOR e IN requests FILTER e._to == '%s' RETURN e._from)[0] FILTER d._id == e RETURN d", + $_row['_id'] + ) + )) + && $_row['market'] !== $work->market + ) { + // Изменён магазин (подразумевается, что внутри google sheet) + + if ($request = collection::search( + $arangodb->session, + sprintf( + "FOR e IN requests FILTER e._from == '%s' && e._to == '%s' LIMIT 1 RETURN e", + $market->getId(), + $_row['_id'] + ) + )) { + // Инициализировано ребро: market => work + + if ($_market = collection::search( + $arangodb->session, + sprintf( + "FOR d IN markets FILTER d.id == '%s' LIMIT 1 RETURN d", + $_row['market'] + ) + )) { + // Инициализирована инстанция документа в базе данных нового мазагина + + // Реинициализация магазина + $request->_from = $_market->getId(); + + // Обновление в базе данных + document::update($arangodb->session, $request); + } + } + } + + // Инициализация счётчика итераций + $i = 0; + + // Реинициализация данных в инстанции документа в базе данных с данными из Google Sheet + foreach (array_diff_key($work->getAll(), ['_key' => true, 'created' => true]) as $key => $value) { + // Перебор всех записанных значений в инстанции документа в базе данных + + // Конвертация + $work->{$key} = is_array($value) ? ['number' => $_row[$key] ?? $value, 'converted' => $raw[$i]] : $_row[$key] ?? $value; + + // Запись в счётчик итераций + ++$i; + } + } + + // Обновление инстанции документа в базе данных + document::update($arangodb->session, $work); } else if ( - !empty($_row['market']) + !empty($_row['imported_market']) && collection::init($arangodb->session, 'requests', true) && collection::init($arangodb->session, 'markets') - && ($market = collection::search($arangodb->session, sprintf("FOR d IN markets FILTER d.id == '%s' RETURN d", $_row['market']))) + && ($market = collection::search($arangodb->session, sprintf("FOR d IN markets FILTER d.id == '%s' RETURN d", $_row['imported_market']))) && $work = collection::search( $arangodb->session, sprintf( "FOR d IN works FILTER d._id == '%s' RETURN d", - document::write($arangodb->session, 'works', array_diff_key($_row, ['_id' => true, 'market' => true, 'worker' => true])) + document::write($arangodb->session, 'works', [ + 'imported_created_in_sheets' => ['number' => $_row['imported_created_in_sheets'] ?? '', 'converted' => $raw[0] ?? ''], + 'imported_date' => ['number' => $_row['imported_date'] ?? '', 'converted' => $raw[1] ?? ''], + 'imported_market' => $_row['imported_market'] ?? '', + 'imported_worker' => $_row['imported_worker'] ?? '', + 'imported_work' => $_row['imported_work'] ?? '', + 'imported_start' => ['number' => $_row['imported_start'] ?? '', 'converted' => $raw[5] ?? ''], + 'imported_end' => ['number' => $_row['imported_end'] ?? '', 'converted' => $raw[6] ?? ''], + 'imported_hours' => $_row['imported_hours'] ?? '', + 'created_in_sheets' => ['number' => $_row['created_in_sheets'] ?? '', 'converted' => $raw[8] ?? ''], + 'date' => ['number' => $_row['date'] ?? '', 'converted' => $raw[9] ?? ''], + 'market' => $_row['market'] ?? '', + 'type' => $_row['type'] ?? '', + 'address' => $_row['address'] ?? '', + 'worker' => $_row['worker'] ?? '', + 'name' => $_row['name'] ?? '', + 'work' => $_row['work'] ?? '', + 'start' => ['number' => $_row['start'] ?? '', 'converted' => $raw[16] ?? ''], + 'end' => ['number' => $_row['end'] ?? '', 'converted' => $raw[17] ?? ''], + 'hours' => $_row['hours'] ?? '', + 'tax' => $_row['tax'] ?? '', + 'confirmed' => $_row['confirmed'] ?? '', + 'commentary' => $_row['commentary'] ?? '', + 'response' => $_row['response'] ?? '', + 'transfer_to_sheets' => false + ]) ) ) ) { @@ -165,38 +344,74 @@ function sync(Row &$row): void // Запись идентификатора только что созданной инстанции документа в базе данных $_row['_id'] = $work->getId(); - // Замена NULL на пустую строку - foreach ($_row as $key => &$value) if ($value === null) $value = ''; - // Реинициализация строки с новыми данными по ссылке (приоритет из базы данных) - $row = $row->set((new Flow())->read(From::array([init($_row, true)]))->fetch(1)[0]->get('row')); + $row = $row->set((new Flow())->read(From::array([init([ + 'imported_created_in_sheets' => $raw[0] ?? '', + 'imported_date' => $raw[1] ?? '', + 'imported_market' => $_row['imported_market'] ?? '', + 'imported_worker' => $_row['imported_worker'] ?? '', + 'imported_work' => $_row['imported_work'] ?? '', + 'imported_start' => $raw[5] ?? '', + 'imported_end' => $raw[6] ?? '', + 'imported_hours' => $_row['imported_hours'] ?? '', + 'created_in_sheets' => $raw[0] ?? '', + 'date' => $raw[1] ?? '', + 'market' => $_row['imported_market'] ?? '', + 'type' => $_row['type'] ?? '', + 'address' => $_row['address'] ?? '', + 'worker' => $_row['imported_worker'] ?? '', + 'name' => $_row['name'] ?? '', + 'work' => $_row['imported_work'] ?? '', + 'start' => $raw[5] ?? '', + 'end' => $raw[6] ?? '', + 'hours' => $_row['imported_hours'] ?? '', + 'tax' => $_row['tax'] ?? '', + 'confirmed' => $_row['confirmed'] ?? '', + 'commentary' => $_row['commentary'] ?? '', + 'response' => $_row['response'] ?? '', + '_id' => $_row['_id'] ?? '', + ], true)]))->fetch(1)[0]->get('row')); } else return; else throw new exception('Не удалось инициализировать коллекцию'); } -$settings = json_decode(require('../settings/works/google.php'), true); -$document = require('../settings/works/document.php'); -$sheets = require('../settings/works/sheets.php'); +$settings = json_decode(require(__DIR__ . '/../settings/works/google.php'), true); +$document = require(__DIR__ . '/../settings/works/document.php'); +$sheets = require(__DIR__ . '/../settings/works/sheets.php'); $client = new Client(); $client->setScopes(Sheets::SPREADSHEETS); $client->setAuthConfig($settings); foreach ($sheets as $sheet) { + // Перебор таблиц + + // Инициализация обработчика таблиц $sheets = new Sheets($client); - $rows = (new Flow())->read(new GoogleSheetExtractor($sheets, $document, new Columns($sheet, 'A', 'L'), true, 1000, 'row')); + // Инициализация инстанции Flow для Google Sheet API + $rows = (new Flow())->read(new GoogleSheetExtractor($sheets, $document, new Columns($sheet, 'A', 'X'), true, 1000, 'row', ['valueRenderOption' => 'FORMULA'])); + // Инициализация счётчика итераций $i = 1; foreach ($rows->fetch(10000) as $row) { + // Перебор строк + + // Запись счётчика ++$i; + + // Инициализация буфера строки $buffer = $row; - sync($row); + + // Синхронизация с базой данных + sync($row, $sheets->spreadsheets_values->get($document, "$sheet!A$i:X$i")[0] ?? null); + + // Запись изменений строки в Google Sheet if ($buffer !== $row) $sheets->spreadsheets_values->update( $document, - "$sheet!A$i:L$i", + "$sheet!A$i:X$i", new ValueRange(['values' => [array_values($row->entries()->toArray()['row'])]]), ['valueInputOption' => 'USER_ENTERED'] );