1: <?php
2:
3: namespace Mypos\IPC;
4:
5: /**
6: * Process IPC method: IPCPurchase.
7: * Collect, validate and send API params
8: */
9: class Purchase extends Base
10: {
11: const PURCHASE_TYPE_FULL = 1;
12: const PURCHASE_TYPE_SIMPLIFIED_CALL = 2;
13: const PURCHASE_TYPE_SIMPLIFIED_PAYMENT_PAGE = 3;
14:
15: const CARD_TOKEN_REQUEST_NONE = 0;
16: const CARD_TOKEN_REQUEST_ONLY_STORE = 1;
17: const CARD_TOKEN_REQUEST_PAY_AND_STORE = 2;
18:
19: const PAYMENT_METHOD_STANDARD = 1;
20: const PAYMENT_METHOD_IDEAL = 2;
21: const PAYMENT_METHOD_BOTH = 3;
22: /**
23: * @var Cart
24: */
25: private $cart;
26: /**
27: * @var Customer
28: */
29: private $customer;
30: private $url_ok, $url_cancel, $url_notify;
31: private $currency = 'EUR', $note, $orderID, $cardTokenRequest, $paymentParametersRequired, $expiresIn = '86400';
32: private $paymentMethod;
33:
34: /**
35: * Return purchase object
36: *
37: * @param Config $cnf
38: */
39: public function __construct(Config $cnf)
40: {
41: $this->paymentMethod = self::PAYMENT_METHOD_BOTH;
42: $this->setCnf($cnf);
43: }
44:
45: /**
46: * Purchase identifier - must be unique
47: *
48: * @param string $orderID
49: *
50: * @return Purchase
51: */
52: public function setOrderID($orderID)
53: {
54: $this->orderID = $orderID;
55:
56: return $this;
57: }
58:
59: /**
60: * Optional note to purchase
61: *
62: * @param string $note
63: *
64: * @return Purchase
65: */
66: public function setNote($note)
67: {
68: $this->note = $note;
69:
70: return $this;
71: }
72:
73: /**
74: * Merchant Site URL where client comes after unsuccessful payment
75: *
76: * @param string $urlCancel
77: *
78: * @return Purchase
79: */
80: public function setUrlCancel($urlCancel)
81: {
82: $this->url_cancel = $urlCancel;
83:
84: return $this;
85: }
86:
87: /**
88: * Merchant Site URL where IPC posts Purchase Notify requests
89: *
90: * @param string $urlNotify
91: *
92: * @return Purchase
93: */
94: public function setUrlNotify($urlNotify)
95: {
96: $this->url_notify = $urlNotify;
97:
98: return $this;
99: }
100:
101: /**
102: * Whether to return Card Token for current client card
103: *
104: * @param integer $cardTokenRequest
105: */
106: public function setCardTokenRequest($cardTokenRequest)
107: {
108: $this->cardTokenRequest = $cardTokenRequest;
109: }
110:
111: /**
112: * Defines the packet of details needed from merchant and client to make payment
113: *
114: * @param integer $paymentParametersRequired
115: */
116: public function setPaymentParametersRequired($paymentParametersRequired)
117: {
118: $this->paymentParametersRequired = $paymentParametersRequired;
119: }
120:
121: /**
122: *
123: * @param $expiresIn
124: * @return Purchase
125: */
126: public function setExpiresIn($expiresIn)
127: {
128: $this->expiresIn = $expiresIn;
129:
130: return $this;
131: }
132:
133: public function getExpiresIn()
134: {
135: return $this->expiresIn;
136: }
137:
138: /**
139: * Initiate API request
140: *
141: * @return boolean
142: * @throws IPC_Exception
143: */
144: public function process($submitForm = true)
145: {
146: $this->validate();
147:
148: $this->_addPostParam('IPCmethod', 'IPCPurchase');
149: $this->_addPostParam('IPCVersion', $this->getCnf()->getVersion());
150: $this->_addPostParam('IPCLanguage', $this->getCnf()->getLang());
151: $this->_addPostParam('SID', $this->getCnf()->getSid());
152: $this->_addPostParam('WalletNumber', $this->getCnf()->getWallet());
153: $this->_addPostParam('KeyIndex', $this->getCnf()->getKeyIndex());
154: $this->_addPostParam('Source', $this->getCnf()->getSource());
155:
156: $this->_addPostParam('Currency', $this->getCurrency());
157: if (!$this->isNoCartPurchase()) {
158: $this->_addPostParam('Amount', $this->cart->getTotal());
159: }
160:
161: $this->_addPostParam('OrderID', $this->getOrderID());
162: $this->_addPostParam('URL_OK', $this->getUrlOk());
163: $this->_addPostParam('URL_Cancel', $this->getUrlCancel());
164: $this->_addPostParam('URL_Notify', $this->getUrlNotify());
165:
166: $this->_addPostParam('Note', $this->getNote());
167: $this->_addPostParam('expires_in', $this->getExpiresIn());
168:
169: // Add partner details
170: $this->_addPostParam('ApplicationID', $this->getCnf()->getApplicationID());
171: $this->_addPostParam('PartnerID', $this->getCnf()->getPartnerID());
172:
173: $this->_addPostParam('customeremail', $this->getCustomer()->getEmail());
174: $this->_addPostParam('customerphone', $this->getCustomer()->getPhone());
175: $this->_addPostParam('customerfirstnames', $this->getCustomer()->getFirstName());
176: $this->_addPostParam('customerfamilyname', $this->getCustomer()->getLastName());
177: $this->_addPostParam('customercountry', $this->getCustomer()->getCountry());
178: $this->_addPostParam('customercity', $this->getCustomer()->getCity());
179: $this->_addPostParam('customerzipcode', $this->getCustomer()->getZip());
180: $this->_addPostParam('customeraddress', $this->getCustomer()->getAddress());
181:
182: if (!$this->isNoCartPurchase()) {
183: $this->_addPostParam('CartItems', $this->cart->getItemsCount());
184: $items = $this->cart->getCart();
185: $i = 1;
186: foreach ($items as $v) {
187: $this->_addPostParam('Article_' . $i, $v['name']);
188: $this->_addPostParam('Quantity_' . $i, $v['quantity']);
189: $this->_addPostParam('Price_' . $i, $v['price']);
190: $this->_addPostParam('Amount_' . $i, $v['price'] * $v['quantity']);
191: $this->_addPostParam('Currency_' . $i, $this->getCurrency());
192: if (!empty($v['delivery'])) {
193: $this->_addPostParam('Delivery_' . $i, $v['delivery']);
194: }
195:
196: $i++;
197: }
198: }
199:
200: $this->_addPostParam('CardTokenRequest', $this->getCardTokenRequest());
201: $this->_addPostParam('PaymentParametersRequired', $this->getPaymentParametersRequired());
202: $this->_addPostParam('PaymentMethod', $this->getPaymentMethod());
203:
204: if ($submitForm) {
205: $this->_processHtmlPost();
206: }
207:
208: return true;
209: }
210:
211: public function getFormParameters($escapeParameters = false)
212: {
213: return $this->_buildArrayParameters($escapeParameters);
214: }
215:
216: /**
217: * Validate all set purchase details
218: *
219: * @return boolean
220: * @throws IPC_Exception
221: */
222: public function validate()
223: {
224:
225: if ($this->getUrlCancel() === null || !Helper::isValidURL($this->getUrlCancel())) {
226: throw new IPC_Exception('Invalid Cancel URL');
227: }
228:
229: if ($this->getUrlNotify() === null || !Helper::isValidURL($this->getUrlNotify())) {
230: throw new IPC_Exception('Invalid Notify URL');
231: }
232:
233: if ($this->getUrlOk() === null || !Helper::isValidURL($this->getUrlOk())) {
234: throw new IPC_Exception('Invalid Success URL');
235: }
236:
237: if ($this->getCardTokenRequest() === null || !in_array($this->getCardTokenRequest(), [
238: self::CARD_TOKEN_REQUEST_NONE,
239: self::CARD_TOKEN_REQUEST_ONLY_STORE,
240: self::CARD_TOKEN_REQUEST_PAY_AND_STORE,
241: ])) {
242: throw new IPC_Exception('Invalid value provided for CardTokenRequest params');
243: }
244:
245: if ($this->getPaymentParametersRequired() === null || !in_array($this->getPaymentParametersRequired(), [
246: self::PURCHASE_TYPE_FULL,
247: self::PURCHASE_TYPE_SIMPLIFIED_CALL,
248: self::PURCHASE_TYPE_SIMPLIFIED_PAYMENT_PAGE,
249: ])) {
250: throw new IPC_Exception('Invalid value provided for PaymentParametersRequired params');
251: }
252:
253: if ($this->getCurrency() === null) {
254: throw new IPC_Exception('Invalid currency');
255: }
256:
257: try {
258: $this->getCnf()->validate();
259: } catch (\Exception $ex) {
260: throw new IPC_Exception('Invalid Config details: ' . $ex->getMessage());
261: }
262:
263: if (!$this->isNoCartPurchase()) {
264: if ($this->getCart() === null) {
265: throw new IPC_Exception('Missing Cart details');
266: }
267:
268: try {
269: $this->getCart()->validate();
270: } catch (\Exception $ex) {
271: throw new IPC_Exception('Invalid Cart details: ' . $ex->getMessage());
272: }
273: }
274:
275: if ($this->getPaymentParametersRequired() == self::PURCHASE_TYPE_FULL) {
276: try {
277: if (!$this->getCustomer()) {
278: throw new IPC_Exception('Customer details not set!');
279: }
280: $this->getCustomer()->validate($this->getPaymentParametersRequired());
281: } catch (\Exception $ex) {
282: throw new IPC_Exception('Invalid Customer details: ' . $ex->getMessage());
283: }
284: }
285:
286: if ($this->getCnf()->getVersion() === '1.4.1'){
287: if ($this->getCnf()->getPartnerID() == null){
288: throw new IPC_Exception('Required parameter: Partner ID');
289: }
290:
291: if ($this->getCnf()->getApplicationID() == null){
292: throw new IPC_Exception('Required parameter: Application ID');
293: }
294: }
295:
296: return true;
297: }
298:
299: /**
300: * Merchant Site URL where client comes after unsuccessful payment
301: *
302: * @return string
303: */
304: public function getUrlCancel()
305: {
306: return $this->url_cancel;
307: }
308:
309: /**
310: * Merchant Site URL where IPC posts Purchase Notify requests
311: *
312: * @var string
313: */
314: public function getUrlNotify()
315: {
316: return $this->url_notify;
317: }
318:
319: /**
320: * Merchant Site URL where client comes after successful payment
321: *
322: * @return string
323: */
324: public function getUrlOk()
325: {
326: return $this->url_ok;
327: }
328:
329: /**
330: * Merchant Site URL where client comes after successful payment
331: *
332: * @param string $urlOk
333: *
334: * @return Purchase
335: */
336: public function setUrlOk($urlOk)
337: {
338: $this->url_ok = $urlOk;
339:
340: return $this;
341: }
342:
343: /**
344: * Whether to return Card Token for current client card
345: *
346: * @return integer
347: */
348: public function getCardTokenRequest()
349: {
350: return $this->cardTokenRequest;
351: }
352:
353: /**
354: * Defines the packet of details needed from merchant and client to make payment
355: *
356: * @return integer
357: */
358: public function getPaymentParametersRequired()
359: {
360: return $this->paymentParametersRequired;
361: }
362:
363: /**
364: * ISO-4217 Three letter currency code
365: *
366: * @return string
367: */
368: public function getCurrency()
369: {
370: return $this->currency;
371: }
372:
373: /**
374: * ISO-4217 Three letter currency code
375: *
376: * @param string $currency
377: *
378: * @return Purchase
379: */
380: public function setCurrency($currency)
381: {
382: $this->currency = $currency;
383:
384: return $this;
385: }
386:
387: /**
388: * If request is only for card token request without payment, the Amount and Cart params are not required
389: *
390: * @return bool
391: */
392: private function isNoCartPurchase()
393: {
394: return $this->getCardTokenRequest() == self::CARD_TOKEN_REQUEST_ONLY_STORE;
395: }
396:
397: /**
398: * Cart object
399: *
400: * @return Cart
401: */
402: public function getCart()
403: {
404: return $this->cart;
405: }
406:
407: /**
408: * Cart object
409: *
410: * @param Cart $cart
411: *
412: * @return Purchase
413: */
414: public function setCart(Cart $cart)
415: {
416: $this->cart = $cart;
417:
418: return $this;
419: }
420:
421: /**
422: * @return Customer
423: */
424: public function getCustomer()
425: {
426: return $this->customer;
427: }
428:
429: /**
430: * Customer object
431: *
432: * @param Customer $customer
433: *
434: * @return Purchase
435: */
436: public function setCustomer(Customer $customer)
437: {
438: $this->customer = $customer;
439:
440: return $this;
441: }
442:
443: /**
444: * Purchase identifier
445: *
446: * @return string
447: */
448: public function getOrderID()
449: {
450: return $this->orderID;
451: }
452:
453: /**
454: * Optional note to purchase
455: *
456: * @return string
457: */
458: public function getNote()
459: {
460: return $this->note;
461: }
462:
463: /**
464: * @return mixed
465: */
466: public function getPaymentMethod()
467: {
468: return $this->paymentMethod;
469: }
470:
471: /**
472: * @param mixed $paymentMethod
473: */
474: public function setPaymentMethod($paymentMethod)
475: {
476: $this->paymentMethod = $paymentMethod;
477: }
478: }
479: