Comments 5
А 1с то здесь зачем? Оно не выполняет ровным счетом ничего, закиньте также эти файлы в условный гигачат, и будет то же самое, если он умеет файлы читать)
Я так понял, что она должна была написать код, потом показать результат его выполнения. Можно посмотреть код, который был создан в данном случае ?
import pandas as pd
from pathlib import Path
from collections import defaultdict, deque
def read_csv_smart(path):
for enc in ["utf-8", "utf-8-sig", "cp1251", "latin1"]:
try:
return pd.read_csv(path, encoding=enc)
except Exception:
continue
# fallback
return pd.read_csv(path, encoding="latin1", errors="ignore")
# Load
purchases = read_csv_smart("/mnt/data/file-7hqUPaq8LxdUaPjygcVFrh-purchases.csv")
sales = read_csv_smart("/mnt/data/file-Q1Zn1817nakCUSQTtTxs25-sales.csv")
# Normalize column names
purchases.columns = [c.strip().lower() for c in purchases.columns]
sales.columns = [c.strip().lower() for c in sales.columns]
# Map Russian columns
# дата, товар, количество, сумма
req_cols = ["дата", "товар", "количество", "сумма"]
for df_name, df in [("Закупки", purchases), ("Продажи", sales)]:
missing = [c for c in req_cols if c not in df.columns]
if missing:
raise ValueError(f"{df_name}: отсутствуют столбцы {missing}. Найдены: {list(df.columns)}")
# Prepare dataframes
p_df = purchases[["дата", "товар", "количество", "сумма"]].copy()
s_df = sales[["дата", "товар", "количество", "сумма"]].copy()
# Parse dates (dd.mm.yy)
for df in (p_df, s_df):
df["дата"] = pd.to_datetime(df["дата"], format="%d.%m.%y", errors="coerce")
df["количество"] = pd.to_numeric(df["количество"], errors="coerce")
df["сумма"] = pd.to_numeric(df["сумма"], errors="coerce")
# Drop bad rows
p_df = p_df.dropna(subset=["дата", "товар", "количество", "сумма"])
s_df = s_df.dropna(subset=["дата", "товар", "количество", "сумма"])
# Compute unit cost for purchases
p_df = p_df[p_df["количество"] > 0]
p_df["unit_cost"] = p_df["сумма"] / p_df["количество"]
# For sales, revenue is given as total "сумма"
s_df = s_df[s_df["количество"] > 0]
s_df["revenue"] = s_df["сумма"]
# Sort
p_df = p_df.sort_values(["товар", "дата"]).reset_index(drop=True)
s_df = s_df.sort_values(["товар", "дата"]).reset_index(drop=True)
# Build FIFO queues per product
purchase_queues = defaultdict(deque)
for prod, grp in p_df.groupby("товар", sort=False):
for _, r in grp.iterrows():
purchase_queues[prod].append([float(r["количество"]), float(r["unit_cost"]), r["дата"]])
# Process sales
rows = []
shortages = defaultdict(float)
for prod, grp in s_df.groupby("товар", sort=False):
for _, r in grp.iterrows():
qty = float(r["количество"])
revenue = float(r["revenue"])
remaining = qty
cogs = 0.0
pq = purchase_queues[prod]
while remaining > 0 and pq:
lot_qty, lot_cost, lot_date = pq[0]
use = min(remaining, lot_qty)
cogs += use * lot_cost
lot_qty -= use
remaining -= use
if lot_qty == 0:
pq.popleft()
else:
pq[0][0] = lot_qty
if remaining > 0:
shortages[prod] += remaining
rows.append({
"date": r["дата"],
"product": prod,
"qty_sold": qty,
"revenue": revenue,
"cogs_fifo_known": cogs,
"gross_profit_known": revenue - cogs,
"uncosted_qty_due_to_shortage": max(0.0, remaining)
})
res_df = pd.DataFrame(rows)
# Aggregate per product
agg = res_df.groupby("product", as_index=False).agg(
revenue=("revenue", "sum"),
cogs_fifo_known=("cogs_fifo_known", "sum"),
gross_profit=("gross_profit_known", "sum"),
qty_sold=("qty_sold", "sum"),
uncosted_qty=("uncosted_qty_due_to_shortage", "sum")
).sort_values("gross_profit", ascending=False)
# Display results
display(agg)
# Totals
totals = pd.DataFrame({
"product": ["ИТОГО"],
"revenue": [agg["revenue"].sum()],
"cogs_fifo_known": [agg["cogs_fifo_known"].sum()],
"gross_profit": [agg["gross_profit"].sum()],
"qty_sold": [agg["qty_sold"].sum()],
"uncosted_qty": [agg["uncosted_qty"].sum()],
})
display(totals)
# If shortages, show brief note
if (agg["uncosted_qty"] > 0).any():
display({"Примечание": "Обнаружены продажи без достаточного запаса на момент продажи. COGS рассчитан только для доступной части. Проверьте последовательность дат закупок/продаж."})
Зря Вы 1С выбрали в статье в качестве среды для написания запросов к LLM. Это приводит к тому, что смотришь на результат с точки зрения применения 1С, а тут нужно чтобы бы просто работало.
Может быть с точки зрения ИТ консультанта, продвигающего LLM тут все хорошо, типа смотрите, написал одно предлжение и все сделано. Но с мой точки зрения написанное работать не будет, и получается что основная задача не выполнена.
Проблемы (писал как я вижу выполнение этого кода, возможно в чем-то ошибся):
Себестоимость рассчитана делением суммы закупки на количество. Это приведет к ошибкам - будут не сходиться копейки. Пример: Поступили 3 товара на сумму 100 руб. Для равномерного списания себестоимости необходимо по каждой входящей партии учитывать остаток не только количества, но и суммы. Расчет себестоимости проводить на момент списания. (Решение через систему линейных уравнений, применяемое в ERP, я тут не рассматриваю).
Не учтен "момент времени". Данные отсортированы просто по дате. Но в одну дату может быть несколько документов. Для того, чтобы гарантировать их порядок в пределах даты, необходимо добавить еще одну колонку (например порядковый номер) и применять сортировку сначала по дате, затем по порядковому номеру.
При списании не учитывается дата поступления. То есть она без ограничения списывает партии из будущих поставок, а так не должно быть. Поступление должно быть не позже этой же даты или конца месяца.
Нет поддержки возвратов. То есть записей с отрицательным количеством.
Мелочи типа правильно добавить округления, try без обработки except, то что нельзя сравнивать float равно 0 я даже не рассматриваю.
Реально можно взять готовый пример импорта данных для pandas, изменить в нем названия и типы колонок и получить во входных таблицах тоже самое. С примерно теми же затратами времени.
А что касается основного алгоритма то проще писать его самому чем пытаться адаптировать то что здесь написано. Потому что хорошо, когда есть явная ошибка. А при исправлении чужого кода легко получить мелкую неявную ошибку. Которая допущена в январе, но не проявится сразу, а проявится в декабре. И придется объяснять руководству, что нам надо открывать период и перезакрывать все месяца с начала года, с пересдачей отчетности.
Использование code interpreter от OpenAI в 1С