Coverage for mindsdb / integrations / handlers / paypal_handler / paypal_tables.py: 0%

101 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-21 00:36 +0000

1import paypalrestsdk 

2import pandas as pd 

3from typing import Text, List, Dict 

4 

5from mindsdb_sql_parser import ast 

6from mindsdb.integrations.libs.api_handler import APITable 

7 

8from mindsdb.integrations.utilities.handlers.query_utilities import SELECTQueryParser, SELECTQueryExecutor 

9 

10 

11class PaymentsTable(APITable): 

12 

13 def select(self, query: ast.Select) -> pd.DataFrame: 

14 """ 

15 Pulls PayPal Payments data. 

16 Parameters 

17 ---------- 

18 query : ast.Select 

19 Given SQL SELECT query 

20 Returns 

21 ------- 

22 pd.DataFrame 

23 PayPal Payments matching the query 

24 Raises 

25 ------ 

26 ValueError 

27 If the query contains an unsupported condition 

28 """ 

29 

30 select_statement_parser = SELECTQueryParser( 

31 query, 

32 'payments', 

33 self.get_columns() 

34 ) 

35 selected_columns, where_conditions, order_by_conditions, result_limit = select_statement_parser.parse_query() 

36 

37 payments_df = pd.json_normalize(self.get_payments(count=result_limit)) 

38 select_statement_executor = SELECTQueryExecutor( 

39 payments_df, 

40 selected_columns, 

41 where_conditions, 

42 order_by_conditions 

43 ) 

44 payments_df = select_statement_executor.execute_query() 

45 

46 return payments_df 

47 

48 def get_columns(self) -> List[Text]: 

49 return pd.json_normalize(self.get_payments(count=1)).columns.tolist() 

50 

51 def get_payments(self, **kwargs) -> List[Dict]: 

52 connection = self.handler.connect() 

53 payments = paypalrestsdk.Payment.all(kwargs, api=connection) 

54 return [payment.to_dict() for payment in payments['payments']] 

55 

56 

57class InvoicesTable(APITable): 

58 

59 def select(self, query: ast.Select) -> pd.DataFrame: 

60 select_statement_parser = SELECTQueryParser( 

61 query, 

62 'invoices', 

63 self.get_columns() 

64 ) 

65 selected_columns, where_conditions, order_by_conditions, result_limit = select_statement_parser.parse_query() 

66 

67 invoices_df = pd.json_normalize(self.get_invoices(count=result_limit)) 

68 select_statement_executor = SELECTQueryExecutor( 

69 invoices_df, 

70 selected_columns, 

71 where_conditions, 

72 order_by_conditions 

73 ) 

74 invoices_df = select_statement_executor.execute_query() 

75 

76 return invoices_df 

77 

78 def get_columns(self) -> List[Text]: 

79 return pd.json_normalize(self.get_invoices(count=1)).columns.tolist() 

80 

81 def get_invoices(self, **kwargs) -> List[Dict]: 

82 connection = self.handler.connect() 

83 invoices = paypalrestsdk.Invoice.all(kwargs, api=connection) 

84 return [invoice.to_dict() for invoice in invoices['invoices']] 

85 

86 

87class SubscriptionsTable(APITable): 

88 def select(self, query: ast.Select) -> pd.DataFrame: 

89 select_statement_parser = SELECTQueryParser( 

90 query, 

91 'subscriptions', 

92 self.get_columns() 

93 ) 

94 selected_columns, where_conditions, order_by_conditions, result_limit = select_statement_parser.parse_query() 

95 

96 subscriptions_df = pd.json_normalize(self.get_subscriptions(count=result_limit)) 

97 select_statement_executor = SELECTQueryExecutor( 

98 subscriptions_df, 

99 selected_columns, 

100 where_conditions, 

101 order_by_conditions 

102 ) 

103 subscriptions_df = select_statement_executor.execute_query() 

104 return subscriptions_df 

105 

106 def get_columns(self) -> List[Text]: 

107 return pd.json_normalize(self.get_subscriptions(count=1)).columns.tolist() 

108 

109 def get_subscriptions(self, **kwargs) -> List[Dict]: 

110 connection = self.handler.connect() 

111 subscriptions = paypalrestsdk.BillingPlan.all(kwargs, api=connection) 

112 return [subscription.to_dict() for subscription in subscriptions['plans']] 

113 

114 

115class OrdersTable(APITable): 

116 """The PayPal Orders Table implementation""" 

117 

118 def select(self, query: ast.Select) -> pd.DataFrame: 

119 """ 

120 Pulls PayPal Orders data. 

121 Parameters 

122 ---------- 

123 query : ast.Select 

124 Given SQL SELECT query 

125 Returns 

126 ------- 

127 pd.DataFrame 

128 PayPal Orders matching the query 

129 Raises 

130 ------ 

131 ValueError 

132 If the query contains an unsupported condition 

133 """ 

134 select_statement_parser = SELECTQueryParser( 

135 query, 

136 'orders', 

137 self.get_columns() 

138 ) 

139 selected_columns, where_conditions, order_by_conditions, result_limit = select_statement_parser.parse_query() 

140 

