Skip to content

Commit

Permalink
Merge pull request #41 from EventStore/tony-20240320
Browse files Browse the repository at this point in the history
Loan Application Demo v2.0 code push
  • Loading branch information
realtonyyoung authored Mar 20, 2024
2 parents 0083437 + 3ff0221 commit 3382190
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 30 deletions.
21 changes: 14 additions & 7 deletions LoanApplication/Python/CreditCheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import config
import time
import traceback
import datetime
import random

# Print some information messages to the user
print("\n\n***** CreditCheck *****\n")
Expand Down Expand Up @@ -53,13 +55,17 @@
# For each eent received
for loan_request_event in persistent_subscription:
# Introduce some delay
time.sleep(5)
time.sleep(config.CLIENT_PRE_WORK_DELAY)

if config.DEBUG:
print(' Received event: id=' + str(loan_request_event.id) + '; type=' + loan_request_event.type + '; stream_name=' + str(loan_request_event.stream_name) + '; data=\'' + str(loan_request_event.data) + '\'')

# Get the current commit version of the loan request stream for this loan request
COMMIT_VERSION = esdb.get_current_version(stream_name=loan_request_event.stream_name)

# Get the event data out of JSON format and into a python dictionary so we can use it
_loan_request_data = json.loads(loan_request_event.data)
_loan_request_metadata = json.loads(loan_request_event.metadata)

# Create a data structure to hold the credit score that we will return
_credit_score = -1
Expand All @@ -76,26 +82,27 @@
_credit_score = 1
# If we can't map the user name to one of the above, send for manual processing
else:
_credit_score = 5
_credit_score = random.randint(1,10)

_ts = str(datetime.datetime.now())

# Create a dictionary with the credit check data
_credit_checked_event_data = {"Score": _credit_score, "NationalID": _loan_request_data.get("NationalID")}
_credit_checked_event_data = {"Score": _credit_score, "NationalID": _loan_request_data.get("NationalID"), "CreditCheckedTimestamp": _ts}
_credit_checked_event_metadata = {"$correlationId": _loan_request_metadata.get("$correlationId"), "$causationId": str(loan_request_event.id), "transactionTimestamp": _ts}
# Create a credit checked event with the event data
credit_checked_event = NewEvent(type=config.EVENT_TYPE_CREDIT_CHECKED, data=bytes(json.dumps(_credit_checked_event_data), 'utf-8'))
credit_checked_event = NewEvent(type=config.EVENT_TYPE_CREDIT_CHECKED, metadata=bytes(json.dumps(_credit_checked_event_metadata), 'utf-8'), data=bytes(json.dumps(_credit_checked_event_data), 'utf-8'))

if config.DEBUG:
print(' Processing credit check - CreditChecked: ' + str(_credit_checked_event_data) + '\n')

print(' Processing credit check - CreditChecked for NationalID ' + str(_credit_checked_event_data["NationalID"]) + ' with a Score of ' + str(_credit_checked_event_data["Score"]))

# Get the current commit version of the loan request stream for this loan request
COMMIT_VERSION = esdb.get_current_version(stream_name=loan_request_event.stream_name)
# Append the event to the stream
CURRENT_POSITION = esdb.append_to_stream(stream_name=loan_request_event.stream_name, current_version=COMMIT_VERSION, events=[credit_checked_event])

# Acknowledge the original event
persistent_subscription.ack(loan_request_event.ack_id)

# Introduce some delay
time.sleep(5)
time.sleep(config.CLIENT_POST_WORK_DELAY)

21 changes: 15 additions & 6 deletions LoanApplication/Python/LoanDecider.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import config
import time
import traceback
import datetime

# Print some messages for the user
print("\n\n***** LoanDecider *****\n")
Expand Down Expand Up @@ -63,11 +64,17 @@
# For each event in the subscription
for credit_check_event in catchup_subscription:
# Introduce some delay
time.sleep(5)
time.sleep(config.CLIENT_PRE_WORK_DELAY)

