dana-medical-site/migrations/import/dedup_and_label.py
2026-10-14 13:33:13 +00:00

93 lines
4.7 KiB
Python
Raw 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 -*-
"""
Убирает точные дубли позиций прайса (одинаковый раздел+название+цена, возникшие
из-за пересечения источников: старый сайт Bitrix + 3 файла 1С). Если у одной и
той же услуги в разных источниках цена расходится — оставляет по одной строке
на каждую цену и подписывает источник в скобках, а не молча выбирает одну.
"""
import csv, io
import build_price_map as b
LABEL_ORDER = ['старый прайс', 'ЦОМ', 'Остео', 'Дети']
def esc(s):
# В PostgreSQL со standard_conforming_strings обратный слэш — обычный символ,
# удваивать его нельзя: имена приезжали в базу с лишним слэшем.
return "'" + str(s).replace("'", "''") + "'"
# ---------- Bitrix-происхождение (уже в базе) ----------
bitrix = [] # (id, slug, name, price)
with io.open('bitrix_items.csv', encoding='utf-8') as f:
for row in csv.reader(f):
bitrix.append((int(row[0]), row[1], row[2], float(row[3])))
# ---------- 1С: те же три файла, но с меткой источника ----------
DEPT_LABEL = {'D:/ЦОМ.xlsx': 'ЦОМ', 'D:/Остео.xlsx': 'Остео', 'D:/Дана Дети.xls': 'Дети'}
c1c = [] # (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)
items = b.extract(rows, ncol, pcol)
label = DEPT_LABEL[path]
for sec, name, price in items:
key = (sec or '').strip().lower()
slug = b.MAP.get(key, 'prochee-price')
c1c.append((label, slug, name.strip(), price))
# ---------- группировка: (slug, name) -> {price: {labels}} ----------
groups = {} # (slug, name) -> {price: set(labels)}
bitrix_by_key = {} # (slug, name) -> [(id, price), ...]
for pid, slug, name, price in bitrix:
key = (slug, name)
bitrix_by_key.setdefault(key, []).append((pid, price))
groups.setdefault(key, {}).setdefault(price, set()).add('старый прайс')
for label, slug, name, price in c1c:
key = (slug, name)
groups.setdefault(key, {}).setdefault(price, set()).add(label)
updates = [] # (id, new_name)
inserts = [] # (slug, name, price)
deletes = [] # id (bitrix rows made redundant — only happens if a bitrix row
# duplicates another bitrix row exactly; not expected, kept for safety)
for (slug, name), pricemap in groups.items():
bitrix_rows = bitrix_by_key.get((slug, name), [])
if len(pricemap) == 1:
# все источники сходятся в одной цене — ничего не меняем/не плодим
if not bitrix_rows:
(price,) = pricemap.keys()
inserts.append((slug, name, price))
# если bitrix_rows уже есть — они и представляют эту цену, 1С дублировать не нужно
continue
# расхождение цен — подписываем каждую цену источниками
bitrix_prices = {p for _, p in bitrix_rows}
for price, labels in pricemap.items():
label_str = ', '.join(l for l in LABEL_ORDER if l in labels)
new_name = '%s (%s)' % (name, label_str)
if price in bitrix_prices:
for pid, p in bitrix_rows:
if p == price:
updates.append((pid, new_name))
else:
inserts.append((slug, new_name, price))
o = io.open('seed_dedup.sql', 'w', encoding='utf-8')
o.write('BEGIN;\n')
# сначала снести прежнюю "плоскую" заливку 1С (3585 строк без дедупа), затем
# переименовать конфликтующие bitrix-строки и вставить заново уже с разметкой
o.write("DELETE FROM price_items WHERE legacy_id IS NULL;\n")
for pid, new_name in updates:
o.write("UPDATE price_items SET name=%s WHERE id=%d;\n" % (esc(new_name), pid))
for slug, name, price in inserts:
o.write("INSERT INTO price_items (section_id,name,price,sort,published) "
"SELECT id,%s,%s,100,true FROM price_sections WHERE slug=%s;\n" % (
esc(name), price, esc(slug)))
o.write('COMMIT;\n')
o.close()
print('групп (раздел,название):', len(groups))
print('групп с расхождением цены:', sum(1 for v in groups.values() if len(v) > 1))
print('обновлений имени (bitrix-строки):', len(updates))
print('новых вставок:', len(inserts))