Did some modifications...

This commit is contained in:
Joan
2025-10-29 11:14:34 +01:00
parent 8bcf8c8819
commit c012f03cb4
8 changed files with 420 additions and 168 deletions

View File

@@ -9,7 +9,7 @@ import os # Import os to get BOT_TOKEN
# Import necessary functions from your project structure
# Adjust the path if paypal_processor.py is not in the root 'app' directory
# Assuming it can access the other modules directly as in the docker setup:
from helpers import generate_table_image, format_last_participants_list, get_paypal_access_token
from helpers import generate_table_image, format_last_participants_list, get_paypal_access_token, is_vip_member_of_homelabs, send_raffle_update_image
from database import (
get_user_by_invoice_id, confirm_reserved_numbers,
get_raffle_name, get_raffle,
@@ -19,7 +19,7 @@ from database import (
get_last_n_other_participants, get_remaining_numbers,
delete_reservation_timestamp, cancel_reservation_by_id
)
from config import BOT_TOKEN, BOT_NAME, WEBHOOK_ID, TYC_DOCUMENT_URL, REVERSE_CHANNELS, NEWRELIC_API_KEY, PAYPAL_URL, ADMIN_IDS
from config import BOT_TOKEN, BOT_NAME, WEBHOOK_ID, TYC_DOCUMENT_URL, REVERSE_CHANNELS, NEWRELIC_API_KEY, PAYPAL_URL, ADMIN_IDS, VIP_DISCOUNT_PER_NUMBER
from newrelic_telemetry_sdk import Log, LogClient
app = Flask(__name__)
@@ -126,7 +126,6 @@ def send_telegram_photo(chat_id, photo_path, caption=None, keyboard=None, parse_
if 'photo' in files and files['photo']:
files['photo'].close()
# --- CORRECTED FUNCTION ---
def receive_paypal_payment(invoice_id, payment_status, payment_amount_str):
"""Processes verified PayPal payment data."""
logger.info(f"Processing payment for Invoice: {invoice_id}, Status: {payment_status}, Amount: {payment_amount_str}")
@@ -147,7 +146,13 @@ def receive_paypal_payment(invoice_id, payment_status, payment_amount_str):
raffle_id = participant_data['raffle_id']
numbers_str = participant_data['numbers']
raffle_details = get_raffle(raffle_id)
price_per_number = raffle_details['price']
original_price_per_number = raffle_details['price']
is_vip = is_vip_member_of_homelabs(user_id)
if is_vip:
logger.info(f"User {user_id} ({current_user_name}) is a VIP member. Applying discount.")
price_per_number = max(1, raffle_details['price'] - VIP_DISCOUNT_PER_NUMBER) # Ensure price doesn't go negative
else:
price_per_number = raffle_details['price']
channel_id_to_announce = raffle_details['channel_id']
update_message_id = raffle_details['update_message_id']
@@ -206,144 +211,15 @@ def receive_paypal_payment(invoice_id, payment_status, payment_amount_str):
# Raffle name can be added here if desired, requires one more DB call or adding it to get_user_by_invoice_id
)
# Generate table image
if generate_table_image(raffle_id):
image_path = f"/app/data/raffles/raffle_table_{raffle_id}.png"
# Get general raffle details (like description) for announcement caption
raffle_details_general = get_raffle(raffle_id) # Fetches name, description, image_id
if not raffle_details_general:
logger.error(f"Could not fetch general raffle details for ID {raffle_id} after payment confirmation.")
return # Or handle more gracefully
raffle_description_for_announce = raffle_details_general['description']
remaining_numbers_amount = get_remaining_numbers_amount(raffle_id)
# If it's the last number, update the main message and delete the participate button
if remaining_numbers_amount == 0:
keyboard = None
main_announcement = f"🎯🏆🎯 <b>Sorteo '{raffle_name}' terminado</b> 🎯🏆🎯\n\n"
main_announcement += f"{raffle_details['description']}\n\n"
main_announcement += f"🌍 Envío internacional: {'Sí ✅' if raffle_details['international_shipping'] else 'No ❌'}\n"
main_announcement += f"💵 <b>Donación mínima:</b> {raffle_details['price']}\n"
main_announcement += f"📜 <b>Normas y condiciones:</b> {TYC_DOCUMENT_URL}"
main_message_id = get_main_message_id(raffle_id)
requests.post(f"{TELEGRAM_API_URL}/editMessageCaption", json={
"chat_id": channel_id_to_announce,
"message_id": main_message_id,
"caption": main_announcement,
"reply_markup": keyboard,
"parse_mode": "HTML"
})
else:
url = f"https://t.me/{BOT_NAME}?start=join_{raffle_id}"
keyboard = {
"inline_keyboard": [
[
{"text": "✅ ¡Participar Ahora! ✅", "url": url}
]
]
}
main_announcement = f"🏆 Sorteo '{raffle_name}' en progreso 🏆\n\n"
main_announcement += f"{raffle_details['description']}\n\n"
main_announcement += f"🌍 Envío internacional: {'Sí ✅' if raffle_details['international_shipping'] else 'No ❌'}\n"
main_announcement += f"💵 <b>Donación mínima:</b> {raffle_details['price']}\n"
main_announcement += f"🗒️ Quedan {remaining_numbers_amount} participaciones disponibles. ¡Date prisa! 🗒️\n\n"
main_announcement += f"📜 <b>Normas y condiciones:</b> {TYC_DOCUMENT_URL}"
main_message_id = get_main_message_id(raffle_id)
requests.post(f"{TELEGRAM_API_URL}/editMessageCaption", json={
"chat_id": channel_id_to_announce,
"message_id": main_message_id,
"caption": main_announcement,
"reply_markup": keyboard,
"parse_mode": "HTML"
})
last_other_participants = get_last_n_other_participants(raffle_id, n=4)
last_participants_text = format_last_participants_list(last_other_participants)
escaped_current_user_name = current_user_name
numbers_text = ""
if len(numbers) > 1:
numbers_text = f"con las participaciones: {', '.join(numbers)}"
else:
numbers_text = f"con la participación: {', '.join(numbers)}"
new_participant_line = f"🗳️ @{escaped_current_user_name} se ha unido al sorteo {numbers_text}. ¡Mucha suerte! 🗳️"
remaining_numbers_text = ""
if remaining_numbers_amount > 10:
remaining_numbers_text = f"🗒️ Todavía hay {remaining_numbers_amount} participaciones disponibles. 🗒️"
elif remaining_numbers_amount == 1:
remaining_numbers = get_remaining_numbers(raffle_id)
remaining_numbers_text = f"⏰⏰⏰ ¡Última participación! ⏰⏰⏰\n\n"
remaining_numbers_text += f"Queda la participación: {remaining_numbers[0]}"
elif remaining_numbers_amount == 0:
remaining_numbers_text = "⌛ ¡Ya no hay participaciones! ⌛\n\n"
remaining_numbers_text += "¡El resultado del sorteo se dará a conocer a las 21:45h!"
else:
remaining_numbers = get_remaining_numbers(raffle_id)
remaining_numbers_text = f"🔔🔔🔔 ¡Últimas {remaining_numbers_amount} participaciones disponibles! 🔔🔔🔔\n\n"
remaining_numbers_text += f"Quedan las participaciones: {', '.join(remaining_numbers)}"
caption = (
f"{new_participant_line}\n\n"
f"{last_participants_text}\n\n"
f"{remaining_numbers_text}\n\n"
f"{raffle_description_for_announce}\n\n"
f"🔎 Ver detalles: https://t.me/{REVERSE_CHANNELS.get(channel_id_to_announce)}/{get_main_message_id(raffle_id)}\n\n"
f"🌍 Envío internacional: {'Sí ✅' if raffle_details['international_shipping'] else 'No ❌'}\n"
f"💵 Donación mínima: {price_per_number}\n\n"
f"📜 Normas y condiciones: {TYC_DOCUMENT_URL} \n\n"
)
update_message_id = get_update_message_id(raffle_id)
sent_or_edited_message_id = None
if update_message_id:
logger.info(f"Attempting to edit message {update_message_id} in channel {channel_id_to_announce}")
# Try deleting old message first
try:
delete_payload = {'chat_id': channel_id_to_announce, 'message_id': update_message_id}
delete_response = requests.post(f"{TELEGRAM_API_URL}/deleteMessage", data=delete_payload)
if delete_response.status_code == 200:
logger.info(f"Successfully deleted old message {update_message_id} in channel {channel_id_to_announce}")
else:
logger.warning(f"Failed to delete old message {update_message_id} in channel {channel_id_to_announce}: {delete_response.text}. Will send new.")
except Exception as e_del:
logger.warning(f"Error deleting old message {update_message_id}: {e_del}. Will send new.")
# Always send new photo after delete attempt, ensures updated image is shown
new_msg_info = send_telegram_photo(channel_id_to_announce, image_path, caption=caption, keyboard=keyboard, parse_mode='HTML')
if new_msg_info and isinstance(new_msg_info, dict) and 'message_id' in new_msg_info: # If send_telegram_photo returns message object
sent_or_edited_message_id = new_msg_info['message_id']
elif isinstance(new_msg_info, bool) and new_msg_info is True: # If it just returns True/False
# We can't get message_id this way. Need send_telegram_photo to return it.
logger.warning("send_telegram_photo did not return message_id, cannot store for future edits.")
else: # Sending new failed
logger.error(f"Failed to send new photo to channel {channel_id_to_announce} after deleting old.")
else: # No previous message, send new
logger.info(f"No previous message found for raffle {raffle_id} in channel {channel_id_to_announce}. Sending new.")
new_msg_info = send_telegram_photo(channel_id_to_announce, image_path, caption=caption, keyboard=keyboard, parse_mode='HTML')
# Similar logic to get sent_or_edited_message_id as above
if new_msg_info and isinstance(new_msg_info, dict) and 'message_id' in new_msg_info:
sent_or_edited_message_id = new_msg_info['message_id']
elif isinstance(new_msg_info, bool) and new_msg_info is True:
logger.warning("send_telegram_photo did not return message_id for new message.")
if sent_or_edited_message_id:
store_update_message_id(raffle_id, sent_or_edited_message_id)
# Send image confirmation to user (price not needed in this caption)
user_caption = f"¡Apuntado satisfactoriamente al sorteo '{raffle_name}'! Tus participaciones son: {', '.join(numbers)}"
send_telegram_photo(user_id, image_path, caption=user_caption)
# Send raffle update image with participant info
if send_raffle_update_image(raffle_id, current_user_name, numbers, BOT_TOKEN):
# Send image confirmation to user
if generate_table_image(raffle_id):
image_path = f"/app/data/raffles/raffle_table_{raffle_id}.png"
user_caption = f"¡Apuntado satisfactoriamente al sorteo '{raffle_name}'! Tus participaciones son: {', '.join(numbers)}"
send_telegram_photo(user_id, image_path, caption=user_caption)
else:
logger.error(f"Failed to generate raffle table image for {raffle_id} after payment.")
logger.error(f"Failed to send raffle update image for {raffle_id} after payment.")
else:
# This case means the DB update failed, which is serious if payment was valid.
@@ -358,6 +234,22 @@ def receive_paypal_payment(invoice_id, payment_status, payment_amount_str):
# admin_chat_id = "YOUR_ADMIN_CHAT_ID"
# send_telegram_message(admin_chat_id, f"CRITICAL DB Error: Failed to confirm numbers for invoice {invoice_id}, user {user_id}, raffle {raffle_id}. Payment was valid. Manual check needed.")
def notify_user_of_pending_review(invoice_id, payment_status, status_details):
"""Notify user that their payment is pending review."""
participant_data = get_user_by_invoice_id(invoice_id)
if not participant_data:
logger.warning(f"No participant found for Invoice ID: {invoice_id}. Cannot notify about pending review.")
return
user_id = participant_data['user_id']
send_telegram_message(
user_id,
f"⚠️ Tu pago para la factura {invoice_id} está pendiente de revisión por PayPal.\n"
f"El estado actual es '{payment_status}' con detalles: '{status_details}'.\n"
f"El sorteo solo se confirma con pagos 'Completed'. Cuando el pago sea confirmado, recibirás una notificación.\n"
f"Tus números reservados se mantendrán durante este proceso."
)
def capture_order(order_id, access_token):
url = f"{PAYPAL_URL}/v2/checkout/orders/{order_id}/capture"
headers = {
@@ -442,6 +334,7 @@ def paypal_webhook():
status_details = resource["status_details"]["reason"]
delete_reservation_timestamp(invoice_id)
notify_user_of_pending_review(invoice_id, payment_status, status_details)
if status_details == "PENDING_REVIEW":
logger.info(f"Payment for invoice {invoice_id} is pending review. Notifying admins.")
@@ -498,4 +391,4 @@ if __name__ == "__main__":
exit(1)
TELEGRAM_API_URL = f"https://api.telegram.org/bot{BOT_TOKEN}" # Set global URL
app.run(port=5000, debug=False, host="0.0.0.0") # Disable debug in production
app.run(port=5000, debug=False, host="0.0.0.0") # Disable debug in production