Skip to content

Commit

Permalink
Merge pull request #59 from Adyen/develop
Browse files Browse the repository at this point in the history
Release 1.0.0
  • Loading branch information
khushboo-singhvi authored Apr 8, 2024
2 parents 4d84b45 + d977881 commit 09a5014
Show file tree
Hide file tree
Showing 14 changed files with 190 additions and 56 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Webhook Module for PHP (Beta)
# Webhook Module for PHP

Adyen library for handling notification webhooks.

Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
}
},
"require-dev": {
"phpunit/phpunit": "^9.5.0",
"squizlabs/php_codesniffer": "^3.5"
"phpunit/phpunit": "~9.6.0",
"squizlabs/php_codesniffer": "~3.8.0"
}
}
2 changes: 2 additions & 0 deletions src/EventCodes.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,6 @@ final class EventCodes
const CHARGEBACK = "CHARGEBACK";
const CHARGEBACK_REVERSED = "CHARGEBACK_REVERSED";
const SECOND_CHARGEBACK = "SECOND_CHARGEBACK";
const NOTIFICATION_OF_CHARGEBACK = "NOTIFICATION_OF_CHARGEBACK";
const REQUEST_FOR_INFORMATION = "REQUEST_FOR_INFORMATION";
}
5 changes: 5 additions & 0 deletions src/Notification.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ public function getEventCode(): string
return $this->eventCode;
}

public function getAdditionalData(): array
{
return $this->additionalData ?? [];
}

public function isSuccess(): bool
{
return in_array($this->success, [true, "true"], true);
Expand Down
1 change: 1 addition & 0 deletions src/PaymentStates.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ final class PaymentStates
public const STATE_IN_PROGRESS = 'in_progress';
public const STATE_PENDING = 'pending';
public const STATE_PAID = 'paid';
public const STATE_AUTHORIZED = 'authorized';
public const STATE_FAILED = 'failed';
public const STATE_REFUNDED = 'refunded';
public const STATE_PARTIALLY_REFUNDED = 'partially_refunded';
Expand Down
59 changes: 59 additions & 0 deletions src/Processor/AbstractDisputeNotificationProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php declare(strict_types=1);
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Webhook Module for PHP
*
* Copyright (c) 2021 Adyen N.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*
*/

namespace Adyen\Webhook\Processor;

use Adyen\Webhook\PaymentStates;

abstract class AbstractDisputeNotificationProcessor extends Processor implements ProcessorInterface
{
const DISPUTE_STATUS_UNDEFENDED = "Undefended";
const DISPUTE_STATUS_LOST = "Lost";
const DISPUTE_STATUS_ACCEPTED = "Accepted";
const FINAL_DISPUTE_STATUSES = [
self::DISPUTE_STATUS_LOST,
self::DISPUTE_STATUS_ACCEPTED,
self::DISPUTE_STATUS_UNDEFENDED
];
const DISPUTE_STATUS = "disputeStatus";
const CHARGEBACK_ORDER_STATES = [
PaymentStates::STATE_PAID,
PaymentStates::STATE_IN_PROGRESS,
];

public function process(): ?string
{
$state = $this->initialState;
$additionalData = $this->notification->getAdditionalData();
$disputeStatus = $additionalData[self::DISPUTE_STATUS] ?? null;

if ($this->notification->isSuccess() &&
isset($disputeStatus) &&
in_array($disputeStatus, self::FINAL_DISPUTE_STATUSES) &&
in_array($state, self::CHARGEBACK_ORDER_STATES)) {
$state = PaymentStates::STATE_REFUNDED;
}

return $state;
}
}
6 changes: 5 additions & 1 deletion src/Processor/AuthorisationProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ public function process(): ?string
$state,
[PaymentStates::STATE_NEW, PaymentStates::STATE_IN_PROGRESS, PaymentStates::STATE_PENDING]
)) {
$state = $this->notification->isSuccess() ? PaymentStates::STATE_PAID : PaymentStates::STATE_FAILED;
if ($this->notification->isSuccess()) {
$state = $this->isAutoCapture ? PaymentStates::STATE_PAID : PaymentStates::STATE_AUTHORIZED;
} else {
$state = PaymentStates::STATE_FAILED;
}
}

return $state;
Expand Down
16 changes: 1 addition & 15 deletions src/Processor/ChargebackProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,7 @@

namespace Adyen\Webhook\Processor;

use Adyen\Webhook\PaymentStates;

class ChargebackProcessor extends Processor implements ProcessorInterface
class ChargebackProcessor extends AbstractDisputeNotificationProcessor implements ProcessorInterface
{
public function process(): ?string
{
$state = $this->initialState;

if (in_array(
$state,
[PaymentStates::STATE_NEW, PaymentStates::STATE_IN_PROGRESS, PaymentStates::STATE_PENDING]
)) {
$state = $this->notification->isSuccess() ? PaymentStates::CHARGE_BACK : PaymentStates::STATE_FAILED;
}

return $state;
}
}
32 changes: 32 additions & 0 deletions src/Processor/NotificationOfChargebackProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Webhook Module for PHP
*
* Copyright (c) 2021 Adyen N.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*
*/

