|
@@ -1504,6 +1504,45 @@ def loan_id_exists(loan_id):
|
|
|
return current_cursor.fetchone()[0]
|
|
|
|
|
|
|
|
|
+def time_travel(delta_t):
|
|
|
+ """
|
|
|
+ Modify all timestamps in the database by -delta_t.
|
|
|
+ A positive delta_t travels into the future, a negative delta_t to the past.
|
|
|
+ Be careful with time travel into the past though.
|
|
|
+ :param delta_t: time in seconds to travel
|
|
|
+ """
|
|
|
+ tables = execute('''
|
|
|
+ SELECT name
|
|
|
+ FROM sqlite_master
|
|
|
+ WHERE type = 'table'
|
|
|
+ ''').fetchall()
|
|
|
+
|
|
|
+ for (table,) in tables:
|
|
|
+ columns = execute(f'''
|
|
|
+ SELECT * FROM {table}
|
|
|
+ LIMIT 1
|
|
|
+ ''').description
|
|
|
+ timestamp_columns = []
|
|
|
+ for column in columns:
|
|
|
+ name = column[0]
|
|
|
+ if re.search(r'(?:^|_)dt(?:$|_)', name):
|
|
|
+ timestamp_columns.append(name)
|
|
|
+ if len(timestamp_columns) != 0:
|
|
|
+ updates = ',\n'.join(f'"{column}" = "{column}" + ?' for column in timestamp_columns)
|
|
|
+ execute(f'''
|
|
|
+ UPDATE {table}
|
|
|
+ SET {updates}
|
|
|
+ ''', tuple(delta_t for _ in timestamp_columns))
|
|
|
+
|
|
|
+
|
|
|
+def user_has_loan_with_id(user_id, loan_id):
|
|
|
+ execute('''
|
|
|
+ SELECT EXISTS (SELECT * FROM loans WHERE rowid = ? AND user_id = ?)
|
|
|
+ ''', (loan_id, user_id))
|
|
|
+
|
|
|
+ return current_cursor.fetchone()[0]
|
|
|
+
|
|
|
+
|
|
|
def tender_calendar():
|
|
|
return execute('''
|
|
|
SELECT dt, mro_interest, maturity_dt
|
|
@@ -1522,7 +1561,7 @@ def required_minimum_reserve(user_id):
|
|
|
WHERE b.issuer_id = ?
|
|
|
AND ownership.user_id = ?
|
|
|
''', (user_id, bank_id())).fetchone()[0]
|
|
|
- return min(0, global_control_value('cash_reserve_ratio') * borrowed_money - global_control_value('cash_reserve_free_amount'))
|
|
|
+ return max(0, global_control_value('cash_reserve_ratio') * borrowed_money - global_control_value('cash_reserve_free_amount'))
|
|
|
|
|
|
|
|
|
def issue_bond(user_id, ownable_name, coupon, maturity_dt):
|