dana-python 2.2.2__tar.gz → 3.0.0__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 (254) hide show
  1. {dana_python-2.2.2/dana_python.egg-info → dana_python-3.0.0}/PKG-INFO +7 -10
  2. {dana_python-2.2.2 → dana_python-3.0.0}/README.md +1 -1
  3. {dana_python-2.2.2 → dana_python-3.0.0}/dana/utils/snap_configuration.py +3 -3
  4. {dana_python-2.2.2 → dana_python-3.0.0}/dana/webhook/webhook.py +38 -16
  5. {dana_python-2.2.2 → dana_python-3.0.0/dana_python.egg-info}/PKG-INFO +7 -10
  6. {dana_python-2.2.2 → dana_python-3.0.0}/dana_python.egg-info/SOURCES.txt +3 -0
  7. dana_python-3.0.0/dana_python.egg-info/requires.txt +7 -0
  8. {dana_python-2.2.2 → dana_python-3.0.0}/pyproject.toml +6 -9
  9. dana_python-3.0.0/tests/test_dependency_floors.py +25 -0
  10. dana_python-3.0.0/tests/test_snap_configuration.py +15 -0
  11. {dana_python-2.2.2 → dana_python-3.0.0}/tests/test_webhook.py +66 -0
  12. dana_python-3.0.0/tests/test_webhook_key_selection.py +35 -0
  13. dana_python-2.2.2/dana_python.egg-info/requires.txt +0 -10
  14. {dana_python-2.2.2 → dana_python-3.0.0}/LICENSE +0 -0
  15. {dana_python-2.2.2 → dana_python-3.0.0}/dana/__init__.py +0 -0
  16. {dana_python-2.2.2 → dana_python-3.0.0}/dana/api_client.py +0 -0
  17. {dana_python-2.2.2 → dana_python-3.0.0}/dana/api_response.py +0 -0
  18. {dana_python-2.2.2 → dana_python-3.0.0}/dana/base/__init__.py +0 -0
  19. {dana_python-2.2.2 → dana_python-3.0.0}/dana/base/configuration.py +0 -0
  20. {dana_python-2.2.2 → dana_python-3.0.0}/dana/base/model.py +0 -0
  21. {dana_python-2.2.2 → dana_python-3.0.0}/dana/base/types.py +0 -0
  22. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/__init__.py +0 -0
  23. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/__init__.py +0 -0
  24. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/api/__init__.py +0 -0
  25. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/api/disbursement_api.py +0 -0
  26. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/custom_validation.py +0 -0
  27. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/enum.py +0 -0
  28. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/__init__.py +0 -0
  29. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/bank_account_inquiry_request.py +0 -0
  30. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/bank_account_inquiry_request_additional_info.py +0 -0
  31. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/bank_account_inquiry_response.py +0 -0
  32. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/bank_account_inquiry_response_additional_info.py +0 -0
  33. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/dana_account_inquiry_request.py +0 -0
  34. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/dana_account_inquiry_request_additional_info.py +0 -0
  35. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/dana_account_inquiry_response.py +0 -0
  36. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/money.py +0 -0
  37. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/transfer_to_bank_inquiry_status_request.py +0 -0
  38. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/transfer_to_bank_inquiry_status_response.py +0 -0
  39. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/transfer_to_bank_request.py +0 -0
  40. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/transfer_to_bank_request_additional_info.py +0 -0
  41. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/transfer_to_bank_response.py +0 -0
  42. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/transfer_to_dana_inquiry_status_request.py +0 -0
  43. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/transfer_to_dana_inquiry_status_response.py +0 -0
  44. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/transfer_to_dana_request.py +0 -0
  45. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/transfer_to_dana_request_additional_info.py +0 -0
  46. {dana_python-2.2.2 → dana_python-3.0.0}/dana/disbursement/v1/models/transfer_to_dana_response.py +0 -0
  47. {dana_python-2.2.2 → dana_python-3.0.0}/dana/exceptions.py +0 -0
  48. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/__init__.py +0 -0
  49. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/__init__.py +0 -0
  50. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/api/__init__.py +0 -0
  51. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/api/merchant_management_api.py +0 -0
  52. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/enum.py +0 -0
  53. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/__init__.py +0 -0
  54. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/address_info.py +0 -0
  55. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/asset_card_list_item.py +0 -0
  56. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/business_docs.py +0 -0
  57. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/create_division_request.py +0 -0
  58. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/create_division_request_ext_info.py +0 -0
  59. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/create_division_response.py +0 -0
  60. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/create_division_response_response.py +0 -0
  61. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/create_division_response_response_body.py +0 -0
  62. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/create_division_response_response_head.py +0 -0
  63. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/create_shop_request.py +0 -0
  64. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/create_shop_response.py +0 -0
  65. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/create_shop_response_response.py +0 -0
  66. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/create_shop_response_response_body.py +0 -0
  67. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/create_shop_response_response_head.py +0 -0
  68. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/division_resource_info.py +0 -0
  69. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/member_asset_result_info.py +0 -0
  70. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/merchant_account_info.py +0 -0
  71. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/merchant_certificate_info.py +0 -0
  72. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/merchant_contact_address.py +0 -0
  73. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/merchant_contact_email.py +0 -0
  74. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/merchant_contact_mobile_no.py +0 -0
  75. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/merchant_corporate_certificate.py +0 -0
  76. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/merchant_information.py +0 -0
  77. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/merchant_resource_information.py +0 -0
  78. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/mobile_no_info.py +0 -0
  79. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/pic_info.py +0 -0
  80. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_asset_card_list_request.py +0 -0
  81. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_asset_card_list_response.py +0 -0
  82. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_asset_card_list_response_response.py +0 -0
  83. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_asset_card_list_response_response_body.py +0 -0
  84. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_asset_card_list_response_response_head.py +0 -0
  85. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_division_request.py +0 -0
  86. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_division_response.py +0 -0
  87. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_division_response_response.py +0 -0
  88. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_division_response_response_body.py +0 -0
  89. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_division_response_response_head.py +0 -0
  90. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_merchant_info_request.py +0 -0
  91. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_merchant_info_response.py +0 -0
  92. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_merchant_info_response_response.py +0 -0
  93. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_merchant_info_response_response_body.py +0 -0
  94. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_merchant_info_response_response_head.py +0 -0
  95. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_merchant_resource_request.py +0 -0
  96. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_merchant_resource_response.py +0 -0
  97. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_merchant_resource_response_response.py +0 -0
  98. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_merchant_resource_response_response_body.py +0 -0
  99. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_merchant_resource_response_response_head.py +0 -0
  100. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_shop_request.py +0 -0
  101. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_shop_response.py +0 -0
  102. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_shop_response_response.py +0 -0
  103. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_shop_response_response_body.py +0 -0
  104. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/query_shop_response_response_head.py +0 -0
  105. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/result_info.py +0 -0
  106. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/shop_resource_info.py +0 -0
  107. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/update_division_request.py +0 -0
  108. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/update_division_response.py +0 -0
  109. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/update_division_response_response.py +0 -0
  110. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/update_division_response_response_body.py +0 -0
  111. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/update_division_response_response_head.py +0 -0
  112. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/update_shop_request.py +0 -0
  113. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/update_shop_response.py +0 -0
  114. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/update_shop_response_response.py +0 -0
  115. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/update_shop_response_response_head.py +0 -0
  116. {dana_python-2.2.2 → dana_python-3.0.0}/dana/merchant_management/v1/models/user_name.py +0 -0
  117. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/__init__.py +0 -0
  118. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/__init__.py +0 -0
  119. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/api/__init__.py +0 -0
  120. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/api/payment_gateway_api.py +0 -0
  121. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/custom_validation.py +0 -0
  122. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/enum.py +0 -0
  123. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/__init__.py +0 -0
  124. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/actor_context.py +0 -0
  125. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/amount_detail.py +0 -0
  126. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/audit_info.py +0 -0
  127. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/buyer.py +0 -0
  128. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/cancel_order_request.py +0 -0
  129. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/cancel_order_response.py +0 -0
  130. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/consult_pay_payment_info.py +0 -0
  131. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/consult_pay_request.py +0 -0
  132. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/consult_pay_request_additional_info.py +0 -0
  133. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/consult_pay_response.py +0 -0
  134. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/create_order_by_api_additional_info.py +0 -0
  135. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/create_order_by_api_request.py +0 -0
  136. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/create_order_by_redirect_additional_info.py +0 -0
  137. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/create_order_by_redirect_request.py +0 -0
  138. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/create_order_response.py +0 -0
  139. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/create_order_response_additional_info.py +0 -0
  140. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/env_info.py +0 -0
  141. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/goods.py +0 -0
  142. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/money.py +0 -0
  143. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/order_api_object.py +0 -0
  144. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/order_redirect_object.py +0 -0
  145. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/pay_option_additional_info.py +0 -0
  146. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/pay_option_detail.py +0 -0
  147. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/pay_option_info.py +0 -0
  148. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/payment_view.py +0 -0
  149. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/promo_info.py +0 -0
  150. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/query_payment_request.py +0 -0
  151. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/query_payment_response.py +0 -0
  152. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/query_payment_response_additional_info.py +0 -0
  153. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/refund_option_bill.py +0 -0
  154. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/refund_order_request.py +0 -0
  155. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/refund_order_request_additional_info.py +0 -0
  156. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/refund_order_response.py +0 -0
  157. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/seller.py +0 -0
  158. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/shipping_info.py +0 -0
  159. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/status_detail.py +0 -0
  160. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/time_detail.py +0 -0
  161. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/url_param.py +0 -0
  162. {dana_python-2.2.2 → dana_python-3.0.0}/dana/payment_gateway/v1/models/virtual_account_info.py +0 -0
  163. {dana_python-2.2.2 → dana_python-3.0.0}/dana/rest.py +0 -0
  164. {dana_python-2.2.2 → dana_python-3.0.0}/dana/utils/date_validation.py +0 -0
  165. {dana_python-2.2.2 → dana_python-3.0.0}/dana/utils/models.py +0 -0
  166. {dana_python-2.2.2 → dana_python-3.0.0}/dana/utils/open_api_configuration.py +0 -0
  167. {dana_python-2.2.2 → dana_python-3.0.0}/dana/utils/open_api_header.py +0 -0
  168. {dana_python-2.2.2 → dana_python-3.0.0}/dana/utils/script.py +0 -0
  169. {dana_python-2.2.2 → dana_python-3.0.0}/dana/utils/snap_header.py +0 -0
  170. {dana_python-2.2.2 → dana_python-3.0.0}/dana/utils/url.py +0 -0
  171. {dana_python-2.2.2 → dana_python-3.0.0}/dana/webhook/__init__.py +0 -0
  172. {dana_python-2.2.2 → dana_python-3.0.0}/dana/webhook/finish_notify_payment_info.py +0 -0
  173. {dana_python-2.2.2 → dana_python-3.0.0}/dana/webhook/finish_notify_request.py +0 -0
  174. {dana_python-2.2.2 → dana_python-3.0.0}/dana/webhook/finish_notify_request_additional_info.py +0 -0
  175. {dana_python-2.2.2 → dana_python-3.0.0}/dana/webhook/finish_notify_response.py +0 -0
  176. {dana_python-2.2.2 → dana_python-3.0.0}/dana/webhook/money.py +0 -0
  177. {dana_python-2.2.2 → dana_python-3.0.0}/dana/webhook/pay_option_info.py +0 -0
  178. {dana_python-2.2.2 → dana_python-3.0.0}/dana/webhook/shop_info.py +0 -0
  179. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/__init__.py +0 -0
  180. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/__init__.py +0 -0
  181. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/api/__init__.py +0 -0
  182. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/api/widget_api.py +0 -0
  183. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/custom_validation.py +0 -0
  184. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/enum.py +0 -0
  185. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/__init__.py +0 -0
  186. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/account_info.py +0 -0
  187. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/account_unbinding_request.py +0 -0
  188. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/account_unbinding_request_additional_info.py +0 -0
  189. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/account_unbinding_response.py +0 -0
  190. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/amount_detail.py +0 -0
  191. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/apply_ott_request.py +0 -0
  192. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/apply_ott_request_additional_info.py +0 -0
  193. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/apply_ott_response.py +0 -0
  194. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/apply_ott_response_user_resources_inner.py +0 -0
  195. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/apply_token_authorization_code_request.py +0 -0
  196. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/apply_token_refresh_token_request.py +0 -0
  197. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/apply_token_response.py +0 -0
  198. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/apply_token_response_additional_info.py +0 -0
  199. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/apply_token_response_additional_info_user_info.py +0 -0
  200. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/balance_inquiry_request.py +0 -0
  201. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/balance_inquiry_request_additional_info.py +0 -0
  202. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/balance_inquiry_response.py +0 -0
  203. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/buyer.py +0 -0
  204. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/cancel_order_request.py +0 -0
  205. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/cancel_order_response.py +0 -0
  206. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/env_info.py +0 -0
  207. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/goods.py +0 -0
  208. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/international_order_info.py +0 -0
  209. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/international_order_info_exchange_rate.py +0 -0
  210. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/money.py +0 -0
  211. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/oauth2_url_data.py +0 -0
  212. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/oauth2_url_data_seamless_data.py +0 -0
  213. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/order.py +0 -0
  214. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/pay_option_detail.py +0 -0
  215. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/pay_option_detail_additional_info.py +0 -0
  216. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/pay_option_info.py +0 -0
  217. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/payment_promo_info.py +0 -0
  218. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/payment_view.py +0 -0
  219. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/query_payment_request.py +0 -0
  220. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/query_payment_response.py +0 -0
  221. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/query_payment_response_additional_info.py +0 -0
  222. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/query_user_profile_request.py +0 -0
  223. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/query_user_profile_response.py +0 -0
  224. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/query_user_profile_response_response.py +0 -0
  225. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/query_user_profile_response_response_body.py +0 -0
  226. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/query_user_profile_response_response_head.py +0 -0
  227. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/refund_order_request.py +0 -0
  228. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/refund_order_request_additional_info.py +0 -0
  229. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/refund_order_response.py +0 -0
  230. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/refund_promo_info.py +0 -0
  231. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/result_info.py +0 -0
  232. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/seller.py +0 -0
  233. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/service_info.py +0 -0
  234. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/shipping_info.py +0 -0
  235. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/status_detail.py +0 -0
  236. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/time_detail.py +0 -0
  237. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/url_param.py +0 -0
  238. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/user_resource_info.py +0 -0
  239. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/virtual_account_info.py +0 -0
  240. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/widget_payment_request.py +0 -0
  241. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/widget_payment_request_additional_info.py +0 -0
  242. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/models/widget_payment_response.py +0 -0
  243. {dana_python-2.2.2 → dana_python-3.0.0}/dana/widget/v1/util.py +0 -0
  244. {dana_python-2.2.2 → dana_python-3.0.0}/dana_python.egg-info/dependency_links.txt +0 -0
  245. {dana_python-2.2.2 → dana_python-3.0.0}/dana_python.egg-info/top_level.txt +0 -0
  246. {dana_python-2.2.2 → dana_python-3.0.0}/setup.cfg +0 -0
  247. {dana_python-2.2.2 → dana_python-3.0.0}/tests/test_disbursement_api.py +0 -0
  248. {dana_python-2.2.2 → dana_python-3.0.0}/tests/test_disbursement_custom_validation_enrich.py +0 -0
  249. {dana_python-2.2.2 → dana_python-3.0.0}/tests/test_merchant_management_api.py +0 -0
  250. {dana_python-2.2.2 → dana_python-3.0.0}/tests/test_payment_gateway_api.py +0 -0
  251. {dana_python-2.2.2 → dana_python-3.0.0}/tests/test_payment_gateway_with_automation.py +0 -0
  252. {dana_python-2.2.2 → dana_python-3.0.0}/tests/test_snap_header.py +0 -0
  253. {dana_python-2.2.2 → dana_python-3.0.0}/tests/test_widget_api.py +0 -0
  254. {dana_python-2.2.2 → dana_python-3.0.0}/tests/test_widget_with_automation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dana-python