namespace Adyen\Webhook\Processor;

class NotificationOfChargebackProcessor extends AbstractDisputeNotificationProcessor implements ProcessorInterface
{
public function process(): ?string
{
return $this->unchanged();
}
}
14 changes: 12 additions & 2 deletions src/Processor/Processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,26 @@ abstract class Processor implements ProcessorInterface
*/
protected $initialState;

/**
* @var bool
*/
protected $isAutoCapture;

abstract public function process(): ?string;

/**
* @param Notification $notification
* @param string $state
* @param bool $isAutoCapture
* @throws InvalidDataException
*/
public function __construct(Notification $notification, string $state)
{
public function __construct(
Notification $notification,
string $state,
bool $isAutoCapture = true
) {
$this->notification = $notification;
$this->isAutoCapture = $isAutoCapture;
$this->validateState($state);

$this->initialState = $state;
Expand Down
20 changes: 15 additions & 5 deletions src/Processor/ProcessorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@
namespace Adyen\Webhook\Processor;

use Adyen\Webhook\EventCodes;
use Adyen\Webhook\Exception\InvalidDataException;
use Adyen\Webhook\Notification;

class ProcessorFactory
{
private static $adyenEventCodeProcessors = [
private static array $adyenEventCodeProcessors = [
EventCodes::AUTHORISATION => AuthorisationProcessor::class,
EventCodes::OFFER_CLOSED => OfferClosedProcessor::class,
EventCodes::REFUND => RefundProcessor::class,
Expand All @@ -51,20 +52,29 @@ class ProcessorFactory
EventCodes::VOID_PENDING_REFUND => VoidPendingRefundProcessor::class,
EventCodes::CHARGEBACK => ChargebackProcessor::class,
EventCodes::CHARGEBACK_REVERSED => ChargebackReversedProcessor::class,
EventCodes::SECOND_CHARGEBACK => SecondChargebackProcessor::class
EventCodes::SECOND_CHARGEBACK => SecondChargebackProcessor::class,
EventCodes::NOTIFICATION_OF_CHARGEBACK => NotificationOfChargebackProcessor::class,
EventCodes::REQUEST_FOR_INFORMATION => RequestForInformationProcessor::class
];

/**
* @param Notification $notification
* @param string $paymentState
* @param bool $isAutoCapture
* @return ProcessorInterface
* @throws InvalidDataException
*/
public static function create(
Notification $notification,
string $paymentState
string $paymentState,
bool $isAutoCapture = true
): ProcessorInterface {
return array_key_exists($notification->getEventCode(), self::$adyenEventCodeProcessors)
? new self::$adyenEventCodeProcessors[$notification->getEventCode()]($notification, $paymentState)
: new DefaultProcessor($notification, $paymentState);
? new self::$adyenEventCodeProcessors[$notification->getEventCode()](
$notification,
$paymentState,
$isAutoCapture
)
: new DefaultProcessor($notification, $paymentState, $isAutoCapture);
}
}
32 changes: 32 additions & 0 deletions src/Processor/RequestForInformationProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Webhook Module for PHP
*
* Copyright (c) 2022 Adyen N.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*
*/

namespace Adyen\Webhook\Processor;

class RequestForInformationProcessor extends AbstractDisputeNotificationProcessor implements ProcessorInterface
{
public function process(): ?string
{
return $this->unchanged();
}
}
16 changes: 1 addition & 15 deletions src/Processor/SecondChargebackProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,7 @@

namespace Adyen\Webhook\Processor;

use Adyen\Webhook\PaymentStates;

class SecondChargebackProcessor extends Processor implements ProcessorInterface
class SecondChargebackProcessor extends AbstractDisputeNotificationProcessor implements ProcessorInterface
{
public function process(): ?string
{
$state = $this->initialState;

if (in_array(
$state,
[PaymentStates::STATE_NEW, PaymentStates::STATE_IN_PROGRESS, PaymentStates::STATE_PENDING]
)) {
$state = $this->notification->isSuccess() ? PaymentStates::CHARGE_BACK : PaymentStates::STATE_FAILED;
}

return $state;
}
}
37 changes: 22 additions & 15 deletions tests/Unit/Processor/ProcessorFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@
use Adyen\Webhook\Processor\RefundedWithDataProcessor;
use Adyen\Webhook\Processor\RefundFailedProcessor;
use Adyen\Webhook\Processor\RefundProcessor;


use Adyen\Webhook\Processor\ReportAvailableProcessor;
use Adyen\Webhook\Processor\SecondChargebackProcessor;
use Adyen\Webhook\Processor\VoidPendingRefundProcessor;
Expand Down Expand Up @@ -141,6 +139,8 @@ public function processorPaymentStatesProvider(): array
{
return [
[EventCodes::AUTHORISATION, PaymentStates::STATE_NEW, PaymentStates::STATE_PAID, 'true'],
[EventCodes::AUTHORISATION, PaymentStates::STATE_NEW, PaymentStates::STATE_FAILED, 'false'],
[EventCodes::AUTHORISATION, PaymentStates::STATE_NEW, PaymentStates::STATE_AUTHORIZED, 'true', false],
[EventCodes::AUTHORISATION, PaymentStates::STATE_IN_PROGRESS, PaymentStates::STATE_PAID, 'true'],
[EventCodes::AUTHORISATION, PaymentStates::STATE_PENDING, PaymentStates::STATE_PAID, 'true'],
[EventCodes::CANCELLATION, PaymentStates::STATE_NEW, PaymentStates::STATE_CANCELLED, 'true'],
Expand Down Expand Up @@ -184,31 +184,38 @@ public function processorPaymentStatesProvider(): array
[EventCodes::VOID_PENDING_REFUND, PaymentStates::STATE_NEW, PaymentStates::STATE_CANCELLED, 'true'],
[EventCodes::VOID_PENDING_REFUND, PaymentStates::STATE_IN_PROGRESS, PaymentStates::STATE_CANCELLED, 'true'],
[EventCodes::VOID_PENDING_REFUND, PaymentStates::STATE_PENDING, PaymentStates::STATE_CANCELLED, 'true'],
[EventCodes::CHARGEBACK, PaymentStates::STATE_NEW, PaymentStates::CHARGE_BACK, 'true'],
[EventCodes::CHARGEBACK, PaymentStates::STATE_IN_PROGRESS, PaymentStates::CHARGE_BACK, 'true'],
[EventCodes::CHARGEBACK, PaymentStates::STATE_PENDING, PaymentStates::CHARGE_BACK, 'true'],
[EventCodes::CHARGEBACK, PaymentStates::STATE_NEW, PaymentStates::STATE_NEW, 'true'],
[EventCodes::CHARGEBACK, PaymentStates::STATE_IN_PROGRESS, PaymentStates::STATE_IN_PROGRESS, 'true'],
[EventCodes::CHARGEBACK, PaymentStates::STATE_PENDING, PaymentStates::STATE_PENDING, 'true'],
[EventCodes::CHARGEBACK_REVERSED, PaymentStates::STATE_NEW, PaymentStates::STATE_CANCELLED, 'true'],
[EventCodes::CHARGEBACK_REVERSED, PaymentStates::STATE_IN_PROGRESS, PaymentStates::STATE_CANCELLED, 'true'],
[EventCodes::CHARGEBACK_REVERSED, PaymentStates::STATE_IN_PROGRESS, PaymentStates::STATE_CANCELLED,
'true'],
[EventCodes::CHARGEBACK_REVERSED, PaymentStates::STATE_PENDING, PaymentStates::STATE_CANCELLED, 'true'],
[EventCodes::SECOND_CHARGEBACK, PaymentStates::STATE_NEW, PaymentStates::CHARGE_BACK, 'true'],
[EventCodes::SECOND_CHARGEBACK, PaymentStates::STATE_IN_PROGRESS, PaymentStates::CHARGE_BACK, 'true'],
[EventCodes::SECOND_CHARGEBACK, PaymentStates::STATE_PENDING, PaymentStates::CHARGE_BACK, 'true'],
[EventCodes::SECOND_CHARGEBACK, PaymentStates::STATE_NEW, PaymentStates::STATE_FAILED, 'false'],
[EventCodes::SECOND_CHARGEBACK, PaymentStates::STATE_IN_PROGRESS, PaymentStates::STATE_FAILED, 'false'],
[EventCodes::SECOND_CHARGEBACK, PaymentStates::STATE_PENDING, PaymentStates::STATE_FAILED, 'false']
[EventCodes::SECOND_CHARGEBACK, PaymentStates::STATE_NEW, PaymentStates::STATE_NEW, 'true'],
[EventCodes::SECOND_CHARGEBACK, PaymentStates::STATE_IN_PROGRESS, PaymentStates::STATE_IN_PROGRESS, 'true'],
[EventCodes::SECOND_CHARGEBACK, PaymentStates::STATE_PENDING, PaymentStates::STATE_PENDING, 'true'],
[EventCodes::SECOND_CHARGEBACK, PaymentStates::STATE_NEW, PaymentStates::STATE_NEW, 'false'],
[EventCodes::SECOND_CHARGEBACK, PaymentStates::STATE_IN_PROGRESS, PaymentStates::STATE_IN_PROGRESS,
'false'],
[EventCodes::SECOND_CHARGEBACK, PaymentStates::STATE_PENDING, PaymentStates::STATE_PENDING, 'false']
];
}

/**
* @dataProvider processorPaymentStatesProvider
*/
public function testProcessorPaymentStates($eventCode, $originalState, $expectedState, $success)
{
public function testProcessorPaymentStates(
$eventCode,
$originalState,
$expectedState,
$success,
$isAutoCapture = true
) {
$notification = $this->createNotificationSuccess([
'eventCode' => $eventCode,
'success' => $success,
]);
$processor = ProcessorFactory::create($notification, $originalState);
$processor = ProcessorFactory::create($notification, $originalState, $isAutoCapture);
$newState = $processor->process();
$this->assertEquals($expectedState, $newState);
}
Expand Down

0 comments on commit 09a5014

Please sign in to comment.