CoolFace
Apppublic

codeBOKER/customer_service

sourceHugging Faceupdated 3mo agoView on Hugging Face
1likes
service.py304 linesDownload Raw Back to transfers
1import json2from datetime import datetime3from pathlib import Path4from threading import Lock5from typing import Any, Dict, Optional6 7 8DATA_FILE = Path(__file__).with_name("mock_bank_accounts.json")9PENDING_FILE = Path(__file__).with_name("pending_transfers.json")10_LOCK = Lock()11 12 13def _read_json(path: Path, default: Any) -> Any:14    if not path.exists():15        return default16 17    with path.open("r", encoding="utf-8") as file:18        return json.load(file)19 20 21def _write_json(path: Path, data: Any) -> None:22    with path.open("w", encoding="utf-8") as file:23        json.dump(data, file, ensure_ascii=True, indent=2)24 25 26def _load_bank_data() -> Dict[str, Any]:27    return _read_json(DATA_FILE, {"accounts": [], "transactions": []})28 29 30def _save_bank_data(data: Dict[str, Any]) -> None:31    _write_json(DATA_FILE, data)32 33 34def _load_pending_transfers() -> Dict[str, Any]:35    return _read_json(PENDING_FILE, {})36 37 38def _save_pending_transfers(data: Dict[str, Any]) -> None:39    _write_json(PENDING_FILE, data)40 41 42def _find_account_by_telegram_id(accounts: list[Dict[str, Any]], telegram_id: int) -> Optional[Dict[str, Any]]:43    return next((account for account in accounts if account.get("telegram_id") == telegram_id), None)44 45 46def _find_account_by_serial_id(accounts: list[Dict[str, Any]], serial_id: str) -> Optional[Dict[str, Any]]:47    normalized_id = str(serial_id).strip()48    return next((account for account in accounts if str(account.get("serial_id")) == normalized_id), None)49 50 51def get_sender_account(telegram_id: int, user_name: str = None) -> Dict[str, Any]:52    with _LOCK:53        data = _load_bank_data()54        sender = _find_account_by_telegram_id(data["accounts"], telegram_id)55        if sender:56            is_real = sender.get("is_real", True)57            is_illusion = not is_real or sender.get("name", "").startswith("Test User")58            return {59                "success": True,60                "account": sender,61                "is_real": is_real,62                "is_illusion": is_illusion,63            }64 65        # Ask for user name before creating illusion account66        if not user_name:67            return {68                "success": False,69                "need_user_name": True,70                "message": "I need to create an illusion account for testing purposes. What is your name?",71            }72 73        # Create illusion account for testing purposes74        new_account = {75            "telegram_id": telegram_id,76            "account_id": f"ACC-{telegram_id}",77            "serial_id": str(9000 + telegram_id % 1000),78            "name": f"Test User {user_name}",79            "balance": 2000.0,80            "currency": "YER",81            "is_real": False82        }83        84        data["accounts"].append(new_account)85        _save_bank_data(data)86        87        return {88            "success": True,89            "account": new_account,90            "is_real": False,91            "is_illusion": True,92            "message": f"I've created an illusion account for {user_name} with 2000 YER balance to try sending money. This is for testing purposes only."93        }94 95 96def get_account_balance(telegram_id: int) -> Dict[str, Any]:97    sender_result = get_sender_account(telegram_id)98    if not sender_result["success"]:99        return sender_result100 101    account = sender_result["account"]102    result = {103        "success": True,104        "telegram_id": telegram_id,105        "account_id": account["account_id"],106        "serial_id": account["serial_id"],107        "name": account["name"],108        "balance": account.get("balance", 0.0),109        "currency": account.get("currency", "YER"),110        "is_real": sender_result.get("is_real", True),111        "is_illusion": sender_result.get("is_illusion", False),112    }113    114    if result["is_illusion"]:115        result["message"] = "This is an illusion account created for testing purposes with 2000 YER balance."116    117    return result118 119 120def get_receiver_account_name(receiver_serial_id: str) -> Dict[str, Any]:121    with _LOCK:122        data = _load_bank_data()123        receiver = _find_account_by_serial_id(data["accounts"], receiver_serial_id)124 125        if not receiver:126            return {127                "success": False,128                "message": f"No account was found for ID {receiver_serial_id}.",129            }130 131        return {132            "success": True,133            "serial_id": receiver["serial_id"],134            "name": receiver["name"],135            "account_id": receiver["account_id"],136            "currency": receiver.get("currency", "YER"),137        }138 139 140def prepare_transfer(telegram_id: int, receiver_serial_id: str, amount: Optional[float] = None) -> Dict[str, Any]:141    with _LOCK:142        data = _load_bank_data()143        sender = _find_account_by_telegram_id(data["accounts"], telegram_id)144        if not sender:145            return {146                "success": False,147                "message": "You do not have an account in the bank system. Please visit the bank to create an account first.",148            }149 150        receiver = _find_account_by_serial_id(data["accounts"], receiver_serial_id)151        if not receiver:152            return {153                "success": False,154                "message": f"No account was found for ID {receiver_serial_id}.",155            }156 157        if receiver["serial_id"] == sender["serial_id"]:158            return {159                "success": False,160                "message": "You cannot transfer money to the same account.",161            }162 163        pending_transfers = _load_pending_transfers()164        pending_payload = {165            "telegram_id": telegram_id,166            "sender_name": sender["name"],167            "sender_serial_id": sender["serial_id"],168            "receiver_name": receiver["name"],169            "receiver_serial_id": receiver["serial_id"],170            "receiver_account_id": receiver["account_id"],171            "amount": amount,172            "currency": sender.get("currency", "YER"),173            "created_at": datetime.utcnow().isoformat(),174        }175        pending_transfers[str(telegram_id)] = pending_payload176        _save_pending_transfers(pending_transfers)177 178        return {179            "success": True,180            "pending_transfer": pending_payload,181            "message": f"Receiver found: {receiver['name']}. Waiting for user confirmation.",182        }183 184 185def get_pending_transfer(telegram_id: int) -> Dict[str, Any]:186    with _LOCK:187        pending_transfers = _load_pending_transfers()188        pending_transfer = pending_transfers.get(str(telegram_id))189 190        if not pending_transfer:191            return {192                "success": False,193                "message": "No pending transfer was found for this Telegram user.",194            }195 196        return {197            "success": True,198            "pending_transfer": pending_transfer,199        }200 201 202def confirm_transfer(telegram_id: int) -> Dict[str, Any]:203    with _LOCK:204        data = _load_bank_data()205        pending_transfers = _load_pending_transfers()206        pending_transfer = pending_transfers.get(str(telegram_id))207 208        if not pending_transfer:209            return {210                "success": False,211                "message": "There is no pending transfer to confirm.",212            }213 214        sender = _find_account_by_telegram_id(data["accounts"], telegram_id)215        receiver = _find_account_by_serial_id(data["accounts"], pending_transfer["receiver_serial_id"])216 217        if not sender or not receiver:218            return {219                "success": False,220                "message": "The sender or receiver account could not be found.",221            }222 223        amount = pending_transfer.get("amount")224        if amount is None:225            return {226                "success": False,227                "message": "The transfer amount is missing. Ask the user for the amount before confirming.",228            }229 230        try:231            amount_value = float(amount)232        except (TypeError, ValueError):233            return {234                "success": False,235                "message": "The transfer amount is invalid.",236            }237 238        if amount_value <= 0:239            return {240                "success": False,241                "message": "The transfer amount must be greater than zero.",242            }243 244        if float(sender.get("balance", 0.0)) < amount_value:245            return {246                "success": False,247                "message": f"Insufficient balance. Available balance is {sender.get('balance', 0.0):.2f} {sender.get('currency', 'YER')}.",248            }249 250        sender["balance"] = round(float(sender["balance"]) - amount_value, 2)251        receiver["balance"] = round(float(receiver.get("balance", 0.0)) + amount_value, 2)252 253        transaction = {254            "transaction_id": f"TX-{datetime.utcnow().strftime('%Y%m%d%H%M%S%f')}",255            "telegram_id": telegram_id,256            "sender_serial_id": sender["serial_id"],257            "receiver_serial_id": receiver["serial_id"],258            "receiver_name": receiver["name"],259            "amount": amount_value,260            "currency": sender.get("currency", "YER"),261            "created_at": datetime.utcnow().isoformat(),262        }263        data.setdefault("transactions", []).append(transaction)264        _save_bank_data(data)265 266        pending_transfers.pop(str(telegram_id), None)267        _save_pending_transfers(pending_transfers)268 269        # Check if sender is an illusion account using is_real variable270        is_real = sender.get("is_real", True)271        is_illusion = not is_real272        273        message = f"Transfer completed successfully to {receiver['name']}."274        if is_illusion:275            message += " ⚠️ Please note: This process was not real - it was for testing purposes only. No actual money was transferred."276        277        return {278            "success": True,279            "transaction": transaction,280            "sender_balance": sender["balance"],281            "is_real": is_real,282            "is_illusion": is_illusion,283            "message": message,284        }285 286 287def cancel_transfer(telegram_id: int) -> Dict[str, Any]:288    with _LOCK:289        pending_transfers = _load_pending_transfers()290        removed = pending_transfers.pop(str(telegram_id), None)291        _save_pending_transfers(pending_transfers)292 293        if not removed:294            return {295                "success": False,296                "message": "There is no pending transfer to cancel.",297            }298 299        return {300            "success": True,301            "message": "The pending transfer has been canceled.",302        }303 304