-
Notifications
You must be signed in to change notification settings - Fork 8
Sample Project Banking
valhuber edited this page Jan 1, 2021
·
6 revisions
This illustrates complex logic, including multiple sums, integrated with a Python event.
cd examples/banking/tests
python transfer_funds.py
Customers
have Checking
and Savings
accounts, with _Trans
details for deposits and withdrawals.
The logic rolls up the transaction / accounts into the customer, and verifies the balance.
It also provides for TRANSFERFUND
, explored below.
def activate_basic_rules():
def transfer_funds(row: TRANSFERFUND, old_row: TRANSFERFUND, logic_row: LogicRow):
"""
Command Pattern: insert (and save) transfer_funds row
Rules then adjust Checking and Customer rollups, and validate credit
"""
if logic_row.ins_upd_dlt == "ins" or True: # logic engine fills parents for insert
logic_row.log("Transfer from source to target")
fromCustNum = row.FromCustNum
toCustNum = row.ToCustNum
acctNum = row.FromAcct
trans_date = datetime.datetime(2020, 10, 1)
transferAmt = row.TransferAmt
transID = row.TransId
# need to lookup the From Acct to see if it is checking or savings - that way we can reverse the flow
deposit = models.SAVINGSTRANS(TransId=transID, CustNum=toCustNum, AcctNum=acctNum, DepositAmt=transferAmt, WithdrawlAmt=0,
TransDate=trans_date)
logic_row.insert("Deposit to savings", deposit)
withdrawal = models.CHECKINGTRANS(TransId=transID, CustNum=fromCustNum, AcctNum=acctNum,
DepositAmt=0, WithdrawlAmt=transferAmt, TransDate=trans_date)
logic_row.insert("Withdraw from CHECKINGTRANS", withdrawal)
Rule.sum(derive=CHECKING.Deposits, as_sum_of=CHECKINGTRANS.DepositAmt)
Rule.sum(derive=CHECKING.Withdrawls, as_sum_of=CHECKINGTRANS.WithdrawlAmt)
Rule.formula(derive=CHECKING.AvailableBalance, as_expression=lambda row: row.Deposits - row.Withdrawls)
Rule.count(derive=CHECKING.ItemCount, as_count_of=CHECKINGTRANS)
Rule.sum(derive=CUSTOMER.CheckingAcctBal, as_sum_of=CHECKING.AvailableBalance)
Rule.sum(derive=CUSTOMER.SavingsAcctBal, as_sum_of=SAVING.AvailableBalance)
Rule.formula(derive=CUSTOMER.TotalBalance, as_expression=lambda row: row.CheckingAcctBal + row.SavingsAcctBal)
Rule.constraint(validate=CUSTOMER,
as_condition=lambda row: row.CheckingAcctBal >= 0,
error_msg="Your Checking balance of ({row.CheckingAcctBal}) is less than 0)")
Rule.constraint(validate=CUSTOMER,
as_condition=lambda row: row.SavingsAcctBal >= 0,
error_msg="Your Savings balance of ({row.SavingsAcctBal}) is less than 0)")
Rule.sum(derive=SAVING.Withdrawls, as_sum_of=SAVINGSTRANS.WithdrawlAmt)
Rule.sum(derive=SAVING.Deposits, as_sum_of=SAVINGSTRANS.DepositAmt)
Rule.formula(derive=SAVING.AvailableBalance, as_expression=lambda row: row.Deposits - row.Withdrawls)
Rule.count(derive=SAVING.ItemCount, as_count_of=SAVINGSTRANS)
Rule.formula(derive=CHECKINGTRANS.Total, as_expression=lambda row: row.DepositAmt - row.WithdrawlAmt)
Rule.formula(derive=SAVINGSTRANS.Total, as_expression=lambda row: row.DepositAmt - row.WithdrawlAmt)
Rule.commit_row_event(on_class=TRANSFERFUND, calling=transfer_funds)
Let's explore examples/banking/tests/transfer_funds.py
trans_date = datetime(2020, 10, 1)
deposit = models.CHECKINGTRANS(TransId=1, CustNum=1, AcctNum=1,
DepositAmt=100, WithdrawlAmt=0, TransDate=trans_date)
print("\n\nCustomer Account Deposit Checking Setup - Deposit $100 to CHECKINGTRANS ")
session.add(deposit)
session.commit()
Which:
- Adjusts
derive=CHECKING.Deposits, as_sum_of=CHECKINGTRANS.DepositAmt
- Adjusts
derive=CHECKING.ItemCount, as_count_of=CHECKINGTRANS
- Which recomputes
derive=CHECKING.AvailableBalance, as_expression=lambda row: row.Deposits - row.Withdrawls
- Which adjusts
derive=CUSTOMER.CheckingAcctBal, as_sum_of=CHECKING.AvailableBalance
Visible in the log:
Customer Account Deposit Checking Setup - Deposit $100 to CHECKINGTRANS
Logic Phase: BEFORE COMMIT - 2020-10-06 08:01:37,290 - logic_logger - DEBUG
Logic Phase: ROW LOGIC (sqlalchemy before_flush) - 2020-10-06 08:01:37,290 - logic_logger - DEBUG
/Users/val/python/pycharm/Logic-Bank/venv/lib/python3.8/site-packages/sqlalchemy/sql/sqltypes.py:661: SAWarning: Dialect sqlite+pysqlite does *not* support Decimal objects natively, and SQLAlchemy must convert from floating point - rounding errors and other issues may occur. Please consider storing Decimal numbers as strings or integers on this platform for lossless storage.
util.warn(
..CHECKINGTRANS[1] {Insert - client} AcctNum: 1, ChkNo: None, CustNum: 1, DepositAmt: 100, ImageURL: None, Total: None, TransDate: 2020-10-01 00:00:00, TransId: 1, WithdrawlAmt: 0 row@: 0x10ee03850 - 2020-10-06 08:01:37,292 - logic_logger - DEBUG
..CHECKINGTRANS[1] {Formula Total} AcctNum: 1, ChkNo: None, CustNum: 1, DepositAmt: 100, ImageURL: None, Total: 100, TransDate: 2020-10-01 00:00:00, TransId: 1, WithdrawlAmt: 0 row@: 0x10ee03850 - 2020-10-06 08:01:37,321 - logic_logger - DEBUG
....CHECKING[1 | 1] {Update - Adjusting CHECKING} AcctNum: 1, AcctType: C, AvailableBalance: 0.00, CreditCode: 1, CreditLimit: 1000.00, CurrentBalance: 0.00, CustNum: 1, Deposits: [0.00-->] 100.00, ItemCount: [0-->] 1, Withdrawls: 0.00 row@: 0x10f876310 - 2020-10-06 08:01:37,324 - logic_logger - DEBUG
....CHECKING[1 | 1] {Formula AvailableBalance} AcctNum: 1, AcctType: C, AvailableBalance: [0.00-->] 100.00, CreditCode: 1, CreditLimit: 1000.00, CurrentBalance: 0.00, CustNum: 1, Deposits: [0.00-->] 100.00, ItemCount: [0-->] 1, Withdrawls: 0.00 row@: 0x10f876310 - 2020-10-06 08:01:37,325 - logic_logger - DEBUG
......CUSTOMER[1] {Update - Adjusting CUSTOMER} CheckingAcctBal: [0.00-->] 100.00, City: Daytona Beach, CustNum: 1, Name: Tyler Bank, Phone: 5556078094, SavingsAcctBal: 0.00, State: FL, Street: 1234 N BEACH ST, TotalBalance: 0.00, ZIP: 32174, emailAddress: [email protected] row@: 0x10f876250 - 2020-10-06 08:01:37,335 - logic_logger - DEBUG
......CUSTOMER[1] {Formula TotalBalance} CheckingAcctBal: [0.00-->] 100.00, City: Daytona Beach, CustNum: 1, Name: Tyler Bank, Phone: 5556078094, SavingsAcctBal: 0.00, State: FL, Street: 1234 N BEACH ST, TotalBalance: [0.00-->] 100.00, ZIP: 32174, emailAddress: [email protected] row@: 0x10f876250 - 2020-10-06 08:01:37,336 - logic_logger - DEBUG
Logic Phase: COMMIT - 2020-10-06 08:01:37,340 - logic_logger - DEBUG
Logic Phase: FLUSH (sqlalchemy flush processing - 2020-10-06 08:01:37,340 - logic_logger - DEBUG
..CUSTOMER[1] {Customer Account Deposit Checking Setup OK - balance is 100} CheckingAcctBal: [0.00-->] 100.00, City: Daytona Beach, CustNum: 1, Name: Tyler Bank, Phone: 5556078094, SavingsAcctBal: 0.00, State: FL, Street: 1234 N BEACH ST, TotalBalance: [0.00-->] 100.00, ZIP: 32174, emailAddress: [email protected] row@: 0x10f876250 - 2020-10-06 08:01:37,358 - logic_logger - DEBUG
Operates as follows:
- Client inserts a
TRANSFER_FUNDS
row- Per Command Pattern, this runs
transfer_funds()
in theCommit Logic
Phase - It inserts
Savings
andChecking
rows
- Per Command Pattern, this runs
- Sum rules adjust
Savings.Deposits
- Which chains to adjust
Customer.CheckingAcctBal
"""
********* Transfer 10 from checking to savings (main test) *********
"""
transfer = models.TRANSFERFUND(TransId=2, FromCustNum=1, FromAcct=1, ToCustNum=1, ToAcct=1, TransferAmt=10, TransDate=trans_date)
print("\n\nTransfer 10 from checking to savings (main test) ")
session.add(transfer)
session.commit()
The portion of the log from the main test:
Transfer 10 from checking to savings (main test)
Logic Phase: BEFORE COMMIT - 2020-10-06 07:57:35,962 - logic_logger - DEBUG
Logic Phase: ROW LOGIC (sqlalchemy before_flush) - 2020-10-06 07:57:35,962 - logic_logger - DEBUG
..TRANSFERFUND[2] {Insert - client} FromAcct: 1, FromCustNum: 1, ToAcct: 1, ToCustNum: 1, TransDate: 2020-10-01 00:00:00, TransId: 2, TransferAmt: 10 row@: 0x10c634280 - 2020-10-06 07:57:35,963 - logic_logger - DEBUG
Logic Phase: COMMIT - 2020-10-06 07:57:35,975 - logic_logger - DEBUG
..TRANSFERFUND[2] {Commit Event} FromAcct: 1, FromCustNum: 1, ToAcct: 1, ToCustNum: 1, TransDate: 2020-10-01 00:00:00, TransId: 2, TransferAmt: 10 row@: 0x10c634280 - 2020-10-06 07:57:35,976 - logic_logger - DEBUG
..TRANSFERFUND[2] {Transfer from source to target} FromAcct: 1, FromCustNum: 1, ToAcct: 1, ToCustNum: 1, TransDate: 2020-10-01 00:00:00, TransId: 2, TransferAmt: 10 row@: 0x10c634280 - 2020-10-06 07:57:35,977 - logic_logger - DEBUG
....SAVINGSTRANS[2] {Insert - Deposit to savings} AcctNum: 1, CustNum: 1, DepositAmt: 10, Total: None, TransDate: 2020-10-01 00:00:00, TransId: 2, WithdrawlAmt: 0 row@: 0x10c677a00 - 2020-10-06 07:57:35,979 - logic_logger - DEBUG
....SAVINGSTRANS[2] {Formula Total} AcctNum: 1, CustNum: 1, DepositAmt: 10, Total: [None-->] 10, TransDate: 2020-10-01 00:00:00, TransId: 2, WithdrawlAmt: 0 row@: 0x10c677a00 - 2020-10-06 07:57:35,988 - logic_logger - DEBUG
......SAVING[1 | 1] {Update - Adjusting SAVING} AcctNum: 1, AcctType: S, AvailableBalance: 0.00, CurrentBalance: 0.00, CustNum: 1, Deposits: [0.00-->] 10.00, ItemCount: [0-->] 1, Withdrawls: 0.00 row@: 0x10c6888b0 - 2020-10-06 07:57:35,990 - logic_logger - DEBUG
......SAVING[1 | 1] {Formula AvailableBalance} AcctNum: 1, AcctType: S, AvailableBalance: [0.00-->] 10.00, CurrentBalance: 0.00, CustNum: 1, Deposits: [0.00-->] 10.00, ItemCount: [0-->] 1, Withdrawls: 0.00 row@: 0x10c6888b0 - 2020-10-06 07:57:35,990 - logic_logger - DEBUG
........CUSTOMER[1] {Update - Adjusting CUSTOMER} CheckingAcctBal: 100.00, City: Daytona Beach, CustNum: 1, Name: Tyler Bank, Phone: 5556078094, SavingsAcctBal: [0.00-->] 10.00, State: FL, Street: 1234 N BEACH ST, TotalBalance: 100.00, ZIP: 32174, emailAddress: tyler.bank@acme.com row@: 0x10c6775b0 - 2020-10-06 07:57:35,993 - logic_logger - DEBUG
........CUSTOMER[1] {Formula TotalBalance} CheckingAcctBal: 100.00, City: Daytona Beach, CustNum: 1, Name: Tyler Bank, Phone: 5556078094, SavingsAcctBal: [0.00-->] 10.00, State: FL, Street: 1234 N BEACH ST, TotalBalance: [100.00-->] 110.00, ZIP: 32174, emailAddress: tyler.bank@acme.com row@: 0x10c6775b0 - 2020-10-06 07:57:35,993 - logic_logger - DEBUG
....CHECKINGTRANS[2] {Insert - Withdraw from CHECKINGTRANS} AcctNum: 1, ChkNo: None, CustNum: 1, DepositAmt: 0, ImageURL: None, Total: None, TransDate: 2020-10-01 00:00:00, TransId: 2, WithdrawlAmt: 10 row@: 0x10c677280 - 2020-10-06 07:57:35,996 - logic_logger - DEBUG
....CHECKINGTRANS[2] {Formula Total} AcctNum: 1, ChkNo: None, CustNum: 1, DepositAmt: 0, ImageURL: None, Total: [None-->] -10, TransDate: 2020-10-01 00:00:00, TransId: 2, WithdrawlAmt: 10 row@: 0x10c677280 - 2020-10-06 07:57:36,000 - logic_logger - DEBUG
......CHECKING[1 | 1] {Update - Adjusting CHECKING} AcctNum: 1, AcctType: C, AvailableBalance: 100.00, CreditCode: 1, CreditLimit: 1000.00, CurrentBalance: 0.00, CustNum: 1, Deposits: 100.00, ItemCount: [1-->] 2, Withdrawls: [0.00-->] 10.00 row@: 0x10c634310 - 2020-10-06 07:57:36,001 - logic_logger - DEBUG
......CHECKING[1 | 1] {Formula AvailableBalance} AcctNum: 1, AcctType: C, AvailableBalance: [100.00-->] 90.00, CreditCode: 1, CreditLimit: 1000.00, CurrentBalance: 0.00, CustNum: 1, Deposits: 100.00, ItemCount: [1-->] 2, Withdrawls: [0.00-->] 10.00 row@: 0x10c634310 - 2020-10-06 07:57:36,002 - logic_logger - DEBUG
........CUSTOMER[1] {Update - Adjusting CUSTOMER} CheckingAcctBal: [100.00-->] 90.00, City: Daytona Beach, CustNum: 1, Name: Tyler Bank, Phone: 5556078094, SavingsAcctBal: 10.00, State: FL, Street: 1234 N BEACH ST, TotalBalance: 110.00, ZIP: 32174, emailAddress: tyler.bank@acme.com row@: 0x10c6775b0 - 2020-10-06 07:57:36,003 - logic_logger - DEBUG
........CUSTOMER[1] {Formula TotalBalance} CheckingAcctBal: [100.00-->] 90.00, City: Daytona Beach, CustNum: 1, Name: Tyler Bank, Phone: 5556078094, SavingsAcctBal: 10.00, State: FL, Street: 1234 N BEACH ST, TotalBalance: [110.00-->] 100.00, ZIP: 32174, emailAddress: tyler.bank@acme.com row@: 0x10c6775b0 - 2020-10-06 07:57:36,004 - logic_logger - DEBUG
Logic Phase: FLUSH (sqlalchemy flush processing - 2020-10-06 07:57:36,005 - logic_logger - DEBUG
Developed with PyCharm
User Project Operations
Logic Bank Internals