velocity-python 0.1.27__tar.gz → 0.1.28__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 (188) hide show
  1. {velocity_python-0.1.27/src/velocity_python.egg-info → velocity_python-0.1.28}/PKG-INFO +1 -1
  2. {velocity_python-0.1.27 → velocity_python-0.1.28}/pyproject.toml +1 -1
  3. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/payment/authorizenet_adapter.py +185 -14
  5. velocity_python-0.1.28/src/velocity/payment/authorizenet_mirror.py +211 -0
  6. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/payment/braintree_adapter.py +74 -28
  7. velocity_python-0.1.28/src/velocity/payment/braintree_mirror.py +210 -0
  8. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/payment/stripe_adapter.py +129 -40
  9. velocity_python-0.1.28/src/velocity/payment/stripe_mirror.py +310 -0
  10. {velocity_python-0.1.27 → velocity_python-0.1.28/src/velocity_python.egg-info}/PKG-INFO +1 -1
  11. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity_python.egg-info/SOURCES.txt +4 -0
  12. velocity_python-0.1.28/tests/test_payment_authorizenet_adapter.py +173 -0
  13. velocity_python-0.1.28/tests/test_payment_braintree_adapter.py +182 -0
  14. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_payment_stripe_adapter.py +175 -1
  15. velocity_python-0.1.27/tests/test_payment_braintree_adapter.py +0 -77
  16. {velocity_python-0.1.27 → velocity_python-0.1.28}/LICENSE +0 -0
  17. {velocity_python-0.1.27 → velocity_python-0.1.28}/README.md +0 -0
  18. {velocity_python-0.1.27 → velocity_python-0.1.28}/setup.cfg +0 -0
  19. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/__init__.py +0 -0
  20. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/amplify.py +0 -0
  21. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/amplify_build.py +0 -0
  22. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/assets/__init__.py +0 -0
  23. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/assets/backfill.py +0 -0
  24. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/assets/indexing.py +0 -0
  25. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/assets/references.py +0 -0
  26. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/assets/service.py +0 -0
  27. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/assets/usage_index.py +0 -0
  28. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/dirty_pipeline.py +0 -0
  29. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/handlers/__init__.py +0 -0
  30. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/handlers/base_handler.py +0 -0
  31. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/handlers/context.py +0 -0
  32. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/handlers/context_factory.py +0 -0
  33. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/handlers/exceptions.py +0 -0
  34. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  35. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  36. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  37. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  38. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/handlers/perf.py +0 -0
  39. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/handlers/response.py +0 -0
  40. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  41. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/s3.py +0 -0
  42. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/ssm_config.py +0 -0
  43. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/tests/__init__.py +0 -0
  44. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  45. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  46. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/aws/tests/test_response.py +0 -0
  47. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/__init__.py +0 -0
  48. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/core/__init__.py +0 -0
  49. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/core/async_support.py +0 -0
  50. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/core/column.py +0 -0
  51. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/core/database.py +0 -0
  52. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/core/decorators.py +0 -0
  53. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/core/engine.py +0 -0
  54. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/core/result.py +0 -0
  55. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/core/row.py +0 -0
  56. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/core/sequence.py +0 -0
  57. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/core/table.py +0 -0
  58. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/core/transaction.py +0 -0
  59. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/core/view.py +0 -0
  60. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/exceptions.py +0 -0
  61. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/migrations.py +0 -0
  62. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/__init__.py +0 -0
  63. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/base/__init__.py +0 -0
  64. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/base/initializer.py +0 -0
  65. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/base/operators.py +0 -0
  66. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/base/sql.py +0 -0
  67. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/base/types.py +0 -0
  68. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/mysql/__init__.py +0 -0
  69. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/mysql/operators.py +0 -0
  70. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/mysql/reserved.py +0 -0
  71. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/mysql/sql.py +0 -0
  72. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/mysql/types.py +0 -0
  73. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/postgres/__init__.py +0 -0
  74. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/postgres/operators.py +0 -0
  75. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/postgres/reserved.py +0 -0
  76. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/postgres/sql.py +0 -0
  77. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/postgres/types.py +0 -0
  78. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  79. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/sqlite/operators.py +0 -0
  80. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  81. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/sqlite/sql.py +0 -0
  82. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/sqlite/types.py +0 -0
  83. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  84. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  85. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  86. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  87. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/sqlserver/types.py +0 -0
  88. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/servers/tablehelper.py +0 -0
  89. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/__init__.py +0 -0
  90. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/common_db_test.py +0 -0
  91. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/__init__.py +0 -0
  92. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/common.py +0 -0
  93. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_column.py +0 -0
  94. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  95. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_database.py +0 -0
  96. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  97. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  98. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  99. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_result.py +0 -0
  100. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_row.py +0 -0
  101. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  102. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  103. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  104. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  105. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  106. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_table.py +0 -0
  107. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  108. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  109. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/sql/__init__.py +0 -0
  110. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/sql/common.py +0 -0
  111. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  112. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  113. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  114. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_db_utils.py +0 -0
  115. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_postgres.py +0 -0
  116. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  117. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  118. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_result_caching.py +0 -0
  119. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  120. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  121. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  122. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  123. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_sql_builder.py +0 -0
  124. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_tablehelper.py +0 -0
  125. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/tests/test_view_helper.py +0 -0
  126. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/db/utils.py +0 -0
  127. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/logging.py +0 -0
  128. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/__init__.py +0 -0
  129. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/conv/__init__.py +0 -0
  130. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/conv/iconv.py +0 -0
  131. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/conv/oconv.py +0 -0
  132. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/db.py +0 -0
  133. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/export.py +0 -0
  134. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/format.py +0 -0
  135. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/mail.py +0 -0
  136. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/merge.py +0 -0
  137. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/pdf.py +0 -0
  138. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/tests/__init__.py +0 -0
  139. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/tests/test_db.py +0 -0
  140. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/tests/test_fix.py +0 -0
  141. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/tests/test_format.py +0 -0
  142. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/tests/test_iconv.py +0 -0
  143. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/tests/test_merge.py +0 -0
  144. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/tests/test_oconv.py +0 -0
  145. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/tests/test_original_error.py +0 -0
  146. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/tests/test_timer.py +0 -0
  147. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/timer.py +0 -0
  148. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/misc/tools.py +0 -0
  149. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/payment/__init__.py +0 -0
  150. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/payment/base_adapter.py +0 -0
  151. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity/payment/charge_rules.py +0 -0
  152. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  153. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity_python.egg-info/entry_points.txt +0 -0
  154. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity_python.egg-info/requires.txt +0 -0
  155. {velocity_python-0.1.27 → velocity_python-0.1.28}/src/velocity_python.egg-info/top_level.txt +0 -0
  156. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_amplify_build.py +0 -0
  157. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_asset_indexing.py +0 -0
  158. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_asset_references.py +0 -0
  159. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_assets_service.py +0 -0
  160. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_async_support.py +0 -0
  161. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_batch_operations.py +0 -0
  162. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_concurrency_safety.py +0 -0
  163. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_connection_pool.py +0 -0
  164. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_connection_resilience.py +0 -0
  165. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_decorators.py +0 -0
  166. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_dirty_pipeline_fast_path.py +0 -0
  167. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_email_processing.py +0 -0
  168. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_iconv_money_to_cents.py +0 -0
  169. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_lambda_handler.py +0 -0
  170. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_lambda_handler_auth.py +0 -0
  171. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_mixins_import.py +0 -0
  172. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_n_plus_one.py +0 -0
  173. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_observability.py +0 -0
  174. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_payment_profile_sorting.py +0 -0
  175. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_pdf.py +0 -0
  176. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_prepared_statements.py +0 -0
  177. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_psycopg3_upgrade.py +0 -0
  178. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_query_cache.py +0 -0
  179. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_row_batch_update.py +0 -0
  180. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_row_cache_staleness.py +0 -0
  181. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_row_dirty_tracking.py +0 -0
  182. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_schema_migrations.py +0 -0
  183. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_security_hardening.py +0 -0
  184. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_spreadsheet_functions.py +0 -0
  185. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_sqs_per_record_transactions.py +0 -0
  186. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  187. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_table_alter.py +0 -0
  188. {velocity_python-0.1.27 → velocity_python-0.1.28}/tests/test_where_clause_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.27
3
+ Version: 0.1.28
4
4
  Summary: A rapid application development library for interfacing with data storage
5
5
  Author-email: Velocity Team <info@codeclubs.org>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "velocity-python"
7
- version = "0.1.27"
7
+ version = "0.1.28"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.27"
1
+ __version__ = version = "0.1.28"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -29,6 +29,13 @@ from typing import Any, Dict, List, Optional
29
29
  from authorizenet import apicontractsv1, apicontrollers
30
30
 
31
31
  from .base_adapter import PaymentProcessorAdapter, ProcessorError
32
+ from .authorizenet_mirror import (
33
+ sync_client_payment_account_from_authorize_account,
34
+ upsert_authorize_account_record,
35
+ upsert_authorize_customer_profile_record,
36
+ upsert_authorize_payment_profile_record,
37
+ upsert_authorize_transaction_record,
38
+ )
32
39
 
33
40
  logger = logging.getLogger(__name__)
34
41
 
@@ -132,20 +139,25 @@ class AuthorizeNetAdapter(PaymentProcessorAdapter):
132
139
  placeholder record so the routing layer can treat it uniformly.
133
140
  """
134
141
  client_id = client_data["client_id"]
135
-
136
- payment_account = tx.table("client_payment_accounts").new()
137
- payment_account["client_id"] = client_id
138
- payment_account["processor_type"] = "authorize_net"
139
- payment_account["processor_account_id"] = f"an_{client_id}"
140
- payment_account["account_status"] = "active"
141
- payment_account["charges_enabled"] = True
142
- payment_account["payouts_enabled"] = False
143
- payment_account["details_submitted"] = True
144
- payment_account["requirements_data"] = {}
145
- payment_account["capabilities"] = {
146
- "card_payments": True,
147
- "manual_settlement": True,
142
+ account = {
143
+ "client_id": client_id,
144
+ "processor_account_id": f"an_{client_id}",
145
+ "status": "active",
146
+ "charges_enabled": True,
147
+ "payouts_enabled": False,
148
+ "verification_status": "verified",
149
+ "metadata": {"account_type": "shared_merchant"},
148
150
  }
151
+ upsert_authorize_account_record(
152
+ tx,
153
+ account,
154
+ source="api:authorizenet_adapter.create_account",
155
+ )
156
+ sync_client_payment_account_from_authorize_account(
157
+ tx,
158
+ account,
159
+ client_id=client_id,
160
+ )
149
161
 
150
162
  return {
151
163
  "processor_account_id": f"an_{client_id}",
@@ -161,7 +173,7 @@ class AuthorizeNetAdapter(PaymentProcessorAdapter):
161
173
  """
