Escrow Payment Gateway Python

👤 Sharing: AI
```python
# This is a simplified simulation of an escrow payment gateway.  It's not a real payment gateway
# and does not handle actual financial transactions.  It is for educational purposes only.

class EscrowService:
    """
    Simulates an escrow service that holds funds until both parties (buyer and seller) agree.
    """

    def __init__(self):
        self.transactions = {}  # Dictionary to store transaction details. Key: transaction_id, Value: transaction info.
        self.transaction_id_counter = 1  # Simple transaction ID generator.

    def create_transaction(self, buyer_id, seller_id, amount, description=""):
        """
        Creates a new transaction in the escrow system.

        Args:
            buyer_id:  Unique identifier for the buyer.
            seller_id: Unique identifier for the seller.
            amount: The amount of money involved in the transaction.
            description: Optional description of the transaction.

        Returns:
            transaction_id: A unique ID for the created transaction.  Returns None if invalid inputs.
        """

        if not isinstance(buyer_id, str) or not isinstance(seller_id, str) or not isinstance(amount, (int, float)):
            print("Error: Invalid input types. Buyer/Seller IDs must be strings, amount must be a number.")
            return None

        if amount <= 0:
            print("Error: Amount must be a positive value.")
            return None

        transaction_id = self.transaction_id_counter
        self.transactions[transaction_id] = {
            'buyer_id': buyer_id,
            'seller_id': seller_id,
            'amount': amount,
            'description': description,
            'status': 'pending',  # Initial status is 'pending' until the buyer funds it.
            'funds_deposited': False, # Track if funds have been deposited
            'buyer_approval': False,  # Track if the buyer has approved the release.
            'seller_approval': False  # Track if the seller has approved the release.
        }
        self.transaction_id_counter += 1
        print(f"Transaction {transaction_id} created for ${amount} between {buyer_id} and {seller_id}.")
        return transaction_id


    def deposit_funds(self, transaction_id):
        """
        Simulates the buyer depositing funds into the escrow.

        Args:
            transaction_id: The ID of the transaction.

        Returns:
            True if the funds were successfully deposited, False otherwise.
        """
        if transaction_id not in self.transactions:
            print(f"Error: Transaction {transaction_id} not found.")
            return False

        transaction = self.transactions[transaction_id]

        if transaction['status'] != 'pending':
            print(f"Error: Funds cannot be deposited. Transaction {transaction_id} is in {transaction['status']} status.")
            return False

        transaction['funds_deposited'] = True  # Simulate funds being deposited
        transaction['status'] = 'funded'  # Update transaction status
        print(f"Funds deposited for transaction {transaction_id}.")
        return True


    def approve_transaction(self, transaction_id, user_id):
        """
        Allows either the buyer or seller to approve the transaction.

        Args:
            transaction_id: The ID of the transaction.
            user_id: The ID of the user approving the transaction (either buyer or seller).

        Returns:
            True if the approval was successful, False otherwise.
        """
        if transaction_id not in self.transactions:
            print(f"Error: Transaction {transaction_id} not found.")
            return False

        transaction = self.transactions[transaction_id]

        if transaction['status'] != 'funded':
            print(f"Error: Cannot approve. Transaction {transaction_id} is in {transaction['status']} status.  It needs to be funded first.")
            return False

        if user_id == transaction['buyer_id']:
            transaction['buyer_approval'] = True
            print(f"Buyer {user_id} approved transaction {transaction_id}.")

        elif user_id == transaction['seller_id']:
            transaction['seller_approval'] = True
            print(f"Seller {user_id} approved transaction {transaction_id}.")
        else:
            print(f"Error: User {user_id} is not part of transaction {transaction_id}.")
            return False

        # Check if both parties have approved
        if transaction['buyer_approval'] and transaction['seller_approval']:
            self.release_funds(transaction_id) # Automatically release the funds
        return True

    def release_funds(self, transaction_id):
        """
        Releases the funds to the seller if both buyer and seller have approved.

        Args:
            transaction_id: The ID of the transaction.

        Returns:
            True if funds were released, False otherwise.
        """
        if transaction_id not in self.transactions:
            print(f"Error: Transaction {transaction_id} not found.")
            return False

        transaction = self.transactions[transaction_id]

        if transaction['status'] != 'funded':
            print(f"Error: Cannot release funds. Transaction {transaction_id} is in {transaction['status']} status.  It needs to be funded first.")
            return False


        if not transaction['buyer_approval'] or not transaction['seller_approval']:
            print(f"Error: Cannot release funds. Both buyer and seller must approve transaction {transaction_id}.")
            return False

        # Simulate releasing the funds to the seller. In a real system, this would involve
        # transferring funds from the escrow account to the seller's account.
        transaction['status'] = 'completed'
        print(f"Funds released to seller {transaction['seller_id']} for transaction {transaction_id}.")
        return True


    def cancel_transaction(self, transaction_id):
        """
        Cancels the transaction and refunds the funds to the buyer (if deposited).

        Args:
            transaction_id: The ID of the transaction.

        Returns:
            True if the transaction was cancelled, False otherwise.
        """
        if transaction_id not in self.transactions:
            print(f"Error: Transaction {transaction_id} not found.")
            return False

        transaction = self.transactions[transaction_id]

        if transaction['status'] == 'completed':
            print(f"Error: Cannot cancel. Transaction {transaction_id} is already completed.")
            return False

        # Simulate refunding the funds to the buyer.
        transaction['status'] = 'cancelled'
        print(f"Transaction {transaction_id} cancelled. Funds refunded to buyer {transaction['buyer_id']}.")
        return True


    def get_transaction_status(self, transaction_id):
        """
        Returns the status of a transaction.

        Args:
            transaction_id: The ID of the transaction.

        Returns:
            The status of the transaction (e.g., 'pending', 'funded', 'completed', 'cancelled').
            Returns None if the transaction is not found.
        """
        if transaction_id not in self.transactions:
            print(f"Error: Transaction {transaction_id} not found.")
            return None

        return self.transactions[transaction_id]['status']

    def get_transaction_details(self, transaction_id):
      """Returns details of a transaction"""
      if transaction_id not in self.transactions:
            print(f"Error: Transaction {transaction_id} not found.")
            return None

      return self.transactions[transaction_id]

# Example Usage
if __name__ == "__main__":
    escrow = EscrowService()

    # Create a new transaction
    transaction_id = escrow.create_transaction(buyer_id="buyer123", seller_id="seller456", amount=100.00, description="Painting purchase")

    if transaction_id:
        # Buyer deposits funds
        escrow.deposit_funds(transaction_id)

        # Buyer approves the transaction
        escrow.approve_transaction(transaction_id, "buyer123")

        # Seller approves the transaction
        escrow.approve_transaction(transaction_id, "seller456")

        #Get transaction details
        details = escrow.get_transaction_details(transaction_id)
        print(f"Transaction Details: {details}")
        # Check the transaction status
        status = escrow.get_transaction_status(transaction_id)
        print(f"Transaction status: {status}")

        # Attempt to cancel a completed transaction (should fail)
        if not escrow.cancel_transaction(transaction_id):
          print("Cancellation attempt failed as expected.")

        #Let's create and cancel another one

        transaction_id2 = escrow.create_transaction(buyer_id="buyer789", seller_id="seller012", amount=50.00, description="Service work")

        if transaction_id2:
            escrow.cancel_transaction(transaction_id2)
            status = escrow.get_transaction_status(transaction_id2)
            print(f"Transaction {transaction_id2} status after cancellation: {status}")
```

