Completed
Push — master ( 530061...ece7ee )
by Jeroen De
82:37 queued 40:45
created

AddDonationHandler::handle()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 3
nop 1
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\Euro\Euro;
11
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationRequest;
12
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationResponse;
13
use WMDE\Fundraising\Frontend\Factories\FunFunFactory;
14
use WMDE\Fundraising\Frontend\Infrastructure\AmountParser;
15
use WMDE\Fundraising\Frontend\Infrastructure\PiwikVariableCollector;
16
use WMDE\Fundraising\Frontend\PaymentContext\Domain\Model\BankData;
17
use WMDE\Fundraising\Frontend\PaymentContext\Domain\Model\Iban;
18
use WMDE\Fundraising\Frontend\PaymentContext\Domain\Model\PaymentType;
19
use WMDE\Fundraising\Frontend\Presentation\SelectedConfirmationPage;
20
21
/**
22
 * @license GNU GPL v2+
23
 * @author Kai Nissen < [email protected] >
24
 * @author Jeroen De Dauw < [email protected] >
25
 */
26
class AddDonationHandler {
27
28
	private $ffFactory;
29
	private $app;
30
31
	public function __construct( FunFunFactory $ffFactory, Application $app ) {
32
		$this->ffFactory = $ffFactory;
33
		$this->app = $app;
34
	}
35
36
	public function handle( Request $request ): Response {
37
		if ( !$this->isSubmissionAllowed( $request ) ) {
38
			return new Response( $this->ffFactory->newSystemMessageResponse( 'donation_rejected_limit' ) );
39
		}
40
41
		$addDonationRequest = $this->createDonationRequest( $request );
42
		$responseModel = $this->ffFactory->newAddDonationUseCase()->addDonation( $addDonationRequest );
43
44
		if ( !$responseModel->isSuccessful() ) {
45
			return new Response( $this->ffFactory->newDonationFormViolationPresenter()->present( $responseModel->getValidationErrors(), $addDonationRequest ) );
46
		}
47
48
		return $this->newHttpResponse( $responseModel );
49
	}
50
51
	private function newHttpResponse( AddDonationResponse $responseModel ): Response {
52
		switch( $responseModel->getDonation()->getPaymentType() ) {
53
			case PaymentType::DIRECT_DEBIT:
54
			case PaymentType::BANK_TRANSFER:
55
				$httpResponse = $this->app->redirect(
56
					$this->app['url_generator']->generate(
57
						'show-donation-confirmation',
58
						[
59
							'id' => $responseModel->getDonation()->getId(),
60
							'accessToken' => $responseModel->getAccessToken()
61
						]
62
					),
63
					Response::HTTP_SEE_OTHER
64
				);
65
66
				break;
67
			case PaymentType::PAYPAL:
68
				$httpResponse = $this->app->redirect(
69
					$this->ffFactory->newPayPalUrlGeneratorForDonations()->generateUrl(
70
						$responseModel->getDonation()->getId(),
71
						$responseModel->getDonation()->getAmount(),
72
						$responseModel->getDonation()->getPaymentIntervalInMonths(),
73
						$responseModel->getUpdateToken(),
74
						$responseModel->getAccessToken()
75
					)
76
				);
77
				break;
78
			case PaymentType::CREDIT_CARD:
79
				$httpResponse = new Response(
80
					$this->ffFactory->newCreditCardPaymentHtmlPresenter()->present( $responseModel )
81
				);
82
				break;
83
			default:
84
				throw new \LogicException( 'This code should not be reached' );
85
		}
86
		return $httpResponse;
87
	}
88
89
	private function createDonationRequest( Request $request ): AddDonationRequest {
90
		$donationRequest = new AddDonationRequest();
91
92
		$donationRequest->setAmount( $this->getEuroAmountFromString( $request->get( 'betrag', '' ) ) );
93
94
		$donationRequest->setPaymentType( $request->get( 'zahlweise', '' ) );
95
		$donationRequest->setInterval( intval( $request->get( 'periode', 0 ) ) );
96
97
		$donationRequest->setDonorType( $request->get( 'addressType', '' ) );
98
		$donationRequest->setDonorSalutation( $request->get( 'salutation', '' ) );
99
		$donationRequest->setDonorTitle( $request->get( 'title', '' ) );
100
		$donationRequest->setDonorCompany( $request->get( 'companyName', '' ) );
101
		$donationRequest->setDonorFirstName( $request->get( 'firstName', '' ) );
102
		$donationRequest->setDonorLastName( $request->get( 'lastName', '' ) );
103
		$donationRequest->setDonorStreetAddress( $request->get( 'street', '' ) );
104
		$donationRequest->setDonorPostalCode( $request->get( 'postcode', '' ) );
105
		$donationRequest->setDonorCity( $request->get( 'city', '' ) );
106
		$donationRequest->setDonorCountryCode( $request->get( 'country', '' ) );
107
		$donationRequest->setDonorEmailAddress( $request->get( 'email', '' ) );
108
109
		if ( $request->get( 'zahlweise', '' ) === PaymentType::DIRECT_DEBIT ) {
110
			$donationRequest->setBankData( $this->getBankDataFromRequest( $request ) );
111
		}
112
113
		$donationRequest->setTracking(
114
			AddDonationRequest::getPreferredValue( [
115
				$request->cookies->get( 'spenden_tracking' ),
116
				$request->request->get( 'tracking' ),
117
				AddDonationRequest::concatTrackingFromVarCouple(
118
					$request->get( 'piwik_campaign', '' ),
119
					$request->get( 'piwik_kwd', '' )
120
				)
121
			] )
122
		);
123
124
		$donationRequest->setOptIn( $request->get( 'info', '' ) );
125
		$donationRequest->setSource(
126
			AddDonationRequest::getPreferredValue( [
127
				$request->cookies->get( 'spenden_source' ),
128
				$request->request->get( 'source' ),
129
				$request->server->get( 'HTTP_REFERER' )
130
			] )
131
		);
132
		$donationRequest->setTotalImpressionCount( intval( $request->get( 'impCount', 0 ) ) );
133
		$donationRequest->setSingleBannerImpressionCount( intval( $request->get( 'bImpCount', 0 ) ) );
134
135
		return $donationRequest;
136
	}
137
138
	private function getBankDataFromRequest( Request $request ): BankData {
139
		$bankData = new BankData();
140
		$bankData->setIban( new Iban( $request->get( 'iban', '' ) ) )
141
			->setBic( $request->get( 'bic', '' ) )
142
			->setAccount( $request->get( 'konto', '' ) )
143
			->setBankCode( $request->get( 'blz', '' ) )
144
			->setBankName( $request->get( 'bankname', '' ) );
145
146
		if ( $bankData->hasIban() && !$bankData->hasCompleteLegacyBankData() ) {
147
			$bankData = $this->newBankDataFromIban( $bankData->getIban() );
148
		}
149
		if ( $bankData->hasCompleteLegacyBankData() && !$bankData->hasIban() ) {
150
			$bankData = $this->newBankDataFromAccountAndBankCode( $bankData->getAccount(), $bankData->getBankCode() );
151
		}
152
153
		return $bankData->freeze()->assertNoNullFields();
154
	}
155
156
	private function newBankDataFromIban( Iban $iban ): BankData {
157
		return $this->ffFactory->newBankDataConverter()->getBankDataFromIban( $iban );
158
	}
159
160
	private function newBankDataFromAccountAndBankCode( string $account, string $bankCode ): BankData {
161
		return $this->ffFactory->newBankDataConverter()->getBankDataFromAccountData( $account, $bankCode );
162
	}
163
164
	private function getEuroAmountFromString( string $amount ): Euro {
165
		$locale = 'de_DE'; // TODO: make this configurable for multilanguage support
166
		try {
167
			return Euro::newFromFloat( ( new AmountParser( $locale ) )->parseAsFloat( $amount ) );
168
		} catch ( \InvalidArgumentException $ex ) {
169
			return Euro::newFromCents( 0 );
170
		}
171
172
	}
173
174
	private function isSubmissionAllowed( Request $request ) {
175
		$lastSubmission = $request->cookies->get( ShowDonationConfirmationHandler::SUBMISSION_COOKIE_NAME, '' );
176
		if ( $lastSubmission === '' ) {
177
			return true;
178
		}
179
180
		$minNextTimestamp = \DateTime::createFromFormat( ShowDonationConfirmationHandler::TIMESTAMP_FORMAT, $lastSubmission )
181
			->add( new \DateInterval( $this->ffFactory->getDonationTimeframeLimit() ) );
182
		if ( $minNextTimestamp > new \DateTime() ) {
183
			return false;
184
		}
185
186
		return true;
187
	}
188
189
}