dana-medical-site/migrations/import/rebuild_price_from_1c_only.py

76 lines
4.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""
Полная перестройка прайса ИСКЛЮЧИТЕЛЬНО из трёх файлов 1С (ЦОМ/Остео/Дети).
Данные из дампа Bitrix (старого сайта) в прайс больше не подмешиваются.
Правила:
- Позиция группируется по (целевой раздел, название).
- Если во всех файлах, где она встретилась, цена одна и та же — одна строка,
имя без изменений.
- Если цена расходится — по одной строке на каждую уникальную цену, имя
подписывается источником в скобках: (ЦОМ), (Остео), (Дети), либо их сочетанием,
если несколько файлов сошлись на одной цене, а другой(ие) — разошлись.
"""
import io
import build_price_map as b
DEPT_LABEL = {'D:/ЦОМ.xlsx': 'ЦОМ', 'D:/Остео.xlsx': 'Остео', 'D:/Дана Дети.xls': 'Дети'}
LABEL_ORDER = ['ЦОМ', 'Остео', 'Дети']
def esc(s):
# В PostgreSQL со standard_conforming_strings обратный слэш — обычный символ.
# Удваивать его нельзя: имя «Справка №003 П\У» превращалось в «П\У».
return "'" + str(s).replace("'", "''") + "'"
items = [] # (label, slug, name, price)
for path, kind, ncol, pcol in b.FILES:
rows = b.parse_xlsx(path) if kind == 'xlsx' else b.parse_xls(path)
parsed = b.extract(rows, ncol, pcol)
label = DEPT_LABEL[path]
for sec, name, price in parsed:
key = (sec or '').strip().lower()
slug = b.MAP.get(key, 'prochee-price')
items.append((label, slug, name.strip(), price))
groups = {} # (slug, name) -> {price: set(labels)}
for label, slug, name, price in items:
groups.setdefault((slug, name), {}).setdefault(price, set()).add(label)
same_label_conflicts = [] # случаи, когда один и тот же файл даёт 2 разные цены
rows_out = [] # (slug, final_name, price)
for (slug, name), pricemap in groups.items():
if len(pricemap) == 1:
(price,) = pricemap.keys()
rows_out.append((slug, name, price))
continue
for price, labels in pricemap.items():
label_str = ', '.join(l for l in LABEL_ORDER if l in labels)
rows_out.append((slug, '%s (%s)' % (name, label_str), price))
# диагностика: конфликт внутри одного и того же файла (не разных отделений)
all_labels_per_price = list(pricemap.values())
if any(len(all_labels_per_price[i] & all_labels_per_price[j]) > 0
for i in range(len(all_labels_per_price))
for j in range(i + 1, len(all_labels_per_price))):
same_label_conflicts.append((name, pricemap))
o = io.open('seed_price_final.sql', 'w', encoding='utf-8')
o.write('BEGIN;\n')
o.write('DELETE FROM price_items;\n') # Legacy full replacement; never run without a separate approved plan.
# Importing an internal price is not permission to publish it on the website.
# Approval/publication must be separate from this offline SQL generator.
for i, (slug, name, price) in enumerate(rows_out):
o.write("INSERT INTO price_items (section_id,name,price,sort,published) "
"SELECT id,%s,%s,%s,false FROM price_sections WHERE slug=%s;\n" % (
esc(name), price, i + 1, esc(slug)))
o.write('COMMIT;\n')
o.close()
print('исходных строк с ценой (3 файла):', len(items))
print('уникальных групп (раздел,название):', len(groups))
print('групп с расхождением цены:', sum(1 for v in groups.values() if len(v) > 1))
print('итоговых строк прайса:', len(rows_out))
print('конфликтов внутри одного файла (2 цены на одно имя в одном отделении):', len(same_label_conflicts))
for name, pm in same_label_conflicts[:15]:
print(' ', name, dict(pm))