Загрузка данных
import openpyxl
from openpyxl.styles import Font, PatternFill, Alignment
from openpyxl.worksheet.datavalidation import DataValidation
# Инициализация книги Excel
wb = openpyxl.Workbook()
# Определение стилей
bold_font = Font(bold=True)
gray_fill = PatternFill(start_color="E0E0E0", end_color="E0E0E0", fill_type="solid")
yellow_fill = PatternFill(start_color="FFFF99", end_color="FFFF99", fill_type="solid")
green_fill = PatternFill(start_color="C6EFCE", end_color="C6EFCE", fill_type="solid")
# === ЛИСТ 1: "Данные" ===
ws1 = wb.active
ws1.title = "Данные"
ws1["A1"] = "Исходные данные коммерческих предложений"
ws1["A1"].font = Font(bold=True, size=12)
ws1.cell(row=3, column=1, value="Параметр").font = bold_font
ws1.cell(row=3, column=1).fill = gray_fill
for col_idx, name in enumerate(["Контрагент 1", "Контрагент 2", "Контрагент 3"], 2):
c = ws1.cell(row=3, column=col_idx, value=name)
c.font = bold_font
c.fill = gray_fill
# Тестовые данные с новыми условиями оплаты (например, 70% и 30%)
data_rows = [
(4, "Цена, руб. (без НДС)", [1000000, 1100000, 950000], "#,##0.00"),
(5, "Сумма НДС, руб.", [200000, 220000, 190000], "#,##0.00"),
(7, "Цена с НДС, руб.", ["=B4+B5", "=C4+C5", "=D4+D5"], "#,##0.00"),
(8, "Количество единиц", [10, 10, 10], "#,##0"),
(9, "Цена за ед. с НДС, руб.", ["=B7/B8", "=C7/C8", "=D7/D8"], "#,##0.00"),
(10, "Способ оплаты", ["Предоплата 100%", "Аванс 70%", "Постоплата 70%"], None),
(11, "Размер аванса, %", [100, 70, 30], "#,##0.0"),
(12, "Срок выполнения, дней", [30, 45, 60], "#,##0"),
(13, "Срок оплаты аванса, дней", [0, 5, 0], "#,##0"),
]
for row_num, label, values, fmt in data_rows:
ws1.cell(row=row_num, column=1, value=label).font = bold_font
for col_idx, val in enumerate(values, 2):
cell = ws1.cell(row=row_num, column=col_idx, value=val)
if fmt:
cell.number_format = fmt
if row_num == 10:
cell.fill = yellow_fill
# Выпадающий список со всеми вариантами оплаты
payment_options = "Предоплата 100%,Аванс 70%,Аванс 50%,Аванс 30%,Постоплата 70%,Постоплата 30%,Постоплата 100%"
dv = DataValidation(
type="list",
formula1=f'"{payment_options}"',
allow_blank=True
)
ws1.add_data_validation(dv)
dv.add("B10:D10")
ws1.column_dimensions["A"].width = 42
for col in ["B", "C", "D", "E", "F", "G"]:
ws1.column_dimensions[col].width = 18
# === ЛИСТ 2: "Расчёт PVP" ===
ws2 = wb.create_sheet("Расчёт PVP")
ws2["A1"] = "Ставка дисконтирования, % годовых"
ws2["A1"].font = bold_font
ws2["B1"] = 15
ws2["B1"].fill = yellow_fill
ws2["B1"].number_format = "0.0"
for col, h in enumerate(["Параметр", "Контрагент 1", "Контрагент 2", "Контрагент 3"], 1):
c = ws2.cell(row=3, column=col, value=h)
c.font = bold_font
c.fill = gray_fill
links = {
4: ("Цена с НДС, руб.", "7", "#,##0.00"),
5: ("Способ оплаты", "10", None),
6: ("Срок выполнения, дней", "12", "#,##0"),
7: ("Срок оплаты аванса, дней", "13", "#,##0"),
8: ("Размер аванса, %", "11", "#,##0.0")
}
for r, (label, src, fmt) in links.items():
ws2.cell(row=r, column=1, value=label).font = bold_font
for col in ["B", "C", "D"]:
c = ws2[f"{col}{r}"]
c.value = f"=Данные!{col}{src}"
if fmt:
c.number_format = fmt
ws2["A10"] = "ПОТОКИ ПЛАТЕЖЕЙ И ПРИВЕДЁННАЯ ЦЕНА (PVP)"
ws2["A10"].font = Font(color="FF0000", bold=True, size=12)
payment_rows = {
11: "Платёж 1 — размер, руб.",
12: "Платёж 1 — срок, дней",
13: "Платёж 1 — PVP, руб.",
14: "Платёж 2 — размер, руб.",
15: "Платёж 2 — срок, дней",
16: "Платёж 2 — PVP, руб.",
17: "ИТОГО PVP, руб."
}
for r, label in payment_rows.items():
ws2.cell(row=r, column=1, value=label).font = bold_font if r == 17 else Font()
# Универсальные формулы для любого % аванса
for col in ["B", "C", "D"]:
# Платёж 1 (Авансовая часть / Предоплата)
ws2[f"{col}11"] = f'=IF({col}5="Предоплата 100%",{col}4,IF({col}5="Постоплата 100%",0,{col}4*{col}8/100))'
ws2[f"{col}12"] = f'=IF({col}5="Предоплата 100%",0,IF({col}5="Постоплата 100%",0,{col}7))'
ws2[f"{col}13"] = f"={col}11/(1+{col}$1/100)^({col}12/365)"
# Платёж 2 (Остаток / Постоплата)
ws2[f"{col}14"] = f'=IF({col}5="Предоплата 100%",0,IF({col}5="Постоплата 100%",{col}4,{col}4*(1-{col}8/100)))'
ws2[f"{col}15"] = f"={col}6"
ws2[f"{col}16"] = f"={col}14/(1+{col}$1/100)^({col}15/365)"
# Итого PVP
ws2[f"{col}17"] = f"={col}13+{col}16"
for r in (11, 13, 14, 16, 17):
ws2[f"{col}{r}"].number_format = "#,##0.00"
for r in (12, 15):
ws2[f"{col}{r}"].number_format = "#,##0"
ws2[f"{col}17"].font = bold_font
ws2.column_dimensions["A"].width = 38
for col in ["B", "C", "D"]:
ws2.column_dimensions[col].width = 18
# === ЛИСТ 3: "Сравнение" ===
ws3 = wb.create_sheet("Сравнение")
ws3.merge_cells("A1:K1")
ws3["A1"] = "СВОДНАЯ ТАБЛИЦА СРАВНЕНИЯ КП"
ws3["A1"].font = Font(bold=True, color="FF0000", size=14)
ws3.row_dimensions[1].height = 22
headers = [
"№", "Контрагент", "Цена, руб.", "Цена с НДС", "Цена за ед.",
"PVP, руб.", "PVP за ед.", "Срок, дней", "Способ оплаты",
"Δ к мин. цене, %", "Δ к мин. PVP, %"
]
for i, h in enumerate(headers, 1):
c = ws3.cell(row=3, column=i, value=h)
c.font = bold_font
c.fill = gray_fill
c.alignment = Alignment(horizontal="center", wrap_text=True)
for r, sc in zip([4, 5, 6], ["B", "C", "D"]):
ws3.cell(row=r, column=1, value=r - 3)
ws3[f"B{r}"] = f"=Данные!{sc}4"
ws3[f"C{r}"] = f"=Данные!{sc}5"
ws3[f"D{r}"] = f"=Данные!{sc}7"
ws3[f"E{r}"] = f"=Данные!{sc}9"
ws3[f"F{r}"] = f"='Расчёт PVP'!{sc}17"
ws3[f"G{r}"] = f"=F{r}/Данные!{sc}8"
ws3[f"H{r}"] = f"=Данные!{sc}12"
ws3[f"I{r}"] = f"=Данные!{sc}10"
ws3[f"J{r}"] = f"=(C{r}-MIN(C4:C6))/MIN(C4:C6)*100"
ws3[f"K{r}"] = f"=(F{r}-MIN(F4:F6))/MIN(F4:F6)*100"
for col in ["C", "D", "E", "F", "G"]:
ws3[f"{col}{r}"].number_format = "#,##0.00"
ws3[f"H{r}"].number_format = "#,##0"
ws3[f"J{r}"].number_format = "0.0"
ws3[f"K{r}"].number_format = "0.0"
ws3["A8"] = "МИН. ЦЕНА"
ws3["A8"].font = bold_font
ws3["B8"] = "=MIN(C4:C6)"
ws3["C8"] = "=MIN(E4:E6)"
ws3["B8"].number_format = "#,##0.00"
ws3["C8"].number_format = "#,##0.00"
ws3["B8"].fill = green_fill
ws3["C8"].fill = green_fill
ws3["A9"] = "МИН. PVP"
ws3["A9"].font = bold_font
ws3["B9"] = "=MIN(F4:F6)"
ws3["C9"] = "=MIN(G4:G6)"
ws3["B9"].number_format = "#,##0.00"
ws3["C9"].number_format = "#,##0.00"
ws3["B9"].fill = green_fill
ws3["C9"].fill = green_fill
ws3["A10"] = "РЕКОМЕНДАЦИЯ"
ws3["A10"].font = bold_font
ws3.merge_cells("B10:K10")
ws3["B10"] = '="Контрагент "&MATCH(MIN(F4:F6),F4:F6,0)'
ws3["B10"].font = Font(bold=True, color="006100")
ws3["B10"].fill = green_fill
column_widths = {
"A": 6, "B": 35, "C": 16, "D": 16, "E": 14,
"F": 16, "G": 14, "H": 12, "I": 20, "J": 16, "K": 16
}
for col, w in column_widths.items():
ws3.column_dimensions[col].width = w
output_filename = "kp_comparison.xlsx"
wb.save(output_filename)
print(f"Файл успешно сохранен как: {output_filename}")