velocity-python 0.1.27__tar.gz → 0.1.29__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.
- {velocity_python-0.1.27/src/velocity_python.egg-info → velocity_python-0.1.29}/PKG-INFO +5 -1
- {velocity_python-0.1.27 → velocity_python-0.1.29}/pyproject.toml +7 -1
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/__init__.py +1 -1
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/mixins/data_service.py +165 -6
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/payment/authorizenet_adapter.py +185 -14
- velocity_python-0.1.29/src/velocity/payment/authorizenet_mirror.py +211 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/payment/braintree_adapter.py +74 -28
- velocity_python-0.1.29/src/velocity/payment/braintree_mirror.py +210 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/payment/stripe_adapter.py +129 -40
- velocity_python-0.1.29/src/velocity/payment/stripe_mirror.py +310 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29/src/velocity_python.egg-info}/PKG-INFO +5 -1
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity_python.egg-info/SOURCES.txt +4 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity_python.egg-info/requires.txt +6 -0
- velocity_python-0.1.29/tests/test_payment_authorizenet_adapter.py +173 -0
- velocity_python-0.1.29/tests/test_payment_braintree_adapter.py +182 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_payment_stripe_adapter.py +175 -1
- velocity_python-0.1.27/tests/test_payment_braintree_adapter.py +0 -77
- {velocity_python-0.1.27 → velocity_python-0.1.29}/LICENSE +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/README.md +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/setup.cfg +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/amplify_build.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/assets/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/assets/backfill.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/assets/indexing.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/assets/references.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/assets/service.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/assets/usage_index.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/dirty_pipeline.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/base_handler.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/context.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/context_factory.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/exceptions.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/perf.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/s3.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/ssm_config.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/tests/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/tests/test_response.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/core/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/core/async_support.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/core/engine.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/core/result.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/core/row.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/core/table.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/core/view.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/exceptions.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/migrations.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/base/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/base/initializer.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/base/operators.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/base/sql.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/base/types.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/mysql/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/mysql/operators.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/mysql/reserved.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/mysql/sql.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/mysql/types.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/postgres/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/postgres/sql.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/sqlite/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/sqlite/operators.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/sqlite/reserved.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/sqlite/sql.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/sqlite/types.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/sqlserver/operators.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/sqlserver/sql.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/sqlserver/types.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/common_db_test.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/common.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_column.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_connections.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_database.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_engine.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_imports.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_result.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_row.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_table.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/sql/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/sql/common.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_db_utils.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_postgres.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_result_caching.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_sql_builder.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_tablehelper.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/tests/test_view_helper.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/db/utils.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/logging.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/export.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/pdf.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/tests/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/tests/test_db.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/tests/test_fix.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/tests/test_format.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/tests/test_iconv.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/tests/test_merge.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/tests/test_oconv.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/tests/test_original_error.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/tests/test_timer.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/payment/__init__.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/payment/base_adapter.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/payment/charge_rules.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity_python.egg-info/entry_points.txt +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_amplify_build.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_asset_indexing.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_asset_references.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_assets_service.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_async_support.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_batch_operations.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_concurrency_safety.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_connection_pool.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_connection_resilience.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_decorators.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_dirty_pipeline_fast_path.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_email_processing.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_iconv_money_to_cents.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_lambda_handler.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_lambda_handler_auth.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_mixins_import.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_n_plus_one.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_observability.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_payment_profile_sorting.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_pdf.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_prepared_statements.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_psycopg3_upgrade.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_query_cache.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_row_batch_update.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_row_cache_staleness.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_row_dirty_tracking.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_schema_migrations.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_security_hardening.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_sqs_per_record_transactions.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_sys_modified_count_postgres_demo.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/tests/test_table_alter.py +0 -0
- {velocity_python-0.1.27 → velocity_python-0.1.29}/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.
|
|
3
|
+
Version: 0.1.29
|
|
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
|
|
@@ -27,6 +27,10 @@ Requires-Dist: boto3>=1.35.0; extra == "aws"
|
|
|
27
27
|
Requires-Dist: requests>=2.32.0; extra == "aws"
|
|
28
28
|
Provides-Extra: excel
|
|
29
29
|
Requires-Dist: openpyxl>=3.1.0; extra == "excel"
|
|
30
|
+
Provides-Extra: parquet
|
|
31
|
+
Requires-Dist: pyarrow>=15.0.0; extra == "parquet"
|
|
32
|
+
Provides-Extra: ods
|
|
33
|
+
Requires-Dist: odfpy>=1.4.0; extra == "ods"
|
|
30
34
|
Provides-Extra: templates
|
|
31
35
|
Requires-Dist: jinja2>=3.1.0; extra == "templates"
|
|
32
36
|
Provides-Extra: pdf
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "velocity-python"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.29"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Velocity Team", email="info@codeclubs.org" },
|
|
10
10
|
]
|
|
@@ -45,6 +45,12 @@ aws = [
|
|
|
45
45
|
excel = [
|
|
46
46
|
"openpyxl>=3.1.0",
|
|
47
47
|
]
|
|
48
|
+
parquet = [
|
|
49
|
+
"pyarrow>=15.0.0",
|
|
50
|
+
]
|
|
51
|
+
ods = [
|
|
52
|
+
"odfpy>=1.4.0",
|
|
53
|
+
]
|
|
48
54
|
templates = [
|
|
49
55
|
"jinja2>=3.1.0",
|
|
50
56
|
]
|
{velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/aws/handlers/mixins/data_service.py
RENAMED
|
@@ -6,11 +6,14 @@ that uses velocity.db for database access.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import base64
|
|
9
|
+
import csv
|
|
9
10
|
import datetime
|
|
10
11
|
import importlib
|
|
12
|
+
import json
|
|
11
13
|
import logging
|
|
12
14
|
import re
|
|
13
|
-
|
|
15
|
+
import xml.etree.ElementTree as ET
|
|
16
|
+
from io import BytesIO, StringIO
|
|
14
17
|
|
|
15
18
|
from velocity.aws import dirty_pipeline
|
|
16
19
|
from velocity.misc import export
|
|
@@ -333,7 +336,8 @@ class DataServiceMixin:
|
|
|
333
336
|
"message": message,
|
|
334
337
|
"missing": missing,
|
|
335
338
|
}
|
|
336
|
-
|
|
339
|
+
_file_export_formats_early = {"excel", "csv", "tsv", "json", "jsonl", "xml", "html", "markdown", "xlsx", "parquet", "ods"}
|
|
340
|
+
if result_format in _file_export_formats_early:
|
|
337
341
|
return {
|
|
338
342
|
"headers": payload.get("headers", []),
|
|
339
343
|
"rows": [],
|
|
@@ -354,7 +358,10 @@ class DataServiceMixin:
|
|
|
354
358
|
swallowed_error = getattr(tx, "_last_return_default_error", None)
|
|
355
359
|
if swallowed_error:
|
|
356
360
|
tx._last_return_default_error = None
|
|
357
|
-
|
|
361
|
+
|
|
362
|
+
_file_export_formats = {"excel", "csv", "tsv", "json", "jsonl", "xml", "html", "markdown", "xlsx", "parquet", "ods"}
|
|
363
|
+
|
|
364
|
+
if result_format in _file_export_formats:
|
|
358
365
|
data = {
|
|
359
366
|
"headers": payload.get(
|
|
360
367
|
"headers", [x.replace("_", " ").title() for x in result.headers]
|
|
@@ -373,7 +380,7 @@ class DataServiceMixin:
|
|
|
373
380
|
|
|
374
381
|
# If the DB call failed but was swallowed (return_default), surface a reason.
|
|
375
382
|
# Common symptoms are empty rows + null SQL.
|
|
376
|
-
if swallowed_error and result_format
|
|
383
|
+
if swallowed_error and result_format in _file_export_formats:
|
|
377
384
|
error_message = swallowed_error.get("message") or "Unknown database error"
|
|
378
385
|
context.response().toast(
|
|
379
386
|
f"Query failed for '{obj}': {error_message.splitlines()[0]}",
|
|
@@ -575,6 +582,143 @@ class DataServiceMixin:
|
|
|
575
582
|
#
|
|
576
583
|
# Payload parameters
|
|
577
584
|
|
|
585
|
+
# ---------------------------------------------------------------------------
|
|
586
|
+
# Export format helpers
|
|
587
|
+
# ---------------------------------------------------------------------------
|
|
588
|
+
|
|
589
|
+
@staticmethod
|
|
590
|
+
def _safe_xml_tag(name):
|
|
591
|
+
"""Sanitise a column name so it is a valid XML element name."""
|
|
592
|
+
tag = re.sub(r"[^a-zA-Z0-9_.-]", "_", str(name))
|
|
593
|
+
if tag and tag[0].isdigit():
|
|
594
|
+
tag = "_" + tag
|
|
595
|
+
return tag or "_col"
|
|
596
|
+
|
|
597
|
+
@classmethod
|
|
598
|
+
def _build_export_buffer(cls, result_format, headers, rows, filename_base):
|
|
599
|
+
"""
|
|
600
|
+
Build a (bytes_buffer, filename, mime_type) tuple for the given
|
|
601
|
+
result_format. Returns None if the format is not handled here.
|
|
602
|
+
"""
|
|
603
|
+
if result_format == "csv":
|
|
604
|
+
buf = StringIO()
|
|
605
|
+
writer = csv.writer(buf)
|
|
606
|
+
writer.writerow(headers)
|
|
607
|
+
writer.writerows(rows)
|
|
608
|
+
return buf.getvalue().encode("utf-8"), f"{filename_base}.csv", "text/csv"
|
|
609
|
+
|
|
610
|
+
if result_format == "tsv":
|
|
611
|
+
buf = StringIO()
|
|
612
|
+
writer = csv.writer(buf, delimiter="\t")
|
|
613
|
+
writer.writerow(headers)
|
|
614
|
+
writer.writerows(rows)
|
|
615
|
+
return buf.getvalue().encode("utf-8"), f"{filename_base}.tsv", "text/tab-separated-values"
|
|
616
|
+
|
|
617
|
+
if result_format == "json":
|
|
618
|
+
data = [dict(zip(headers, row)) for row in rows]
|
|
619
|
+
return json.dumps(data, default=str).encode("utf-8"), f"{filename_base}.json", "application/json"
|
|
620
|
+
|
|
621
|
+
if result_format == "jsonl":
|
|
622
|
+
lines = [json.dumps(dict(zip(headers, row)), default=str) for row in rows]
|
|
623
|
+
return "\n".join(lines).encode("utf-8"), f"{filename_base}.jsonl", "application/x-ndjson"
|
|
624
|
+
|
|
625
|
+
if result_format == "xml":
|
|
626
|
+
root = ET.Element("rows")
|
|
627
|
+
for row in rows:
|
|
628
|
+
row_el = ET.SubElement(root, "row")
|
|
629
|
+
for header, value in zip(headers, row):
|
|
630
|
+
col_el = ET.SubElement(row_el, cls._safe_xml_tag(header))
|
|
631
|
+
col_el.text = "" if value is None else str(value)
|
|
632
|
+
xml_bytes = ET.tostring(root, encoding="unicode").encode("utf-8")
|
|
633
|
+
return xml_bytes, f"{filename_base}.xml", "application/xml"
|
|
634
|
+
|
|
635
|
+
if result_format == "html":
|
|
636
|
+
th_cells = "".join(f"<th>{h}</th>" for h in headers)
|
|
637
|
+
tr_rows = "".join(
|
|
638
|
+
"<tr>" + "".join(f"<td>{'' if v is None else str(v)}</td>" for v in row) + "</tr>"
|
|
639
|
+
for row in rows
|
|
640
|
+
)
|
|
641
|
+
html = (
|
|
642
|
+
f"<!DOCTYPE html><html><head><meta charset='utf-8'></head>"
|
|
643
|
+
f"<body><table border='1'><thead><tr>{th_cells}</tr></thead>"
|
|
644
|
+
f"<tbody>{tr_rows}</tbody></table></body></html>"
|
|
645
|
+
)
|
|
646
|
+
return html.encode("utf-8"), f"{filename_base}.html", "text/html"
|
|
647
|
+
|
|
648
|
+
if result_format == "markdown":
|
|
649
|
+
header_row = "| " + " | ".join(str(h) for h in headers) + " |"
|
|
650
|
+
separator = "| " + " | ".join("---" for _ in headers) + " |"
|
|
651
|
+
data_rows = [
|
|
652
|
+
"| " + " | ".join("" if v is None else str(v) for v in row) + " |"
|
|
653
|
+
for row in rows
|
|
654
|
+
]
|
|
655
|
+
md = "\n".join([header_row, separator] + data_rows)
|
|
656
|
+
return md.encode("utf-8"), f"{filename_base}.md", "text/markdown"
|
|
657
|
+
|
|
658
|
+
if result_format == "xlsx":
|
|
659
|
+
try:
|
|
660
|
+
from openpyxl import Workbook
|
|
661
|
+
except ImportError:
|
|
662
|
+
raise ImportError("openpyxl is required for xlsx export (install velocity-python[excel])")
|
|
663
|
+
wb = Workbook()
|
|
664
|
+
ws = wb.active
|
|
665
|
+
ws.append(list(headers))
|
|
666
|
+
for row in rows:
|
|
667
|
+
ws.append(list(row))
|
|
668
|
+
buf = BytesIO()
|
|
669
|
+
wb.save(buf)
|
|
670
|
+
return (
|
|
671
|
+
buf.getvalue(),
|
|
672
|
+
f"{filename_base}.xlsx",
|
|
673
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
674
|
+
)
|
|
675
|
+
|
|
676
|
+
if result_format == "parquet":
|
|
677
|
+
try:
|
|
678
|
+
import pyarrow as pa
|
|
679
|
+
import pyarrow.parquet as pq
|
|
680
|
+
except ImportError:
|
|
681
|
+
raise ImportError("pyarrow is required for parquet export (install velocity-python[parquet])")
|
|
682
|
+
table = pa.table({h: [row[i] for row in rows] for i, h in enumerate(headers)})
|
|
683
|
+
buf = BytesIO()
|
|
684
|
+
pq.write_table(table, buf)
|
|
685
|
+
return buf.getvalue(), f"{filename_base}.parquet", "application/octet-stream"
|
|
686
|
+
|
|
687
|
+
if result_format == "ods":
|
|
688
|
+
try:
|
|
689
|
+
from odf.opendocument import OpenDocumentSpreadsheet
|
|
690
|
+
from odf.table import Table, TableRow, TableCell
|
|
691
|
+
from odf.text import P
|
|
692
|
+
except ImportError:
|
|
693
|
+
raise ImportError("odfpy is required for ods export (install velocity-python[ods])")
|
|
694
|
+
doc = OpenDocumentSpreadsheet()
|
|
695
|
+
sheet = Table(name="Sheet1")
|
|
696
|
+
doc.spreadsheet.addElement(sheet)
|
|
697
|
+
header_row_el = TableRow()
|
|
698
|
+
for h in headers:
|
|
699
|
+
cell = TableCell()
|
|
700
|
+
cell.addElement(P(text=str(h)))
|
|
701
|
+
header_row_el.addElement(cell)
|
|
702
|
+
sheet.addElement(header_row_el)
|
|
703
|
+
for row in rows:
|
|
704
|
+
tr = TableRow()
|
|
705
|
+
for v in row:
|
|
706
|
+
cell = TableCell()
|
|
707
|
+
cell.addElement(P(text="" if v is None else str(v)))
|
|
708
|
+
tr.addElement(cell)
|
|
709
|
+
sheet.addElement(tr)
|
|
710
|
+
buf = BytesIO()
|
|
711
|
+
doc.save(buf)
|
|
712
|
+
return (
|
|
713
|
+
buf.getvalue(),
|
|
714
|
+
f"{filename_base}.ods",
|
|
715
|
+
"application/vnd.oasis.opendocument.spreadsheet",
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
return None
|
|
719
|
+
|
|
720
|
+
# ---------------------------------------------------------------------------
|
|
721
|
+
|
|
578
722
|
def OnActionQuery(self, tx, context):
|
|
579
723
|
payload = context.payload()
|
|
580
724
|
|
|
@@ -586,8 +730,10 @@ class DataServiceMixin:
|
|
|
586
730
|
if not table:
|
|
587
731
|
raise ValueError("Parameter 'obj' cannot be empty")
|
|
588
732
|
|
|
733
|
+
result_format = payload.get("result_format")
|
|
589
734
|
data = self.query_hook(tx, table, payload, context)
|
|
590
|
-
|
|
735
|
+
|
|
736
|
+
if result_format == "excel":
|
|
591
737
|
filebuffer = BytesIO()
|
|
592
738
|
export.create_spreadsheet(data["headers"], data["rows"], filebuffer)
|
|
593
739
|
context.response().file_download(
|
|
@@ -598,7 +744,20 @@ class DataServiceMixin:
|
|
|
598
744
|
)
|
|
599
745
|
return
|
|
600
746
|
|
|
601
|
-
if
|
|
747
|
+
if result_format in ("csv", "tsv", "json", "jsonl", "xml", "html", "markdown", "xlsx", "parquet", "ods"):
|
|
748
|
+
filename_base = payload.get("filename_base") or table
|
|
749
|
+
built = self._build_export_buffer(result_format, data.get("headers", []), data.get("rows", []), filename_base)
|
|
750
|
+
if built is not None:
|
|
751
|
+
file_bytes, filename, _mime = built
|
|
752
|
+
context.response().file_download(
|
|
753
|
+
{
|
|
754
|
+
"filename": filename,
|
|
755
|
+
"data": base64.b64encode(file_bytes).decode(),
|
|
756
|
+
}
|
|
757
|
+
)
|
|
758
|
+
return
|
|
759
|
+
|
|
760
|
+
if result_format == "raw":
|
|
602
761
|
context.response().set_body(data)
|
|
603
762
|
else:
|
|
604
763
|
context.response().set_table(
|
{velocity_python-0.1.27 → velocity_python-0.1.29}/src/velocity/payment/authorizenet_adapter.py
RENAMED
|
@@ -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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
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 {
|