yeref 0.24.80__tar.gz → 0.24.82__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {yeref-0.24.80 → yeref-0.24.82}/PKG-INFO +1 -1
- {yeref-0.24.80 → yeref-0.24.82}/setup.py +1 -1
- {yeref-0.24.80 → yeref-0.24.82}/yeref/yeref.py +128 -5
- {yeref-0.24.80 → yeref-0.24.82}/yeref.egg-info/PKG-INFO +1 -1
- {yeref-0.24.80 → yeref-0.24.82}/pyproject.toml +0 -0
- {yeref-0.24.80 → yeref-0.24.82}/setup.cfg +0 -0
- {yeref-0.24.80 → yeref-0.24.82}/yeref/__init__.py +0 -0
- {yeref-0.24.80 → yeref-0.24.82}/yeref/l_.py +0 -0
- {yeref-0.24.80 → yeref-0.24.82}/yeref/tonweb.js +0 -0
- {yeref-0.24.80 → yeref-0.24.82}/yeref.egg-info/SOURCES.txt +0 -0
- {yeref-0.24.80 → yeref-0.24.82}/yeref.egg-info/dependency_links.txt +0 -0
- {yeref-0.24.80 → yeref-0.24.82}/yeref.egg-info/top_level.txt +0 -0
@@ -16373,16 +16373,15 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16373
16373
|
total_lost = 0
|
16374
16374
|
total_start = 0
|
16375
16375
|
for j in range(num_months):
|
16376
|
-
# для каждой когорты собираем по календарным месяцам
|
16377
16376
|
for i in range(j, num_months - 1):
|
16378
16377
|
start_cnt = counts[i][j]
|
16379
16378
|
next_cnt = counts[i + 1][j]
|
16380
16379
|
if start_cnt > 0:
|
16381
|
-
lost = start_cnt - next_cnt
|
16380
|
+
lost = max(start_cnt - next_cnt, 0)
|
16382
16381
|
total_lost += lost
|
16383
16382
|
total_start += start_cnt
|
16384
16383
|
|
16385
|
-
avg_churn = (total_lost / total_start
|
16384
|
+
avg_churn = (total_lost / total_start) if total_start else 0
|
16386
16385
|
|
16387
16386
|
path = os.path.join(EXTRA_D, "3_cohort_metrics.csv")
|
16388
16387
|
with open(path, "w", newline="", encoding="utf-8") as f:
|
@@ -16390,11 +16389,10 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16390
16389
|
for r in table:
|
16391
16390
|
writer.writerow(r)
|
16392
16391
|
writer.writerow([])
|
16393
|
-
writer.writerow([f"Churn ~ ×{avg_churn:.
|
16392
|
+
writer.writerow([f"Churn ~ ×{avg_churn:.2f} monthly"])
|
16394
16393
|
|
16395
16394
|
thumb = types.FSInputFile(os.path.join(EXTRA_D, "parse.jpg"))
|
16396
16395
|
await bot.send_document(chat_id=my_tid, document=types.FSInputFile(path), thumbnail=thumb)
|
16397
|
-
|
16398
16396
|
except Exception as e:
|
16399
16397
|
logger.info(log_ % str(e))
|
16400
16398
|
await asyncio.sleep(round(random.uniform(0, 1), 2))
|
@@ -16555,6 +16553,131 @@ async def return_retention_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16555
16553
|
await asyncio.sleep(round(random.uniform(0, 1), 2))
|
16556
16554
|
|
16557
16555
|
|
16556
|
+
async def return_profit_and_loss_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
16557
|
+
try:
|
16558
|
+
sql = 'SELECT USER_LSTS FROM "USER"'
|
16559
|
+
data_users = await db_select_pg(sql, (), BASE_P)
|
16560
|
+
|
16561
|
+
months = ["2025-06", "2025-07", "2025-08", "2025-09"]
|
16562
|
+
data_users = []
|
16563
|
+
for _ in range(30):
|
16564
|
+
# дата входа
|
16565
|
+
entry_month = random.choice(months)
|
16566
|
+
entry_day = random.randint(1, 28)
|
16567
|
+
entry_date = f"{entry_month}-{entry_day:02}"
|
16568
|
+
entry_dt_obj = datetime.strptime(entry_date, '%Y-%m-%d')
|
16569
|
+
entry_dt = f"{entry_dt_obj.strftime('%d-%m-%Y')}_{datetime.now().strftime('%H-%M-%S')}"
|
16570
|
+
utm = random.choice(["/start", "/startapp"])
|
16571
|
+
|
16572
|
+
# месяцы от входа и дальше
|
16573
|
+
valid_months = [m for m in months if datetime.strptime(m + "-01", "%Y-%m-%d") >= entry_dt_obj.replace(day=1)]
|
16574
|
+
if not valid_months:
|
16575
|
+
valid_months = [entry_month]
|
16576
|
+
|
16577
|
+
user_mau = sorted(random.sample(valid_months, k=random.randint(1, len(valid_months))))
|
16578
|
+
user_dau_dates = set()
|
16579
|
+
txs, payments = [], []
|
16580
|
+
|
16581
|
+
# платеж
|
16582
|
+
if user_mau:
|
16583
|
+
pay_month = random.choice(user_mau)
|
16584
|
+
pay_day = random.randint(1, 28)
|
16585
|
+
pay_date = f"{pay_month}-{pay_day:02}"
|
16586
|
+
dt_pay = datetime.strptime(pay_date, "%Y-%m-%d")
|
16587
|
+
# if dt_pay >= entry_dt_obj:
|
16588
|
+
payments = [{
|
16589
|
+
"TYPE": random.choice(["don", "sub", "pst"]),
|
16590
|
+
"DT_START": f"{dt_pay.strftime('%d-%m-%Y')}_14-00-00",
|
16591
|
+
"DT_END": "0",
|
16592
|
+
"AMOUNT": str(random.randint(1, 10))
|
16593
|
+
}]
|
16594
|
+
user_dau_dates.add(pay_date)
|
16595
|
+
|
16596
|
+
# вход в приложение
|
16597
|
+
user_dau_dates.add(entry_date)
|
16598
|
+
for m in user_mau:
|
16599
|
+
day = random.randint(1, 28)
|
16600
|
+
visit = f"{m}-{day:02}"
|
16601
|
+
dt_visit = datetime.strptime(visit, "%Y-%m-%d")
|
16602
|
+
if dt_visit >= entry_dt_obj and random.random() < 0.7:
|
16603
|
+
user_dau_dates.add(visit)
|
16604
|
+
|
16605
|
+
# статусы (отток) с низкой вероятностью
|
16606
|
+
USER_STATUSES = []
|
16607
|
+
if random.random() < 0.2: # 10% шанс оттока
|
16608
|
+
churn_month = random.choice(valid_months)
|
16609
|
+
churn_day = random.randint(1, 28)
|
16610
|
+
churn_date = f"{churn_month}-{churn_day:02}"
|
16611
|
+
churn_ts = datetime.strptime(churn_date, "%Y-%m-%d").strftime("%d-%m-%Y") + "_23-59-59"
|
16612
|
+
USER_STATUSES = [{random.choice(["left", "kicked"]): churn_ts}]
|
16613
|
+
|
16614
|
+
user_dau = sorted(user_dau_dates)
|
16615
|
+
wallet = f"wallet{random.randint(1, 100)}" if txs else random.choice([f"wallet{random.randint(1, 100)}", ""])
|
16616
|
+
|
16617
|
+
data_users.append((
|
16618
|
+
random.randint(100000, 999999),
|
16619
|
+
json.dumps({"USER_WALLET": wallet, "USER_UTM": utm, "USER_DT": entry_dt}),
|
16620
|
+
json.dumps({"USER_DAU": user_dau, "USER_MAU": user_mau, "USER_TXS": txs,
|
16621
|
+
"USER_PAYMENTS": payments, "USER_STATUSES": USER_STATUSES})
|
16622
|
+
))
|
16623
|
+
print(f"gen {data_users=}")
|
16624
|
+
|
16625
|
+
metrics = defaultdict(lambda: {"sum_amount": 0.0})
|
16626
|
+
|
16627
|
+
for (USER_LSTS,) in data_users:
|
16628
|
+
USER_LSTS = json.loads(USER_LSTS or "{}")
|
16629
|
+
USER_PAYMENTS = USER_LSTS.get("USER_PAYMENTS", [])
|
16630
|
+
|
16631
|
+
for pay in USER_PAYMENTS:
|
16632
|
+
dt_p = datetime.strptime(pay.get("DT_START", ""), "%d-%m-%Y_%H-%M-%S")
|
16633
|
+
mo_p = dt_p.strftime("%Y-%m")
|
16634
|
+
amt = float(pay.get("AMOUNT", 0)) * 0.013
|
16635
|
+
metrics[mo_p]["sum_amount"] += amt
|
16636
|
+
|
16637
|
+
def fmt(x):
|
16638
|
+
return f"{x:.2f}".rstrip("0").rstrip(".")
|
16639
|
+
|
16640
|
+
months_sorted = sorted(metrics.keys())
|
16641
|
+
results = []
|
16642
|
+
|
16643
|
+
for mo in months_sorted:
|
16644
|
+
MRR = metrics[mo]["sum_amount"]
|
16645
|
+
COGS = 0.0
|
16646
|
+
GP = MRR - COGS
|
16647
|
+
OPEX = 4.5
|
16648
|
+
OP = GP - OPEX
|
16649
|
+
COMM = MRR * 0.3
|
16650
|
+
EXCH = MRR * 0.01
|
16651
|
+
NP = OP - COMM - EXCH
|
16652
|
+
|
16653
|
+
results.append([
|
16654
|
+
mo.upper()[5:] + "_" + mo[:4], # Format to "JUN_2024"
|
16655
|
+
fmt(MRR),
|
16656
|
+
fmt(COGS),
|
16657
|
+
fmt(GP),
|
16658
|
+
fmt(OPEX),
|
16659
|
+
fmt(OP),
|
16660
|
+
fmt(COMM),
|
16661
|
+
fmt(EXCH),
|
16662
|
+
fmt(NP)
|
16663
|
+
])
|
16664
|
+
|
16665
|
+
path = os.path.join(EXTRA_D, "4_profit_and_loss_metrics.csv")
|
16666
|
+
with open(path, "w", newline="", encoding="utf-8") as f:
|
16667
|
+
writer = csv.writer(f)
|
16668
|
+
writer.writerow([
|
16669
|
+
"Месяц", "Total MRR", "COGS", "Валовая прибыль",
|
16670
|
+
"OPEX", "Операционная прибыль", "Комиссия (30%)", "Обмен (1%)", "Чистая прибыль"
|
16671
|
+
])
|
16672
|
+
for row in results:
|
16673
|
+
writer.writerow(row)
|
16674
|
+
|
16675
|
+
thumb = types.FSInputFile(os.path.join(EXTRA_D, "parse.jpg"))
|
16676
|
+
await bot.send_document(chat_id=my_tid, document=types.FSInputFile(path), thumbnail=thumb)
|
16677
|
+
except Exception as e:
|
16678
|
+
logger.info(log_ % str(e))
|
16679
|
+
await asyncio.sleep(round(random.uniform(0, 1), 2))
|
16680
|
+
|
16558
16681
|
# endregion
|
16559
16682
|
|
16560
16683
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|