From c686f55bc720c30057d33ff360d2ffa692ef4270 Mon Sep 17 00:00:00 2001 From: Vlad Date: Sun, 1 Jun 2025 13:12:29 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20SQL-=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=20?= =?UTF-8?q?=D0=B8=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=87=D0=B8?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=B2=20main.py=20=D0=B4=D0=BB=D1=8F=20=D1=83?= =?UTF-8?q?=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20=D0=B4=D0=B0=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D0=BC=D0=B8=20=D0=BE=20=D0=BF=D0=BE=D0=B2=D1=80=D0=B5?= =?UTF-8?q?=D0=B6=D0=B4=D0=B5=D0=BD=D0=B8=D1=8F=D1=85:=20-=20=D0=98=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=81=20=D0=B2=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B5=20fetch?= =?UTF-8?q?=5Fsalvage=5Fdetailed=5Finfo=20=D0=B4=D0=BB=D1=8F=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D1=8B=D1=85=20=D0=BF=D0=BE=D0=BB=D0=B5=D0=B9=20=D0=B8=20?= =?UTF-8?q?=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=82?= =?UTF-8?q?=D0=BE=D1=87=D0=BD=D0=BE=D1=81=D1=82=D0=B8=20=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D1=85.=20-=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=B0=D1=82=D1=8B,=20=D0=BF?= =?UTF-8?q?=D0=B0=D1=80=D1=81=D0=B8=D0=BD=D0=B3=D0=B0=20=D0=BB=D0=BE=D0=BA?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B8=20=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=BA=D0=B8=20=D1=81=D0=BE=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=8F=D0=BD=D0=B8=D1=8F=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=BE?= =?UTF-8?q?=D0=B1=D0=B8=D0=BB=D1=8F.=20-=20=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=20=D0=B8?= =?UTF-8?q?=D0=BD=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=86=D0=B8=D0=B8=20=D0=BE?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=B2=D1=80=D0=B5=D0=B6=D0=B4=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=D1=85,=20=D0=B2=D0=BA=D0=BB=D1=8E=D1=87=D0=B0=D1=8F=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=87=D0=B5=D1=81=D1=82=D0=B2=D0=BE=20?= =?UTF-8?q?=D1=84=D0=BE=D1=82=D0=BE=D0=B3=D1=80=D0=B0=D1=84=D0=B8=D0=B9.?= =?UTF-8?q?=20=D0=AD=D1=82=D0=B8=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=BE=D0=B2=D1=8B=D1=88=D0=B0=D1=8E?= =?UTF-8?q?=D1=82=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8?= =?UTF-8?q?=D0=B2=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=B8=20=D1=83=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D1=81=D1=82=D0=B2=D0=BE=20=D0=B8=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db.py | 59 ++++++++++----------------- main.py | 124 ++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 121 insertions(+), 62 deletions(-) diff --git a/db.py b/db.py index 568ab85..6d8e9e6 100644 --- a/db.py +++ b/db.py @@ -84,26 +84,19 @@ class OracleDatabase: with conn.cursor() as cur: query = """ SELECT - vin, - make, - model, - vehicle_year, - vehicle_type, - primary_damage, - secondary_damage, - sale_date, - odometer, - sale_title_state, - sale_title_type, - seller, - lot, - estimate_repair_cost, - actual_cash_value, - sale_country, - sale_location - FROM salvagedb.salvagedb - WHERE vin = :vin - ORDER BY sale_date DESC + odo, + odos, + dem1, + dem2, + month||'/'||year as sale_date, + JSON_VALUE(jdata, '$.RepCost') AS j_rep_cost, + JSON_VALUE(jdata, '$.Runs_Drive') AS j_runs_drive, + JSON_VALUE(jdata, '$.Locate') AS j_locate, + (select count(*) from salvagedb.salvage_images si where si.vin = s.vin and fn =1) img_count + FROM salvagedb.salvagedb s + LEFT JOIN salvagedb.addinfo i ON s.num = i.numid + WHERE vin = :vin AND svin = substr(:vin, 1, 10) + ORDER BY year DESC, month DESC """ cur.execute(query, {"vin": vin}) results = cur.fetchall() @@ -112,23 +105,15 @@ class OracleDatabase: detailed_records = [] for row in results: record = { - 'vin': row[0], - 'make': row[1], - 'model': row[2], - 'vehicle_year': row[3], - 'vehicle_type': row[4], - 'primary_damage': row[5], - 'secondary_damage': row[6], - 'sale_date': row[7], - 'odometer': row[8], - 'sale_title_state': row[9], - 'sale_title_type': row[10], - 'seller': row[11], - 'lot': row[12], - 'estimate_repair_cost': row[13], - 'actual_cash_value': row[14], - 'sale_country': row[15], - 'sale_location': row[16] + 'odo': row[0], + 'odos': row[1], + 'dem1': row[2], + 'dem2': row[3], + 'sale_date': row[4], + 'j_rep_cost': row[5], + 'j_runs_drive': row[6], + 'j_locate': row[7], + 'img_count': row[8] } detailed_records.append(record) diff --git a/main.py b/main.py index 56a8805..85ac041 100644 --- a/main.py +++ b/main.py @@ -13,6 +13,65 @@ from db import OracleDatabase from middlewares.db import DbSessionMiddleware +def get_us_state_name(state_code: str) -> str: + """ + Конвертирует двухбуквенный код штата США в полное название + """ + states = { + 'AL': 'Alabama', 'AK': 'Alaska', 'AZ': 'Arizona', 'AR': 'Arkansas', 'CA': 'California', + 'CO': 'Colorado', 'CT': 'Connecticut', 'DE': 'Delaware', 'FL': 'Florida', 'GA': 'Georgia', + 'HI': 'Hawaii', 'ID': 'Idaho', 'IL': 'Illinois', 'IN': 'Indiana', 'IA': 'Iowa', + 'KS': 'Kansas', 'KY': 'Kentucky', 'LA': 'Louisiana', 'ME': 'Maine', 'MD': 'Maryland', + 'MA': 'Massachusetts', 'MI': 'Michigan', 'MN': 'Minnesota', 'MS': 'Mississippi', 'MO': 'Missouri', + 'MT': 'Montana', 'NE': 'Nebraska', 'NV': 'Nevada', 'NH': 'New Hampshire', 'NJ': 'New Jersey', + 'NM': 'New Mexico', 'NY': 'New York', 'NC': 'North Carolina', 'ND': 'North Dakota', 'OH': 'Ohio', + 'OK': 'Oklahoma', 'OR': 'Oregon', 'PA': 'Pennsylvania', 'RI': 'Rhode Island', 'SC': 'South Carolina', + 'SD': 'South Dakota', 'TN': 'Tennessee', 'TX': 'Texas', 'UT': 'Utah', 'VT': 'Vermont', + 'VA': 'Virginia', 'WA': 'Washington', 'WV': 'West Virginia', 'WI': 'Wisconsin', 'WY': 'Wyoming', + 'DC': 'District of Columbia' + } + return states.get(state_code.upper(), state_code) + + +def format_sale_date(date_str: str) -> str: + """ + Форматирует дату продажи из MM/YYYY в красивый формат + """ + if not date_str or date_str == 'None' or '/' not in date_str: + return "Unknown" + + try: + month, year = date_str.split('/') + months = { + '1': 'January', '2': 'February', '3': 'March', '4': 'April', + '5': 'May', '6': 'June', '7': 'July', '8': 'August', + '9': 'September', '10': 'October', '11': 'November', '12': 'December' + } + month_name = months.get(month.lstrip('0'), month) + return f"{month_name} {year}" + except: + return date_str + + +def parse_location(location_str: str) -> str: + r""" + Парсит и форматирует локацию из формата ST\TOWN + """ + if not location_str or location_str == 'None': + return "Unknown Location" + + try: + if '\\' in location_str: + state_code, city = location_str.split('\\', 1) + state_name = get_us_state_name(state_code.strip()) + city_formatted = city.strip().title() + return f"{city_formatted}, {state_name}" + else: + return location_str + except: + return location_str + + if getenv("DEBUG",'0') == '1': logging.basicConfig(level=logging.INFO) else: @@ -489,38 +548,45 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None for idx, record in enumerate(salvage_records[:5], 1): # Показываем максимум 5 записей report += f"📋 **Record #{idx}**\n" + # Дата продажи с красивым форматированием if record['sale_date']: - report += f"📅 **Sale Date:** {record['sale_date']}\n" + formatted_date = format_sale_date(record['sale_date']) + report += f"📅 **Sale Date:** {formatted_date}\n" - if record['primary_damage']: - report += f"⚠️ **Primary Damage:** {record['primary_damage']}\n" + # Основное повреждение + if record['dem1']: + report += f"⚠️ **Primary Damage:** {record['dem1']}\n" - if record['secondary_damage']: - report += f"⚠️ **Secondary Damage:** {record['secondary_damage']}\n" + # Вторичное повреждение + if record['dem2']: + report += f"⚠️ **Secondary Damage:** {record['dem2']}\n" - if record['vehicle_type']: - report += f"🚙 **Vehicle Type:** {record['vehicle_type']}\n" + # Одометр + if record['odo']: + try: + odo_value = int(record['odo']) if record['odo'] else 0 + odo_status = f" ({record['odos']})" if record['odos'] else "" + report += f"🛣️ **Odometer:** {odo_value:,} miles{odo_status}\n" + except (ValueError, TypeError): + report += f"🛣️ **Odometer:** {record['odo']}\n" - if record['odometer']: - report += f"🛣️ **Odometer:** {record['odometer']:,} miles\n" + # Стоимость ремонта + if record['j_rep_cost']: + try: + repair_cost = float(record['j_rep_cost']) if record['j_rep_cost'] else 0 + if repair_cost > 0: + report += f"💰 **Repair Cost:** ${repair_cost:,.2f}\n" + except (ValueError, TypeError): + report += f"💰 **Repair Cost:** ${record['j_rep_cost']}\n" - if record['sale_title_state']: - report += f"📍 **Title State:** {record['sale_title_state']}\n" + # Состояние двигателя/движения + if record['j_runs_drive']: + report += f"🔧 **Engine Status:** {record['j_runs_drive']}\n" - if record['sale_title_type']: - report += f"📄 **Title Type:** {record['sale_title_type']}\n" - - if record['seller']: - report += f"🏢 **Seller:** {record['seller']}\n" - - if record['estimate_repair_cost']: - report += f"💰 **Estimated Repair Cost:** ${record['estimate_repair_cost']:,}\n" - - if record['actual_cash_value']: - report += f"💵 **Actual Cash Value:** ${record['actual_cash_value']:,}\n" - - if record['sale_location']: - report += f"📍 **Sale Location:** {record['sale_location']}\n" + # Локация с конвертированными штатами + if record['j_locate']: + formatted_location = parse_location(record['j_locate']) + report += f"📍 **Sale Location:** {formatted_location}\n" report += "\n" @@ -538,6 +604,14 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None builder.adjust(2) await message.answer(report, reply_markup=builder.as_markup(), parse_mode="Markdown") + + # Отправляем отдельное сообщение о фотографиях + if salvage_records and salvage_records[0]['img_count'] > 0: + img_count = salvage_records[0]['img_count'] + photo_message = f"📸 **Photo Information**\n\n" + photo_message += f"🖼️ **{img_count} damage photos** found in our database for this vehicle.\n" + photo_message += f"These photos show the actual condition and damage of the vehicle during auction." + await message.answer(photo_message, parse_mode="Markdown") else: # Нет записей - возвращаем деньги try: