Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import json 

2import logging 

3import requests 

4import datetime 

5from pytz import timezone, utc 

6from sdc_etl_libs.api_helpers.API import API 

7from sdc_etl_libs.sdc_credentials.sdc_endpoint_credentials import SDCEndpointCredentials 

8 

9 

10logging.basicConfig(level=logging.INFO) 

11 

12 

13class UPS(API): 

14 

15 def __init__(self, schema_: dict = None, endpoint_schema_: dict = None, **kwargs): 

16 

17 self.schema = schema_ 

18 self.endpoint_schema = endpoint_schema_ 

19 

20 self.execution_date = kwargs.get("execution_date", datetime.datetime.now()) 

21 self.base_url = self.endpoint_schema["info"]["access"]["base_url"] 

22 self.endpoint_name = self.endpoint_schema["info"]["access"]["endpoint_name"] 

23 self.timezone = self.endpoint_schema["info"]["opts"]["tz"] 

24 self.datetime_format = self.endpoint_schema["info"]["opts"]["datetime_format"] 

25 

26 def process_endpoint(self, payload_): 

27 """ 

28 Processes a UPS API endpoint. 

29 :param payload_: 

30 :return: Response Data as string. 

31 """ 

32 header = {'Content-type': 'application/json', 'Accept': 'application/json'} 

33 requests_url = f"{self.base_url}" + f"/{self.endpoint_name}" 

34 logging.info(requests_url) 

35 

36 r = requests.post(requests_url, headers=header, data=payload_) 

37 if r.status_code == 200: 

38 return r.text 

39 else: 

40 raise Exception( 

41 f"Failed to get access group data from api. " 

42 f"Status: {r.status_code}") 

43 

44 def get_localized_start_end_time(self, execution_date, tz, datetime_format): 

45 """ 

46 Gets Start Time and End Time from execution date , tz and datetime_format. 

47 :param datetime_format: DateTime format 

48 :param tz: Timezone 

49 :param execution_date: Execution Time in utc 

50 :return: Response start time and end time. 

51 """ 

52 start_time_utc = execution_date 

53 start_time = start_time_utc.replace(tzinfo=utc).astimezone(timezone(tz)) 

54 start_time_str = start_time.strftime(datetime_format) 

55 end_time_str = (start_time + datetime.timedelta(hours=1)).strftime(datetime_format) 

56 return start_time_str, end_time_str 

57 

58 def get_quantum_view_request_payload(self, start_time, end_time): 

59 """ 

60 Gets UPS Request JSON Payload. 

61 :param start_time: Start Time for QV event 

62 :param end_time: End Time for QV Event 

63 :return: payload as a string 

64 """ 

65 credentials = SDCEndpointCredentials.get_credentials(self.endpoint_schema["info"]["access"]["credentials"]) 

66 data = dict() 

67 data["AccessRequest"] = dict() 

68 data["AccessRequest"]["AccessLicenseNumber"] = credentials["access_license_number"] 

69 data["AccessRequest"]["UserId"] = credentials["user_id"] 

70 data["AccessRequest"]["Password"] = credentials["password"] 

71 data["QuantumViewRequest"] = dict() 

72 data["QuantumViewRequest"]["Request"] = dict() 

73 data["QuantumViewRequest"]["Request"]["TransactionReference"] = dict() 

74 data["QuantumViewRequest"]["Request"]["TransactionReference"]["CustomerContext"] = "Tracking Numbers" 

75 data["QuantumViewRequest"]["Request"]["RequestAction"] = "QVEvents" 

76 data["QuantumViewRequest"]["SubscriptionRequest"] = dict() 

77 data["QuantumViewRequest"]["SubscriptionRequest"]["Name"] = credentials["name"] 

78 data["QuantumViewRequest"]["SubscriptionRequest"]["DateTimeRange"] = dict() 

79 data["QuantumViewRequest"]["SubscriptionRequest"]["DateTimeRange"]["BeginDateTime"] = start_time 

80 data["QuantumViewRequest"]["SubscriptionRequest"]["DateTimeRange"]["EndDateTime"] = end_time 

81 return json.dumps(data) 

82 

83 def get_quantum_review_response(self): 

84 """ 

85 Returns the list of all UPS Tracking Events 

86 :return: A flattened Tracking Event list of dictionaries. 

87 """ 

88 start_time, end_time = self.get_localized_start_end_time(self.execution_date, self.timezone, 

89 self.datetime_format) 

90 payload = self.get_quantum_view_request_payload(start_time, end_time) 

91 quantum_view_response = self.process_endpoint(payload) 

92 quantum_view_response_dict = json.loads(quantum_view_response) 

93 out_data = [] 

94 

95 if 'QuantumViewEvents' in quantum_view_response_dict['QuantumViewResponse']: 

96 quantum_events = quantum_view_response_dict['QuantumViewResponse']['QuantumViewEvents'] 

97 else: 

98 return None 

99 if 'SubscriptionEvents' in quantum_events: 

100 if isinstance(quantum_events['SubscriptionEvents'], dict): 

101 quantum_events.update({'SubscriptionEvents': [quantum_events['SubscriptionEvents']]}) 

102 for subscription_event in quantum_events['SubscriptionEvents']: 

103 if isinstance(subscription_event['SubscriptionFile'], dict): 

104 subscription_event.update({'SubscriptionFile': [subscription_event['SubscriptionFile']]}) 

105 subscription_event_name = subscription_event['Name'] 

106 for subscription_file in subscription_event['SubscriptionFile']: 

107 elements_with_nan_val = ['Origin', 'Delivery', 'Manifest'] 

108 file_name = subscription_file["FileName"].strip() 

109 for elem in elements_with_nan_val: 

110 if elem in subscription_file: 

111 data = None 

112 if isinstance(subscription_file[elem], dict): 

113 data = [subscription_file[elem]] 

114 elif isinstance(subscription_file[elem], list): 

115 data = subscription_file[elem] 

116 else: 

117 raise Exception(f"Unknown element type for {elem}") 

118 

119 # add new field to every event 

120 def add_field_to_event(event_, field_, field_value_): 

121 event_[field_] = field_value_ 

122 return event_ 

123 

124 data = [add_field_to_event(x, "FileName", file_name) for x in data] 

125 data = [add_field_to_event(x, "SubscriptionEventName", subscription_event_name) for x in 

126 data] 

127 data = [add_field_to_event(x, "Event", elem.lower()) for x in data] 

128 out_data = out_data + data 

129 return out_data 

130 else: 

131 return None 

132 

133 def get_response_data(self): 

134 """ 

135 Returns the appropriate endpoint response based on the endpoint name 

136 :return: List of flattened dictionaries. 

137 """ 

138 if self.endpoint_name == "QVEvents": 

139 response = self.get_quantum_review_response() 

140 else: 

141 raise Exception("UPS endpoint not supported") 

142 return response