Polars, iter_rows, Цикл for пропускает часть строк
Есть входные данные (движение по складу). Задача под каждый документ подобрать "документ покупки" и посчитать остаток на каждом "документе покупки". Единственный метод, который я нашла: фильтр всех строк по коду продукта, потом перебор каждой строки. Все в принципе работает, кроме приведенного примера. Продали все, т.е. Remains = 0. Но после этого происходит корректировка документа продажи и возврат продукта на склад, после чего он списывается. Мой код останавливается и пропускает последние 2 документа (корректировку и списание). По итогу они теряются в принципе.
Код выложила на Git, потому что длинный цикл получился -> ссылка на код
import polars as pl
data = {
"Doc_N": ['00ОП-000157', '00ОП-002240', '00ОП-001840', '00ОП-000216', '00ОП-000029', ],
"Doc_date": ['27.02.2023', '21.11.2023', '17.04.2024', '01.10.2024', '01.10.2024', ],
"Prod_code": ['ОП-0001201', 'ОП-0001201', 'ОП-0001201', 'ОП-0001201', 'ОП-0001201', ],
"Doc_type": ['income', 'outcome', 'outcome', 'outcome', 'outcome', ],
"Doc_type2": ['purchase', 'sale', 'sale', 'correction', 'writeoff', ],
"Qty": [32, -3, -29, 29, -29, ]
}
main_df = pl.DataFrame(data)
main_df = main_df.with_columns(pl.col("Doc_date").str.to_date('%d.%m.%Y'), pl.col("Qty").cast(pl.Float64, strict=False))
codes = main_df[["Prod_code"]]
codes = codes.unique(subset=['Prod_code'])
results = []
for code in codes.iter_rows(named=True):
new_df = main_df.filter(pl.col("Prod_code") == code["Prod_code"])
new_df = new_df.sort("Doc_date", "Doc_type", "Doc_N", "Qty", descending=[False, False, False, False])
new_df = new_df.with_row_index(name="my_index", offset=1)
max_row = len(new_df)
for row in new_df.iter_rows(named=True):
document = row["Doc_N"]
date = row["Doc_date"]
incom_code = row["Prod_code"]
quantity = row["Qty"]
if row["Doc_type"] != 'income':
matched_documents = []
remaining_qty = abs(quantity)
for prev_row in results:
if (prev_row["Prod_code"] == incom_code
and prev_row.get("Remains", 0) > 0
# and ( (prev_row.get("Remains", 0) > 0) or (prev_row.get("Remains", 0) == None))
# and prev_row.get("my_index") < (prev_row["my_index"])
and prev_row["Doc_date"] <= date ):
available_qty = prev_row["Remains"]
take_qty = min(remaining_qty, available_qty)
if quantity > 0:
prev_row["Remains"] += take_qty
else:
prev_row["Remains"] -= take_qty
if (row["Doc_type2"] == "complectation") or (row["Doc_type2"] == "writeoff"):
matched_documents.append({
"Inc_Doc": prev_row["Doc_N"],
"Inc_Doc_date": prev_row["Doc_date"],
"Inc_Doc_code": incom_code,
"Qty": -take_qty if quantity < 0 else take_qty,
'available_qty': available_qty,
'take_qty': take_qty,
'prev_row["Remains"]': prev_row["Remains"],
"my_index": row["my_index"]
})
else:
matched_documents.append({
"Inc_Doc": prev_row["Doc_N"],
"Inc_Doc_date": prev_row["Doc_date"],
"Inc_Doc_code": "",
"Qty": -take_qty if quantity < 0 else take_qty,
'available_qty': available_qty,
'take_qty': take_qty,
'prev_row["Remains"]': prev_row["Remains"],
"my_index": row["my_index"]
})
remaining_qty -= take_qty
if int(row["my_index"]) == max_row:
break
for matched_doc in matched_documents:
results.append({
"Doc_N": document,
"Doc_date": date,
"Doc_type2": row['Doc_type2'],
"Inc_Doc": matched_doc["Inc_Doc"],
"Inc_Doc_date": matched_doc["Inc_Doc_date"],
"Prod_code": incom_code,
'Qty': matched_doc['Qty'],
"Inc_Doc_code": matched_doc["Inc_Doc_code"],
'available_qty': matched_doc['available_qty'],
'take_qty': matched_doc['take_qty'],
'prev_row["Remains"]': matched_doc['prev_row["Remains"]'],
"my_index": matched_doc["my_index"]
})
else:
results.append({
"Doc_N": document,
"Doc_date": date,
"Doc_type2": row['Doc_type2'],
"Prod_code": incom_code,
'Qty': row['Qty'],
"Remains": quantity,
"my_index": row["my_index"]
})
result_df = pl.DataFrame(results)