if config.DEBUG:
print(' Received event: id=' + str(credit_check_event.id) + '; type=' + credit_check_event.type + '; stream_name=' + str(credit_check_event.stream_name) + '; data=\'' + str(credit_check_event.data) + '\'')

# Get the current commit version for the stream to which we will append
COMMIT_VERSION = esdb.get_current_version(stream_name=credit_check_event.stream_name)

# Get the metadata for the credit check event
_credit_check_metadata = json.loads(credit_check_event.metadata)

# We need to reconstruct state so that we can decide whether to automatically or manually process the loan, and push it onwards for further processing
# Read the stream for this loan request
state_stream = esdb.read_stream(credit_check_event.stream_name)
Expand Down Expand Up @@ -99,18 +106,20 @@
else:
_decision_event_type = config.EVENT_TYPE_LOAN_AUTO_DENIED

_ts = str(datetime.datetime.now())

# Create a dictionary holding the elements of the loan decision
_decision_event_data = {"LoanRequestID": _state_data.get("LoanRequestID")}
_decision_event_data = {"LoanRequestID": _state_data.get("LoanRequestID"), "LoanAutomatedDecisionTimestamp": _ts}
_decision_event_metadata = {"$correlationId": _credit_check_metadata.get("$correlationId"), "$causationId": str(credit_check_event.id), "transactionTimestamp": _ts}

# Create a decision event
decision_event = NewEvent(type=_decision_event_type, data=bytes(json.dumps(_decision_event_data), 'utf-8'))
decision_event = NewEvent(type=_decision_event_type, metadata=bytes(json.dumps(_decision_event_metadata), 'utf-8'), data=bytes(json.dumps(_decision_event_data), 'utf-8'))

if config.DEBUG:
print(' Processing loan decision - ' + _decision_event_type + ': ' + str(_decision_event_data) + '\n')

print(' Processing loan decision for ' + _state_data['User'] + ' with Score of ' + str(_state_data['Score']) + ' - ' + _decision_event_type + '\n Appending to stream: ' + credit_check_event.stream_name + '\n')

# Get the current commit version for the stream to which we will append
COMMIT_VERSION = esdb.get_current_version(stream_name=credit_check_event.stream_name)
# Append the decision event to the stream
CURRENT_POSITION = esdb.append_to_stream(stream_name=credit_check_event.stream_name, current_version=COMMIT_VERSION, events=[decision_event])

Expand All @@ -124,5 +133,5 @@
print(' Checkpoint: ' + str(credit_check_event.link.stream_position) + '\n')

# Introduce some delay
time.sleep(5)
time.sleep(config.CLIENT_POST_WORK_DELAY)

63 changes: 63 additions & 0 deletions LoanApplication/Python/LoanRequestor-commandLine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Import needed libraries
from esdbclient import EventStoreDBClient, NewEvent, StreamState
import json
import config
import time
import traceback
import uuid
import datetime

# Print some information for the user
print("\n\n***** Loan Request Command Processor *****\n")

if config.DEBUG:
print('Connecting to ESDB...')

# Create a connection to ESDB
while True:
try:
# Connect to ESDB using the URL in the config file
esdb = EventStoreDBClient(uri=config.ESDB_URL)

if config.DEBUG:
print(' Connection succeeded!')

# If the connection was successul, exit the loop
break
# If the connection fails, retry again in 10 seconds
except:
print('Connection to ESDB failed, retrying in 10 seconds...')
traceback.print_exc()
time.sleep(10)

# Loop through the samples and append events into the ESDB streams
while True:
print("Requesting a loan:")
# Get the input field data
_user = input(" What is the applicant's name? ")
_nationalid = input(" What is the applicant's national ID? ")
_amount = input(" What is the amount requested? ")
_address = input(" What is the applicant's street address? ")
_city = input(" What is the applicant's city? ")
_region = input(" What is the applicant's region? ")
_country = input(" What is the applicant's country? ")
_postal = input(" What is the applicant's postal code? ")
_loanrequestid = str(uuid.uuid4())
_ts = str(datetime.datetime.now())