3
- Version: 2.2.2
3
+ Version: 3.0.0
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>
@@ -8,19 +8,16 @@ License-Expression: Apache-2.0
8
8
  Project-URL: homepage, https://dashboard.dana.id/api-docs
9
9
  Project-URL: repository, https://github.com/dana-id/dana-python
10
10
  Keywords: DANA,DANA ID Docs,DANA SDK,DANA Python,DANA API Client,DANA Python API Client,DANA Python SDK
11
- Requires-Python: >3.9.1
11
+ Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
- Requires-Dist: annotated-types==0.7.0
15
- Requires-Dist: cffi==2.0.0
16
- Requires-Dist: cryptography<46.0.0,>=44.0.2
17
- Requires-Dist: pycparser==2.23
14
+ Requires-Dist: annotated-types>=0.7.0
15
+ Requires-Dist: cryptography>=50.0.0
18
16
  Requires-Dist: pydantic<3.0.0,>=2.10.6
19
17
  Requires-Dist: pydantic-core<3.0.0,>=2.27.2
20
- Requires-Dist: python-dateutil==2.9.0.post0
21
- Requires-Dist: six==1.17.0
18
+ Requires-Dist: python-dateutil>=2.9.0.post0
22
19
  Requires-Dist: typing-extensions<5.0.0,>=4.12.2
23
- Requires-Dist: urllib3<3.0.0,>=2.3.0
20
+ Requires-Dist: urllib3<3.0.0,>=2.8.0
24
21
  Dynamic: license-file
25
22
 
26
23
  # dana-python
@@ -62,7 +59,7 @@ Here is the link: https://github.com/dana-id/uat-script.
62
59
 
63
60
  ## Requirements.
64
61
 
65
- Python 3.9.1+
62
+ Python 3.10+ (patched releases: 3.11.17, 3.12.15, 3.13.17, 3.14.9, 3.15.1 or later)
66
63
 
67
64
  ## Installation & Usage
68
65
  ### pip install
@@ -37,7 +37,7 @@ Here is the link: https://github.com/dana-id/uat-script.
37
37
 
38
38
  ## Requirements.
39
39
 
40
- Python 3.9.1+
40
+ Python 3.10+ (patched releases: 3.11.17, 3.12.15, 3.13.17, 3.14.9, 3.15.1 or later)
41
41
 
42
42
  ## Installation & Usage
43
43
  ### pip install
@@ -231,9 +231,9 @@ class SnapConfiguration(BaseConfiguration):
231
231
  ) -> None:
232
232
  """Constructor
233
233
  """
234
- self.host = "http://api.sandbox.dana.id" if (api_key["DANA_ENV"] == Env.SANDBOX or api_key["ENV"] == Env.SANDBOX) else \
234
+ self.host = "https://api.sandbox.dana.id" if (api_key["DANA_ENV"] == Env.SANDBOX or api_key["ENV"] == Env.SANDBOX) else \
235
235
  "https://api.saas.dana.id" if (api_key["DANA_ENV"] == Env.PRODUCTION or api_key["ENV"] == Env.PRODUCTION) else None
236
- self._base_path = "http://api.sandbox.dana.id" if (api_key["DANA_ENV"] == Env.SANDBOX or api_key["ENV"] == Env.SANDBOX) else \
236
+ self._base_path = "https://api.sandbox.dana.id" if (api_key["DANA_ENV"] == Env.SANDBOX or api_key["ENV"] == Env.SANDBOX) else \
237
237
  "https://api.saas.dana.id" if (api_key["DANA_ENV"] == Env.PRODUCTION or api_key["ENV"] == Env.PRODUCTION) else None
238
238
  """Default Base url
239
239
  """
@@ -595,7 +595,7 @@ class SnapConfiguration(BaseConfiguration):
595
595
 
596
596
  host_settings = [
597
597
  {
598
- 'url': "http://api.sandbox.dana.id",
598
+ 'url': "https://api.sandbox.dana.id",
599
599
  'description': "No description provided",
600
600
  }
601
601
  ] if (self.api_key["DANA_ENV"] == Env.SANDBOX or self.api_key["ENV"] == Env.SANDBOX) else [
@@ -25,7 +25,7 @@ from cryptography.hazmat.primitives.asymmetric import padding
25
25
 
26
26
  from dana.webhook.finish_notify_request import FinishNotifyRequest
27
27
 
28
- # Sandbox gateway public key used for webhook signature verification when DANA_ENV/ENV is sandbox.
28
+ # Sandbox gateway public key used for webhook signature verification only when DANA_ENV/ENV is explicitly sandbox.
29
29
  SANDBOX_WEBHOOK_PUBLIC_KEY = """-----BEGIN PUBLIC KEY-----
30
30
  MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnaKVGRbin4Wh4KN35OPh
31
31
  ytJBjYTz7QZKSZjmHfiHxFmulfT87rta+IvGJ0rCBgg+1EtKk1hX8G5gPGJs1htJ
@@ -37,9 +37,41 @@ X6JV1OSST1C9sbPGzMHZ8AGB51BM0mok7davD/5irUk+f0C25OgzkwtxAt80dkDo
37
37
  -----END PUBLIC KEY-----"""
38
38
 
39
39
 
40
+ def resolve_webhook_key_content(public_key=None, public_key_path=None) -> str:
41
+ """
42
+ Selects the webhook public key content.
43
+
44
+ The sandbox key is used only when the environment is explicitly sandbox
45
+ (first non-empty of DANA_ENV, ENV, trimmed and lower-cased). In any other
46
+ case, including when neither variable is set, the supplied key is used:
47
+ public_key_path first, then public_key.
48
+
49
+ Raises:
50
+ ValueError: If no key is available or the key file cannot be read.
51
+ """
52
+ env = (os.getenv("DANA_ENV") or os.getenv("ENV") or "").strip().lower()
53
+ if env == "sandbox":
54
+ return SANDBOX_WEBHOOK_PUBLIC_KEY
55
+ if public_key_path:
56
+ try:
57
+ return Path(public_key_path).read_text().strip()
58
+ except Exception as e:
59
+ raise ValueError(f"Failed to read key from file path '{public_key_path}': {e}")
60
+ if public_key:
61
+ return public_key.strip()
62
+ raise ValueError(
63
+ "Either 'public_key' or 'public_key_path' must be provided. "
64
+ "In production, pass your DANA public key via 'public_key' or 'public_key_path'. "
65
+ "Set DANA_ENV=sandbox to use the built-in sandbox key."
66
+ )
67
+
68
+
40
69
  class WebhookParser:
41
70
  """
42
- Verifies incoming webhook signatures and parse webhook request into FinishNotifyRequest object
71
+ Verifies incoming webhook signatures and parse webhook request into FinishNotifyRequest object.
72
+
73
+ The built-in sandbox key is used only when DANA_ENV (or ENV) is explicitly "sandbox";
74
+ otherwise the supplied public_key_path / public_key is required.
43
75
  """
44
76
  def __init__(self, public_key: str = None, public_key_path: str = None):
45
77
  """
@@ -48,23 +80,13 @@ class WebhookParser:
48
80
  public_key (str, optional): The public key as a string. Defaults to None.
49
81
  public_key_path (str, optional): Path to the public key PEM file. Defaults to None.
50
82
  If provided, this will be prioritized over public_key.
83
+ When DANA_ENV (or ENV) is "sandbox", the built-in sandbox key is used and both
84
+ arguments are ignored. For any other value, including unset, one of them is required.
51
85
  Raises:
52
- ValueError: If neither public_key nor public_key_path is provided,
86
+ ValueError: If no key is available (and the environment is not sandbox),
53
87
  if the key file cannot be read, or if the key format is invalid.
54
88
  """
55
- key_input_content = ""
56
- env = (os.getenv("DANA_ENV") or os.getenv("ENV") or "").strip().lower()
57
- if env == "sandbox" or env == "":
58
- key_input_content = SANDBOX_WEBHOOK_PUBLIC_KEY
59
- elif public_key_path:
60
- try:
61
- key_input_content = Path(public_key_path).read_text().strip()
62
- except Exception as e:
63
- raise ValueError(f"Failed to read key from file path '{public_key_path}': {e}")
64
- elif public_key:
65
- key_input_content = public_key.strip()
66
- else:
67
- raise ValueError("Either 'public_key' or 'public_key_path' must be provided.")
89
+ key_input_content = resolve_webhook_key_content(public_key, public_key_path)
68
90
 
69
91
  if not key_input_content:
70
92
  raise ValueError("Key content is empty.")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dana-python
3
- Version: 2.2.2
3
+ Version: 3.0.0
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>
@@ -8,19 +8,16 @@ License-Expression: Apache-2.0
8
8
  Project-URL: homepage, https://dashboard.dana.id/api-docs
9
9
  Project-URL: repository, https://github.com/dana-id/dana-python
10
10
  Keywords: DANA,DANA ID Docs,DANA SDK,DANA Python,DANA API Client,DANA Python API Client,DANA Python SDK
11
- Requires-Python: >3.9.1
11
+ Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
- Requires-Dist: annotated-types==0.7.0
15
- Requires-Dist: cffi==2.0.0
16
- Requires-Dist: cryptography<46.0.0,>=44.0.2
17
- Requires-Dist: pycparser==2.23
14
+ Requires-Dist: annotated-types>=0.7.0
15
+ Requires-Dist: cryptography>=50.0.0
18
16
  Requires-Dist: pydantic<3.0.0,>=2.10.6
19
17
  Requires-Dist: pydantic-core<3.0.0,>=2.27.2
20
- Requires-Dist: python-dateutil==2.9.0.post0
21
- Requires-Dist: six==1.17.0
18
+ Requires-Dist: python-dateutil>=2.9.0.post0
22
19
  Requires-Dist: typing-extensions<5.0.0,>=4.12.2
23
- Requires-Dist: urllib3<3.0.0,>=2.3.0
20
+ Requires-Dist: urllib3<3.0.0,>=2.8.0
24
21
  Dynamic: license-file
25
22
 
26
23
  # dana-python
@@ -62,7 +59,7 @@ Here is the link: https://github.com/dana-id/uat-script.
62
59
 
63
60
  ## Requirements.
64
61
 
65
- Python 3.9.1+
62
+ Python 3.10+ (patched releases: 3.11.17, 3.12.15, 3.13.17, 3.14.9, 3.15.1 or later)
66
63
 
67
64
  ## Installation & Usage
68
65
  ### pip install
@@ -237,12 +237,15 @@ dana_python.egg-info/SOURCES.txt
237
237
  dana_python.egg-info/dependency_links.txt
238
238
  dana_python.egg-info/requires.txt
239
239
  dana_python.egg-info/top_level.txt
240
+ tests/test_dependency_floors.py
240
241
  tests/test_disbursement_api.py
241
242
  tests/test_disbursement_custom_validation_enrich.py
242
243
  tests/test_merchant_management_api.py
243
244
  tests/test_payment_gateway_api.py
244
245
  tests/test_payment_gateway_with_automation.py
246
+ tests/test_snap_configuration.py
245
247
  tests/test_snap_header.py
246
248
  tests/test_webhook.py
249
+ tests/test_webhook_key_selection.py
247
250
  tests/test_widget_api.py
248
251
  tests/test_widget_with_automation.py
@@ -0,0 +1,7 @@
1
+ annotated-types>=0.7.0
2
+ cryptography>=50.0.0
3
+ pydantic<3.0.0,>=2.10.6
4
+ pydantic-core<3.0.0,>=2.27.2
5
+ python-dateutil>=2.9.0.post0
6
+ typing-extensions<5.0.0,>=4.12.2
7
+ urllib3<3.0.0,>=2.8.0
@@ -1,10 +1,10 @@
1
1
  [project]
2
2
  name = "dana-python"
3
- version = "2.2.2"
3
+ version = "3.0.0"
4
4
  readme = "README.md"
5
5
  description = "API Client (SDK) for DANA APIs based on https://dashboard.dana.id/api-docs"
6
6
  license = "Apache-2.0"
7
- requires-python = ">3.9.1"
7
+ requires-python = ">=3.10"
8
8
  authors = [
9
9
  { name = "DANA Package Manager ", email = "package-manager@dana.id" },
10
10
  ]
@@ -13,16 +13,13 @@ maintainers = [
13
13
  ]
14
14
  keywords = ["DANA", "DANA ID Docs", "DANA SDK", "DANA Python", "DANA API Client", "DANA Python API Client", "DANA Python SDK"]
15
15
  dependencies = [
16
- "annotated-types==0.7.0",
17
- "cffi==2.0.0",
18
- "cryptography>=44.0.2,<46.0.0",
19
- "pycparser==2.23",
16
+ "annotated-types>=0.7.0",
17
+ "cryptography>=50.0.0",
20
18
  "pydantic>=2.10.6,<3.0.0",
21
19
  "pydantic-core>=2.27.2,<3.0.0",
22
- "python-dateutil==2.9.0.post0",
23
- "six==1.17.0",
20
+ "python-dateutil>=2.9.0.post0",
24
21
  "typing-extensions>=4.12.2,<5.0.0",
25
- "urllib3>=2.3.0,<3.0.0"
22
+ "urllib3>=2.8.0,<3.0.0"
26
23
  ]
27
24
 
28
25
  [project.urls]
@@ -0,0 +1,25 @@
1
+ from importlib.metadata import version
2
+ try:
3
+ import tomllib # 3.11+
4
+ except ModuleNotFoundError: # Python 3.10
5
+ import tomli as tomllib
6
+ from pathlib import Path
7
+
8
+ PYPROJECT = tomllib.loads((Path(__file__).parent.parent / "pyproject.toml").read_text())
9
+
10
+ def _major_minor(v):
11
+ return tuple(int(p) for p in v.split(".")[:2])
12
+
13
+ def test_requires_python_floor():
14
+ assert PYPROJECT["project"]["requires-python"] == ">=3.10"
15
+
16
+ def test_cryptography_spec_has_floor_and_no_cap():
17
+ spec = next(d for d in PYPROJECT["project"]["dependencies"] if d.startswith("cryptography"))
18
+ assert spec == "cryptography>=50.0.0"
19
+
20
+ def test_urllib3_spec():
21
+ assert "urllib3>=2.8.0,<3.0.0" in PYPROJECT["project"]["dependencies"]
22
+
23
+ def test_installed_versions_are_patched():
24
+ assert _major_minor(version("cryptography")) >= (50, 0)
25
+ assert _major_minor(version("urllib3")) >= (2, 8)
@@ -0,0 +1,15 @@
1
+ from dana.utils.snap_configuration import SnapConfiguration, Env
2
+
3
+
4
+ def _cfg(env):
5
+ return SnapConfiguration(api_key={"DANA_ENV": env, "ENV": None})
6
+
7
+
8
+ def test_sandbox_host_is_https():
9
+ cfg = _cfg(Env.SANDBOX)
10
+ assert cfg.host == "https://api.sandbox.dana.id"
11
+ assert cfg.get_host_settings()[0]["url"] == "https://api.sandbox.dana.id"
12
+
13
+
14
+ def test_production_host_unchanged():
15
+ assert _cfg(Env.PRODUCTION).host == "https://api.saas.dana.id"
@@ -14,13 +14,25 @@
14
14
 
15
15
  import json
16
16
  import os
17
+ import pytest
18
+ from cryptography.hazmat.primitives import serialization
19
+ from cryptography.hazmat.primitives.asymmetric import rsa
17
20
  from dana.webhook.finish_notify_request import FinishNotifyRequest
18
21
  from dana.webhook import WebhookParser
22
+ from dana.webhook.webhook import SANDBOX_WEBHOOK_PUBLIC_KEY
19
23
  from dana.utils.snap_header import SnapHeader
20
24
  # Import fixtures directly from their modules to avoid circular imports
21
25
  from tests.fixtures.api_client import api_instance_payment_gateway
22
26
  from tests.fixtures.payment_gateway import webhook_key_pair
23
27
 
28
+ @pytest.fixture(autouse=True)
29
+ def sandbox_webhook_key(monkeypatch):
30
+ """These payloads are signed with the sandbox gateway key, so select it explicitly
31
+ (an unset DANA_ENV no longer implies sandbox); monkeypatch restores the environment."""
32
+ monkeypatch.setenv("DANA_ENV", "sandbox")
33
+ monkeypatch.delenv("ENV", raising=False)
34
+
35
+
24
36
  class TestWebhookParser:
25
37
  def test_webhook_signature_and_parsing_success(self):
26
38
  # Load keys from environment variables
@@ -312,3 +324,57 @@ class TestWebhookParser:
312
324
  assert result.amount.value == "1000.00"
313
325
  assert result.latest_transaction_status == "00"
314
326
  assert result.transaction_status_desc == "SUCCESS"
327
+
328
+
329
+ def _sandbox_signed_notification():
330
+ """The notification from test_webhook_signature_and_parsing_success, signed with the sandbox gateway key."""
331
+ return {
332
+ "http_method": "POST",
333
+ "relative_path_url": "/api/v2/test-notif/dana",
334
+ "headers": {
335
+ "Channel-Id": "DANA",
336
+ "Charset": "UTF-8",
337
+ "Content-Type": "application/json",
338
+ "User-Agent": "Jakarta Commons-HttpClient/3.1",
339
+ "X-External-Id": "cFQ0PK5yS9wkMTMOVem4fIoUuyuA28jg",
340
+ "X-Partner-Id": "2025090110410957288340",
341
+ "X-Signature": "d/7mle7A+FCl4zvBZ2dMr3s7TVbbaK+toMtZwoev4OmLhn6Ctz/ynMaL3m3vHjAmV3UL3Fq5xp9thZFsO8BY74Vehqr1N9LQblV6i3TfMwT6lMvvhzWr0Fjbasyj23c5nFu1MOxpBiZFMMDNh8GQNLBAehHbjOmNldXSL6OQYRrK/TN9tdDyYFK6ltnKf4BN6bZa2ViAlI/np/U3QBW2LnDL82+8ZK7tYVF5bZyLLUSLXeWXBGQFTSDWqN+JdUHSnxGdQr3hZ7Y9Vqm/7G6rj6NrCxLPiEJYq1DQO3DjokMsORA2lOxzuo53bwqmhmD1mFhJKWF1JmyJuFdo2HB9JA==",
342
+ "X-Timestamp": "2025-09-16T12:11:30+07:00",
343
+ },
344
+ "body": '{"amount":{"currency":"IDR","value":"100000.00"},"originalReferenceNo":"20250916111230999500166191900293793","merchantId":"216620080007039826152","latestTransactionStatus":"00","additionalInfo":{"paidTime":"1757998714761","paymentInfo":{"payOptionInfos":[{"transAmount":{"currency":"IDR","value":"100000.00"},"payAmount":{"currency":"IDR","value":"100000.00"},"payMethod":"NETWORK_PAY","payOption":"NETWORK_PAY_PG_LINKAJA"}],"extendInfo":"{\"externalPromoInfos\":[]}"}},"originalPartnerReferenceNo":"LINKIT25091757998646","createdTime":"1757998647000","finishedTime":"1757998714761","transactionStatusDesc":"SUCCESS"}',
345
+ }
346
+
347
+
348
+ def _other_public_key_pem():
349
+ key = rsa.generate_private_key(public_exponent=65537, key_size=2048).public_key()
350
+ return key.public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo).decode()
351
+
352
+
353
+ class TestWebhookParserOutsideSandbox:
354
+ """Outside an explicit sandbox environment the parser verifies against the supplied key,
355
+ so a sandbox-signed webhook is accepted only if the merchant supplied the sandbox key."""
356
+
357
+ @pytest.fixture(autouse=True)
358
+ def not_sandbox(self, monkeypatch):
359
+ monkeypatch.delenv("DANA_ENV", raising=False)
360
+ monkeypatch.delenv("ENV", raising=False)
361
+
362
+ def test_supplied_key_verifies_when_env_unset(self):
363
+ parser = WebhookParser(public_key=SANDBOX_WEBHOOK_PUBLIC_KEY)
364
+
365
+ result = parser.parse_webhook(**_sandbox_signed_notification())
366
+
367
+ assert result.original_partner_reference_no == "LINKIT25091757998646"
368
+
369
+ @pytest.mark.parametrize("env", [
370
+ {},
371
+ {"DANA_ENV": "production"},
372
+ {"DANA_ENV": "production", "ENV": "sandbox"},
373
+ ])
374
+ def test_sandbox_signed_webhook_rejected_with_merchant_key(self, monkeypatch, env):
375
+ for name, value in env.items():
376
+ monkeypatch.setenv(name, value)
377
+ parser = WebhookParser(public_key=_other_public_key_pem())
378
+
379
+ with pytest.raises(ValueError, match="Signature verification failed"):
380
+ parser.parse_webhook(**_sandbox_signed_notification())
@@ -0,0 +1,35 @@
1
+ import pytest
2
+ from cryptography.hazmat.primitives.asymmetric import rsa
3
+ from cryptography.hazmat.primitives import serialization
4
+ from dana.webhook.webhook import resolve_webhook_key_content, SANDBOX_WEBHOOK_PUBLIC_KEY
5
+
6
+ def _pem():
7
+ k = rsa.generate_private_key(public_exponent=65537, key_size=2048).public_key()
8
+ return k.public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo).decode()
9
+
10
+ @pytest.fixture(autouse=True)
11
+ def _clear_env(monkeypatch):
12
+ monkeypatch.delenv("DANA_ENV", raising=False)
13
+ monkeypatch.delenv("ENV", raising=False)
14
+
15
+ def test_env_unset_uses_supplied_key():
16
+ key = _pem()
17
+ assert resolve_webhook_key_content(key, None) == key.strip()
18
+
19
+ def test_env_unset_without_key_raises():
20
+ with pytest.raises(ValueError, match="Set DANA_ENV=sandbox to use the built-in sandbox key."):
21
+ resolve_webhook_key_content(None, None)
22
+
23
+ def test_explicit_sandbox_ignores_supplied_key(monkeypatch):
24
+ monkeypatch.setenv("DANA_ENV", " Sandbox ")
25
+ assert resolve_webhook_key_content(_pem(), None) == SANDBOX_WEBHOOK_PUBLIC_KEY
26
+
27
+ def test_empty_dana_env_falls_through_to_env(monkeypatch):
28
+ monkeypatch.setenv("DANA_ENV", "")
29
+ monkeypatch.setenv("ENV", "sandbox")
30
+ assert resolve_webhook_key_content(_pem(), None) == SANDBOX_WEBHOOK_PUBLIC_KEY
31
+
32
+ def test_production_uses_key_path_over_string(monkeypatch, tmp_path):
33
+ monkeypatch.setenv("DANA_ENV", "production")
34
+ path_key = _pem(); p = tmp_path / "k.pem"; p.write_text(path_key)
35
+ assert resolve_webhook_key_content(_pem(), str(p)) == path_key.strip()
@@ -1,10 +0,0 @@
1
- annotated-types==0.7.0
2
- cffi==2.0.0
3
- cryptography<46.0.0,>=44.0.2
4
- pycparser==2.23
5
- pydantic<3.0.0,>=2.10.6
6
- pydantic-core<3.0.0,>=2.27.2
7
- python-dateutil==2.9.0.post0
8
- six==1.17.0
9
- typing-extensions<5.0.0,>=4.12.2
10
- urllib3<3.0.0,>=2.3.0
File without changes