# Парсер логов касс
## Основная информация
Это инструкция к `Pyaterochka log parser v.0.1.0`
Парсер состоит из двух файлов:
* `parser.py` - сам код парсера,
* `config.yml` - конфигурационный файл.
Перед запуском парсера, нужно установить Python версиии 3.7.
Все недостающие модули парсер докачает сам при первом запуске.
## Конфигурационный файл (`config.yml`)
Здесь задаются все основные настройки парсера, откуда читать логи, как они называются, сколько файлов читать за раз и так далее, сейчас об этом поподробнее.
* `data_folder` - путь до папки с логами магазина
* `pos_folder` - общая часть названия папок с логами касс (если указано `pos`, значит папки называются `pos*`, где `*` это произвольные символы)
* `log_file_names` - общая часть названия файлов с логами (принцип работы такой же как и у `pos_folder`)
* `res_folder` - путь до папки в которую сохранять результаты парсинга
* `temp_folder` - путь до папки в которую сохранять временные файлы (желательно эту папку удалить после работы)
* `file_from` - с какого файла начинать парсинг (номер файла, не название)
* `file_to` - до какого файла парсить (если ничего не указано, парсить все файлы)
* `files_step` - сколько файлов читать за один раз
* `num_of_workers` - сколько паралельных процессов запускать (выбор зависит от количества ядер процессора)
* `min_time_delta` - минимальное количество времени между сохраняемыми файлами в часах (не ставить меньше 1, так как файлы могут перезаписаться следующими)
* `language` - язык на котором парсер будет писать в консоль
Вот пример конфигурации:
```yaml=
settings:
data_folder: data/O186/
log_file_names: std_pos.log-
pos_folder: pos
res_folder: res/O186/
temp_folder: temp/O186/
file_from: 0
file_to:
files_step: 15
num_of_workers: 4
min_time_delta: 1
language: eng
```
Получается, с данной конфигурацией парсер будет читать из папок:
```
/data/O136/pos1/std_pos.log-0000000
std_pos.log-0100000
...
pos2/std_pos.log-0000000
std_pos.log-0100000
...
...
```
И писать в папку:
```
/res/O186/pos1/merged_logs.json
...
pos2/merged_logs.json
...
...
```
## Запуск парсера
После скачивания нужной версии Python'а и настройки конфигурационного файла можно приступить к запуску парсера, для этого можно просто открыть командную строку в папке с парсером и написать команду `python parser.py` и парсер начнёт свою работу.
Так же у парсера есть пара флагов, которые можно передать при запуске через командную строку:
* `--pos_num` - логи какой кассы парсить (если ничего не передавать, парсятся логи со всех касс)
* `--merge_results` - при передаче этого флага, результаты парсинга объединятся в общий файл по кассе
* `--parse_purchases` - парсить ли данные о покупках (запускать только после того, как был выполнен `merge_results`)
* `--skip_parsing_files` - пропустить парсинг файлов (если он уже был выполнен)
* `--delete_temp_files` - удалить после работы парсера временные файлы
## Результаты работы
После запуска программы могут получиться следующие типы файлов:
* `merged_logs.json` - файл со всеми распарсенными логами этой кассы
* `merged_purchases.json` - файл со всеми операциями связанными с покупками на этой кассе
* `merged_items.json` - файл со всеми купленными товарами на этой кассе (грязный, содержит повторяющуюся информацию)
* `merged_returns.json` - файл со всеми возвращёнными товарами
* `purchases_clean.p` - файл с очищенными данными о покупках (все файлы в формате `.p`, это pickle файлы для распаковки в питоне, в них содержится pandas Dataframe с соответствующими данными)
* `items_clean.p` - файл с очищенным списком купленных товаров
## Примеры результатов:
### `merged_logs.json`
```json
{"time": "2019-02-19 07:35:44.808000", "parsed_type": "bank_payment_end", "parsed_data": null}
{"time": "2019-02-19 07:35:44.850000", "parsed_type": "issurance_or_return_end", "parsed_data": {"id": "22759520"}}
{"time": "2019-02-19 07:35:47.005000", "parsed_type": "authorization_start", "parsed_data": null}
{"time": "2019-02-19 07:37:00.833000", "parsed_type": "check_formation_end", "parsed_data": null}
{"time": "2019-02-19 07:37:23.498000", "parsed_type": "cash_receipt_end_and_drawer_close", "parsed_data": null}
{"time": "2019-02-19 07:38:00.053000", "parsed_type": "check_cashier_id", "parsed_data": {"pos_id": "1", "cashier_name": "Васильева Валерия Александровна", "cashier_type": "Продавец-кассир"}}
{"time": "2019-02-19 07:38:04.385000", "parsed_type": "check_end_print", "parsed_data": null}
{"time": "2019-02-19 07:38:05.184000", "parsed_type": "check_formation_end", "parsed_data": null}
{"time": "2019-02-19 07:38:05.861000", "parsed_type": "plu_search_start", "parsed_data": {"ean": "0", "art_nr": "null"}}
{"time": "2019-02-19 07:38:05.865000", "parsed_type": "plu_search_end", "parsed_data": {"elapsed_time": "4"}}
{"time": "2019-02-19 07:38:06.150000", "parsed_type": "authorization_status", "parsed_data": {"status": "OK", "login_bon_id": "E161001000000000000000000952019021907:37"}}
{"time": "2019-02-19 07:38:06.159000", "parsed_type": "barcode_item3", "parsed_data": null}
{"time": "2019-02-19 07:38:06.375000", "parsed_type": "operation_end", "parsed_data": {"id": "12300276"}}
{"time": "2019-02-19 07:43:06.485000", "parsed_type": "check_formation_end", "parsed_data": null}
```
### `merged_items.json`
```json
{"time": "2019-02-19 09:16:19.556000", "id": 3602487, "i_name": "СИГАРЕТЫ ROTHMANS ДЕМИ КЛИК ПАЧ", "quantity": 1.0, "vat_info": "1", "unit_price": 105.0, "price": 105.0, "unit_name": "ST", "pre_text": "", "post_text": "", "receipt_id": 1, "sub_id": 0}
{"time": "2019-02-19 09:17:11.564000", "receipt_id": 2, "sub_id": 0, "id": 3300573, "groupcode": "1", "quantity": 1.0, "price": 5.0}
{"time": "2019-02-19 09:17:11.564000", "receipt_id": 2, "sub_id": 0, "id": 3296712, "groupcode": "1", "quantity": 1.0, "price": 64.99}
{"time": "2019-02-19 09:17:11.564000", "receipt_id": 2, "sub_id": 0, "id": 3306904, "groupcode": "1", "quantity": 1.0, "price": 69.99}
{"time": "2019-02-19 09:17:11.564000", "receipt_id": 2, "sub_id": 0, "id": 3337159, "groupcode": "1", "quantity": 1.0, "price": 54.99}
{"time": "2019-02-19 09:17:35.435000", "receipt_id": 2, "sub_id": 2, "id": 3300573, "groupcode": "0", "quantity": 1.0, "price": 5.0}
{"time": "2019-02-19 09:17:35.435000", "receipt_id": 2, "sub_id": 2, "id": 3296712, "groupcode": "0", "quantity": 1.0, "price": 64.99}
{"time": "2019-02-19 09:17:35.435000", "receipt_id": 2, "sub_id": 2, "id": 3306904, "groupcode": "0", "quantity": 1.0, "price": 69.99}
{"time": "2019-02-19 09:17:35.435000", "receipt_id": 2, "sub_id": 2, "id": 3337159, "groupcode": "0", "quantity": 1.0, "price": 54.99}
{"time": "2019-02-19 09:17:40.592000", "id": 3300573, "i_name": "Пакет ПЯТЕРОЧКА 65х40см", "quantity": 1.0, "vat_info": "1", "unit_price": 5.0, "price": 5.0, "unit_name": "ST", "pre_text": "", "post_text": "", "receipt_id": 2, "sub_id": 4}
{"time": "2019-02-19 09:17:40.674000", "id": 3296712, "i_name": "РЯЗАН.Мука ПШЕНИЧ.ЭКСТРА 2кг", "quantity": 1.0, "vat_info": "2", "unit_price": 64.99, "price": 64.99, "unit_name": "ST", "pre_text": "", "post_text": "", "receipt_id": 2, "sub_id": 4}
{"time": "2019-02-19 09:17:40.683000", "id": 3306904, "i_name": "МААГ Кишмиш светлый 250г", "quantity": 1.0, "vat_info": "1", "unit_price": 69.99, "price": 69.99, "unit_name": "ST", "pre_text": "", "post_text": "", "receipt_id": 2, "sub_id": 4}
{"time": "2019-02-19 09:17:40.689000", "id": 3337159, "i_name": "BAR.Макар.ДЖИРАНДОЛЕ 500г", "quantity": 1.0, "vat_info": "2", "unit_price": 54.99, "price": 54.99, "unit_name": "ST", "pre_text": "", "post_text": "", "receipt_id": 2, "sub_id": 4}
```
### `merged_purchases.json`
```json
{"time": "2019-02-19 09:16:22.026000", "store_id": "E161", "type": "check", "r_id": 1, "pos_id": "1", "cashier_name": "Васильева Валерия Александровна", "cashier_type": "Продавец-кассир", "sub_id": 0, "num_of_items": 1, "receipt_id": -1}
{"type": "lrequest", "time": "2019-02-19 09:17:11.564000", "receipt_id": 109065, "r_id": 2, "sub_id": 0, "lcard_num": "7789000097893459", "amount": 194.97, "amount_pbp": null, "num_of_items": 4, "store_id": "E161"}
{"time": "2019-02-19 09:17:17.167000", "type": "lresponse", "r_id": 2, "sub_id": 1, "lname": null, "ladded_points": 104, "lpromo_points": 0, "ltotal": 104, "error_code": 0}
{"type": "lrequest", "time": "2019-02-19 09:17:35.435000", "receipt_id": 109065, "r_id": 2, "sub_id": 2, "lcard_num": "7789000097893459", "amount": 194.97, "amount_pbp": 1.0, "num_of_items": 4, "store_id": "E161"}
{"time": "2019-02-19 09:17:35.989000", "type": "lresponse", "r_id": 2, "sub_id": 3, "lname": "мария", "ladded_points": 9, "lpromo_points": 0, "ltotal": 113, "error_code": 0}
{"time": "2019-02-19 09:17:45.890000", "store_id": "E161", "type": "check", "r_id": 2, "pos_id": "1", "cashier_name": "Васильева Валерия Александровна", "cashier_type": "Продавец-кассир", "sub_id": 4, "card_type": "MIR Premium DBT", "card_num": "************3147", "card_name": "DEMENKOVA MARIYA", "amount": 194.97, "num_of_items": 4, "receipt_id": -1}
{"time": "2019-02-19 09:18:18.814000", "store_id": "E161", "type": "check", "r_id": 3, "pos_id": "1", "cashier_name": "Васильева Валерия Александровна", "cashier_type": "Продавец-кассир", "sub_id": 0, "num_of_items": 2, "receipt_id": -1}
{"time": "2019-02-19 09:21:30.326000", "store_id": "E161", "type": "check", "r_id": 4, "pos_id": "1", "cashier_name": "Васильева Валерия Александровна", "cashier_type": "Продавец-кассир", "sub_id": 0, "card_type": "Visa", "card_num": "************0983", "card_name": null, "amount": 264.2, "num_of_items": 3, "receipt_id": -1}
{"time": "2019-02-19 09:26:07.165000", "store_id": "E161", "type": "check", "r_id": 5, "pos_id": "1", "cashier_name": "Васильева Валерия Александровна", "cashier_type": "Продавец-кассир", "sub_id": 0, "num_of_items": 1, "receipt_id": -1}
{"time": "2019-02-19 09:30:29.046000", "store_id": "E161", "type": "check", "r_id": 6, "pos_id": "1", "cashier_name": "Васильева Валерия Александровна", "cashier_type": "Продавец-кассир", "sub_id": 0, "card_type": "MASTERCARD", "card_num": "************9718", "card_name": "BATURIN LEV", "amount": 88.0, "num_of_items": 1, "receipt_id": -1}
{"time": "2019-02-19 09:37:42.234000", "store_id": "E161", "type": "check", "r_id": 7, "pos_id": "1", "cashier_name": "Васильева Валерия Александровна", "cashier_type": "Продавец-кассир", "sub_id": 0, "card_type": "Visa", "card_num": "************6231", "card_name": null, "amount": 45.99, "num_of_items": 1, "receipt_id": -1}
{"time": "2019-02-19 09:38:02.517000", "store_id": "E161", "type": "check", "r_id": 8, "pos_id": "1", "cashier_name": "Васильева Валерия Александровна", "cashier_type": "Продавец-кассир", "sub_id": 0, "card_type": "Mastercard", "card_num": "************3050", "card_name": null, "amount": 95.0, "num_of_items": 1, "receipt_id": -1}
{"time": "2019-02-19 09:56:00.184000", "store_id": "E161", "type": "check", "r_id": 9, "pos_id": "1", "cashier_name": "Васильева Валерия Александровна", "cashier_type": "Продавец-кассир", "sub_id": 0, "num_of_items": 3, "receipt_id": -1}
{"type": "lrequest", "time": "2019-02-19 09:58:53.575000", "receipt_id": 109073, "r_id": 10, "sub_id": 0, "lcard_num": "7789004690698281", "amount": 479.0, "amount_pbp": 1.0, "num_of_items": 5, "store_id": "E161"}
{"time": "2019-02-19 09:58:54.500000", "type": "lresponse", "r_id": 10, "sub_id": 1, "lname": "\u0435\u043b\u0435\u043d\u0430", "ladded_points": 23, "lpromo_points": 0, "ltotal": 937, "error_code": 0}
{"time": "2019-02-19 09:59:03.570000", "store_id": "E161", "type": "check", "r_id": 10, "pos_id": "1", "cashier_name": "Васильева Валерия Александровна", "cashier_type": "Продавец-кассир", "sub_id": 2, "num_of_items": 6, "receipt_id": -1}
{"time": "2019-02-19 10:01:12.964000", "store_id": "E161", "type": "check", "r_id": 11, "pos_id": "1", "cashier_name": "Васильева Валерия Александровна", "cashier_type": "Продавец-кассир", "sub_id": 0, "card_type": "Visa", "card_num": "************0738", "card_name": null, "amount": 45.1, "num_of_items": 1, "receipt_id": -1}
```
### `clean_purchases.p`
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right">
<th></th>
<th>time</th>
<th>init_amount</th>
<th>final_amount</th>
<th>lname</th>
<th>lcard_num</th>
<th>ladded_points</th>
<th>lpromo_points</th>
<th>ltotal</th>
<th>card_name</th>
<th>card_type</th>
<th>card_num</th>
<th>store_id</th>
<th>pos_id</th>
<th>cashier_name</th>
<th>cashier_type</th>
</tr>
<tr>
<th>receipt_id</th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<th>1</th>
<td>2019-02-19 09:16:22.026</td>
<td>105.00</td>
<td>105.00</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>E161</td>
<td>1</td>
<td>Васильева Валерия Александровна</td>
<td>Продавец-кассир</td>
</tr>
<tr>
<th>2</th>
<td>2019-02-19 09:17:45.890</td>
<td>194.97</td>
<td>194.97</td>
<td>мария</td>
<td>7789000097893459</td>
<td>9.0</td>
<td>0.0</td>
<td>113.0</td>
<td>DEMENKOVA MARIYA</td>
<td>MIR Premium DBT</td>
<td>************3147</td>
<td>E161</td>
<td>1</td>
<td>Васильева Валерия Александровна</td>
<td>Продавец-кассир</td>
</tr>
<tr>
<th>3</th>
<td>2019-02-19 09:18:18.814</td>
<td>148.99</td>
<td>148.00</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>E161</td>
<td>1</td>
<td>Васильева Валерия Александровна</td>
<td>Продавец-кассир</td>
</tr>
</tbody>
</table>
### `clean_items.p`
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right">
<th></th>
<th>id</th>
<th>price</th>
<th>quantity</th>
</tr>
<tr>
<th>receipt_id</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<th>1</th>
<td>3602487</td>
<td>105.00</td>
<td>1.0</td>
</tr>
<tr>
<th>2</th>
<td>3300573</td>
<td>5.00</td>
<td>1.0</td>
</tr>
<tr>
<th>2</th>
<td>3296712</td>
<td>64.99</td>
<td>1.0</td>
</tr>
<tr>
<th>2</th>
<td>3306904</td>
<td>69.99</td>
<td>1.0</td>
</tr>
<tr>
<th>2</th>
<td>3337159</td>
<td>54.99</td>
<td>1.0</td>
</tr>
<tr>
<th>3</th>
<td>3628404</td>
<td>37.99</td>
<td>1.0</td>
</tr>
<tr>
<th>3</th>
<td>3674398</td>
<td>111.00</td>
<td>1.0</td>
</tr>
<tr>
<th>4</th>
<td>41930</td>
<td>97.80</td>
<td>1.0</td>
</tr>
<tr>
<th>4</th>
<td>3639576</td>
<td>51.40</td>
<td>1.0</td>
</tr>
<tr>
<th>4</th>
<td>3356406</td>
<td>115.00</td>
<td>1.0</td>
</tr>
</tbody>
</table>