yeref 0.25.5__py3-none-any.whl → 0.25.7__py3-none-any.whl

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/yeref.py CHANGED
@@ -16013,7 +16013,7 @@ async def calc_metrics(bot, PROJECT_USERNAME, dataroom_folder_id, EXTRA_D, BASE_
16013
16013
 
16014
16014
  # --- Начинаем сразу с объединённого цикла по всем метрикам r1–r5 ---
16015
16015
  metrics_paths = [r1, r2, r3, r4, r5]
16016
- tables = [] # сюда будем складывать словари вида {'name': basename, 'rows': [[...], ...]}
16016
+ tables = []
16017
16017
 
16018
16018
  # 1) Собираем существующие CSV-файлы
16019
16019
  for path in metrics_paths:
@@ -16038,45 +16038,43 @@ async def calc_metrics(bot, PROJECT_USERNAME, dataroom_folder_id, EXTRA_D, BASE_
16038
16038
  http_auth = credentials.authorize(httplib2.Http())
16039
16039
  sheets_service = build('sheets', 'v4', http=http_auth, cache_discovery=False)
16040
16040
 
16041
- # 4) Переименовываем стандартный лист «Лист1»/«Sheet1» PROJECT_USERNAME
16041
+ # 4) Получаем metadata, ищем лист с названием PROJECT_USERNAME
16042
16042
  spreadsheet = sheets_service.spreadsheets().get(spreadsheetId=dataroom_folder_id).execute()
16043
- sheet_id_to_rename = None
16043
+ sheet_id_target = None
16044
16044
  for sheet in spreadsheet.get('sheets', []):
16045
16045
  props = sheet.get('properties', {})
16046
- title = props.get('title', '')
16047
- if title in ['Лист1', 'Sheet1']:
16048
- sheet_id_to_rename = props.get('sheetId')
16046
+ if props.get('title') == PROJECT_USERNAME:
16047
+ sheet_id_target = props.get('sheetId')
16048
+ logger.info(f"Найден существующий лист '{PROJECT_USERNAME}', sheetId={sheet_id_target}")
16049
16049
  break
16050
16050
 
16051
- if sheet_id_to_rename is not None:
16052
- rename_request = {
16051
+ # 5) Если листа нет — создаём новый лист с названием PROJECT_USERNAME
16052
+ if sheet_id_target is None:
16053
+ add_request = {
16053
16054
  'requests': [
16054
16055
  {
16055
- 'updateSheetProperties': {
16056
+ 'addSheet': {
16056
16057
  'properties': {
16057
- 'sheetId': sheet_id_to_rename,
16058
16058
  'title': PROJECT_USERNAME
16059
- },
16060
- 'fields': 'title'
16059
+ }
16061
16060
  }
16062
16061
  }
16063
16062
  ]
16064
16063
  }
16065
- sheets_service.spreadsheets().batchUpdate(
16064
+ response = sheets_service.spreadsheets().batchUpdate(
16066
16065
  spreadsheetId=dataroom_folder_id,
16067
- body=rename_request
16066
+ body=add_request
16068
16067
  ).execute()
16069
- logger.info(f"Лист переименован в '{PROJECT_USERNAME}'.")
16070
- else:
16071
- logger.warning("Не найден лист 'Лист1' или 'Sheet1' для переименования.")
16068
+ sheet_id_target = response['replies'][0]['addSheet']['properties']['sheetId']
16069
+ logger.info(f"Создан новый лист '{PROJECT_USERNAME}', sheetId={sheet_id_target}")
16072
16070
 
16073
- # 5) Готовим запросы для записи всех таблиц одна за другой с промежутком
16071
+ # 6) Готовим запросы для записи всех таблиц одна за другой с промежутком
16074
16072
  safe_title = PROJECT_USERNAME.replace("'", "\\'")
16075
16073
  offset = 1 # первая строка, с которой начнём писать
16076
16074
  data_requests = []
16077
16075
 
16078
16076
  for tbl in tables:
16079
- # 5.1) Заголовок: имя CSV-файла
16077
+ # 6.1) Заголовок: имя CSV-файла
16080
16078
  header_range = f"'{safe_title}'!A{offset}"
16081
16079
  data_requests.append({
16082
16080
  'range': header_range,
@@ -16086,7 +16084,7 @@ async def calc_metrics(bot, PROJECT_USERNAME, dataroom_folder_id, EXTRA_D, BASE_
16086
16084
  logger.info(f"Добавлен заголовок '{tbl['name']}' → A{offset}")
16087
16085
  offset += 1
16088
16086
 
16089
- # 5.2) Содержимое CSV: все строки сразу под заголовком
16087
+ # 6.2) Содержимое CSV: все строки сразу под заголовком
16090
16088
  data_range = f"'{safe_title}'!A{offset}"
16091
16089
  data_requests.append({
16092
16090
  'range': data_range,
@@ -16096,10 +16094,10 @@ async def calc_metrics(bot, PROJECT_USERNAME, dataroom_folder_id, EXTRA_D, BASE_
16096
16094
  logger.info(f"Добавлены {len(tbl['rows'])} строк из '{tbl['name']}' → A{offset}")
16097
16095
  offset += len(tbl['rows'])
16098
16096
 
16099
- # 5.3) Оставляем минимум 2 пустые строки перед следующей таблицей
16097
+ # 6.3) Оставляем минимум 2 пустые строки перед следующей таблицей
16100
16098
  offset += 2
16101
16099
 
16102
- # 6) Выполняем единый batchUpdate для всех data_requests
16100
+ # 7) Выполняем единый batchUpdate для всех data_requests
16103
16101
  write_body = {
16104
16102
  'valueInputOption': 'USER_ENTERED',
16105
16103
  'data': data_requests
@@ -16342,7 +16340,7 @@ async def return_unit_metrics(bot, data_users, EXTRA_D):
16342
16340
  factors = [1 + v for v in cmgr_vals]
16343
16341
  avg = math.prod(factors) ** (1 / len(factors))
16344
16342
  writer.writerow([])
16345
- writer.writerow([f"Rev ~ ×{round(avg, 2)} monthly"])
16343
+ writer.writerow([f"Rev ~ ×{round(avg, 2)} monthly".replace('.', ',')])
16346
16344
 
16347
16345
  result = f_name
16348
16346
  thumb = types.FSInputFile(os.path.join(EXTRA_D, "parse.jpg"))
@@ -16437,7 +16435,7 @@ async def return_cohort_metrics(bot, data_users, EXTRA_D):
16437
16435
  for r in table:
16438
16436
  writer.writerow(r)
16439
16437
  writer.writerow([])
16440
- writer.writerow([f"Churn ~ ×{avg_churn:.2f} monthly"])
16438
+ writer.writerow([f"Churn ~ ×{avg_churn:.2f} monthly".replace('.', ',')])
16441
16439
 
16442
16440
  result = f_name
16443
16441
  thumb = types.FSInputFile(os.path.join(EXTRA_D, "parse.jpg"))
@@ -16511,12 +16509,12 @@ async def return_retention_metrics(bot, data_users, EXTRA_D):
16511
16509
  else:
16512
16510
  rev = rev_by_cohort[c].get(offset, 0.0)
16513
16511
  if rev > 0:
16514
- cell = f"{rev:.1f}"
16512
+ cell = f"{rev:.1f}".replace('.', ',')
16515
16513
  row.append(cell)
16516
16514
  row_sum += rev
16517
16515
  else:
16518
- row.append("0.0")
16519
- row.append(f"{row_sum:.1f}")
16516
+ row.append("0,0")
16517
+ row.append(f"{row_sum:.1f}".replace('.', ','))
16520
16518
  writer.writerow(row)
16521
16519
 
16522
16520
  factors = []
@@ -16529,7 +16527,7 @@ async def return_retention_metrics(bot, data_users, EXTRA_D):
16529
16527
  avg_multiplier = math.prod(factors) ** (1 / len(factors)) if factors else 1.0
16530
16528
 
16531
16529
  writer.writerow([])
16532
- writer.writerow([f"NRR ~ ×{avg_multiplier:.2f} monthly"])
16530
+ writer.writerow([f"NRR ~ ×{avg_multiplier:.2f} monthly".replace('.', ',')])
16533
16531
 
16534
16532
  result = f_name
16535
16533
  thumb = types.FSInputFile(os.path.join(EXTRA_D, "parse.jpg"))
@@ -16546,6 +16544,7 @@ async def return_profit_and_loss_metrics(bot, data_users, EXTRA_D):
16546
16544
  try:
16547
16545
  metrics = defaultdict(lambda: {"sum_amount": 0.0})
16548
16546
 
16547
+ # Собираем данные по месяцам
16549
16548
  for USER_TID, USER_VARS, USER_LSTS in data_users:
16550
16549
  USER_LSTS = json.loads(USER_LSTS or "{}")
16551
16550
  USER_PAYMENTS = USER_LSTS.get("USER_PAYMENTS", [])
@@ -16556,12 +16555,14 @@ async def return_profit_and_loss_metrics(bot, data_users, EXTRA_D):
16556
16555
  amt = float(pay.get("AMOUNT", 0)) * 0.013
16557
16556
  metrics[mo_p]["sum_amount"] += amt
16558
16557
 
16558
+ # Функция форматирования с запятой
16559
16559
  def fmt(x):
16560
- return f"{x:.2f}".rstrip("0").rstrip(".") if x is not None else ""
16560
+ return f"{x:.2f}".rstrip("0").rstrip(".").replace(".", ",") if x is not None else ""
16561
16561
 
16562
16562
  # Сортируем месяцы
16563
16563
  months_sorted = sorted(metrics.keys())
16564
16564
  results = []
16565
+ np_values = []
16565
16566
 
16566
16567
  for mo in months_sorted:
16567
16568
  MRR = metrics[mo]["sum_amount"]
@@ -16570,12 +16571,12 @@ async def return_profit_and_loss_metrics(bot, data_users, EXTRA_D):
16570
16571
  OPEX = 4.5
16571
16572
  OP = GP - OPEX
16572
16573
 
16573
- # из OP сначала вычитаем 30%, затем из результата вычитаем 1%
16574
- after_comm = OP * 0.70 # остаётся после 30% комиссии
16575
- after_fiat = after_comm * 0.99 # остаётся после ещё 1% на обмен
16576
- COMM = OP - after_comm # сама комиссия (30% от OP)
16577
- EXCH = after_comm - after_fiat # сама часть обмена (1% от остатка после комиссии)
16578
- NP = after_fiat # чистая прибыль
16574
+ # комиссия 30% и обмен 1%
16575
+ after_comm = OP * 0.70
16576
+ after_fiat = after_comm * 0.99
16577
+ COMM = OP - after_comm
16578
+ EXCH = after_comm - after_fiat
16579
+ NP = after_fiat
16579
16580
 
16580
16581
  results.append([
16581
16582
  mo,
@@ -16588,16 +16589,27 @@ async def return_profit_and_loss_metrics(bot, data_users, EXTRA_D):
16588
16589
  fmt(EXCH),
16589
16590
  fmt(NP)
16590
16591
  ])
16592
+ np_values.append(NP)
16593
+
16594
+ # Вычисляем средний NP (если есть хотя бы одно значение)
16595
+ avg_np = sum(np_values) / len(np_values) if np_values else 0.0
16596
+ avg_np_str = fmt(avg_np)
16591
16597
 
16592
16598
  f_name = os.path.join(EXTRA_D, "5_profit_and_loss_metrics.csv")
16593
16599
  with open(f_name, "w", newline="", encoding="utf-8") as f:
16594
16600
  writer = csv.writer(f)
16601
+ # Заголовок
16595
16602
  writer.writerow([
16596
16603
  "Mo", "MRR", "COGS", "Gross Profit",
16597
16604
  "OPEX", "Operating Profit", "Comission (30%)", "Fiat (1%)", "Net Profit"
16598
16605
  ])
16606
+ # Строки по месяцам
16599
16607
  for row in results:
16600
16608
  writer.writerow(row)
16609
+ # Пустая строка перед средним
16610
+ writer.writerow([])
16611
+ # Строка со средним Net Profit
16612
+ writer.writerow([f"Average Net Profit: {avg_np_str}"])
16601
16613
 
16602
16614
  result = f_name
16603
16615
  thumb = types.FSInputFile(os.path.join(EXTRA_D, "parse.jpg"))
@@ -16607,6 +16619,7 @@ async def return_profit_and_loss_metrics(bot, data_users, EXTRA_D):
16607
16619
  await asyncio.sleep(round(random.uniform(0, 1), 2))
16608
16620
  finally:
16609
16621
  return result
16622
+
16610
16623
  # endregion
16611
16624
 
16612
16625
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yeref
3
- Version: 0.25.5
3
+ Version: 0.25.7
4
4
  Summary: desc-f
5
5
  Author: john smith
6
6
  Dynamic: author
@@ -0,0 +1,8 @@
1
+ yeref/__init__.py,sha256=Qpv3o6Xa78VdLcsSRmctGtpnYE9btpAkCekgGhgJyXM,49
2
+ yeref/l_.py,sha256=LMX_olmJwq-tgoALJCnhV_fGrL_i_43yBLkLIcEVqGo,1176743
3
+ yeref/tonweb.js,sha256=Jf6aFOQ1OIY4q7fINYz-m5LsI3seMus124M5SYYZmtE,443659
4
+ yeref/yeref.py,sha256=wRpSWql996MWX-i-4GjL4SUHNmNjwheGS0I0yrx7eRg,1056354
5
+ yeref-0.25.7.dist-info/METADATA,sha256=020yfGCI6pVZfOZEIAcchgFDr7IsnqdOluNCjrHkPo4,118
6
+ yeref-0.25.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
+ yeref-0.25.7.dist-info/top_level.txt,sha256=yCQKchWHbfV-3OuQPYRdi2loypD-nmbDJbtt3OuKKkY,6
8
+ yeref-0.25.7.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- yeref/__init__.py,sha256=Qpv3o6Xa78VdLcsSRmctGtpnYE9btpAkCekgGhgJyXM,49
2
- yeref/l_.py,sha256=LMX_olmJwq-tgoALJCnhV_fGrL_i_43yBLkLIcEVqGo,1176743
3
- yeref/tonweb.js,sha256=Jf6aFOQ1OIY4q7fINYz-m5LsI3seMus124M5SYYZmtE,443659
4
- yeref/yeref.py,sha256=ljsCvG1omKMY2PpVKfFunM1eTcMNd7w_aW_GFX3b8Ps,1055985
5
- yeref-0.25.5.dist-info/METADATA,sha256=L3eS_VIOpEfv271siW57nYb5571PNCcE-XqbHoAID-k,118
6
- yeref-0.25.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
- yeref-0.25.5.dist-info/top_level.txt,sha256=yCQKchWHbfV-3OuQPYRdi2loypD-nmbDJbtt3OuKKkY,6
8
- yeref-0.25.5.dist-info/RECORD,,
File without changes