dana-python 2.0.0__tar.gz → 2.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. {dana_python-2.0.0/dana_python.egg-info → dana_python-2.1.1}/PKG-INFO +4 -4
  2. {dana_python-2.0.0 → dana_python-2.1.1}/README.md +1 -1
  3. {dana_python-2.0.0 → dana_python-2.1.1}/dana/exceptions.py +5 -1
  4. dana_python-2.1.1/dana/payment_gateway/v1/custom_validation.py +333 -0
  5. {dana_python-2.0.0 → dana_python-2.1.1}/dana/rest.py +6 -1
  6. {dana_python-2.0.0 → dana_python-2.1.1}/dana/utils/open_api_header.py +33 -8
  7. {dana_python-2.0.0 → dana_python-2.1.1}/dana/utils/script.py +16 -1
  8. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/api/widget_api.py +65 -0
  9. dana_python-2.1.1/dana/widget/v1/custom_validation.py +112 -0
  10. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/enum.py +11 -2
  11. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/account_info.py +10 -3
  12. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/account_unbinding_request.py +10 -3
  13. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/account_unbinding_request_additional_info.py +10 -3
  14. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/account_unbinding_response.py +10 -3
  15. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/amount_detail.py +10 -3
  16. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/apply_ott_request.py +10 -3
  17. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/apply_ott_request_additional_info.py +10 -3
  18. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/apply_ott_response.py +10 -3
  19. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/apply_ott_response_user_resources_inner.py +10 -3
  20. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/apply_token_authorization_code_request.py +10 -3
  21. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/apply_token_refresh_token_request.py +10 -3
  22. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/apply_token_response.py +10 -3
  23. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/apply_token_response_additional_info.py +10 -3
  24. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/apply_token_response_additional_info_user_info.py +10 -3
  25. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/balance_inquiry_request.py +10 -3
  26. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/balance_inquiry_request_additional_info.py +10 -3
  27. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/balance_inquiry_response.py +10 -3
  28. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/buyer.py +10 -3
  29. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/cancel_order_request.py +10 -3
  30. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/cancel_order_response.py +10 -3
  31. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/env_info.py +10 -3
  32. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/goods.py +10 -3
  33. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/international_order_info.py +10 -3
  34. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/international_order_info_exchange_rate.py +10 -3
  35. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/money.py +10 -3
  36. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/oauth2_url_data.py +10 -3
  37. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/oauth2_url_data_seamless_data.py +10 -3
  38. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/order.py +10 -3
  39. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/pay_option_detail.py +10 -3
  40. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/pay_option_detail_additional_info.py +10 -3
  41. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/pay_option_info.py +10 -3
  42. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/payment_promo_info.py +10 -3
  43. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/payment_view.py +10 -3
  44. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/query_payment_request.py +10 -3
  45. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/query_payment_response.py +10 -3
  46. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/query_payment_response_additional_info.py +10 -3
  47. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/query_user_profile_request.py +16 -7
  48. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/query_user_profile_response.py +10 -3
  49. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/query_user_profile_response_response.py +10 -3
  50. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/query_user_profile_response_response_body.py +10 -3
  51. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/query_user_profile_response_response_head.py +10 -3
  52. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/refund_order_request.py +10 -3
  53. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/refund_order_request_additional_info.py +10 -3
  54. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/refund_order_response.py +10 -3
  55. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/refund_promo_info.py +10 -3
  56. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/result_info.py +10 -3
  57. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/seller.py +10 -3
  58. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/service_info.py +10 -3
  59. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/shipping_info.py +10 -3
  60. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/status_detail.py +10 -3
  61. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/time_detail.py +10 -3
  62. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/url_param.py +10 -3
  63. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/user_resource_info.py +12 -5
  64. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/virtual_account_info.py +10 -3
  65. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/widget_payment_request.py +10 -3
  66. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/widget_payment_request_additional_info.py +10 -3
  67. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/widget_payment_response.py +10 -3
  68. {dana_python-2.0.0 → dana_python-2.1.1/dana_python.egg-info}/PKG-INFO +4 -4
  69. {dana_python-2.0.0 → dana_python-2.1.1}/dana_python.egg-info/requires.txt +2 -2
  70. {dana_python-2.0.0 → dana_python-2.1.1}/pyproject.toml +4 -4
  71. {dana_python-2.0.0 → dana_python-2.1.1}/tests/test_payment_gateway_api.py +216 -0
  72. {dana_python-2.0.0 → dana_python-2.1.1}/tests/test_widget_with_automation.py +180 -0
  73. dana_python-2.0.0/dana/payment_gateway/v1/custom_validation.py +0 -184
  74. dana_python-2.0.0/dana/widget/v1/custom_validation.py +0 -80
  75. {dana_python-2.0.0 → dana_python-2.1.1}/LICENSE +0 -0
  76. {dana_python-2.0.0 → dana_python-2.1.1}/dana/__init__.py +0 -0
  77. {dana_python-2.0.0 → dana_python-2.1.1}/dana/api_client.py +0 -0
  78. {dana_python-2.0.0 → dana_python-2.1.1}/dana/api_response.py +0 -0
  79. {dana_python-2.0.0 → dana_python-2.1.1}/dana/base/__init__.py +0 -0
  80. {dana_python-2.0.0 → dana_python-2.1.1}/dana/base/configuration.py +0 -0
  81. {dana_python-2.0.0 → dana_python-2.1.1}/dana/base/model.py +0 -0
  82. {dana_python-2.0.0 → dana_python-2.1.1}/dana/base/types.py +0 -0
  83. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/__init__.py +0 -0
  84. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/__init__.py +0 -0
  85. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/api/__init__.py +0 -0
  86. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/api/disbursement_api.py +0 -0
  87. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/enum.py +0 -0
  88. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/__init__.py +0 -0
  89. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/bank_account_inquiry_request.py +0 -0
  90. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/bank_account_inquiry_request_additional_info.py +0 -0
  91. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/bank_account_inquiry_response.py +0 -0
  92. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/bank_account_inquiry_response_additional_info.py +0 -0
  93. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/dana_account_inquiry_request.py +0 -0
  94. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/dana_account_inquiry_request_additional_info.py +0 -0
  95. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/dana_account_inquiry_response.py +0 -0
  96. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/money.py +0 -0
  97. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/transfer_to_bank_inquiry_status_request.py +0 -0
  98. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/transfer_to_bank_inquiry_status_response.py +0 -0
  99. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/transfer_to_bank_request.py +0 -0
  100. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/transfer_to_bank_request_additional_info.py +0 -0
  101. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/transfer_to_bank_response.py +0 -0
  102. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/transfer_to_dana_inquiry_status_request.py +0 -0
  103. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/transfer_to_dana_inquiry_status_response.py +0 -0
  104. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/transfer_to_dana_request.py +0 -0
  105. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/transfer_to_dana_request_additional_info.py +0 -0
  106. {dana_python-2.0.0 → dana_python-2.1.1}/dana/disbursement/v1/models/transfer_to_dana_response.py +0 -0
  107. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/__init__.py +0 -0
  108. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/__init__.py +0 -0
  109. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/api/__init__.py +0 -0
  110. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/api/merchant_management_api.py +0 -0
  111. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/enum.py +0 -0
  112. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/__init__.py +0 -0
  113. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/address_info.py +0 -0
  114. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/business_docs.py +0 -0
  115. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/create_division_request.py +0 -0
  116. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/create_division_request_ext_info.py +0 -0
  117. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/create_division_response.py +0 -0
  118. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/create_division_response_response.py +0 -0
  119. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/create_division_response_response_body.py +0 -0
  120. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/create_division_response_response_head.py +0 -0
  121. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/create_shop_request.py +0 -0
  122. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/create_shop_response.py +0 -0
  123. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/create_shop_response_response.py +0 -0
  124. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/create_shop_response_response_body.py +0 -0
  125. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/create_shop_response_response_head.py +0 -0
  126. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/division_resource_info.py +0 -0
  127. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/merchant_resource_information.py +0 -0
  128. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/mobile_no_info.py +0 -0
  129. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/pic_info.py +0 -0
  130. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_division_request.py +0 -0
  131. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_division_response.py +0 -0
  132. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_division_response_response.py +0 -0
  133. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_division_response_response_body.py +0 -0
  134. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_division_response_response_head.py +0 -0
  135. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_merchant_resource_request.py +0 -0
  136. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_merchant_resource_response.py +0 -0
  137. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_merchant_resource_response_response.py +0 -0
  138. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_merchant_resource_response_response_body.py +0 -0
  139. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_merchant_resource_response_response_head.py +0 -0
  140. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_shop_request.py +0 -0
  141. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_shop_response.py +0 -0
  142. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_shop_response_response.py +0 -0
  143. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_shop_response_response_body.py +0 -0
  144. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/query_shop_response_response_head.py +0 -0
  145. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/result_info.py +0 -0
  146. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/shop_resource_info.py +0 -0
  147. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/update_division_request.py +0 -0
  148. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/update_division_response.py +0 -0
  149. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/update_division_response_response.py +0 -0
  150. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/update_division_response_response_body.py +0 -0
  151. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/update_division_response_response_head.py +0 -0
  152. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/update_shop_request.py +0 -0
  153. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/update_shop_response.py +0 -0
  154. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/update_shop_response_response.py +0 -0
  155. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/update_shop_response_response_head.py +0 -0
  156. {dana_python-2.0.0 → dana_python-2.1.1}/dana/merchant_management/v1/models/user_name.py +0 -0
  157. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/__init__.py +0 -0
  158. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/__init__.py +0 -0
  159. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/api/__init__.py +0 -0
  160. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/api/payment_gateway_api.py +0 -0
  161. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/enum.py +0 -0
  162. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/__init__.py +0 -0
  163. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/actor_context.py +0 -0
  164. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/amount_detail.py +0 -0
  165. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/audit_info.py +0 -0
  166. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/buyer.py +0 -0
  167. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/cancel_order_request.py +0 -0
  168. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/cancel_order_response.py +0 -0
  169. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/consult_pay_payment_info.py +0 -0
  170. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/consult_pay_request.py +0 -0
  171. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/consult_pay_request_additional_info.py +0 -0
  172. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/consult_pay_response.py +0 -0
  173. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/create_order_by_api_additional_info.py +0 -0
  174. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/create_order_by_api_request.py +0 -0
  175. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/create_order_by_redirect_additional_info.py +0 -0
  176. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/create_order_by_redirect_request.py +0 -0
  177. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/create_order_response.py +0 -0
  178. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/create_order_response_additional_info.py +0 -0
  179. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/env_info.py +0 -0
  180. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/goods.py +0 -0
  181. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/money.py +0 -0
  182. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/order_api_object.py +0 -0
  183. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/order_redirect_object.py +0 -0
  184. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/pay_option_additional_info.py +0 -0
  185. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/pay_option_detail.py +0 -0
  186. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/pay_option_info.py +0 -0
  187. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/payment_view.py +0 -0
  188. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/promo_info.py +0 -0
  189. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/query_payment_request.py +0 -0
  190. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/query_payment_response.py +0 -0
  191. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/query_payment_response_additional_info.py +0 -0
  192. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/refund_option_bill.py +0 -0
  193. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/refund_order_request.py +0 -0
  194. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/refund_order_request_additional_info.py +0 -0
  195. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/refund_order_response.py +0 -0
  196. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/seller.py +0 -0
  197. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/shipping_info.py +0 -0
  198. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/status_detail.py +0 -0
  199. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/time_detail.py +0 -0
  200. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/url_param.py +0 -0
  201. {dana_python-2.0.0 → dana_python-2.1.1}/dana/payment_gateway/v1/models/virtual_account_info.py +0 -0
  202. {dana_python-2.0.0 → dana_python-2.1.1}/dana/utils/date_validation.py +0 -0
  203. {dana_python-2.0.0 → dana_python-2.1.1}/dana/utils/models.py +0 -0
  204. {dana_python-2.0.0 → dana_python-2.1.1}/dana/utils/open_api_configuration.py +0 -0
  205. {dana_python-2.0.0 → dana_python-2.1.1}/dana/utils/snap_configuration.py +0 -0
  206. {dana_python-2.0.0 → dana_python-2.1.1}/dana/utils/snap_header.py +0 -0
  207. {dana_python-2.0.0 → dana_python-2.1.1}/dana/utils/url.py +0 -0
  208. {dana_python-2.0.0 → dana_python-2.1.1}/dana/webhook/__init__.py +0 -0
  209. {dana_python-2.0.0 → dana_python-2.1.1}/dana/webhook/finish_notify_payment_info.py +0 -0
  210. {dana_python-2.0.0 → dana_python-2.1.1}/dana/webhook/finish_notify_request.py +0 -0
  211. {dana_python-2.0.0 → dana_python-2.1.1}/dana/webhook/finish_notify_request_additional_info.py +0 -0
  212. {dana_python-2.0.0 → dana_python-2.1.1}/dana/webhook/finish_notify_response.py +0 -0
  213. {dana_python-2.0.0 → dana_python-2.1.1}/dana/webhook/money.py +0 -0
  214. {dana_python-2.0.0 → dana_python-2.1.1}/dana/webhook/pay_option_info.py +0 -0
  215. {dana_python-2.0.0 → dana_python-2.1.1}/dana/webhook/shop_info.py +0 -0
  216. {dana_python-2.0.0 → dana_python-2.1.1}/dana/webhook/webhook.py +0 -0
  217. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/__init__.py +0 -0
  218. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/__init__.py +0 -0
  219. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/api/__init__.py +0 -0
  220. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/models/__init__.py +0 -0
  221. {dana_python-2.0.0 → dana_python-2.1.1}/dana/widget/v1/util.py +0 -0
  222. {dana_python-2.0.0 → dana_python-2.1.1}/dana_python.egg-info/SOURCES.txt +0 -0
  223. {dana_python-2.0.0 → dana_python-2.1.1}/dana_python.egg-info/dependency_links.txt +0 -0
  224. {dana_python-2.0.0 → dana_python-2.1.1}/dana_python.egg-info/top_level.txt +0 -0
  225. {dana_python-2.0.0 → dana_python-2.1.1}/setup.cfg +0 -0
  226. {dana_python-2.0.0 → dana_python-2.1.1}/tests/test_disbursement_api.py +0 -0
  227. {dana_python-2.0.0 → dana_python-2.1.1}/tests/test_merchant_management_api.py +0 -0
  228. {dana_python-2.0.0 → dana_python-2.1.1}/tests/test_payment_gateway_with_automation.py +0 -0
  229. {dana_python-2.0.0 → dana_python-2.1.1}/tests/test_snap_header.py +0 -0
  230. {dana_python-2.0.0 → dana_python-2.1.1}/tests/test_webhook.py +0 -0
  231. {dana_python-2.0.0 → dana_python-2.1.1}/tests/test_widget_api.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dana-python
