|
Warning
|
Breaking Change: The semantics of |
Previously, message idempotency checks and resource concurrency guards were conflated under the same API /order-resource-locks which used a temporal lock with auto-expiration.
This is incorrect, as for message idempotency, it must use a permanent lock.
To solve this, the locking architecture was decoupled into permanent and short-lived temporal locking behaviors.
ExternalResourceLockProvider)Within OrderOperationServices, the client-side provider ResourceLockProvider and its implementation ExternalResourceLockProvider have been modified:
* obtainLock() (Semantics Updated): This method now strictly routes requests to the updated /order-resource-locks endpoint to obtain a permanent lock. It is used exclusively for message idempotency and deduplication checks.
* obtainTemporalLock() (New Methods): Added default and abstract overloaded methods to obtain a short-lived temporal lock (routing to POST /order-resource-locks/temporal). Callers can optionally pass a custom Duration for lockTtl, or default to the configuration defined under the broadleaf.orderoperation.providers.order.temporal-locks-uri property mapping in orderoperation-defaults.yml.
obtainTemporalLockAll listeners and webhooks guarding resource concurrency have been migrated from obtainLock() to the new obtainTemporalLock() method. This ensures they only obtain temporal, auto-expiring locks rather than permanent ones.
Migrated components include:
* Fulfillments:
AbstractPaymentReversalFulfillmentStatusChangeListener (guarding ORDER_PAYMENT_MANAGEMENT on order cancellations)
FulfillmentCapturingPaymentListener (guarding ORDER_FULFILLMENT_MANAGEMENT during capture)
FutureInventoryStockChangeListener (guarding ORDER_FULFILLMENT_MANAGEMENT during inventory allocation)
PaymentReversalFulfillmentCancelledListener (guarding ORDER_FULFILLMENT_MANAGEMENT during reversal)
SplitFutureInventoryFulfillmentListener (guarding ORDER_FULFILLMENT_MANAGEMENT during splits)
* Returns:
PaymentRefundReturnConfirmedListener (guarding RETURN_AUTHORIZATION_MANAGEMENT)
* Transaction Webhooks:
FulfillmentAwaitingRefundResultWebhookListener (guarding ORDER_FULFILLMENT_MANAGEMENT)
FulfillmentCaptureWebhookListener (guarding ORDER_FULFILLMENT_MANAGEMENT)
** ReturnConfirmationRefundWebhookListener (guarding RETURN_AUTHORIZATION_MANAGEMENT)
In SplitFutureInventoryFulfillmentListener, locks were previously obtained inside a loop but lacked reliable release safeguards. This release implements robust try-finally blocks within the processing loop to guarantee that every temporal lock obtained via obtainTemporalLock() is securely released via resourceLockProvider.releaseLock() regardless of whether the processing succeeds or raises an exception.
Fulfillment Grand Total Short-Circuit: Updated FulfillmentCapturingPaymentListener to short-circuit execution when the fulfillment grand total is $0.00. It now transitions the fulfillment status directly to PAYMENT_CAPTURED and fires a capture result status of UNNECESSARY instead of attempting to fetch payment summaries.
Payment Lookup Graceful 404 Handling: Refactored ExternalPaymentProvider to catch downstream 404 Not Found responses when querying payment or transaction summaries. Instead of throwing EntityMissingException when an order or cart has no payment records, the provider now returns empty collections or an empty TransactionSummary.
Refund & Reversal Bypass & Short-Circuit: Updated the refund and reverse authorization execution logic in DefaultPaymentRefundService and DefaultPaymentAuthReversalService to completely bypass interactions with Payment Transaction Services (PTS) and the Payment Service Provider (PSP) when the order has no payments and/or the total transaction amount is $0.00. This prevents useless and invalid zero-dollar transactions from being sent to gateways or locking empty payments unnecessarily.
Distinguished the oauth2FilterFunctionSupplier bean from the common shared singleton, so it can be overridden independently instead of being tied to a bean instance shared with other consumers. Connection configuration for this bean was also modernized.
Avoid threadlocal context issues for access tokens on webclient builders in Spring Boot 4, backwards compatible with Spring Boot 3.5.
Added missing fulfillmentPendingInventoryOutput message binding
Fixed bug where discounts are ignored and non-taxable shipping charge is included in commit tax calculation
Fixed commitTaxes to use merchandiseTotal instead of merchandiseSubtotal. Prior to this fix, applied discounts would not be considered in the tax calculation
Skip TaxItem for fulfillment charge if it’s not taxable
Add property spring.cloud.stream.bindings.fulfillmentPendingInventoryOutput.destination: fulfillmentPendingInventory to correctly bind fulfillment pending inventory notifications.
Fixed an issue where @JsonIgnore on FulfillmentStatusChangeEvent#order/#fulfillment prevented the order and fulfillment IDs from being serialized at all.
As part of this fix, FulfillmentStatusChangeEvent now carries orderId and fulfillmentId directly instead of the full Order/OrderFulfillment payload.
Avalara Tax fixes
Set reversalRequestId on ReverseTaxTransactionRequest so unique ID can be passed for reversal transactions
Update returned tax items to only include confirmed return items
Updated external provider WebClient calls to merge multi-value HTTP headers from getHeaders(ContextInfo) instead of overwriting same-named headers, fixing compatibility across Spring Boot 3.5 & 4.