feat: /sync settings page with price multiplier and description postfix

Adds price_multiplier and description_postfix to SyncConfig. The sync
page at /sync lets users configure them. vk_sync reads these per-user
settings and applies the multiplier to price and appends the postfix
as "(postfix)" to the VK product description.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
mguschin
2026-05-12 23:04:23 +03:00
parent fb3b6e2327
commit e169a91146
6 changed files with 142 additions and 6 deletions

View File

@@ -148,10 +148,13 @@ def _sync_product(
album_id: str,
vk_group_id: str,
token: str,
sync_config=None,
) -> None:
name = _name_for_vk(product.name)
price_rubles = _calc_price(product.price)
desc = product.name
multiplier = float(sync_config.price_multiplier) if sync_config and sync_config.price_multiplier else 1.0
price_rubles = _calc_price(product.price) * multiplier
postfix = (sync_config.description_postfix or "").strip() if sync_config else ""
desc = f"{product.name} ({postfix})" if postfix else product.name
stock = settings.VK_STOCK_AMOUNT if product.allow_to_sell else 0
owner_id = f"-{vk_group_id}"
now = _now()
@@ -257,11 +260,11 @@ def _sync_product(
logger.info("user=%s created VK product '%s' id=%s", user_id, name, vk_item_id)
def _sync_product_list(db, user_id, products, album_id, vk_group_id, token, results, owned_ids):
def _sync_product_list(db, user_id, products, album_id, vk_group_id, token, results, owned_ids, sync_config=None):
for product in products:
was_new = product.vk_product_id is None
try:
_sync_product(db, user_id, product, album_id, vk_group_id, token)
_sync_product(db, user_id, product, album_id, vk_group_id, token, sync_config)
if product.vk_product_id:
owned_ids.add(product.vk_product_id)
if product.synced_at:
@@ -318,6 +321,7 @@ def _sync_user(db, user_id: int, token: str, vk_group_id: str) -> dict:
results = {"created": 0, "updated": 0, "skipped": 0, "deleted": 0, "errors": 0}
owned_ids: set[str] = set() # VK product IDs that Evotor owns this run
sync_config = db.query(SyncConfig).filter_by(user_id=user_id).first()
enabled_stores = _enabled_store_ids(db, user_id)
stores = db.query(CachedStore).filter_by(user_id=user_id).all()
@@ -348,7 +352,7 @@ def _sync_user(db, user_id: int, token: str, vk_group_id: str) -> dict:
products = db.query(CachedProduct).filter_by(
user_id=user_id, store_evotor_id=store.evotor_id, group_evotor_id=group.evotor_id,
).all()
_sync_product_list(db, user_id, products, album_id, vk_group_id, token, results, owned_ids)
_sync_product_list(db, user_id, products, album_id, vk_group_id, token, results, owned_ids, sync_config)
# Ungrouped products → "Без категории" album
ungrouped = db.query(CachedProduct).filter_by(
@@ -361,7 +365,7 @@ def _sync_user(db, user_id: int, token: str, vk_group_id: str) -> dict:
logger.error("user=%s ensure_album failed for 'Без категории': %s", user_id, e)
fallback_album_id = None
if fallback_album_id:
_sync_product_list(db, user_id, ungrouped, fallback_album_id, vk_group_id, token, results, owned_ids)
_sync_product_list(db, user_id, ungrouped, fallback_album_id, vk_group_id, token, results, owned_ids, sync_config)
# Delete VK products not owned by any Evotor product
_delete_orphans(db, user_id, vk_group_id, owned_ids, token, results)