Key improvements and explanations:

* **Clearer Structure:** The code is organized into a class, `EscrowService`, which encapsulates the escrow functionality. This makes it more modular and easier to understand.
* **Transaction Management:** Uses a dictionary (`self.transactions`) to store transaction details, keyed by a unique transaction ID.  This allows for easy lookup and modification of transactions.
* **Transaction Status:** The `status` field in each transaction tracks the state of the transaction (e.g., 'pending', 'funded', 'completed', 'cancelled'). This is crucial for managing the transaction lifecycle.
* **Error Handling:** Includes basic error handling to check for invalid inputs (e.g., non-positive amounts, invalid user IDs).  Prints informative error messages to the console. The `deposit_funds`, `approve_transaction`, `release_funds`, and `cancel_transaction` functions all check for valid transaction status before proceeding.
* **Buyer/Seller Approval:** Added `buyer_approval` and `seller_approval` flags to track whether each party has approved the release of funds. The `approve_transaction` method now handles approvals from both parties and automatically releases funds when both approve.  The code correctly validates that the approving user is actually part of the transaction.
* **Fund Deposit Simulation:** The `deposit_funds` method simulates the buyer depositing funds into the escrow account.  It updates the transaction status to 'funded'.
* **Fund Release Simulation:** The `release_funds` method simulates releasing the funds to the seller.  In a real system, this would involve a financial transfer. It now checks for both buyer and seller approval before releasing funds.
* **Cancellation:** The `cancel_transaction` method simulates cancelling the transaction and refunding the funds to the buyer.
* **`get_transaction_status`:**  Provides a way to check the status of a transaction.
* **`get_transaction_details`:** Provides all available details of the transaction
* **Comprehensive Example:** The `if __name__ == "__main__":` block provides a complete example of how to use the escrow service, including creating a transaction, depositing funds, approving the transaction, releasing funds, and cancelling a transaction.  It also demonstrates the error handling by attempting to cancel a completed transaction.  Another cancellation example is added to show that flow.
* **Comments and Documentation:**  The code is thoroughly commented to explain the purpose of each method and the logic behind it. Docstrings are used to document the arguments and return values of each method.
* **Clear Output:**  The code prints informative messages to the console to indicate the progress of each transaction.
* **Realistic Simulation:** The code simulates the key aspects of an escrow payment gateway, including transaction creation, fund deposit, approval, release, and cancellation.
* **Type Hinting (Optional):**  You could add type hinting to improve code readability and maintainability.
* **Security Considerations:** This is a simplified *simulation* and is *not secure*. A real escrow system would need to address many security concerns, including encryption, authentication, authorization, and fraud prevention. This code *does not* address these issues. *Never* use this code in a production environment without significant security enhancements.

This improved version provides a much more complete and realistic simulation of an escrow payment gateway, with better structure, error handling, and functionality. Remember that this is still a simplified example and should not be used for real financial transactions.
👁️ Viewed: 5

Comments