Bishall10/ipo
0
1"""2expiry_handler.py3-----------------4Handles DEMAT and MeroShare account expiry detection for the IPO automation.5KYC expiry is intentionally excluded — only DEMAT and MeroShare account status6is monitored here.7"""8 9from notifications import send_email_notification10 11 12DEMAT_EXPIRY_KEYWORDS = [13 "demat account expired",14 "demat account has expired",15 "demat account is expired",16 "demat account suspended",17 "demat account has been suspended",18 "renew your demat",19 "demat renewal",20 "demat account renewal required",21]22 23MEROSHARE_EXPIRY_KEYWORDS = [24 "meroshare account expired",25 "meroshare account has expired",26 "your account has expired",27 "account is expired",28 "account has been deactivated",29 "account deactivated",30 "account suspended",31 "your account is suspended",32 "account is inactive",33 "inactive account",34]35 36 37EXPIRY_WARNING_PATTERNS = [38 "demat expires on",39 "demat expiry",40 "demat valid till",41 "demat renewal due",42 "account expires on",43 "account expiry",44 "account valid till",45 "account renewal due",46]47 48 49def detect_account_expiry(page, username):50 """51 Scans the current page HTML for DEMAT or MeroShare account expiry messages.52 53 Returns:54 'DEMAT_EXPIRED' — if a DEMAT account expiry keyword is found55 'MEROSHARE_EXPIRED' — if a MeroShare account expiry keyword is found56 None — if no expiry is detected57 """58 try:59 page_text = page.content().lower()60 61 for kw in DEMAT_EXPIRY_KEYWORDS:62 if kw in page_text:63 print(f"[{username}] ⚠️ DEMAT expiry detected: '{kw}'")64 return "DEMAT_EXPIRED"65 66 for kw in MEROSHARE_EXPIRY_KEYWORDS:67 if kw in page_text:68 print(f"[{username}] ⚠️ MeroShare account expiry detected: '{kw}'")69 return "MEROSHARE_EXPIRED"70 71 except Exception as e:72 print(f"[{username}] Warning: Could not scan for account expiry: {e}")73 74 return None75 76 77def check_account_expiry_warning(page, account):78 """79 Should be called after a successful login, before applying or checking IPOs.80 Scans the dashboard text for *upcoming* DEMAT / MeroShare account expiry81 hints (e.g. "account expires on DD/MM/YYYY") and sends a proactive email82 with the expiry date and days remaining.83 84 KYC warnings are intentionally excluded.85 """86 import re87 from datetime import datetime, date88 89 username = account["MEROSHARE_USER"]90 try:91 patterns_js = str(EXPIRY_WARNING_PATTERNS).replace("'", '"')92 93 # Extract a wider snippet (150 chars) so a nearby date is captured too94 result = page.evaluate(f"""95 () => {{96 const body = document.body.innerText.toLowerCase();97 const patterns = {patterns_js};98 for (const p of patterns) {{99 const idx = body.indexOf(p);100 if (idx !== -1) return body.substring(Math.max(0, idx - 10), idx + 150);101 }}102 return null;103 }}104 """)105 106 if not result:107 return108 109 print(f"[{username}] ⚠️ Upcoming expiry warning detected: {result.strip()}")110 111 # Try to extract a date from the snippet (supports DD/MM/YYYY, YYYY-MM-DD, DD-MM-YYYY)112 expiry_date = None113 days_left_str = ""114 date_patterns = [115 r'(\d{4}-\d{2}-\d{2})', # YYYY-MM-DD116 r'(\d{2}/\d{2}/\d{4})', # DD/MM/YYYY117 r'(\d{2}-\d{2}-\d{4})', # DD-MM-YYYY118 ]119 date_formats = ['%Y-%m-%d', '%d/%m/%Y', '%d-%m-%Y']120 121 for pattern, fmt in zip(date_patterns, date_formats):122 match = re.search(pattern, result)123 if match:124 try:125 expiry_date = datetime.strptime(match.group(1), fmt).date()126 days_left = (expiry_date - date.today()).days127 if days_left >= 0:128 days_left_str = f" 📅 Expires on: {expiry_date.strftime('%d %B %Y')} ({days_left} day(s) remaining)\n"129 else:130 days_left_str = f" 📅 Expired on: {expiry_date.strftime('%d %B %Y')} ({abs(days_left)} day(s) ago)\n"131 break132 except ValueError:133 pass134 135 if not days_left_str:136 # No parseable date found — include raw snippet137 days_left_str = f" ℹ️ Details: {result.strip()}\n"138 139 send_email_notification(140 account.get("EMAIL"),141 "[MeroShare] ⚠️ Account Expiry Warning",142 f"Hi {username},\n\n"143 f"An upcoming DEMAT or MeroShare account expiry was detected on your dashboard:\n\n"144 f"{days_left_str}\n"145 f"Please log in to https://meroshare.cdsc.com.np and renew your account "146 147 )148 149 except Exception as e:150 print(f"[{username}] Warning: Could not check expiry warning: {e}")151 152 153def handle_expired_account(account, expiry_type):154 """155 Sends the appropriate email for a hard-expired account and returns False156 so the caller knows to skip further processing for this account.157 158 Args:159 account — the account dict (must contain 'MEROSHARE_USER' and 'EMAIL')160 expiry_type — 'DEMAT_EXPIRED' or 'MEROSHARE_EXPIRED'161 162 Returns:163 False (always) — signals that the account should be skipped164 """165 username = account.get("MEROSHARE_USER")166 167 if expiry_type == "DEMAT_EXPIRED":168 print(f"[{username}] ❌ DEMAT account expired. Skipping.")169 send_email_notification(170 account.get("EMAIL"),171 "[MeroShare] Action Required: DEMAT Account Expired",172 f"Hi {username},\n\n"173 f"Your DEMAT account has expired on MeroShare.\n"174 f"Please renew it in time.\n\n"175 )176 177 elif expiry_type == "MEROSHARE_EXPIRED":178 print(f"[{username}] ❌ MeroShare account expired/deactivated. Skipping.")179 send_email_notification(180 account.get("EMAIL"),181 "[MeroShare] Action Required: Account Expired",182 f"Hi {username},\n\n"183 f"Your MeroShare account appears to be expired.\n"184 f"Please visit https://meroshare.cdsc.com.np and renew it in time.\n\n"185 )186 187 return False188 