# Create a dictionary for the event data, and compose the stream name to which we will append it
_loan_request_data = {"User": _user, "NationalID": _nationalid, "Amount": _amount, "LoanRequestID": _loanrequestid, "LoanRequestedTimestamp": _ts, "RequestorAddress": _address, "RequestorCity": _city, "RequestorRegion": _region, "RequestorCountry": _country, "RequestorPostalCode": _postal}
_loan_request_metadata = {"$correlationId": _loanrequestid, "$causationId": _loanrequestid, "transactionTimestamp": _ts}
_loan_request_stream_name = config.STREAM_PREFIX + '-' + _loanrequestid

# Create a loan request event
loan_request_event = NewEvent(type=config.EVENT_TYPE_LOAN_REQUESTED, metadata=bytes(json.dumps(_loan_request_metadata), 'utf-8'), data=bytes(json.dumps(_loan_request_data), 'utf-8'), id=_loanrequestid)

print('Command Received - LoanRequested: ' + str(_loan_request_data) + '\n Appending to stream: ' + _loan_request_stream_name + '\n\n')

# Append the event to the stream
CURRENT_POSITION = esdb.append_to_stream(stream_name=_loan_request_stream_name, current_version=StreamState.ANY, events=[loan_request_event])

# Wait a few seconds to let the event wind through the system
time.sleep(20)

22 changes: 16 additions & 6 deletions LoanApplication/Python/LoanRequestor-testCases.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import time
import traceback
import uuid
import datetime

# Print some information for the user
print("\n\n***** Loan Request Command Processor *****\n")
Expand All @@ -31,30 +32,39 @@

# Let's create some event data that will be appended to ESDB streams, simulating loan approval requests
_loan_request_data = []
_loan_request_metadata = []
_loan_request_stream_name = []
_loan_request_uuid = []

# Simulate an automatically approved loan
_uuid = str(uuid.uuid4())
_loan_request_data.append({"User": "Yves", "NationalID": 12345, "Amount": 10000, "LoanRequestID": _uuid})
_ts = str(datetime.datetime.now())
_loan_request_data.append({"User": "Yves", "NationalID": 12345, "Amount": 10000, "LoanRequestID": _uuid, "LoanRequestedTimestamp": _ts, "RequestorAddress": "123 Outta My Way", "RequestorCity": "Anytown", "RequestorRegion": "Wideopen", "RequestorCountry": "Fakeland", "RequestorPostalCode": "ABC 123"})
_loan_request_metadata.append({"$correlationId": _uuid, "$causationId": _uuid, "transactionTimestamp": _ts})
_loan_request_stream_name.append(config.STREAM_PREFIX + '-' + _uuid)
_loan_request_uuid.append(_uuid)

# Simulate a loan requiring manual approval / denial
_uuid = str(uuid.uuid4())
_loan_request_data.append({"User": "Tony", "NationalID": 54321, "Amount": 5000, "LoanRequestID": _uuid})
_ts = str(datetime.datetime.now())
_loan_request_data.append({"User": "Tony", "NationalID": 54321, "Amount": 5000, "LoanRequestID": _uuid, "LoanRequestedTimestamp": _ts, "RequestorAddress": "456 Some Street", "RequestorCity": "Prettyville", "RequestorRegion": "Wideopen", "RequestorCountry": "Fakeland", "RequestorPostalCode": "DEF 342"})
_loan_request_metadata.append({"$correlationId": _uuid, "$causationId": _uuid, "transactionTimestamp": _ts})
_loan_request_stream_name.append(config.STREAM_PREFIX + '-' + _uuid)
_loan_request_uuid.append(_uuid)

