Skip to content

feat(payment): PI-5431 [SPIKE] [FE] Surcharging (Bluesnap, Adyen) - PoC [do not merge] - #3313

Open
bc-ania wants to merge 1 commit into
masterfrom
PI-5431
Open

feat(payment): PI-5431 [SPIKE] [FE] Surcharging (Bluesnap, Adyen) - PoC [do not merge]#3313
bc-ania wants to merge 1 commit into
masterfrom
PI-5431

Conversation

@bc-ania

@bc-ania bc-ania commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

What/Why?

Adds in-flight card surcharging for AdyenV3 and Bluesnap Direct. Once the shopper fills and validates their card (before Place Order), the strategy asks backend whether a surcharge applies for that card and, if so, applies it as a checkout fee so it can be shown in the order summary.

The FE stays provider-agnostic: it forwards a card handle to the backend, which proxies it to the provider (Adyen /cardDetails, Bluesnap /surcharge/calculate), applies compliance rules, and returns a normalized surcharge value.

Rollout/Rollback

This is just PoC, do not merge

Testing

video_1280.mp4

Note

High Risk
Changes checkout totals and payment strategy behavior during card entry; relies on unimplemented BE endpoints and leaves stale surcharge fees when cards change.

Overview
Adds in-flight card surcharging so shoppers can see a surcharge in the order summary before Place Order, wired for Adyen V3 and Bluesnap Direct credit card flows.

Introduces a shared SurchargeActionHandler that POSTs provider-agnostic card handles to /api/storefront/checkouts/{id}/surcharge-check, and when eligible applies a custom_fee via new applyFees on the payment integration service. Core gains FeeActionCreator / FeeRequestSender and checkout state updates on ApplyFeesSucceeded (fees, totals), mirroring store credit / coupons.

Adyen tracks BIN via onBinValue and runs the check when the card component is valid. Bluesnap captures card metadata on onType and triggers the handler when the card number field validates. Handler dedupes by BIN and serializes concurrent checks; failures are logged without blocking checkout.

PoC notes: storefront fees and surcharge-check proxies are not implemented on BE yet; removing or replacing an existing surcharge when the card changes is explicitly TODO (no remove endpoint).

Reviewed by Cursor Bugbot for commit c2285b3. Bugbot is set up for automated code reviews on this repo. Configure here.

@bc-ania bc-ania changed the title feat(payment): PI-5431 [SPIKE] [FE] Surcharging (Bluesnap, Adyen) feat(payment): PI-5431 [SPIKE] [FE] Surcharging (Bluesnap, Adyen) - PoC [do not merge] Jul 14, 2026
@bc-ania
bc-ania marked this pull request as ready for review July 14, 2026 12:36
@bc-ania
bc-ania requested review from a team as code owners July 14, 2026 12:36
Comment thread packages/adyen-integration/src/adyenv3/adyenv3-payment-strategy.ts
private _hasSurcharge(): boolean {
const checkout = this._paymentIntegrationService.getState().getCheckout();

return Boolean(checkout?.fees?.some((fee) => fee.name === SURCHARGE_FEE_NAME));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate surcharge detection name mismatch

Medium Severity

_hasSurcharge looks for a fee named corporate_card_surcharge, but applied fees use body.name from the surcharge API. If the backend returns a different name, duplicate surcharges can be applied and duplicate prevention never triggers.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 30940ab. Configure here.

Comment thread packages/core/src/fee/fee-request-sender.ts

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

There are 4 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c2285b3. Configure here.


// Concurrency guard: allow only one check at a time
if (this._isChecking) {
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped checks while surcharge in flight

Medium Severity

When a surcharge check is already running, applyInFlight returns immediately without queueing or retrying. A newer card change during that window is ignored, so the checkout can keep a surcharge from the previous card or never evaluate the latest card.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c2285b3. Configure here.

// TODO (surcharging): if a surcharge fee is already applied and the new card is
// NOT eligible, the stale fee must be removed server-side (needs a BE remove
// endpoint). The Fees API only adds fees today.
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ineligible card keeps surcharge fee

High Severity

When checkSurcharge reports the current card is not eligible (or amount ≤ 0), applyInFlight returns without clearing an existing surcharge fee on the checkout, so totals can still include a fee for a card that no longer qualifies.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c2285b3. Configure here.

cardData: {
encryptedCardNumber: pm.encryptedCardNumber,
brand: (pm as unknown as { brand?: string }).brand,
bin: this._bin,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Adyen BIN on re-entry

Medium Severity

this._bin is only updated in onBinValue and is not cleared when the card becomes invalid or the PAN changes. A later valid onChange can reuse the previous BIN for deduplication and surcharge payloads before Adyen emits a new BIN.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c2285b3. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant