velocity-python 0.2.7__py3-none-any.whl → 0.2.8__py3-none-any.whl

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/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.2.7"
1
+ __version__ = version = "0.2.8"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -113,6 +113,24 @@ def parse_braintree_environment(value: Any = None) -> str:
113
113
  return name
114
114
 
115
115
 
116
+ def _decline_details(transaction: Any) -> Dict[str, Any]:
117
+ """The processor's own verdict on a declined sale, for callers that decide
118
+ whether to try the card again: ``processor_response_code``,
119
+ ``processor_response_text`` and ``processor_response_type``
120
+ (``approved`` / ``soft_declined`` / ``hard_declined`` -- Braintree's
121
+ classification; a hard decline will not be approved on retry). Only the
122
+ keys Braintree set; empty without a transaction (gateway rejection or
123
+ validation failure)."""
124
+ if transaction is None:
125
+ return {}
126
+ details = {
127
+ "processor_response_code": _attr(transaction, "processor_response_code"),
128
+ "processor_response_text": _attr(transaction, "processor_response_text"),
129
+ "processor_response_type": _attr(transaction, "processor_response_type"),
130
+ }
131
+ return {key: value for key, value in details.items() if value not in (None, "")}
132
+
133
+
116
134
  def _deep_errors(result: Any) -> List[str]:
117
135
  errors = getattr(getattr(result, "errors", None), "deep_errors", None) or []
118
136
  return [scrub(f"{error.code}: {error.message}") for error in errors]
@@ -556,7 +574,11 @@ class BraintreeAdapter(PaymentProcessorAdapter):
556
574
  "expires_at": None,
557
575
  "error_message": error_message,
558
576
  "metadata": _with_reference(
559
- {"braintree_errors": _deep_errors(result)}, order_id
577
+ {
578
+ "braintree_errors": _deep_errors(result),
579
+ **_decline_details(result.transaction),
580
+ },
581
+ order_id,
560
582
  ),
561
583
  }
562
584
 
@@ -674,7 +696,12 @@ class BraintreeAdapter(PaymentProcessorAdapter):
674
696
  )
675
697
  error_message = scrub(result.transaction.processor_response_text)
676
698
  return failure(
677
- "failed", error_message, {"braintree_errors": _deep_errors(result)}
699
+ "failed",
700
+ error_message,
701
+ {
702
+ "braintree_errors": _deep_errors(result),
703
+ **_decline_details(result.transaction),
704
+ },
678
705
  )
679
706
 