# Simulate another loan requiring manual approval / denial
_uuid = str(uuid.uuid4())
_loan_request_data.append({"User": "David", "NationalID": 43521, "Amount": 5000, "LoanRequestID": _uuid})
_ts = str(datetime.datetime.now())
_loan_request_data.append({"User": "David", "NationalID": 43521, "Amount": 5000, "LoanRequestID": _uuid, "LoanRequestedTimestamp": _ts, "RequestorAddress": "789 Back Lane", "RequestorCity": "Smalltown", "RequestorRegion": "Wideopen", "RequestorCountry": "Fakeland", "RequestorPostalCode": "GHJ 876"})
_loan_request_metadata.append({"$correlationId": _uuid, "$causationId": _uuid, "transactionTimestamp": _ts})
_loan_request_stream_name.append(config.STREAM_PREFIX + '-' + _uuid)
_loan_request_uuid.append(_uuid)

# Simulate a loan that is automatically denied
_uuid = str(uuid.uuid4())
_loan_request_data.append({"User": "Rob", "NationalID": 34251, "Amount": 3000, "LoanRequestID": _uuid})
_ts = str(datetime.datetime.now())
_loan_request_data.append({"User": "Rob", "NationalID": 34251, "Amount": 3000, "LoanRequestID": _uuid, "LoanRequestedTimestamp": _ts, "RequestorAddress": "742 Evergreen Terrace", "RequestorCity": "Springton", "RequestorRegion": "Wideopen", "RequestorCountry": "Fakeland", "RequestorPostalCode": "TSE 184"})
_loan_request_metadata.append({"$correlationId": _uuid, "$causationId": _uuid, "transactionTimestamp": _ts})
_loan_request_stream_name.append(config.STREAM_PREFIX + '-' + _uuid)
_loan_request_uuid.append(_uuid)

Expand All @@ -63,15 +73,15 @@
# Loop through the samples and append events into the ESDB streams
while loop_counter < len(_loan_request_data):
# Create a loan request event
loan_request_event = NewEvent(type=config.EVENT_TYPE_LOAN_REQUESTED, data=bytes(json.dumps(_loan_request_data[loop_counter]), 'utf-8'), id=_loan_request_uuid[loop_counter])
loan_request_event = NewEvent(type=config.EVENT_TYPE_LOAN_REQUESTED, metadata=bytes(json.dumps(_loan_request_metadata[loop_counter]), 'utf-8'), data=bytes(json.dumps(_loan_request_data[loop_counter]), 'utf-8'), id=_loan_request_uuid[loop_counter])

print('Command Received - LoanRequested: ' + str(_loan_request_data[loop_counter]) + '\n Appending to stream: ' + _loan_request_stream_name[loop_counter])

# Append the event to the stream
CURRENT_POSITION = esdb.append_to_stream(stream_name=_loan_request_stream_name[loop_counter], current_version=StreamState.ANY, events=[loan_request_event])

# Wait a few seconds to let the event wind through the system
time.sleep(10)
time.sleep(20)

# Increment the loop counter
loop_counter+=1
Expand Down
39 changes: 36 additions & 3 deletions LoanApplication/Python/LoanRequestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import time
import traceback
import uuid
import datetime

# Create some variables to hold state with the GUI
esdb = None
Expand Down Expand Up @@ -45,7 +46,7 @@ def __init__(self):

# Add the panel to the window, and create a grid to hold the labels, inputs, and button
panel = wx.Panel(self)
field_grid = wx.GridSizer(rows=5, cols=2, hgap=5, vgap=5)
field_grid = wx.GridSizer(rows=10, cols=2, hgap=5, vgap=5)