3
- Version: 2.0.0
3
+ Version: 2.1.1
4
4
  Summary: API Client (SDK) for DANA APIs based on https://dashboard.dana.id/api-docs
5
5
  Author-email: DANA Package Manager <package-manager@dana.id>
6
6
  Maintainer-email: DANA Package Manager <package-manager@dana.id>
@@ -12,9 +12,9 @@ Requires-Python: >3.9.1
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: annotated-types==0.7.0
15
- Requires-Dist: cffi==1.17.1
15
+ Requires-Dist: cffi==2.0.0
16
16
  Requires-Dist: cryptography<46.0.0,>=44.0.2
17
- Requires-Dist: pycparser==2.22
17
+ Requires-Dist: pycparser==2.23
18
18
  Requires-Dist: pydantic<3.0.0,>=2.10.6
19
19
  Requires-Dist: pydantic-core<3.0.0,>=2.27.2
20
20
  Requires-Dist: python-dateutil==2.9.0.post0
@@ -88,7 +88,7 @@ Before using the SDK, please make sure to set the following environment variable
88
88
  | ---------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
89
89
  | `ENV` or `DANA_ENV` | Defines which environment the SDK will use. Possible values: `SANDBOX` or `PRODUCTION`. | `SANDBOX` |
90
90
  | `X_PARTNER_ID` | Unique identifier for partner, provided by DANA, also known as `clientId`. | 1970010100000000000000 |
