Fix Stripe authorization lifecycle timing
This commit is contained in:
1 parent
21038d68ca
commit
61ea299b0e
5 files changed
+157
-19
No files matched your search
@@ -7,10 +7,11 @@ defined('ABSPATH') || exit;
|
||||
/**
|
||||
* bsc_order_audit: one row per order line, written once at checkout
|
||||
* (CheckoutRecheck::run_checks()) and updated once — either on refund
|
||||
* (record_refund(), a post-capture reversal) or on void (record_void(),
|
||||
* a pre-capture supplier-order failure — the far more common case under
|
||||
* the preauth-then-capture flow). Style mirrors Catalog\SupplierOffer
|
||||
* exactly.
|
||||
* (record_refund(), a post-capture reversal) or after a confirmed void
|
||||
* (record_void()). Requesting cancellation alone is not confirmation: the
|
||||
* Stripe status-change hook exposes no success result, so callers must
|
||||
* reconcile the order note/dashboard before recording a void. Style mirrors
|
||||
* Catalog\SupplierOffer exactly.
|
||||
*/
|
||||
class AuditTrail
|
||||
{
|
||||
@@ -68,7 +69,7 @@ class AuditTrail
|
||||
* against the expectation this row already captured at checkout time.
|
||||
* Only reachable now for a refund *after* a real capture (e.g. a
|
||||
* manual admin refund post-fulfillment) — a failed supplier order
|
||||
* before capture goes through record_void() instead, below.
|
||||
* before capture uses record_void() only after Stripe confirms release.
|
||||
*/
|
||||
public static function record_refund(int $order_id): void
|
||||
{
|
||||
@@ -83,10 +84,9 @@ class AuditTrail
|
||||
}
|
||||
|
||||
/**
|
||||
* Preauth-then-capture rework: a failed supplier order before capture
|
||||
* reverses the hold (Order\SupplierOrderJob::fail_and_release())
|
||||
* rather than refunding a charge that was never made — genuinely
|
||||
* zero cost, not the processing-fee loss record_refund() models.
|
||||
* A confirmed pre-capture authorization release is genuinely zero cost,
|
||||
* unlike the processing-fee loss record_refund() models. Do not call this
|
||||
* merely because cancellation was requested.
|
||||
*/
|
||||
public static function record_void(int $order_id): void
|
||||
{
|
||||
|
||||
@@ -28,17 +28,20 @@ class SupplierOrderJob
|
||||
{
|
||||
public static function register(): void
|
||||
{
|
||||
add_action('woocommerce_order_status_on-hold', [self::class, 'accept_stripe_authorization']);
|
||||
// Stripe fires this only after it has persisted the transaction ID,
|
||||
// captured flag, and On hold status. The generic On hold transition
|
||||
// fires too early inside Stripe's process_response() and can race the
|
||||
// save of `_stripe_charge_captured=no`.
|
||||
add_action('wc_gateway_stripe_process_response', [self::class, 'accept_stripe_authorization'], 10, 2);
|
||||
add_action('woocommerce_order_status_' . OrderStatuses::AUTHORIZED, [self::class, 'schedule_for_order']);
|
||||
add_action('bsc_submit_supplier_order', [self::class, 'run']);
|
||||
}
|
||||
|
||||
/** Promote only manually authorized orders from the official Stripe gateway. */
|
||||
public static function accept_stripe_authorization(int $order_id): void
|
||||
public static function accept_stripe_authorization(object $response, \WC_Order $order): void
|
||||
{
|
||||
$order = wc_get_order($order_id);
|
||||
if (
|
||||
!$order
|
||||
!$order->has_status('on-hold')
|
||||
|| !self::is_stripe_order($order)
|
||||
|| $order->get_meta('_stripe_charge_captured') !== 'no'
|
||||
) {
|
||||
@@ -160,9 +163,17 @@ class SupplierOrderJob
|
||||
*/
|
||||
private static function fail_and_release(\WC_Order $order, string $reason): void
|
||||
{
|
||||
$order->update_meta_data('_bsc_stripe_release_requested', 'yes');
|
||||
$order->save();
|
||||
$order->update_status('cancelled', $reason . ' Releasing the Stripe authorization.');
|
||||
AuditTrail::record_void($order->get_id());
|
||||
$order->update_status(OrderStatuses::EXCEPTION, 'Stripe authorization release requested; order requires review.');
|
||||
// Stripe's cancelled-status handler performs the API call but exposes
|
||||
// no success result to third-party callbacks. Do not record a
|
||||
// confirmed zero-cost void here; a failed API call must remain visible
|
||||
// for reconciliation instead of being reported as successful.
|
||||
$order->update_status(
|
||||
OrderStatuses::EXCEPTION,
|
||||
'Stripe authorization release requested; verify the Stripe order note or dashboard before closing review.'
|
||||
);
|
||||
}
|
||||
|
||||
private static function is_stripe_order(\WC_Order $order): bool
|
||||
|
||||
Reference in new issue
Block a user