Passed
Pull Request — master (#1310)
by Gabriel
28:51
created

ApplyForMembershipHandler::logSelectedBuckets()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 4
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare( strict_types = 1 );
4
5
namespace WMDE\Fundraising\Frontend\App\RouteHandlers;
6
7
use Silex\Application;
8
use Symfony\Component\HttpFoundation\Request;
9
use Symfony\Component\HttpFoundation\Response;
10
use WMDE\Fundraising\Frontend\BucketTesting\Logging\Events\MembershipApplicationCreated;
11
use WMDE\Fundraising\Frontend\Factories\FunFunFactory;
12
use WMDE\Fundraising\MembershipContext\Tracking\MembershipApplicationTrackingInfo;
13
use WMDE\Fundraising\MembershipContext\UseCases\ApplyForMembership\ApplyForMembershipRequest;
14
use WMDE\Fundraising\MembershipContext\UseCases\ApplyForMembership\ApplyForMembershipResponse;
15
use WMDE\Fundraising\PaymentContext\Domain\Model\BankData;
16
use WMDE\Fundraising\PaymentContext\Domain\Model\Iban;
17
use WMDE\Fundraising\PaymentContext\Domain\Model\PaymentMethod;
18
19
/**
20
 * @license GNU GPL v2+
21
 * @author Kai Nissen < [email protected] >
22
 */
23
class ApplyForMembershipHandler {
24
25
	public const SUBMISSION_COOKIE_NAME = 'memapp_timestamp';
26
	public const TIMESTAMP_FORMAT = 'Y-m-d H:i:s';
27
28
	private $ffFactory;
29
	private $app;
30
31 17
	public function __construct( FunFunFactory $ffFactory, Application $app ) {
32 17
		$this->ffFactory = $ffFactory;
33 17
		$this->app = $app;
34 17
	}
35
36 17
	public function handle( Request $request ): Response {
37 17
		if ( !$this->isSubmissionAllowed( $request ) ) {
38 1
			return new Response( $this->ffFactory->newSystemMessageResponse( 'membership_application_rejected_limit' ) );
39
		}
40
41 16
		$applyForMembershipRequest = $this->createMembershipRequest( $request );
42 16
		$responseModel = $this->ffFactory->newApplyForMembershipUseCase()->applyForMembership( $applyForMembershipRequest );
43
44 16
		if ( !$responseModel->isSuccessful() ) {
45 2
			return new Response(
46 2
				$this->ffFactory->newMembershipFormViolationPresenter()->present(
47 2
					$applyForMembershipRequest,
48 2
					$request->request->get( 'showMembershipTypeOption' ) === 'true'
49
				)
50
			);
51
		}
52
53 14
		$httpResponse = $this->newHttpResponse( $responseModel );
54
55 14
		$cookie = $this->ffFactory->getCookieBuilder();
56 14
		$httpResponse->headers->setCookie(
57 14
			$cookie->newCookie(
58 14
				self::SUBMISSION_COOKIE_NAME,
59 14
				date( self::TIMESTAMP_FORMAT )
60
			)
61
		);
62 14
		$this->logSelectedBuckets( $responseModel );
63 14
		return $httpResponse;
64
	}
65
66 16
	private function createMembershipRequest( Request $httpRequest ): ApplyForMembershipRequest {
67 16
		$request = new ApplyForMembershipRequest();
68
69 16
		$request->setMembershipType( $httpRequest->request->get( 'membership_type', '' ) );
70
71 16
		if ( $httpRequest->request->get( 'adresstyp', '' )  === 'firma' ) {
72 1
			$request->markApplicantAsCompany();
73
		}
74
75 16
		$request->setApplicantSalutation( $httpRequest->request->get( 'anrede', '' ) );
76 16
		$request->setApplicantTitle( $httpRequest->request->get( 'titel', '' ) );
77 16
		$request->setApplicantFirstName( $httpRequest->request->get( 'vorname', '' ) );
78 16
		$request->setApplicantLastName( $httpRequest->request->get( 'nachname', '' ) );
79 16
		$request->setApplicantCompanyName( $httpRequest->request->get( 'firma', '' ) );
80
81 16
		$request->setApplicantStreetAddress( $this->filterAutofillCommas( $httpRequest->request->get( 'strasse', '' ) ) );
82 16
		$request->setApplicantPostalCode( $httpRequest->request->get( 'postcode', '' ) );
83 16
		$request->setApplicantCity( $httpRequest->request->get( 'ort', '' ) );
84 16
		$request->setApplicantCountryCode( $httpRequest->request->get( 'country', '' ) );
85
86 16
		$request->setApplicantEmailAddress( $httpRequest->request->get( 'email', '' ) );
87 16
		$request->setApplicantPhoneNumber( $httpRequest->request->get( 'phone', '' ) );
88 16
		$request->setApplicantDateOfBirth( $httpRequest->request->get( 'dob', '' ) );
89
90 16
		$request->setPaymentType( $httpRequest->request->get( 'payment_type', '' ) );
91 16
		$request->setPaymentIntervalInMonths( (int)$httpRequest->request->get( 'membership_fee_interval', 0 ) );
92
		// TODO: German format expected here, amount should be converted based on user's locale
93 16
		$request->setPaymentAmountInEuros( str_replace( ',', '.', $httpRequest->request->get( 'membership_fee', '' ) ) );
94
95 16
		$request->setTrackingInfo( new MembershipApplicationTrackingInfo(
96 16
			$httpRequest->request->get( 'templateCampaign', '' ),
97 16
			$httpRequest->request->get( 'templateName', '' )
98
		) );
99
100 16
		$request->setPiwikTrackingString( $httpRequest->attributes->get( 'trackingCode' ) );
101
102 16
		$request->setOptsIntoDonationReceipt( $httpRequest->request->getBoolean( 'donationReceipt', true ) );
103
104 16
		$bankData = new BankData();
105
106 16
		$bankData->setBankName( $httpRequest->request->get( 'bank_name', '' ) );
107 16
		$bankData->setIban( new Iban( $httpRequest->request->get( 'iban', '' ) ) );
108 16
		$bankData->setBic( $httpRequest->request->get( 'bic', '' ) );
109 16
		$bankData->setAccount( $httpRequest->request->get( 'account_number', '' ) );
110 16
		$bankData->setBankCode( $httpRequest->request->get( 'bank_code', '' ) );
111
112 16
		$bankData->assertNoNullFields()->freeze();
113 16
		$request->setBankData( $bankData );
114 16
		$request->assertNoNullFields()->freeze();
115
116 16
		return $request;
117
	}
118
119 17
	private function isSubmissionAllowed( Request $request ) {
120 17
		$lastSubmission = $request->cookies->get( self::SUBMISSION_COOKIE_NAME, '' );
121 17
		if ( $lastSubmission === '' ) {
122 15
			return true;
123
		}
124
125 2
		$minNextTimestamp = \DateTime::createFromFormat( self::TIMESTAMP_FORMAT, $lastSubmission )
126 2
			->add( new \DateInterval( $this->ffFactory->getMembershipApplicationTimeframeLimit() ) );
127 2
		if ( $minNextTimestamp > new \DateTime() ) {
128 1
			return false;
129
		}
130
131 1
		return true;
132
	}
133
134 14
	private function newHttpResponse( ApplyForMembershipResponse $responseModel ): Response {
135 14
		switch( $responseModel->getMembershipApplication()->getPayment()->getPaymentMethod()->getId() ) {
136 14
			case PaymentMethod::DIRECT_DEBIT:
137 11
				$httpResponse = $this->app->redirect(
138 11
					$this->app['url_generator']->generate(
139 11
						'show-membership-confirmation',
140
						[
141 11
							'id' => $responseModel->getMembershipApplication()->getId(),
142 11
							'accessToken' => $responseModel->getAccessToken()
143
						]
144
					),
145 11
					Response::HTTP_SEE_OTHER
146
				);
147
148 11
				break;
149 3
			case PaymentMethod::PAYPAL:
150 3
				$httpResponse = $this->app->redirect(
151 3
					$this->ffFactory->newPayPalUrlGeneratorForMembershipApplications()->generateUrl(
152 3
						$responseModel->getMembershipApplication()->getId(),
153 3
						$responseModel->getMembershipApplication()->getPayment()->getAmount(),
154 3
						$responseModel->getMembershipApplication()->getPayment()->getIntervalInMonths(),
155 3
						$responseModel->getUpdateToken(),
156 3
						$responseModel->getAccessToken()
157
					)
158
				);
159 3
				break;
160
			default:
161
				throw new \LogicException( 'This code should not be reached' );
162
		}
163 14
		return $httpResponse;
164
	}
165
166
	/**
167
	 * Safari and Chrome concatenate street autofill values (e.g. house number and street name) with a comma.
168
	 * This method removes the commas.
169
	 *
170
	 * @param string $value
171
	 * @return string
172
	 */
173 16
	private function filterAutofillCommas( string $value ): string {
174 16
		return trim( preg_replace( ['/,/', '/\s{2,}/'], [' ', ' '], $value ) );
175
	}
176
177 14
	private function logSelectedBuckets( ApplyForMembershipResponse $responseModel ) {
178 14
		$this->ffFactory->getBucketLogger()->writeEvent(
179 14
			new MembershipApplicationCreated( $responseModel->getMembershipApplication()->getId() ),
180 14
			...$this->ffFactory->getSelectedBuckets()
181
		);
182
	}
183
}