91
- | `PRIVATE_KEY` | Your private key string. | `-----BEGIN PRIVATE KEY-----MIIBVgIBADANBg...LsvTqw==-----END PRIVATE KEY-----` |
91
+ | `PRIVATE_KEY` | Your private key string. | |
92
92
  | `PRIVATE_KEY_PATH` | Path to your private key file. If both are set, `PRIVATE_KEY_PATH` is used. | /path/to/your_private_key.pem |
93
93
  | `DANA_PUBLIC_KEY` | DANA public key string for parsing webhook. | `-----BEGIN PUBLIC KEY-----MIIBIjANBgkq...Do/QIDAQAB-----END PUBLIC KEY-----` |
94
94
  | `DANA_PUBLIC_KEY_PATH` | Path to DANA public key file for parsing webhook. If both set, `DANA_PUBLIC_KEY_PATH is used. | /path/to/dana_public_key.pem |
@@ -63,7 +63,7 @@ Before using the SDK, please make sure to set the following environment variable
63
63
  | ---------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
64
64
  | `ENV` or `DANA_ENV` | Defines which environment the SDK will use. Possible values: `SANDBOX` or `PRODUCTION`. | `SANDBOX` |
65
65
  | `X_PARTNER_ID` | Unique identifier for partner, provided by DANA, also known as `clientId`. | 1970010100000000000000 |
66
- | `PRIVATE_KEY` | Your private key string. | `-----BEGIN PRIVATE KEY-----MIIBVgIBADANBg...LsvTqw==-----END PRIVATE KEY-----` |
66
+ | `PRIVATE_KEY` | Your private key string. | |
67
67
  | `PRIVATE_KEY_PATH` | Path to your private key file. If both are set, `PRIVATE_KEY_PATH` is used. | /path/to/your_private_key.pem |
68
68
  | `DANA_PUBLIC_KEY` | DANA public key string for parsing webhook. | `-----BEGIN PUBLIC KEY-----MIIBIjANBgkq...Do/QIDAQAB-----END PUBLIC KEY-----` |
69
69
  | `DANA_PUBLIC_KEY_PATH` | Path to DANA public key file for parsing webhook. If both set, `DANA_PUBLIC_KEY_PATH is used. | /path/to/dana_public_key.pem |
