from pathlib import Path
import re, json
src = Path("/mnt/data/configurator-mvp-clean.html")
html = src.read_text(encoding="utf-8")
# 1) Inject cart button in Step 4 row (after WhatsApp button), and in side summary maybe.
# Find the Step 4 row block
step4_row_pattern = r'(
\s*[\s\S]*?)(
\s*\n\s*
]*>Заказать комплект в WhatsApp)',
r'\1\n В корзину ',
row_html,
count=1
)
html = html[:m.start(1)] + row_html_new + html[m.end(1):]
# Side summary: add "В корзину" button under WA
side_pattern = r'()'
m2 = re.search(side_pattern, html)
if not m2:
raise RuntimeError("waOrderSide not found")
side_block = m2.group(1)
if 'id="addToCartSide"' not in html:
insert = side_block + '\n\n В корзину '
html = html[:m2.start(1)] + insert + html[m2.end(1):]
# 2) Expand DATA brands/models.
def make_brand(id_, name, icon="badge"):
return {"id": id_, "name": name, "icon": icon}
brands = [
make_brand("vw","Volkswagen"),
make_brand("skoda","Skoda"),
make_brand("kia","Kia"),
make_brand("hyundai","Hyundai"),
make_brand("renault","Renault"),
make_brand("toyota","Toyota"),
make_brand("nissan","Nissan"),
make_brand("ford","Ford"),
make_brand("chevrolet","Chevrolet"),
make_brand("lada","Lada"),
make_brand("bmw","BMW"),
make_brand("mercedes","Mercedes-Benz"),
make_brand("audi","Audi"),
make_brand("mazda","Mazda"),
make_brand("mitsubishi","Mitsubishi"),
make_brand("honda","Honda"),
make_brand("peugeot","Peugeot"),
make_brand("opel","Opel"),
# Top-5 Chinese brands (by sales in РФ 2025)
make_brand("haval","Haval"),
make_brand("chery","Chery"),
make_brand("geely","Geely"),
make_brand("changan","Changan"),
make_brand("jetour","Jetour"),
]
models = {
"vw":[("polo","Polo"),("tiguan","Tiguan"),("passat","Passat"),("golf","Golf"),("jetta","Jetta")],
"skoda":[("rapid","Rapid"),("octavia","Octavia"),("kodiaq","Kodiaq"),("fabia","Fabia"),("superb","Superb")],
"kia":[("rio","Rio"),("ceed","Ceed"),("sportage","Sportage"),("k5","K5"),("seltos","Seltos")],
"hyundai":[("solaris","Solaris"),("creta","Creta"),("elantra","Elantra"),("tucson","Tucson"),("i30","i30")],
"renault":[("logan","Logan"),("duster","Duster"),("sandero","Sandero"),("kaptur","Kaptur"),("arkana","Arkana")],
"toyota":[("camry","Camry"),("corolla","Corolla"),("rav4","RAV4"),("prado","Land Cruiser Prado"),("highlander","Highlander")],
"nissan":[("qashqai","Qashqai"),("xtrail","X-Trail"),("almera","Almera"),("juke","Juke"),("teana","Teana")],
"ford":[("focus","Focus"),("kuga","Kuga"),("mondeo","Mondeo"),("fiesta","Fiesta"),("explorer","Explorer")],
"chevrolet":[("cruze","Cruze"),("aveo","Aveo"),("niva","Niva"),("captiva","Captiva"),("lacetti","Lacetti")],
"lada":[("granta","Granta"),("vesta","Vesta"),("niva_travel","Niva Travel"),("niva_legend","Niva Legend"),("largus","Largus")],
"bmw":[("3","3 Series"),("5","5 Series"),("x3","X3"),("x5","X5"),("x1","X1")],
"mercedes":[("c","C-Class"),("e","E-Class"),("glc","GLC"),("gle","GLE"),("a","A-Class")],
"audi":[("a4","A4"),("a6","A6"),("q5","Q5"),("q7","Q7"),("a3","A3")],
"mazda":[("m3","Mazda 3"),("m6","Mazda 6"),("cx5","CX-5"),("cx30","CX-30"),("cx9","CX-9")],
"mitsubishi":[("outlander","Outlander"),("asx","ASX"),("lancer","Lancer"),("pajero_sport","Pajero Sport"),("eclipse_cross","Eclipse Cross")],
"honda":[("civic","Civic"),("crv","CR-V"),("accord","Accord"),("fit","Fit"),("pilot","Pilot")],
"peugeot":[("308","308"),("3008","3008"),("408","408"),("partner","Partner"),("5008","5008")],
"opel":[("astra","Astra"),("insignia","Insignia"),("corsa","Corsa"),("zafira","Zafira"),("mokka","Mokka")],
# Chinese
"haval":[("jolion","Jolion"),("f7","F7"),("dargo","Dargo"),("h6","H6"),("m6","M6")],
"chery":[("tiggo4","Tiggo 4 Pro"),("tiggo7","Tiggo 7 Pro Max"),("tiggo8","Tiggo 8 Pro Max"),("arrizo8","Arrizo 8")],
"geely":[("coolray","Coolray"),("atlas","Atlas"),("monjaro","Monjaro"),("tugella","Tugella"),("emgrand","Emgrand")],
"changan":[("cs35","CS35 Plus"),("cs55","CS55 Plus"),("cs75","CS75 Plus"),("unik","UNI-K"),("unit","UNI-T")],
"jetour":[("dashing","Dashing"),("x70","X70"),("x90","X90 Plus"),("t2","T2")],
}
modelsByBrand = {bid: [{"id": mid, "name": mname, "icon": mid} for mid, mname in items] for bid, items in models.items()}
# Replace DATA.brands and modelsByBrand in script.
# We'll locate the JS object starting with "var DATA = {" and replace its brands and modelsByBrand sections via regex.
def js_obj_literal(py_obj):
return json.dumps(py_obj, ensure_ascii=False)
brands_js = js_obj_literal(brands)
models_js = js_obj_literal(modelsByBrand)
# Replace brands array
html = re.sub(
r'brands:\s*\[[\s\S]*?\],\s*modelsByBrand:',
lambda m: f'brands: {brands_js},\n modelsByBrand:',
html,
count=1
)
# Replace modelsByBrand object literal
html = re.sub(
r'modelsByBrand:\s*\{[\s\S]*?\},\s*engines:',
lambda m: f'modelsByBrand: {models_js},\n engines:',
html,
count=1
)
# 3) Add cart integration functions to JS: use #order hash approach
# We'll inject after updateWhatsAppLinks() function definition or near helpers.
inject_marker = "function updateWhatsAppLinks(){"
idx = html.find(inject_marker)
if idx == -1:
raise RuntimeError("inject marker not found")
# Add a cart helper only once
if "function addBundleToTildaCart" not in html:
cart_helper = r'''
function addBundleToTildaCart(){
// Надежная интеграция с Tilda ST100 через hash-ссылку #order:Название=Цена
// Источник: справка Tilda по корзине ST100.
if(!(state.brand && state.model && state.engine)){
alert('Сначала выберите марку, модель и двигатель.');
return;
}
var title = 'Комплект ТО: ' + state.brand.name + ' ' + state.model.name + ' ' + state.engine.name;
var price = calcTotal();
// Важно: в hash у Tilda допускаются пробелы, но безопаснее кодировать.
// Формат: #order:Название товара =1000
var hash = '#order:' + encodeURIComponent(title) + ' =' + encodeURIComponent(String(price));
// Устанавливаем hash
window.location.hash = hash;
// Если на странице есть tcart, пытаемся открыть корзину (если включено авт-открытие — сработает и так)
try{
if(typeof window.tcart__openCart === 'function'){
window.tcart__openCart();
}
}catch(e){}
}
'''
html = html[:idx] + cart_helper + "\n" + html[idx:]
# 4) Wire buttons click handlers near actions
if "addToCartBundle" in html and "addToCartBundle.addEventListener" not in html:
# Insert after back4 handler block
insert_after = "back4.addEventListener('click', function(){ setStep(3); });"
pos = html.find(insert_after)
if pos == -1:
raise RuntimeError("insert point not found")
pos_end = pos + len(insert_after)
handlers = """
\n\n var addToCartBundle = document.getElementById('addToCartBundle');
var addToCartSide = document.getElementById('addToCartSide');
if(addToCartBundle){
addToCartBundle.addEventListener('click', function(){
addBundleToTildaCart();
});
}
if(addToCartSide){
addToCartSide.addEventListener('click', function(){
addBundleToTildaCart();
});
}
"""
html = html[:pos_end] + handlers + html[pos_end:]
# 5) Update note text: we keep privacy note.
out = Path("/mnt/data/configurator-mvp-cart-brands.html")
out.write_text(html, encoding="utf-8")
# Verification: ensure no header/footer
forbidden = ["site-header","site-footer","partials/header","partials/footer","",""]
viol = [x for x in forbidden if x in html]
(str(out), viol, len(brands), len(modelsByBrand))