diff --git a/scripts/app/gen_trans_data.py b/scripts/app/gen_trans_data.py index 81afd65..5861a44 100644 --- a/scripts/app/gen_trans_data.py +++ b/scripts/app/gen_trans_data.py @@ -89,7 +89,7 @@ def gen_trans_data(user_data, device_obj, card_obj, ip_obj, transaction_obj, app # generate transaction status and error code rejection_rates_dict = gen_trans_rejection_rates(trans_data = trans_data) - trans_data[['transaction_status', 'transaction_error_code']] = trans_data.apply(lambda series: gen_trans_status(series = series, rejection_rates_dict = rejection_rates_dict, rejection_codes = transaction_obj.rejection_codes), result_type = 'expand', axis = 1) + trans_data[['transaction_status', 'transaction_error_code']] = trans_data.apply(lambda series: gen_trans_status(series = series, rejection_rates_dict = rejection_rates_dict), result_type = 'expand', axis = 1) # sort data by transaction date trans_data = trans_data.sort_values(by = 'transaction_date').reset_index(drop = True) diff --git a/scripts/cons.py b/scripts/cons.py index b6b7d08..3212d90 100644 --- a/scripts/cons.py +++ b/scripts/cons.py @@ -49,6 +49,10 @@ data_model_card_types_dict = {'visa':0.5, 'mastercard':0.5} data_model_payment_channels = {'paypal':0.4, 'adyen':0.3, 'worldpay':0.2, 'docomo':0.1} data_model_transaction_status = {'successful':0.94, 'pending':0.03, 'rejected':0.03} -data_model_rejection_codes = {'E900:ConnectionTimeout':0.2, 'E901:SuspectedFraud':0.2, 'E902:AuthenicationFailure':0.2, 'E903:UserCancelled':0.2, 'E904:InsufficientFunds':0.2} data_model_inconsistent_country_codes_rejection_rate = {1:0.001, 2:0.005, 3:0.01} -data_model_non_card_trans_methods = {'wallet':0.95, 'points':0.05} \ No newline at end of file +data_model_non_card_trans_methods = {'wallet':0.95, 'points':0.05} +data_model_rejection_codes_fraud = {'E900:ConnectionTimeout':0.15, 'E901:SuspectedFraud':0.35, 'E902:AuthenicationFailure':0.20, 'E903:UserCancelled':0.15, 'E904:InsufficientFunds':0.15} +data_model_rejection_codes_connection = {'E900:ConnectionTimeout':0.35, 'E901:SuspectedFraud':0.15, 'E902:AuthenicationFailure':0.15, 'E903:UserCancelled':0.2, 'E904:InsufficientFunds':0.15} +data_model_rejection_codes_user = {'E900:ConnectionTimeout':0.15, 'E901:SuspectedFraud':0.15, 'E902:AuthenicationFailure':0.15, 'E903:UserCancelled':0.35, 'E904:InsufficientFunds':0.2} +data_model_rejection_codes_funds = {'E900:ConnectionTimeout':0.15, 'E901:SuspectedFraud':0.15, 'E902:AuthenicationFailure':0.15, 'E903:UserCancelled':0.2, 'E904:InsufficientFunds':0.35} +data_model_rejection_codes_authentication = {'E900:ConnectionTimeout':0.15, 'E901:SuspectedFraud':0.2, 'E902:AuthenicationFailure':0.35, 'E903:UserCancelled':0.15, 'E904:InsufficientFunds':0.15} \ No newline at end of file diff --git a/scripts/objects/Transaction.py b/scripts/objects/Transaction.py index 6528be8..1cd0cf8 100644 --- a/scripts/objects/Transaction.py +++ b/scripts/objects/Transaction.py @@ -55,7 +55,6 @@ def __init__(self, n_transaction_hashes, start_date, end_date): self.lam = cons.data_model_poisson_lambda_params["transaction"] self.payment_channels = cons.data_model_payment_channels self.transaction_status = cons.data_model_transaction_status - self.rejection_codes = cons.data_model_rejection_codes self.transaction_hashes_cnts_dict = gen_idhash_cnt_dict( idhash_type="hash", n=self.n_transaction_hashes, lam=self.lam ) diff --git a/scripts/utilities/gen_trans_status.py b/scripts/utilities/gen_trans_status.py index 77eeecd..5a7e316 100644 --- a/scripts/utilities/gen_trans_status.py +++ b/scripts/utilities/gen_trans_status.py @@ -3,7 +3,7 @@ import cons -def gen_trans_status(series, rejection_rates_dict, rejection_codes): +def gen_trans_status(series, rejection_rates_dict): """Generates the transaction status for a pandas series from the transaction level telecom payments data given the rejection rates dictionary from the same data Parameters @@ -12,8 +12,6 @@ def gen_trans_status(series, rejection_rates_dict, rejection_codes): A pandas series from the transaction level telecom payments data rejection_rates_dict : dict Rejection rates generated the transaction level telecom payments data - rejection_codes : dict - A dictionary of rejection codes and assoicated proportions Returns ------- @@ -27,35 +25,35 @@ def gen_trans_status(series, rejection_rates_dict, rejection_codes): # add rejections based on crime rates within country codes if rejection_rates_dict["country_code_trans_reject_rate_dict"][np.random.choice(a=series[country_code_columns].dropna().to_list(), size=1)[0]] >= random.uniform(0, 1): status = "rejected" - error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0] + error_code = np.random.choice(a=list(cons.data_model_rejection_codes_fraud.keys()),p=list(cons.data_model_rejection_codes_fraud.values()),size=1)[0] # add rejections based on domain frequencies elif rejection_rates_dict["domain_email_trans_reject_rate_dict"][series["email_domain"]] >= random.uniform(0, 1): status = "rejected" - error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0] + error_code = np.random.choice(a=list(cons.data_model_rejection_codes_authentication.keys()),p=list(cons.data_model_rejection_codes_authentication.values()),size=1)[0] # add rejections based on inconsistent country codes elif cons.data_model_inconsistent_country_codes_rejection_rate[series[country_code_columns].dropna().nunique()] >= random.uniform(0, 1): status = "rejected" - error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0] + error_code = np.random.choice(a=list(cons.data_model_rejection_codes_connection.keys()),p=list(cons.data_model_rejection_codes_connection.values()),size=1)[0] # add rejections based on shared ips, cards and devices elif series["device_hash"] == series["device_hash"] and rejection_rates_dict["shared_devices_reject_rate_dict"][series["device_hash"]] >= random.uniform(0, 1): status = "rejected" - error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0] + error_code = np.random.choice(a=list(cons.data_model_rejection_codes_fraud.keys()),p=list(cons.data_model_rejection_codes_fraud.values()),size=1)[0] elif series["ip_hash"] == series["ip_hash"] and rejection_rates_dict["shared_ips_reject_rate_dict"][series["ip_hash"]] >= random.uniform(0, 1): status = "rejected" - error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0] + error_code = np.random.choice(a=list(cons.data_model_rejection_codes_fraud.keys()),p=list(cons.data_model_rejection_codes_fraud.values()),size=1)[0] elif series["card_hash"] == series["card_hash"] and rejection_rates_dict["shared_cards_reject_rate_dict"][series["card_hash"]] >= random.uniform(0, 1): status = "rejected" - error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0] + error_code = np.random.choice(a=list(cons.data_model_rejection_codes_fraud.keys()),p=list(cons.data_model_rejection_codes_fraud.values()),size=1)[0] # add rejections based on counts of devices, ips and cards elif rejection_rates_dict["count_devices_reject_rate_dict"][series["userid"]] >= random.uniform(0, 1): status = "rejected" - error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0] + error_code = np.random.choice(a=list(cons.data_model_rejection_codes_funds.keys()),p=list(cons.data_model_rejection_codes_funds.values()),size=1)[0] elif rejection_rates_dict["count_ips_reject_rate_dict"][series["userid"]] >= random.uniform(0, 1): status = "rejected" - error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0] + error_code = np.random.choice(a=list(cons.data_model_rejection_codes_funds.keys()),p=list(cons.data_model_rejection_codes_funds.values()),size=1)[0] elif rejection_rates_dict["count_cards_reject_rate_dict"][series["userid"]] >= random.uniform(0, 1): status = "rejected" - error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0] + error_code = np.random.choice(a=list(cons.data_model_rejection_codes_funds.keys()),p=list(cons.data_model_rejection_codes_funds.values()),size=1)[0] # otherwise return successful status else: status = np.random.choice(a=['successful', 'pending'], size=1, p=[0.98, 0.02])[0]