Skip to content

Add Credit2000 payment gateway (disabled by default) - #49

Open
Amitsananes wants to merge 4 commits into
milzer-tech:mainfrom
Amitsananes:feature/credit2000-payment-gateway
Open

Add Credit2000 payment gateway (disabled by default)#49
Amitsananes wants to merge 4 commits into
milzer-tech:mainfrom
Amitsananes:feature/credit2000-payment-gateway

Conversation

@Amitsananes

Copy link
Copy Markdown

Summary

  • Adds Credit2000 SOAP ASMX gateway (SendParamToCredit2000getTokenAndApproveCreditXML) aligned with authorize → book → capture/abort.
  • Registers the gateway in config/checkout.php with CHECKOUT_CREDIT2000_ACTIVE=false by default.
  • Adds unit tests for prepare/authorize/capture/abort; updates gateway registration assertions.

Configuration (staging, after merge)

  • CHECKOUT_CREDIT2000_VENDOR_NAME
  • CHECKOUT_CREDIT2000_COMPANY_KEY
  • CHECKOUT_CREDIT2000_ACTIVE=true only after credentials + E2E

Notes for reviewers

Existing repository-wide tooling findings (not introduced by this PR)

  • Full-repo pint --test fails largely due to pre-existing line_ending (and related style) differences across many existing files. This PR only ran/fixed Pint on the Credit2000-touched paths.
  • Full-repo phpstan analyse reports a pre-existing error in src/Livewire/TripDetailsPage.php (URL / temporarySignedRoute() unknown class). Credit2000 paths analyse cleanly.
  • Full-repo rector --dry-run proposes changes in unrelated existing files; those were not applied.

Unverified merchant capability

  • Credit2000 terminal support for approval-only action_Type=5 (required for authorize → book → capture) is not yet verified against the live merchant terminal. Confirm with Credit2000 / staging E2E before enabling in staging.

Test plan

  • Unit: Credit2000GatewayTest
  • Full package Pest suite (166 passed, 1 skipped)
  • Staging E2E: IBE → checkout → Credit2000 approval → Nezasa book → capture
  • Staging failure path: approval → booking fail → abort

Implements authorize → book → capture/abort via Credit2000 SOAP ASMX, disabled by default until staging credentials are configured.

Co-authored-by: Cursor <cursoragent@cursor.com>

Copilot AI 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.

Pull request overview

Adds a disabled-by-default Credit2000 SOAP payment gateway supporting authorization, capture, and abort flows.

Changes:

  • Implements Credit2000 SOAP requests, response parsing, currency mapping, and gateway lifecycle.
  • Adds configuration and operational documentation.
  • Adds unit coverage and gateway registration assertions.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
CREDIT2000.md Documents setup and lifecycle.
config/checkout.php Registers and configures the gateway.
src/Integrations/Credit2000/Connectors/Credit2000Connector.php Defines the Saloon connector.
src/Integrations/Credit2000/Enums/Credit2000CurrencyEnum.php Maps supported currencies.
src/Integrations/Credit2000/Requests/Credit2000SoapRequest.php Builds SOAP HTTP requests.
src/Integrations/Credit2000/Resources/Credit2000PaymentResource.php Implements provider operations.
src/Integrations/Credit2000/Support/Credit2000Xml.php Provides XML and identifier helpers.
src/Payments/Gateways/Credit2000/Credit2000Gateway.php Implements payment lifecycle behavior.
tests/Unit/Payments/Credit2000GatewayTest.php Tests gateway operations.
tests/Unit/Payments/Gateways/PaymentGatewaysTest.php Verifies gateway registration.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +170 to +173
$expectedTotal = (string) ($persistentData['total_pyment'] ?? '');
$callbackTotalRaw = (string) ($callback['TotalPayment'] ?? $callback['TotalP'] ?? '');

if ($expectedTotal !== '' && $callbackTotalRaw !== '' && ! $this->amountsMatch($expectedTotal, $callbackTotalRaw)) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed in \�93e2a8: \�uthorize()\ no longer relies on optional callback amount fields. After the redirect returns a UID, we call Credit2000 server-to-server via \getTokenAndApprovePro(uid)\ and require the provider-returned \uID, \product_Id, \ otal_Pyment, \currency, and \�ction_Type\ to match the persisted \prepare_data\ before authorization succeeds.

This is implemented with mocked unit coverage, but we are not treating Copilot Finding #1 as fully resolved until staging validates live \getTokenAndApprovePro\ responses against the real terminal.

Comment on lines +269 to +273
$capture = Credit2000Connector::make()->payment()->creditXml([
'cardNumber' => $token,
'validationMonth' => $month ?? '00',
'validationYear' => $year ?? '00',
'actionType' => self::ACTION_CHARGE,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed in \1527c40: \prepare_action_type=2\ (SendParams Test) is now rejected in \prepare(), and \capture()\ refuses to call CreditXML \�ctionType=4\ if a test prepare was stored. Documented test mode is therefore blocked from reaching a live charge path.

Comment on lines +314 to +321
// Approval-only and never captured: nothing to refund at the provider.
if ($token === '' || (! $alreadyCaptured && ! $chargedOnPage)) {
$resultData['cancel'] = [
'returnCode' => self::RETURN_OK,
'mode' => 'release_uncaptured_approval',
];

return new AbortResult(isSuccessful: true, persistentData: $resultData);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Credit2000 confirmed there is no provider API to release/cancel an uncaptured ActionType 5 approval. Uncaptured approvals normally expire automatically within approximately 3 business days (depending on the merchant–acquirer agreement). Endpoint confirmed: pci_emv_ver4.

Addressed in 6feada5:

  • Uncaptured abort no longer fabricates returnCode=000 or claims an immediate provider-side release (release_uncaptured_approval).
  • Checkout records cancel.mode=uncaptured_approval_left_to_expire, returns AbortResult(isSuccessful: true) because no capture occurred, and still blocks later capture().
  • Charged flows still refund via CreditXML actionType=7.

Tests: 18 Credit2000 tests passed; full Pest suite 174 passed, 1 skipped.

Amitsananes and others added 3 commits August 25, 2026 13:41
Block prepare_action_type=2 and refuse CreditXML charge=4 if test prepare was stored, so documented Test mode cannot transition to a real charge.

Co-authored-by: Cursor <cursoragent@cursor.com>
Bind callback UIDs to persisted prepare data using provider-returned product_Id, total_Pyment, currency, action_Type, and uID. Finding milzer-tech#1 remains unverified until staging validates live Pro responses.

Co-authored-by: Cursor <cursoragent@cursor.com>
Credit2000 confirmed there is no release API; leave approvals to expire instead of fabricating a provider return code, and point defaults at pci_emv_ver4.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

2 participants