# Create fields and labels for the User, NationalID, and Amount data
self.field_user = wx.TextCtrl(panel)
Expand All @@ -54,6 +55,16 @@ def __init__(self):
self.label_nationalid = wx.StaticText(panel, wx.ID_ANY, 'NationalID')
self.field_amount = wx.TextCtrl(panel)
self.label_amount = wx.StaticText(panel, wx.ID_ANY, 'Amount')
self.field_address = wx.TextCtrl(panel)
self.label_address = wx.StaticText(panel, wx.ID_ANY, 'Address')
self.field_city = wx.TextCtrl(panel)
self.label_city = wx.StaticText(panel, wx.ID_ANY, 'City')
self.field_region = wx.TextCtrl(panel)
self.label_region = wx.StaticText(panel, wx.ID_ANY, 'Region')
self.field_country = wx.TextCtrl(panel)
self.label_country = wx.StaticText(panel, wx.ID_ANY, 'Country')
self.field_postal = wx.TextCtrl(panel)
self.label_postal = wx.StaticText(panel, wx.ID_ANY, 'Postal Code')

# Create a read-only field and label for the LoanRequestID data, which we'll set to a UUID
self.field_loanrequestid = wx.TextCtrl(panel, style=wx.TE_READONLY)
Expand All @@ -66,6 +77,16 @@ def __init__(self):
field_grid.Add(self.field_nationalid, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.label_amount, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.field_amount, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.label_address, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.field_address, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.label_city, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.field_city, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.label_region, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.field_region, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.label_country, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.field_country, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.label_postal, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.field_postal, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.label_loanrequestid, 0, wx.ALL | wx.EXPAND)
field_grid.Add(self.field_loanrequestid, 0, wx.ALL | wx.EXPAND)

Expand Down Expand Up @@ -94,14 +115,21 @@ def on_press(self, event):
_user = self.field_user.GetValue()
_nationalid = self.field_nationalid.GetValue()
_amount = self.field_amount.GetValue()
_address = self.field_address.GetValue()
_city = self.field_city.GetValue()
_region = self.field_region.GetValue()
_country = self.field_country.GetValue()
_postal = self.field_postal.GetValue()
_loanrequestid = self.field_loanrequestid.GetValue()
_ts = str(datetime.datetime.now())

# Create a dictionary for the event data, and compose the stream name to which we will append it
_loan_request_data = {"User": _user, "NationalID": _nationalid, "Amount": _amount, "LoanRequestID": _loanrequestid}
_loan_request_data = {"User": _user, "NationalID": _nationalid, "Amount": _amount, "LoanRequestID": _loanrequestid, "LoanRequestedTimestamp": _ts, "RequestorAddress": _address, "RequestorCity": _city, "RequestorRegion": _region, "RequestorCountry": _country, "RequestorPostalCode": _postal}
_loan_request_metadata = {"$correlationId": _loanrequestid, "$causationId": _loanrequestid, "transactionTimestamp": _ts}
_loan_request_stream_name = config.STREAM_PREFIX + '-' + _loanrequestid

# Create a loan request event
loan_request_event = NewEvent(type=config.EVENT_TYPE_LOAN_REQUESTED, data=bytes(json.dumps(_loan_request_data), 'utf-8'), id=_loanrequestid)
loan_request_event = NewEvent(type=config.EVENT_TYPE_LOAN_REQUESTED, metadata=bytes(json.dumps(_loan_request_metadata), 'utf-8'), data=bytes(json.dumps(_loan_request_data), 'utf-8'), id=_loanrequestid)

print('Command Received - LoanRequested: ' + str(_loan_request_data) + '\n Appending to stream: ' + _loan_request_stream_name)

Expand All @@ -112,6 +140,11 @@ def on_press(self, event):
self.field_user.SetValue('')
self.field_nationalid.SetValue('')
self.field_amount.SetValue('')
self.field_address.SetValue('')
self.field_city.SetValue('')
self.field_region.SetValue('')
self.field_country.SetValue('')
self.field_postal.SetValue('')
self.field_loanrequestid.SetValue(str(uuid.uuid4()))

# Create a GUI panel to show submitted and approved / denied applications
Expand Down
Loading

0 comments on commit 3382190

Please sign in to comment.