141 id = None 

142 subset_where_conditions = [] 

143 for op, arg1, arg2 in where_conditions: 

144 if arg1 == 'id': 

145 if op == '=': 

146 id = arg2 

147 else: 

148 raise NotImplementedError("Only '=' operator is supported for 'ids' column") 

149 elif arg1 in ['state', 'amount', 'create_time', 'update_time', 'links', 'pending_reason', 'parent_payment']: 

150 subset_where_conditions.append([op, arg1, arg2]) 

151 

152 if not id: 

153 raise NotImplementedError("id column is required for this table") 

154 

155 orders_df = pd.json_normalize(self.get_orders(id)) 

156 select_statement_executor = SELECTQueryExecutor( 

157 orders_df, 

158 selected_columns, 

159 subset_where_conditions, 

160 order_by_conditions 

161 ) 

162 orders_df = select_statement_executor.execute_query() 

163 return orders_df 

164 

165 def get_columns(self) -> List[Text]: 

166 return ["id", 

167 "status", 

168 "intent", 

169 "purchase_units", 

170 "links", 

171 "create_time"] 

172 

173 # restore this or similar header list for API 2.0 refactor 

174 # restore this list when restore paypalsdk api, and retired the request call 

175 # return ["id", 

176 # "status", 

177 # "intent", 

178 # "gross_total_amount.value", 

179 # "gross_total_amount.currency", 

180 # "purchase_units", 

181 # "metadata.supplementary_data", 

182 # "redirect_urls.return_url", 

183 # "redirect_urls.cancel_url", 

184 # "links", 

185 # "create_time"] 

186 

187 def get_orders(self, id) -> List[Dict]: 

188 # we can use the paypalrestsdk api to get the order if they refactor their code 

189 connection = self.handler.connect() 

190 endpoint = f"v2/checkout/orders/{id}" 

191 order = connection.get(endpoint) 

192 if not order: 

193 raise ValueError("Could not get order, check order id") 

194 return order 

195 

196 

197class PayoutsTable(APITable): 

198 

199 def select(self, query: ast.Select) -> pd.DataFrame: 

200 """ 

201 Pulls PayPal payouts data. 

202 Parameters 

203 ---------- 

204 query : ast.Select 

205 Given SQL SELECT query 

206 Returns 

207 ------- 

208 pd.DataFrame 

209 PayPal payouts matching the query 

210 Raises 

211 ------ 

212 ValueError 

213 If the query contains an unsupported condition 

214 """ 

215 

216 select_statement_parser = SELECTQueryParser( 

217 query, 

218 'payouts', 

219 self.get_columns() 

220 ) 

221 selected_columns, where_conditions, order_by_conditions, result_limit = select_statement_parser.parse_query() 

222 

223 payout_batch_id = "" 

224 

225 for a_where in where_conditions: 

226 if a_where[1] == "payout_batch_id": 

227 if a_where[0] != "=": 

228 raise ValueError("Unsupported where operation for state") 

229 

230 payout_batch_id = a_where[2] 

231 if not payout_batch_id: 

232 raise NotImplementedError("payout_batch_id column is required for this table") 

233 

234 payouts_data = self.get_payout(payout_batch_id) # Get the data 

235 payouts_df = pd.DataFrame(payouts_data) # Create a DataFrame 

236 

237 select_statement_executor = SELECTQueryExecutor( 

238 payouts_df, 

239 selected_columns, 

240 where_conditions, 

241 order_by_conditions 

242 ) 

243 

244 payouts_df = select_statement_executor.execute_query() 

245 

246 return payouts_df 

247 

248 def get_columns(self) -> List[Text]: 

249 return [ 

250 "payout_batch_id", 

251 "batch_status", 

252 "time_created", 

253 "time_completed", 

254 "sender_batch_id", 

255 "email_subject", 

256 "email_message", 

257 "funding_source", 

258 "amount_currency", 

259 "amount_value", 

260 "fees_currency", 

261 "fees_value", 

262 ] 

263 

264 def get_payout(self, payout_batch_id: str) -> List[Dict]: 

265 connection = self.handler.connect() 

266 endpoint = f"v1/payments/payouts/{payout_batch_id}" 

267 payout = connection.get(endpoint) 

268 

269 payout_data = { 

270 "payout_batch_id": payout['batch_header']['payout_batch_id'], 

271 "batch_status": payout['batch_header']['batch_status'], 

272 "time_created": payout['batch_header']['time_created'], 

273 "time_completed": payout['batch_header']['time_completed'], 

274 "sender_batch_id": payout['batch_header']['sender_batch_header']['sender_batch_id'], 

275 "email_subject": payout['batch_header']['sender_batch_header']['email_subject'], 

276 "email_message": payout['batch_header']['sender_batch_header']['email_message'], 

277 "funding_source": payout['batch_header']['funding_source'], 

278 "amount_currency": payout['batch_header']['amount']['currency'], 

279 "amount_value": payout['batch_header']['amount']['value'], 

280 "fees_currency": payout['batch_header']['fees']['currency'], 

281 "fees_value": payout['batch_header']['fees']['value'], 

282 } 

283 

284 return [payout_data]