162
174
  Authorize.Net shared merchant is always active if credentials are valid.
163
175
  """
164
- return {
176
+ account = {
165
177
  "account_id": processor_account_id,
166
178
  "status": "active",
167
179
  "charges_enabled": True,
@@ -172,6 +184,26 @@ class AuthorizeNetAdapter(PaymentProcessorAdapter):
172
184
  "verification_status": "verified",
173
185
  "metadata": {"account_type": "shared_merchant"},
174
186
  }
187
+ payment_account = tx.table("client_payment_accounts").find(
188
+ {
189
+ "processor_account_id": processor_account_id,
190
+ "processor_type": "authorize_net",
191
+ }
192
+ )
193
+ client_id = payment_account.get("client_id") if payment_account else None
194
+ if client_id:
195
+ account["client_id"] = client_id
196
+ upsert_authorize_account_record(
197
+ tx,
198
+ account,
199
+ source="api:authorizenet_adapter.get_account_status",
200
+ )
201
+ sync_client_payment_account_from_authorize_account(
202
+ tx,
203
+ account,
204
+ client_id=client_id,
205
+ )
206
+ return account
175
207
 
176
208
  def create_onboarding_link(
177
209
  self, tx, processor_account_id: str, return_url: str, refresh_url: str
@@ -225,12 +257,33 @@ class AuthorizeNetAdapter(PaymentProcessorAdapter):
225
257
  parts = e.error_message.split()
226
258
  for part in parts:
227
259
  if part.strip().isdigit():
260
+ upsert_authorize_customer_profile_record(
261
+ tx,
262
+ {
263
+ "customer_profile_id": part.strip(),
264
+ "email_address": email_address,
265
+ "description": customer_data.get(
266
+ "name", email_address
267
+ ),
268
+ },
269
+ source="api:authorizenet_adapter.get_or_create_customer_profile",
270
+ )
228
271
  return {
229
272
  "customer_profile_id": part.strip(),
230
273
  "created": False,
231
274
  }
232
275
  raise
233
276
 
277
+ upsert_authorize_customer_profile_record(
278
+ tx,
279
+ {
280
+ "customer_profile_id": response["customerProfileId"],
281
+ "email_address": email_address,
282
+ "description": customer_data.get("name", email_address),
283
+ },
284
+ source="api:authorizenet_adapter.get_or_create_customer_profile",
285
+ )
286
+
234
287
  return {
235
288
  "customer_profile_id": response["customerProfileId"],
236
289
  "created": True,
@@ -287,6 +340,24 @@ class AuthorizeNetAdapter(PaymentProcessorAdapter):
287
340
 
288
341
  controller = apicontrollers.createCustomerPaymentProfileController(request)
289
342
  response = self._execute(controller)
343
+ upsert_authorize_payment_profile_record(
344
+ tx,
345
+ {
346
+ "customer_profile_id": customer_profile_id,
347
+ "payment_profile_id": response["customerPaymentProfileId"],
348
+ "last4": str(payment_data.get("card_number") or "")[-4:] or None,
349
+ "expiration_date": payment_data.get("expiration_date"),
350
+ "billing_first_name": payment_data.get("first_name"),
351
+ "billing_last_name": payment_data.get("last_name"),
352
+ "billing_address": payment_data.get("address"),
353
+ "billing_city": payment_data.get("city"),
354
+ "billing_state": payment_data.get("state"),
355
+ "billing_zip": payment_data.get("zip"),
356
+ "is_default": payment_data.get("set_default", True),
357
+ "metadata": payment_data.get("metadata") or {},
358
+ },
359
+ source="api:authorizenet_adapter.attach_payment_method",
360
+ )
290
361
 
291
362
  return {
292
363
  "customer_profile_id": customer_profile_id,
@@ -326,6 +397,16 @@ class AuthorizeNetAdapter(PaymentProcessorAdapter):
326
397
  else:
327
398
  raise
328
399
 
400
+ upsert_authorize_payment_profile_record(
401
+ tx,
402
+ {
403
+ "customer_profile_id": customer_profile_id,
404
+ "payment_profile_id": payment_method_id,
405
+ "detached": True,
406
+ },
407
+ source="api:authorizenet_adapter.detach_payment_method",
408
+ )
409
+
329
410
  return {"payment_profile_id": payment_method_id, "detached": True}
330
411
 
331
412
  def delete_customer_profile(self, tx, customer_profile_id: str) -> Dict[str, Any]:
@@ -343,6 +424,12 @@ class AuthorizeNetAdapter(PaymentProcessorAdapter):
343
424
  else:
344
425
  raise
345
426
 
427
+ upsert_authorize_customer_profile_record(
428
+ tx,
429
+ {"customer_profile_id": customer_profile_id, "deleted": True},
430
+ source="api:authorizenet_adapter.delete_customer_profile",
431
+ )
432
+
346
433
  return {"customer_profile_id": customer_profile_id, "deleted": True}
347
434
 
348
435
  # ========================================================================
@@ -385,6 +472,24 @@ class AuthorizeNetAdapter(PaymentProcessorAdapter):
385
472
  response = self._execute(controller)
386
473
  trans = response.get("transactionResponse", {})
387
474
  code = int(trans.get("responseCode", 3))
475
+ status = "authorized" if RESPONSE_CODES.get(code) == "Approved" else "failed"
476
+ upsert_authorize_transaction_record(
477
+ tx,
478
+ {
479
+ "processor_transaction_id": trans.get("transId"),
480
+ "amount": float(amount_dollars),
481
+ "status": status,
482
+ "reason_for_transaction": payment_data.get("description"),
483
+ "remote_authcode": trans.get("authCode"),
484
+ "remote_responsecode": code,
485
+ "supported_id": payment_data.get("client_id"),
486
+ "supported_name": payment_data.get("description"),
487
+ "email_address": payment_data.get("customer_email")
488
+ or payment_data.get("donor_email"),
489
+ "raw_payload": response,
490
+ },
491
+ source="api:authorizenet_adapter.authorize_payment",
492
+ )
388
493
 
389
494
  if RESPONSE_CODES.get(code) == "Approved":
390
495
  return {
@@ -492,6 +597,24 @@ class AuthorizeNetAdapter(PaymentProcessorAdapter):
492
597
  response = self._execute(controller)
493
598
  trans = response.get("transactionResponse", {})
494
599
  code = int(trans.get("responseCode", 3))
600
+ status = RESPONSE_CODES.get(code, "Error")
601
+ upsert_authorize_transaction_record(
602
+ tx,
603
+ {
604
+ "processor_transaction_id": trans.get("transId"),
605
+ "amount": float(amount_dollars),
606
+ "status": status,
607
+ "reason_for_transaction": order.description if client_id or campaign else None,
608
+ "remote_authcode": trans.get("authCode"),
609
+ "remote_responsecode": code,
610
+ "supported_id": client_id or None,
611
+ "supported_name": campaign or None,
612
+ "email_address": payment_data.get("customer_email")
613
+ or payment_data.get("donor_email"),
614
+ "raw_payload": response,
615
+ },
616
+ source="api:authorizenet_adapter.charge_stored_payment_method",
617
+ )
495
618
 
496
619
  if RESPONSE_CODES.get(code) == "Approved":
497
620
  return {
@@ -581,6 +704,23 @@ class AuthorizeNetAdapter(PaymentProcessorAdapter):
581
704
  response = self._execute(controller)
582
705
  trans = response.get("transactionResponse", {})
583
706
  code = int(trans.get("responseCode", 3))
707
+ upsert_authorize_transaction_record(
708
+ tx,
709
+ {
710
+ "processor_transaction_id": trans.get("transId")
711
+ or processor_transaction_id,
712
+ "amount": float(decimal.Decimal(amount) / 100)
713
+ if amount is not None
714
+ else None,
715
+ "status": "captured"
716
+ if RESPONSE_CODES.get(code) == "Approved"
717
+ else "failed",
718
+ "remote_authcode": trans.get("authCode"),
719
+ "remote_responsecode": code,
720
+ "raw_payload": response,
721
+ },
722
+ source="api:authorizenet_adapter.capture_payment",
723
+ )
584
724
 
585
725
  if RESPONSE_CODES.get(code) == "Approved":
586
726
  captured_cents = amount if amount is not None else 0
@@ -635,6 +775,20 @@ class AuthorizeNetAdapter(PaymentProcessorAdapter):
635
775
  response = self._execute(controller)
636
776
  trans = response.get("transactionResponse", {})
637
777
  code = int(trans.get("responseCode", 3))
778
+ upsert_authorize_transaction_record(
779
+ tx,
780
+ {
781
+ "processor_transaction_id": trans.get("transId")
782
+ or processor_transaction_id,
783
+ "status": "cancelled"
784
+ if RESPONSE_CODES.get(code) == "Approved"
785
+ else "failed",
786
+ "remote_authcode": trans.get("authCode"),
787
+ "remote_responsecode": code,
788
+ "raw_payload": response,
789
+ },
790
+ source="api:authorizenet_adapter.cancel_payment",
791
+ )
638
792
 
639
793
  if RESPONSE_CODES.get(code) == "Approved":
640
794
  return {
@@ -695,6 +849,23 @@ class AuthorizeNetAdapter(PaymentProcessorAdapter):
695
849
  response = self._execute(controller)
696
850
  trans = response.get("transactionResponse", {})
697
851
  code = int(trans.get("responseCode", 3))
852
+ upsert_authorize_transaction_record(
853
+ tx,
854
+ {
855
+ "processor_transaction_id": trans.get("transId")
856
+ or processor_charge_id,
857
+ "amount": float(decimal.Decimal(amount) / 100)
858
+ if amount is not None
859
+ else None,
860
+ "status": "Refunded"
861
+ if RESPONSE_CODES.get(code) == "Approved"
862
+ else "Error",
863
+ "remote_authcode": trans.get("authCode"),
864
+ "remote_responsecode": code,
865
+ "raw_payload": response,
866
+ },
867
+ source="api:authorizenet_adapter.refund_payment",
868
+ )
698
869
 
699
870
  if RESPONSE_CODES.get(code) == "Approved":
700
871
  return {
@@ -0,0 +1,211 @@
1
+ import json
2
+ from datetime import datetime, timezone
3
+ from typing import Any, Dict, Optional
4
+
5
+
6
+ def _get_value(data: Any, key: str, default: Any = None) -> Any:
7
+ if isinstance(data, dict):
8
+ return data.get(key, default)
9
+ return getattr(data, key, default)
10
+
11
+
12
+ def _to_jsonable(value: Any) -> Any:
13
+ if value is None or isinstance(value, (str, int, float, bool)):
14
+ return value
15
+ if isinstance(value, dict):
16
+ return {str(key): _to_jsonable(item) for key, item in value.items()}
17
+ if isinstance(value, (list, tuple, set)):
18
+ return [_to_jsonable(item) for item in value]
19
+ if hasattr(value, "__dict__"):
20
+ return {
21
+ str(key): _to_jsonable(item)
22
+ for key, item in vars(value).items()
23
+ if not str(key).startswith("_")
24
+ }
25
+ return str(value)
26
+
27
+
28
+ def _json_dumps(value: Any) -> Optional[str]:
29
+ if value is None:
30
+ return None
31
+ return json.dumps(_to_jsonable(value), default=str)
32
+
33
+
34
+ def _table(tx, table_name: str):
35
+ if tx is None:
36
+ return None
37
+ try:
38
+ table = tx.table(table_name)
39
+ except Exception:
40
+ return None
41
+ try:
42
+ if hasattr(table, "exists") and not table.exists():
43
+ return None
44
+ except Exception:
45
+ pass
46
+ return table
47
+
48
+
49
+ def _upsert(tx, table_name: str, payload: Dict[str, Any], key: Dict[str, Any]):
50
+ table = _table(tx, table_name)
51
+ if not table:
52
+ return None
53
+ table.upsert(payload, key)
54
+ return payload
55
+
56
+
57
+ def _now() -> datetime:
58
+ return datetime.now(timezone.utc)
59
+
60
+
61
+ def upsert_authorize_account_record(
62
+ tx, account: Dict[str, Any], *, source: str = "api:authorizenet"
63
+ ) -> Optional[Dict[str, Any]]:
64
+ processor_account_id = _get_value(account, "processor_account_id") or _get_value(
65
+ account, "account_id"
66
+ )
67
+ if not processor_account_id:
68
+ return None
69
+ payload = {
70
+ "processor_account_id": processor_account_id,
71
+ "client_id": _get_value(account, "client_id"),
72
+ "account_status": _get_value(account, "status"),
73
+ "charges_enabled": _get_value(account, "charges_enabled"),
74
+ "payouts_enabled": _get_value(account, "payouts_enabled"),
75
+ "verification_status": _get_value(account, "verification_status"),
76
+ "metadata": _to_jsonable(_get_value(account, "metadata") or {}),
77
+ "raw_payload": _to_jsonable(account),
78
+ "sys_modified_by": source,
79
+ "sys_dirty": True,
80
+ }
81
+ return _upsert(
82
+ tx,
83
+ "authorize_accounts",
84
+ payload,
85
+ {"processor_account_id": processor_account_id},
86
+ )
87
+
88
+
89
+ def sync_client_payment_account_from_authorize_account(
90
+ tx, account: Dict[str, Any], *, client_id: Any
91
+ ):
92
+ if not client_id:
93
+ return None
94
+ processor_account_id = _get_value(account, "processor_account_id") or _get_value(
95
+ account, "account_id"
96
+ )
97
+ if not processor_account_id:
98
+ return None
99
+
100
+ payload = {
101
+ "client_id": client_id,
102
+ "processor_type": "authorize_net",
103
+ "processor_account_id": processor_account_id,
104
+ "account_status": _get_value(account, "status") or "active",
105
+ "capabilities": {
106
+ "card_payments": True,
107
+ "manual_settlement": True,
108
+ },
109
+ "configuration": {
110
+ "verification_status": _get_value(account, "verification_status"),
111
+ },
112
+ "metadata": _to_jsonable(_get_value(account, "metadata") or {}),
113
+ "onboarding_complete": True,
114
+ "charges_enabled": True,
115
+ "payouts_enabled": False,
116
+ "details_submitted": True,
117
+ }
118
+ return _upsert(
119
+ tx,
120
+ "client_payment_accounts",
121
+ payload,
122
+ {"client_id": client_id, "processor_type": "authorize_net"},
123
+ )
124
+
125
+
126
+ def upsert_authorize_customer_profile_record(
127
+ tx, customer_profile: Dict[str, Any], *, source: str = "api:authorizenet"
128
+ ) -> Optional[Dict[str, Any]]:
129
+ customer_profile_id = _get_value(customer_profile, "customer_profile_id") or _get_value(
130
+ customer_profile, "id"
131
+ )
132
+ if not customer_profile_id:
133
+ return None
134
+ payload = {
135
+ "customer_profile_id": customer_profile_id,
136
+ "email_address": _get_value(customer_profile, "email_address")
137
+ or _get_value(customer_profile, "email"),
138
+ "description": _get_value(customer_profile, "description"),
139
+ "deleted": bool(_get_value(customer_profile, "deleted")),
140
+ "metadata": _to_jsonable(_get_value(customer_profile, "metadata") or {}),
141
+ "raw_payload": _to_jsonable(customer_profile),
142
+ "lastupdateddate": _now(),
143
+ "sys_modified_by": source,
144
+ "sys_dirty": True,
145
+ }
146
+ return _upsert(
147
+ tx,
148
+ "authorize_customer_profiles",
149
+ payload,
150
+ {"customer_profile_id": customer_profile_id},
151
+ )
152
+
153
+
154
+ def upsert_authorize_payment_profile_record(
155
+ tx, payment_profile: Dict[str, Any], *, source: str = "api:authorizenet"
156
+ ) -> Optional[Dict[str, Any]]:
157
+ payment_profile_id = _get_value(payment_profile, "payment_profile_id") or _get_value(
158
+ payment_profile, "id"
159
+ )
160
+ if not payment_profile_id:
161
+ return None
162
+ payload = {
163
+ "payment_profile_id": payment_profile_id,
164
+ "customer_profile_id": _get_value(payment_profile, "customer_profile_id"),
165
+ "last4": _get_value(payment_profile, "last4"),
166
+ "expiration_date": _get_value(payment_profile, "expiration_date"),
167
+ "billing_first_name": _get_value(payment_profile, "billing_first_name"),
168
+ "billing_last_name": _get_value(payment_profile, "billing_last_name"),
169
+ "billing_address": _get_value(payment_profile, "billing_address"),
170
+ "billing_city": _get_value(payment_profile, "billing_city"),
171
+ "billing_state": _get_value(payment_profile, "billing_state"),
172
+ "billing_zip": _get_value(payment_profile, "billing_zip"),
173
+ "is_default": _get_value(payment_profile, "is_default"),
174
+ "detached": bool(_get_value(payment_profile, "detached")),
175
+ "metadata": _to_jsonable(_get_value(payment_profile, "metadata") or {}),
176
+ "raw_payload": _to_jsonable(payment_profile),
177
+ "lastupdateddate": _now(),
178
+ "sys_modified_by": source,
179
+ "sys_dirty": True,
180
+ }
181
+ return _upsert(
182
+ tx,
183
+ "authorize_payment_profiles",
184
+ payload,
185
+ {"payment_profile_id": payment_profile_id},
186
+ )
187
+
188
+
189
+ def upsert_authorize_transaction_record(
190
+ tx, transaction: Dict[str, Any], *, source: str = "api:authorizenet"
191
+ ) -> Optional[Dict[str, Any]]:
192
+ remote_transid = _get_value(transaction, "remote_transid") or _get_value(
193
+ transaction, "processor_transaction_id"
194
+ )
195
+ if not remote_transid:
196
+ return None
197
+ payload = {
198
+ "remote_transid": remote_transid,
199
+ "amount": _get_value(transaction, "amount"),
200
+ "status": _get_value(transaction, "status"),
201
+ "lastupdateddate": _now(),
202
+ "createddate": _get_value(transaction, "createddate") or _now(),
203
+ "reason_for_transaction": _get_value(transaction, "reason_for_transaction"),
204
+ "remote_authcode": _get_value(transaction, "remote_authcode"),
205
+ "remote_responsecode": _get_value(transaction, "remote_responsecode"),
206
+ "supported_id": _get_value(transaction, "supported_id"),
207
+ "supported_name": _get_value(transaction, "supported_name"),
208
+ "email_address": _get_value(transaction, "email_address"),
209
+ "reconcile_response": _json_dumps(_get_value(transaction, "raw_payload") or transaction),
210
+ }
211
+ return _upsert(tx, "authorize_transactions", payload, {"remote_transid": remote_transid})