@@ -22,7 +22,7 @@
22
22
  Do not edit the class manually.
23
23
  """ # noqa: E501
24
24
 
25
- from typing import Any, Optional
25
+ from typing import Any, Dict, List, Optional
26
26
  from typing_extensions import Self
27
27
 
28
28
  class OpenApiException(Exception):
@@ -122,7 +122,11 @@ class ApiException(OpenApiException):
122
122
  *,
123
123
  body: Optional[str] = None,
124
124
  data: Optional[Any] = None,
125
+ contexts: Optional[List[Dict[str, str]]] = None,
125
126
  ) -> None:
127
+ self.contexts = contexts
128
+ if contexts is not None and reason is None:
129
+ reason = "; ".join(f"{c['field']}: {c['message']}" for c in contexts)
126
130
  self.status = status
127
131
  self.reason = reason
128
132
  self.body = body
@@ -0,0 +1,333 @@
1
+ # Copyright 2026 PT Espay Debit Indonesia Koe
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ CustomValidation
17
+
18
+ This module provides custom validation functions for Payment Gateway API requests.
19
+ Validations are registered in the validation_registry and executed via custom_validation().
20
+ """
21
+
22
+ import os
23
+ import re
24
+ from typing import Any, Callable, Dict, FrozenSet, List, Set
25
+
26
+ from dana.utils.date_validation import validate_valid_up_to_date
27
+ from dana.exceptions import ApiException
28
+
29
+ # Money value pattern: digits (1-16) + "." + exactly 2 digits (e.g. 10000.00)
30
+ MONEY_VALUE_PATTERN = re.compile(r'^\d{1,16}\.\d{2}$')
31
+
32
+ SANDBOX_ALLOWED_PAY_METHODS: FrozenSet[str] = frozenset({
33
+ 'BALANCE', 'CREDIT_CARD', 'DEBIT_CARD', 'VIRTUAL_ACCOUNT', 'NETWORK_PAY',
34
+ })
35
+
36
+ SANDBOX_ALLOWED_PAY_OPTIONS: FrozenSet[str] = frozenset({
37
+ 'CARD', 'QRIS', 'BRI', 'PANIN', 'CIMB', 'MANDIRI', 'BTPN',
38
+ })
39
+
40
+ CREDIT_DEBIT_CARD_PAY_METHODS: Set[str] = {'CREDIT_CARD', 'DEBIT_CARD'}
41
+ NETWORK_PAY_PG_CARD = 'NETWORK_PAY_PG_CARD'
42
+ EWALLET_PAY_OPTIONS: Set[str] = {
43
+ 'NETWORK_PAY_PG_SPAY',
44
+ 'NETWORK_PAY_PG_OVO',
45
+ 'NETWORK_PAY_PG_GOPAY',
46
+ 'NETWORK_PAY_PG_LINKAJA',
47
+ }
48
+
49
+
50
+ def _is_sandbox() -> bool:
51
+ env = os.getenv('DANA_ENV', os.getenv('ENV', 'sandbox')).lower()
52
+ return env == 'sandbox'
53
+
54
+
55
+ def _pay_option_allowed_in_sandbox(value: str) -> bool:
56
+ if not value or not str(value).strip():
57
+ return False
58
+ s = str(value).strip()
59
+ if s in SANDBOX_ALLOWED_PAY_OPTIONS:
60
+ return True
61
+ for opt in SANDBOX_ALLOWED_PAY_OPTIONS:
62
+ if s.endswith('_' + opt):
63
+ return True
64
+ return False
65
+
66
+
67
+ def _normalize_value(value: Any) -> str:
68
+ if value is None:
69
+ return ''
70
+ if hasattr(value, 'value'):
71
+ return str(getattr(value, 'value')).strip()
72
+ return str(value).strip()
73
+
74
+
75
+ def _trim_str(value: Any) -> str:
76
+ if value is None:
77
+ return ''
78
+ return str(value).strip()
79
+
80
+
81
+ def _rune_len(s: str) -> int:
82
+ return len(list(s))
83
+
84
+
85
+ def _ctx(field: str, message: str) -> Dict[str, str]:
86
+ return {'field': field, 'message': message}
87
+
88
+
89
+ def validate_additional_info_required(request: Any) -> None:
90
+ if request is None:
91
+ return
92
+ if hasattr(request, 'additional_info') and request.additional_info is None:
93
+ raise ApiException(status=0, contexts=[_ctx('additionalInfo', 'additionalInfo is required')])
94
+
95
+
96
+ def validate_money_value_pattern(request: Any) -> None:
97
+ if request is None:
98
+ return
99
+ if not hasattr(request, 'amount') or request.amount is None:
100
+ return
101
+ value = getattr(request.amount, 'value', None)
102
+ if value is None or value == '':
103
+ raise ApiException(status=0, contexts=[_ctx('amount.value', 'amount.value is required')])
104
+ if not MONEY_VALUE_PATTERN.match(str(value)):
105
+ raise ApiException(status=0, contexts=[
106
+ _ctx('amount.value', f'amount.value must match pattern (e.g. 10000.00): got {value!r}')
107
+ ])
108
+
109
+
110
+ def validate_valid_up_to_create_order_request(request: Any) -> None:
111
+ if request is None:
112
+ return
113
+ if hasattr(request, 'valid_up_to') and request.valid_up_to is not None:
114
+ try:
115
+ validate_valid_up_to_date(request.valid_up_to)
116
+ except ValueError as e:
117
+ raise ApiException(status=0, contexts=[
118
+ _ctx('validUpTo', f'validUpTo validation failed: {str(e)}')
119
+ ]) from e
120
+
121
+
122
+ def validate_external_store_id_for_qris(request: Any) -> None:
123
+ if request is None:
124
+ return
125
+ if not hasattr(request, 'pay_option_details') or request.pay_option_details is None:
126
+ return
127
+ has_qris = False
128
+ if isinstance(request.pay_option_details, list):
129
+ for pay_option_detail in request.pay_option_details:
130
+ if hasattr(pay_option_detail, 'pay_option') and pay_option_detail.pay_option == 'NETWORK_PAY_PG_QRIS':
131
+ has_qris = True
132
+ break
133
+ if has_qris:
134
+ external_store_id = None
135
+ if hasattr(request, 'external_store_id'):
136
+ external_store_id = request.external_store_id
137
+ if not external_store_id or (isinstance(external_store_id, str) and external_store_id.strip() == ''):
138
+ raise ApiException(status=0, contexts=[
139
+ _ctx('externalStoreId', 'externalStoreId is required when payOption is NETWORK_PAY_PG_QRIS')
140
+ ])
141
+
142
+
143
+ def validate_sandbox_pay_method_and_pay_option(request: Any) -> None:
144
+ if request is None or not _is_sandbox():
145
+ return
146
+ pay_option_details = getattr(request, 'pay_option_details', None)
147
+ if not pay_option_details or not isinstance(pay_option_details, list):
148
+ return
149
+ for i, detail in enumerate(pay_option_details):
150
+ if not detail:
151
+ continue
152
+ if hasattr(detail, 'pay_method') and detail.pay_method is not None:
153
+ pm_str = _normalize_value(detail.pay_method)
154
+ if pm_str and pm_str not in SANDBOX_ALLOWED_PAY_METHODS:
155
+ raise ApiException(status=0, contexts=[
156
+ _ctx(
157
+ f'payOptionDetails[{i}].payMethod',
158
+ (
159
+ f'In sandbox, payMethod must be one of [{", ".join(sorted(SANDBOX_ALLOWED_PAY_METHODS))}]; '
160
+ f'got {pm_str}'
161
+ ),
162
+ )
163
+ ])
164
+ if hasattr(detail, 'pay_option') and detail.pay_option is not None:
165
+ po_str = _normalize_value(detail.pay_option)
166
+ if po_str and not _pay_option_allowed_in_sandbox(po_str):
167
+ raise ApiException(status=0, contexts=[
168
+ _ctx(
169
+ f'payOptionDetails[{i}].payOption',
170
+ (
171
+ f'In sandbox, payOption must be one of [{", ".join(sorted(SANDBOX_ALLOWED_PAY_OPTIONS))}] '
172
+ f'(or suffix like VIRTUAL_ACCOUNT_BRI); got {po_str}'
173
+ ),
174
+ )
175
+ ])
176
+
177
+
178
+ def validate_conditional_pay_option_additional_info_create_order_request(request: Any) -> None:
179
+ if request is None:
180
+ return
181
+ pay_option_details = getattr(request, 'pay_option_details', None)
182
+ if not pay_option_details or not isinstance(pay_option_details, list):
183
+ return
184
+
185
+ contexts: List[Dict[str, str]] = []
186
+
187
+ for i, detail in enumerate(pay_option_details):
188
+ if not detail:
189
+ continue
190
+ pay_method = _trim_str(getattr(detail, 'pay_method', None))
191
+ pay_option = _trim_str(getattr(detail, 'pay_option', None))
192
+ additional_info = getattr(detail, 'additional_info', None)
193
+ phone_raw = None
194
+ if additional_info is not None:
195
+ phone_raw = getattr(additional_info, 'phone_number', None)
196
+ phone_number = _trim_str(phone_raw)
197
+
198
+ is_card = pay_method in CREDIT_DEBIT_CARD_PAY_METHODS or pay_option == NETWORK_PAY_PG_CARD
199
+ is_ewallet = pay_option in EWALLET_PAY_OPTIONS
200
+
201
+ if is_card or is_ewallet:
202
+ field = f'payOptionDetails[{i}].additionalInfo.phoneNumber'
203
+ if not phone_number:
204
+ contexts.append(
205
+ _ctx(field, f'phoneNumber is required for card/e-wallet payment (payOptionDetails[{i}])')
206
+ )
207
+ else:
208
+ ln = _rune_len(phone_number)
209
+ if ln < 1 or ln > 15:
210
+ contexts.append(
211
+ _ctx(field, f'phoneNumber must be between 1 and 15 characters (payOptionDetails[{i}])')
212
+ )
213
+
214
+ if contexts:
215
+ raise ApiException(status=0, contexts=contexts)
216
+
217
+
218
+ def validate_optional_fields_with_required_nested_create_order_request(request: Any) -> None:
219
+ if request is None:
220
+ return
221
+ additional_info = getattr(request, 'additional_info', None)
222
+ if additional_info is None:
223
+ return
224
+ order = getattr(additional_info, 'order', None)
225
+ if not order:
226
+ return
227
+
228
+ contexts: List[Dict[str, str]] = []
229
+
230
+ buyer = getattr(order, 'buyer', None)
231
+ if buyer:
232
+ ext_type = _trim_str(getattr(buyer, 'external_user_type', None))
233
+ ext_id = _trim_str(getattr(buyer, 'external_user_id', None))
234
+ has_type = bool(ext_type)
235
+ has_id = bool(ext_id)
236
+ if has_id and not has_type:
237
+ contexts.append(
238
+ _ctx(
239
+ 'additionalInfo.order.buyer.externalUserType',
240
+ 'externalUserType is required when externalUserId is filled',
241
+ )
242
+ )
243
+ if has_type and not has_id:
244
+ contexts.append(
245
+ _ctx(
246
+ 'additionalInfo.order.buyer.externalUserId',
247
+ 'externalUserId is required when externalUserType is filled',
248
+ )
249
+ )
250
+
251
+ goods = getattr(order, 'goods', None)
252
+ if isinstance(goods, list) and len(goods) > 0:
253
+ for i, g in enumerate(goods):
254
+ if not g:
255
+ continue
256
+ name = _trim_str(getattr(g, 'name', None))
257
+ if not name:
258
+ contexts.append(
259
+ _ctx(
260
+ f'additionalInfo.order.goods[{i}].name',
261
+ 'name is required when goods is filled',
262
+ )
263
+ )
264
+
265
+ shipping_info = getattr(order, 'shipping_info', None)
266
+ if isinstance(shipping_info, list) and len(shipping_info) > 0:
267
+ for i, s in enumerate(shipping_info):
268
+ if not s:
269
+ continue
270
+ first_name = _trim_str(getattr(s, 'first_name', None))
271
+ if not first_name:
272
+ contexts.append(
273
+ _ctx(
274
+ f'additionalInfo.order.shippingInfo[{i}].firstName',
275
+ 'firstName is required when shippingInfo is filled',
276
+ )
277
+ )
278
+
279
+ if contexts:
280
+ raise ApiException(status=0, contexts=contexts)
281
+
282
+
283
+ validation_registry: Dict[str, List[Callable[[Any], None]]] = {
284
+ 'CreateOrderByApiRequest': [
285
+ validate_additional_info_required,
286
+ validate_money_value_pattern,
287
+ validate_valid_up_to_create_order_request,
288
+ validate_external_store_id_for_qris,
289
+ validate_sandbox_pay_method_and_pay_option,
290
+ validate_conditional_pay_option_additional_info_create_order_request,
291
+ validate_optional_fields_with_required_nested_create_order_request,
292
+ ],
293
+ 'CreateOrderByRedirectRequest': [
294
+ validate_additional_info_required,
295
+ validate_money_value_pattern,
296
+ validate_valid_up_to_create_order_request,
297
+ validate_sandbox_pay_method_and_pay_option,
298
+ validate_conditional_pay_option_additional_info_create_order_request,
299
+ validate_optional_fields_with_required_nested_create_order_request,
300
+ ],
301
+ 'CreateOrderRequest': [
302
+ validate_additional_info_required,
303
+ validate_money_value_pattern,
304
+ validate_valid_up_to_create_order_request,
305
+ validate_external_store_id_for_qris,
306
+ validate_sandbox_pay_method_and_pay_option,
307
+ validate_conditional_pay_option_additional_info_create_order_request,
308
+ validate_optional_fields_with_required_nested_create_order_request,
309
+ ],
310
+ }
311
+
312
+
313
+ def custom_validation(request: Any) -> None:
314
+ """Run all validators for the request type and aggregate client validation contexts."""
315
+ if request is None:
316
+ return
317
+
318
+ class_name = request.__class__.__name__
319
+ if class_name not in validation_registry:
320
+ return
321
+
322
+ aggregated: List[Dict[str, str]] = []
323
+ for validator in validation_registry[class_name]:
324
+ try:
325
+ validator(request)
326
+ except ApiException as e:
327
+ if e.contexts:
328
+ aggregated.extend(e.contexts)
329
+ else:
330
+ raise
331
+
332
+ if aggregated:
333
+ raise ApiException(status=0, contexts=aggregated)
@@ -190,7 +190,12 @@ class RESTClientObject:
190
190
  ):