680
707
  def find_charge_by_reference(
@@ -139,6 +139,16 @@ def _amount_captured(payment_intent: Any, charge: Any, requested: Optional[int])
139
139
  return 0
140
140
 
141
141
 
142
+ def _decline_details(error: Any) -> Dict[str, Any]:
143
+ """``decline_code`` of a card decline (``CardError``): the issuer's reason
144
+ (``insufficient_funds``, ``lost_card``, ``expired_card`` ...), for callers
145
+ that decide whether to try the card again. Empty when Stripe gave none."""
146
+ decline_code = getattr(error, "decline_code", None) or getattr(
147
+ getattr(error, "error", None), "decline_code", None
148
+ )
149
+ return {"decline_code": decline_code} if decline_code else {}
150
+
151
+
142
152
  class StripeAdapter(PaymentProcessorAdapter):
143
153
  """
144
154
  Stripe Connect adapter for payment processing.
@@ -664,6 +674,7 @@ class StripeAdapter(PaymentProcessorAdapter):
664
674
  "error_code": e.code,
665
675
  "error_type": type(e).__name__,
666
676
  "idempotency_key": idempotency_key,
677
+ **_decline_details(e),
667
678
  },
668
679
  }
669
680
  if reference:
@@ -824,6 +835,7 @@ class StripeAdapter(PaymentProcessorAdapter):
824
835
  "error_code": e.code,
825
836
  "error_type": type(e).__name__,
826
837
  "idempotency_key": idempotency_key,
838
+ **_decline_details(e),
827
839
  },
828
840
  }
829
841
  if reference:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.2.7
3
+ Version: 0.2.8
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
@@ -267,7 +267,6 @@ What changed in each release, and what callers must do before upgrading, is in
267
267
  | Testing Guide | `docs/TESTING.md` | Running tests, markers, coverage |
268
268
  | Security | `docs/SECURITY.md` | Pre-commit hooks, credential scanning |
269
269
  | Changelog | `CHANGELOG.md` | Per-release breaking changes, deploy ordering, additions and fixes |
270
- | Improvement Backlog | `docs/IMPROVEMENT_BACKLOG.md` | Proposed and deferred library improvements |
271
270
 
272
271
  ---
273
272
 
@@ -1,4 +1,4 @@
1
- velocity/__init__.py,sha256=yFS8i5a6vkF9fvBhXU1pEodyDqxw4rkW3ZYGgOHV8g4,362
1
+ velocity/__init__.py,sha256=iPrUPi45dX2tx99GwA1L_u5bjx7W7F0Y_zuF6VDGNqw,362
2
2
  velocity/cache.py,sha256=pthvw7gDVEXRzkTcQtA5YVf4Q1IxAamWsba4UReT0RE,8933
3
3
  velocity/logging.py,sha256=MAsZap1cDSdOBNRc_9ezQxup5dHOS0ARxU9NI_-UK3E,4037
4
4
  velocity/aws/__init__.py,sha256=XJJ79gnPlhg3aJij713PB8-vjQOt-BkqxYeGCBOxAu8,3460
@@ -211,7 +211,7 @@ velocity/payment/_mirror_core.py,sha256=tjZOVgueXiXdYcbxBFgv1JsDcRhEq2YVCJCSoJSb
211
211
  velocity/payment/authorizenet_adapter.py,sha256=UnMne4agLwddZOVaihOhlMZz4iBLidjMHsQn1fHTq5U,60261
212
212
  velocity/payment/authorizenet_mirror.py,sha256=IprtAYPDylHTJUUPV31SPKWqoPjdbUn5SfhvYo5BJZ8,7853
213
213
  velocity/payment/base_adapter.py,sha256=eyGo_pkTyc71qyKQ72VZql4WFtc9lp6-cLJEhHoRCE4,35760
214
- velocity/payment/braintree_adapter.py,sha256=tj5PNwiKpf3UwOEkou9z750WOgHP7x4pwpMG0zExhag,41647
214
+ velocity/payment/braintree_adapter.py,sha256=IsdDu8VpmbXHafDMq6YcBGBuxO7FdOG6ALhtLSdPABw,42792
215
215
  velocity/payment/braintree_mirror.py,sha256=7SIRiIjv8HVXMFEKFOLqOWMJ46U1-64lkkTKH9hOp9Q,8497
216
216
  velocity/payment/charge_rules.py,sha256=rWgP_M-0LesQ-lMK1-IbIC8CNHvrxzf3bUlT4bNzbG0,1782
217
217
  velocity/payment/money.py,sha256=kqGTCs6wt1nlKELAtHAdiQi8HjKrI9-QSp56cyIhfbY,5785
@@ -219,13 +219,13 @@ velocity/payment/plaid_api.py,sha256=sCqQdulgRn8bFr4CpCPSQwrXcdkSUwjjWz1aS3J4u90
219
219
  velocity/payment/plaid_webhook.py,sha256=1PFTCScSqVVnyRnZhKMY2gAIn_2qg4UOrruv-wzbyMQ,13637
220
220
  velocity/payment/redact.py,sha256=aaCuQyffZG3Nb9QBEJqfkeEc7MtUxZscpDhdea6zc4o,2767
221
221
  velocity/payment/schema.py,sha256=mF8CnaIFCL4qe7z32ty1yItY1My4wD6mEAvsgZamdLI,9221
222
- velocity/payment/stripe_adapter.py,sha256=6EmVBZZchg2s3Teya0eQGA_8pvSK_teizr036U9G-50,68627
222
+ velocity/payment/stripe_adapter.py,sha256=jt0QbxI6oRBSyopx8yBGB5Nv_6Llz7IKGq1ZgZ6C1Kg,69204
223
223
  velocity/payment/stripe_mirror.py,sha256=6GKJk_PjAgySqFEuxbcuV423OfuGXupVTiGu9QwS5W8,12320
224
224
  velocity/testing/__init__.py,sha256=WtYMDHgCLxOq6mlemcOYV5Y9HqF_2QQgSfuAjFRg69Q,731
225
225
  velocity/testing/fake_db.py,sha256=phgdulk5owf3noUDpEfI7yFsVcKxRGZ82f2BJPYnaiU,53226
226
- velocity_python-0.2.7.dist-info/licenses/LICENSE,sha256=aoN245GG8s9oRUU89KNiGTU4_4OtnNmVi4hQeChg6rM,1076
227
- velocity_python-0.2.7.dist-info/METADATA,sha256=jAHTQgrhvkAti0u-f01xNGRUki6kHB7euSsM3l-iPBY,17782
228
- velocity_python-0.2.7.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
229
- velocity_python-0.2.7.dist-info/entry_points.txt,sha256=nXUKJHkOGQCSPoagdmMNd_qycrle1LVU-GhYknLGM1M,56
230
- velocity_python-0.2.7.dist-info/top_level.txt,sha256=JW2vJPmodgdgSz7H6yoZvnxF8S3fTMIv-YJWCT1sNW0,9
231
- velocity_python-0.2.7.dist-info/RECORD,,
226
+ velocity_python-0.2.8.dist-info/licenses/LICENSE,sha256=aoN245GG8s9oRUU89KNiGTU4_4OtnNmVi4hQeChg6rM,1076
227
+ velocity_python-0.2.8.dist-info/METADATA,sha256=39KY7Vt8KeztkbdTqotqSZDeCbFf3NO62M6GHFtN5Qg,17681
228
+ velocity_python-0.2.8.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
229
+ velocity_python-0.2.8.dist-info/entry_points.txt,sha256=nXUKJHkOGQCSPoagdmMNd_qycrle1LVU-GhYknLGM1M,56
230
+ velocity_python-0.2.8.dist-info/top_level.txt,sha256=JW2vJPmodgdgSz7H6yoZvnxF8S3fTMIv-YJWCT1sNW0,9
231
+ velocity_python-0.2.8.dist-info/RECORD,,