Completed
Pull Request — master (#1951)
by
unknown
63:33
created

index()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 30
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 21
nc 4
nop 2
dl 0
loc 30
rs 9.584
c 0
b 0
f 0
1
<?php
2
3
declare( strict_types = 1 );
4
5
namespace WMDE\Fundraising\Frontend\App\Controllers\Payment;
6
7
use Doctrine\ORM\Query\Parameter;
8
use Psr\Log\LogLevel;
9
use Symfony\Component\HttpFoundation\ParameterBag;
10
use Symfony\Component\HttpFoundation\Request;
11
use Symfony\Component\HttpFoundation\Response;
12
use WMDE\Euro\Euro;
13
use WMDE\Fundraising\Frontend\Factories\FunFunFactory;
14
use WMDE\Fundraising\Frontend\Infrastructure\Payment\PayPalPaymentNotificationVerifierException;
15
use WMDE\Fundraising\MembershipContext\UseCases\HandleSubscriptionSignupNotification\SubscriptionSignupRequest;
16
use WMDE\Fundraising\PaymentContext\RequestModel\PayPalPaymentNotificationRequest;
17
use WMDE\Fundraising\PaymentContext\ResponseModel\PaypalNotificationResponse;
18
19
class PaypalNotificationControllerForMembershipFee {
20
21
	private const TYPE_SUBSCRIPTION_SIGNUP = 'subscr_signup';
22
	private const TYPE_SUBSCRIPTION_PAYMENT = 'subscr_payment';
23
24
	public function index( FunFunFactory $ffFactory, Request $request ): Response {
25
		$post = $request->request;
26
27
		try {
28
			$ffFactory->getPayPalMembershipFeeNotificationVerifier()->verify( $post->all() );
29
		} catch ( PayPalPaymentNotificationVerifierException $e ) {
30
			$ffFactory->getPaypalLogger()->log( LogLevel::ERROR, $e->getMessage(), [
31
				'post_vars' => $post->all()
32
			] );
33
			return $this->createErrorResponse( $e );
34
		}
35
36
		switch ( $post->get( 'txn_type' ) ) {
37
			case self::TYPE_SUBSCRIPTION_SIGNUP:
38
				$useCase = $ffFactory->newMembershipApplicationSubscriptionSignupNotificationUseCase( $this->getUpdateToken( $post ) );
39
				$response = $useCase->handleNotification( $this->newSubscriptionSignupRequestFromPost( $post ) );
40
				break;
41
			case self::TYPE_SUBSCRIPTION_PAYMENT:
42
				$useCase = $ffFactory->newMembershipApplicationSubscriptionPaymentNotificationUseCase( $this->getUpdateToken( $post ) );
43
				$response = $useCase->handleNotification( $this->newSubscriptionPaymentRequestFromPost( $post ) );
44
				break;
45
			default:
46
				$response = PaypalNotificationResponse::newUnhandledResponse( [ 'message' => 'unsupported transaction type' ] );
47
				break;
48
		}
49
50
		$this->logResponseIfNeeded( $ffFactory, $response, $post );
51
52
		// PayPal expects an empty response
53
		return new Response( '', Response::HTTP_OK );
54
	}
55
56
	private function getUpdateToken( ParameterBag $postRequest ): string {
57
		return $this->getValueFromCustomVars( $postRequest->get( 'custom', '' ), 'utoken' );
58
	}
59
60
	private function getValueFromCustomVars( string $customVars, string $key ): string {
61
		$vars = json_decode( $customVars, true );
62
		return !empty( $vars[$key] ) ? $vars[$key] : '';
63
	}
64
65
	private function newSubscriptionSignupRequestFromPost( ParameterBag $postRequest ): SubscriptionSignupRequest {
66
		return ( new SubscriptionSignupRequest() )
67
			->setTransactionType( $postRequest->get( 'txn_type', '' ) )
68
			->setPayerId( $postRequest->get( 'payer_id', '' ) )
69
			->setSubscriptionId( $postRequest->get( 'subscr_id', '' ) )
70
			->setPayerEmail( $postRequest->get( 'payer_email', '' ) )
71
			->setPayerStatus( $postRequest->get( 'payer_status', '' ) )
72
			->setPayerFirstName( $postRequest->get( 'first_name', '' ) )
73
			->setPayerLastName( $postRequest->get( 'last_name', '' ) )
74
			->setPayerAddressName( $postRequest->get( 'address_name', '' ) )
75
			->setPayerAddressStreet( $postRequest->get( 'address_street', '' ) )
76
			->setPayerAddressPostalCode( $postRequest->get( 'address_zip', '' ) )
77
			->setPayerAddressCity( $postRequest->get( 'address_city', '' ) )
78
			->setPayerAddressCountry( $postRequest->get( 'address_country_code', '' ) )
79
			->setPayerAddressStatus( $postRequest->get( 'address_status', '' ) )
80
			->setApplicationId( (int)$postRequest->get( 'item_number', 0 ) )
81
			->setPaymentType( $postRequest->get( 'payment_type', '' ) )
82
			->setCurrencyCode( $postRequest->get( 'mc_currency', '' ) );
83
	}
84
85
	private function newSubscriptionPaymentRequestFromPost( ParameterBag $postRequest ): PayPalPaymentNotificationRequest {
86
		// we're not using Euro class for amounts to avoid exceptions on fees or other fields where the value is < 0
87
		return ( new PayPalPaymentNotificationRequest() )
88
			->setTransactionType( $postRequest->get( 'txn_type', '' ) )
89
			->setTransactionId( $postRequest->get( 'txn_id', '' ) )
90
			->setPayerId( $postRequest->get( 'payer_id', '' ) )
91
			->setSubscriptionId( $postRequest->get( 'subscr_id', '' ) )
92
			->setPayerEmail( $postRequest->get( 'payer_email', '' ) )
93
			->setPayerStatus( $postRequest->get( 'payer_status', '' ) )
94
			->setPayerFirstName( $postRequest->get( 'first_name', '' ) )
95
			->setPayerLastName( $postRequest->get( 'last_name', '' ) )
96
			->setPayerAddressName( $postRequest->get( 'address_name', '' ) )
97
			->setPayerAddressStreet( $postRequest->get( 'address_street', '' ) )
98
			->setPayerAddressPostalCode( $postRequest->get( 'address_zip', '' ) )
99
			->setPayerAddressCity( $postRequest->get( 'address_city', '' ) )
100
			->setPayerAddressCountryCode( $postRequest->get( 'address_country_code', '' ) )
101
			->setPayerAddressStatus( $postRequest->get( 'address_status', '' ) )
102
			->setInternalId( (int)$postRequest->get( 'item_number', 0 ) )
103
			->setCurrencyCode( $postRequest->get( 'mc_currency', '' ) )
104
			->setTransactionFee( $postRequest->get( 'mc_fee', '0' ) )
105
			->setAmountGross( Euro::newFromString( $postRequest->get( 'mc_gross', '0' ) ) )
106
			->setSettleAmount( Euro::newFromString( $postRequest->get( 'settle_amount', '0' ) ) )
107
			->setPaymentTimestamp( $postRequest->get( 'payment_date', '' ) )
108
			->setPaymentStatus( $postRequest->get( 'payment_status', '' ) )
109
			->setPaymentType( $postRequest->get( 'payment_type', '' ) );
110
	}
111
112
	private function createErrorResponse( PayPalPaymentNotificationVerifierException $e ): Response {
113
		switch ( $e->getCode() ) {
114
			case PayPalPaymentNotificationVerifierException::ERROR_WRONG_RECEIVER:
115
				return new Response( $e->getMessage(), Response::HTTP_FORBIDDEN );
116
			case PayPalPaymentNotificationVerifierException::ERROR_VERIFICATION_FAILED:
117
				return new Response( $e->getMessage(), Response::HTTP_FORBIDDEN );
118
			case PayPalPaymentNotificationVerifierException::ERROR_UNSUPPORTED_CURRENCY:
119
				return new Response( $e->getMessage(), Response::HTTP_NOT_ACCEPTABLE );
120
			default:
121
				return new Response( $e->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR );
122
		}
123
	}
124
125
	private function logResponseIfNeeded( FunFunFactory $ffFactory, PaypalNotificationResponse $response, ParameterBag $post ) {
126
		if ( $response->notificationWasHandled() ) {
127
			return;
128
		}
129
130
		$context = $response->getContext();
131
		$message = $context['message'] ?? 'Paypal request not handled';
132
		$logLevel = $response->hasErrors() ? LogLevel::ERROR : LogLevel::INFO;
133
		unset( $context['message'] );
134
		$context['post_vars'] = $post->all();
135
		$ffFactory->getPaypalLogger()->log( $logLevel, $message, $context );
136
	}
137
138
}
139