191
191
  request_body = None
192
192
  if body is not None:
193
- request_body = json.dumps(body)
193
+ # If body is already a string or bytes (e.g. pre-serialized JSON from OpenAPI widget),
194
+ # send as-is to avoid double JSON encoding. Otherwise serialize.
195
+ if isinstance(body, (str, bytes)):
196
+ request_body = body
197
+ else:
198
+ request_body = json.dumps(body)
194
199
  r = self.pool_manager.request(
195
200
  method,
196
201
  url,
@@ -90,12 +90,37 @@ class OpenApiHeader:
90
90
  elif private_key:
91
91
  # Handle escaped newlines
92
92
  private_key = private_key.replace("\\n", "\n")
93
- private_key_obj = serialization.load_pem_private_key(
94
- private_key.encode(),
95
- password=None,
96
- backend=default_backend()
97
- )
98
- return private_key_obj
93
+
94
+ # Check if private key already has PEM headers/footers
95
+ if not private_key.strip().startswith('-----BEGIN'):
96
+ # Raw base64 key content - add PEM headers and footers
97
+ private_key = f"-----BEGIN PRIVATE KEY-----\n{private_key}\n-----END PRIVATE KEY-----"
98
+
99
+ try:
100
+ private_key_obj = serialization.load_pem_private_key(
101
+ private_key.encode(),
102
+ password=None,
103
+ backend=default_backend()
104
+ )
105
+ return private_key_obj
106
+ except ValueError as e:
107
+ # If loading fails, try alternative PEM formats
108
+ if "BEGIN PRIVATE KEY" in private_key:
109
+ # Already in PKCS#8 format, try RSA format
110
+ rsa_key = private_key.replace("-----BEGIN PRIVATE KEY-----", "-----BEGIN RSA PRIVATE KEY-----")
111
+ rsa_key = rsa_key.replace("-----END PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----")
112
+ try:
113
+ from cryptography.hazmat.primitives.serialization import load_pem_private_key
114
+ private_key_obj = load_pem_private_key(
115
+ rsa_key.encode(),
116
+ password=None,
117
+ backend=default_backend()
118
+ )
119
+ return private_key_obj
120
+ except:
121
+ pass
122
+
123
+ raise ValueError(f"Unable to load private key: {str(e)}. Please ensure the private key is in proper PEM format.")
99
124
  else:
100
125
  raise ValueError("Provide one of private_key or private_key_path")
101
126
 
@@ -155,14 +180,14 @@ class OpenApiHeader:
155
180
  # Generate unique request message ID
156
181
  req_msg_id = "sdk" + str(uuid.uuid4())[3:]
157
182
 
158
- # Return auth settings following snap_header pattern
183
+ # Return auth settings following correct field order: version, function, clientId, clientSecret, reqTime, reqMsgId, reserve
159
184
  return {
160
185
  VERSION: generateOpenApiSetting(key=VERSION, value=version),
161
186
  FUNCTION: generateOpenApiSetting(key=FUNCTION, value=function_name),
162
187
  CLIENT_ID: generateOpenApiSetting(key=CLIENT_ID, value=client_id),
188
+ CLIENT_SECRET: generateOpenApiSetting(key=CLIENT_SECRET, value=client_secret),
163
189
  REQ_TIME: generateOpenApiSetting(key=REQ_TIME, value=timestamp),
164
190
  REQ_MSG_ID: generateOpenApiSetting(key=REQ_MSG_ID, value=req_msg_id),
165
- CLIENT_SECRET: generateOpenApiSetting(key=CLIENT_SECRET, value=client_secret),
166
191
  RESERVE: generateOpenApiSetting(key=RESERVE, value="{}")
167
192
  }
168
193
 
@@ -15,10 +15,23 @@
15
15
  import importlib
16
16
  import pkgutil
17
17
  import os
18
+ import re
18
19
  from typing import List
19
20
 
20
21
  PACKAGE_NAME = 'dana'
21
22
 
23
+ # Only single path segments that are valid Python identifiers (no traversal / injection).
24
+ _SAFE_PKG_SEGMENT = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
25
+
26
+
27
+ def _assert_safe_import_segment(name: str, label: str) -> None:
28
+ if not name or not _SAFE_PKG_SEGMENT.fullmatch(name):
29
+ raise ValueError(
30
+ f"Refusing dynamic import: disallowed {label} {name!r} "
31
+ "(expected a single identifier-like package segment)"
32
+ )
33
+
34
+
22
35
  def import_all_models(base_path: str) -> None:
23
36
  """
24
37
  Imports all model modules from subdirectories of the specified base path.
@@ -48,6 +61,8 @@ def import_all_models(base_path: str) -> None:
48
61
  path_to_domain: List[str] = getattr(subdomain.module_finder, 'path', '')
49
62
  domain = os.path.basename(path_to_domain)
50
63
 
51
- # Construct the full module path and import
64
+ # Construct the full module path and import (whitelist segments — no dynamic/untrusted strings)
65
+ _assert_safe_import_segment(domain, "domain")
66
+ _assert_safe_import_segment(subdomain.name, "subdomain")
52
67
  module_name = f"{PACKAGE_NAME}.{domain}.{subdomain.name}.models"
53
68
  importlib.import_module(module_name)
@@ -21,6 +21,7 @@
21
21
  Generated by OpenAPI Generator (https://openapi-generator.tech)
22
22
  Do not edit the class manually.
23
23
  """ # noqa: E501
24
+ import json
24
25
  import warnings
25
26
  from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt
26
27
  from typing import Any, Dict, List, Optional, Tuple, Union, Type
@@ -1901,6 +1902,70 @@ class WidgetApi:
1901
1902
  # authentication setting
1902
1903
  _auth_settings: List[str] = [
1903
1904
  ]
1905
+ # For OPEN_API type, we use CLIENT_SECRET authentication with signature
1906
+ # merge list of auth settings with Open API runtime headers
1907
+ from dana.utils.open_api_header import OpenApiHeader
1908
+ _auth_settings = OpenApiHeader.merge_with_open_api_runtime_headers(_auth_settings)
1909
+ # Create the full request structure for OPEN_API
1910
+ # Wrap the simplified body parameters in the proper DANA request format
1911
+ # Extract accessToken from request body if available (widget-specific)
1912
+ request_body_dict = query_user_profile_request.to_dict()
1913
+ access_token = request_body_dict.get('accessToken', '')
1914
+ # Create body without accessToken (for queryUserProfile)
1915
+ body_without_access_token = {k: v for k, v in request_body_dict.items() if k != 'accessToken'}
1916
+ # Generate head parameters
1917
+ _generated_auth = OpenApiHeader.get_open_api_generated_headers(
1918
+ method='POST',
1919
+ resource_path='/dana/member/query/queryUserProfile.htm',
1920
+ body='{}', # Empty body for head generation
1921
+ function_name="dana.member.query.queryUserProfile",
1922
+ client_id=self.api_client.configuration.get_api_key_with_prefix('X_PARTNER_ID'),
1923
+ client_secret=self.api_client.configuration.get_api_key_with_prefix('CLIENT_SECRET')
1924
+ )
1925
+ # Extract values from auth settings for JSON body, ensuring correct field order
1926
+ head_params = {}
1927
+ # Add fields in the correct order: version, function, clientId, clientSecret, reqTime, reqMsgId
1928
+ for key in ['version', 'function', 'clientId', 'clientSecret', 'reqTime', 'reqMsgId']:
1929
+ if key in _generated_auth:
1930
+ head_params[key] = _generated_auth[key]['value']
1931
+ # Add accessToken before reserve if found in request body (widget-specific)
1932
+ if access_token:
1933
+ head_params['accessToken'] = access_token
1934
+ # Add reserve at the end
1935
+ if 'reserve' in _generated_auth:
1936
+ head_params['reserve'] = _generated_auth['reserve']['value']
1937
+ # Create the full request structure (use body without accessToken)
1938
+ request_body = {
1939
+ "request": {
1940
+ "head": head_params,
1941
+ "body": body_without_access_token
1942
+ }
1943
+ }
1944
+ # Generate signature (pass full structure, function will extract request part)
1945
+ _signature = OpenApiHeader.generate_open_api_signature(
1946
+ body=json.dumps(request_body),
1947
+ private_key=self.api_client.configuration.get_api_key_with_prefix('PRIVATE_KEY')
1948
+ )
1949
+ # Add signature to the request
1950
+ if _signature:
1951
+ request_body['signature'] = _signature
1952
+ # Convert final request to JSON string
1953
+ _body_params = json.dumps(request_body)
1954
+ return self.api_client.param_serialize(
1955
+ method='POST',
1956
+ resource_path='/dana/member/query/queryUserProfile.htm',
1957
+ path_params=_path_params,
1958
+ query_params=_query_params,
1959
+ header_params=_header_params,
1960
+ body=_body_params,
1961
+ post_params=_form_params,
1962
+ files=_files,
1963
+ auth_settings=_auth_settings,
1964
+ collection_formats=_collection_formats,
1965
+ _host=_host,
1966
+ _request_auth=_request_auth,
1967
+ _generated_auth=_generated_auth,
1968
+ )
1904
1969
  @validate_call
1905
1970
  def refund_order(
1906
1971
  self,