90 lines
2.4 KiB
Python
90 lines
2.4 KiB
Python
"""
|
|
One-time migration: backfill amount_usd on purchase credit_transactions.
|
|
|
|
Matches pack by:
|
|
1. pack_id extracted from description "Purchased <pack_id> pack (...)"
|
|
2. Fallback: closest credits count match from app_settings packs
|
|
3. Fallback: test pack = $1.00
|
|
"""
|
|
import asyncio
|
|
import re
|
|
import sys
|
|
import os
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
|
|
|
|
PACK_PRICES = {
|
|
"starter": 49.0,
|
|
"pro": 199.0,
|
|
"scale": 499.0,
|
|
"test": 1.0,
|
|
}
|
|
|
|
CREDITS_TO_PACK = {
|
|
50: ("starter", 49.0),
|
|
220: ("pro", 199.0),
|
|
600: ("scale", 499.0),
|
|
}
|
|
|
|
|
|
def _resolve_price(description: str, credits: int) -> float | None:
|
|
"""Return USD price for a transaction, or None if can't determine."""
|
|
# Try to extract pack_id from description
|
|
m = re.match(r"Purchased\s+(\S+)\s+pack", description or "", re.IGNORECASE)
|
|
if m:
|
|
pack_id = m.group(1).lower()
|
|
if pack_id in PACK_PRICES:
|
|
return PACK_PRICES[pack_id]
|
|
|
|
# Fallback: exact credits match
|
|
if credits in CREDITS_TO_PACK:
|
|
return CREDITS_TO_PACK[credits][1]
|
|
|
|
# Fallback: closest credits match within 10%
|
|
for c, (_, price) in CREDITS_TO_PACK.items():
|
|
if abs(c - credits) / max(c, 1) < 0.1:
|
|
return price
|
|
|
|
return None
|
|
|
|
|
|
async def main():
|
|
from motor.motor_asyncio import AsyncIOMotorClient
|
|
from app.config import Config
|
|
|
|
mongo_uri = os.environ.get("MONGO_URI", Config.MONGO_URI)
|
|
db_name = mongo_uri.rstrip("/").split("/")[-1].split("?")[0] or "cohorta_db"
|
|
client = AsyncIOMotorClient(mongo_uri)
|
|
db = client[db_name]
|
|
|
|
cursor = db.credit_transactions.find({
|
|
"type": "purchase",
|
|
"amount_usd": {"$exists": False},
|
|
})
|
|
|
|
updated = 0
|
|
skipped = 0
|
|
|
|
async for tx in cursor:
|
|
description = tx.get("description", "")
|
|
credits = tx.get("amount", 0)
|
|
price = _resolve_price(description, credits)
|
|
|
|
if price is None:
|
|
print(f" SKIP id={tx['_id']} desc='{description}' credits={credits} — cannot determine price")
|
|
skipped += 1
|
|
continue
|
|
|
|
await db.credit_transactions.update_one(
|
|
{"_id": tx["_id"]},
|
|
{"$set": {"amount_usd": price}},
|
|
)
|
|
print(f" SET id={tx['_id']} desc='{description}' credits={credits} → ${price}")
|
|
updated += 1
|
|
|
|
print(f"\nDone: {updated} updated, {skipped} skipped.")
|
|
client.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|