UNPKG

66.7 kBJavaScriptView Raw
1var DocumentScheme = require("./DocumentScheme.js");
2
3var Billon = {
4 SoapService: require("./SoapService.js"),
5
6 /**
7 * Returns a random universally unique transfer identifier.
8 *
9 * @return {string} The random universally unique identifier.
10 */
11 uniqueId: require('uuid/v1')
12};
13
14/**
15 * Creates an instance of Billon.Payment.
16 *
17 * @constructor
18 * @author Billon sp. z o.o.
19 * @this {Billon.Payment}
20 */
21Billon.Payment = function() {
22
23 /**
24 * A function that run a function from the fourth argument with an object with a merchant data.
25 *
26 * @param {object} requestData An object with a request data.
27 * @param {array} items An array with products.
28 * @param {object} delivery_option A delivery data.
29 * @param {function} cb The function, which should be called with the object with a merchant data.
30 */
31 this.Merchant = function(requestData, items, delivery_option, cb) {
32 cb({});
33 };
34
35 this.CNode = false;
36
37 /**
38 * A function that is to run after receiving response to SOAP request.
39 *
40 * @param {string} requestName A name of the SOAP message
41 * @param {object} parameters A parameters of the SOAP message
42 * @param {object} requestResponse Corporate Node response
43 * @param {object} error Errors when sending SOAP request
44 */
45 this.OnRequestSend = function (requestName, parameters, requestResponse, error) {};
46
47 /**
48 * A function that run a function from the second argument with the object ‘peerLocation’.
49 */
50 this.User = function(cb) {
51 cb(false);
52 };
53
54 /**
55 * A function that run a function from the second argument with an array of product ids.
56 *
57 * @param {object} requestData An object with a request data.
58 * @param {function} cb The function, which should be called with the array of product ids.
59 */
60 this.Products = function(requestData, cb) {
61 cb();
62 };
63
64 /**
65 * A function that run a function from the third argument with a product data or an amount expressed in an object with product data.
66 */
67 this.Product = function(cb) {
68 cb(false);
69 };
70
71 /**
72 * A function that run a function from the third argument with a product data or an amount expressed in an object with product data.
73 *
74 * @param {object} requestData An object with a request data.
75 * @param {(number|object)} item Product data.
76 * @param {function} cb The function
77 * that should be called with an object with the product data or the amount expressed in an object with product data.
78 */
79 this.ProductBillon = function(requestData, item, cb) {
80 cb(item);
81 };
82
83 /**
84 * A function that run a function from the third argument with a delivery data.
85 *
86 * @param {object} requestData An object with a request data.
87 * @param {array} items An array with products.
88 * @param {function} cb The function
89 * that should be called with an object with the delivery data.
90 */
91 this.ProductDelivery = function(requestData, items, cb) {
92 cb(false);
93 };
94
95 /**
96 * A function that run a function from the fourth argument with a path of file to download.
97 *
98 * @param {object} requestData An object with a request data.
99 * @param {array} items An array with products.
100 * @param {object} delivery A delivery data.
101 * @param {object} delivery A payment document.
102 * @param {function} cb The function
103 * that should be called with an object with the path of file to download.
104 */
105 this.ProductDownload = function(requestData, items, delivery, document, cb) {
106 cb(false);
107 };
108
109 /**
110 * A function that run a function from the fourth argument with the payment title.
111 */
112 this.PaymentTitle = function(cb) {
113 cb(false);
114 };
115
116 /**
117 * A function that run a function from the second argument with ISO 4217 code of the currency.
118 *
119 * @param {object} requestData An object with a request data.
120 * @param {function} cb The function
121 * that should be called with ISO 4217 code of the currency.
122 */
123 this.Currency = function(requestData, cb) {
124 cb('PLN');
125 };
126
127 /**
128 * A function that run a function from the second argument with an identifier of series and the type of plate.
129 * @since 2
130 *
131 * @param {function} cb The function, which should be called with an identifier of series and the type of plate.
132 */
133 this.PlatePayment = function(requestData, cb) {
134 cb('', 'NORMAL');
135 };
136
137 /**
138 * A function that run a function from the third argument with false or a changed payment document.
139 *
140 * @param {object} requestData An object with a request data.
141 * @param {object} delivery A payment document.
142 * @param {function} cb The function, which should be called with false or the changed payment document.
143 */
144 this.DocumentParse = function(requestData, document, cb) {
145 cb(document);
146 };
147
148 /**
149 * A function that run a function from the second argument with prices of plates.
150 * @since 2
151 *
152 * @param {object} requestData An object with a request data.
153 * @param {function} cb The function, which should be called with the prices of the plates as arguments.
154 */
155 this.Plates = function(requestData, cb) {
156 cb(false);
157 };
158
159 /**
160 * A function that run a function from the second argument with the maximum amount of the plate payments in series.
161 * @since 2
162 *
163 * @param {object} requestData An object with a request data.
164 * @param {function} cb The function that should be called with the maximum amount,
165 * which is expressed in the number of thousandths of a basic monetary unit, of the plate payments in series.
166 */
167 this.MaxTotalAmount = function(requestData, cb) {
168 cb(0);
169 };
170
171 /**
172 * A function that run a function from the second argument with the duration of the series the plate payments in seconds.
173 * @since 2
174 *
175 * @param {object} requestData An object with a request data.
176 * @param {function} cb The function that should be called with the duration of the series the plate payments in seconds.
177 */
178 this.Duration = function(requestData, cb) {
179 cb(0);
180 };
181
182 /**
183 * A function that run a function from second argument with the maximum number of payments in a series of the plate payments.
184 * @since 2
185 *
186 * @param {object} requestData An object with a request data.
187 * @param {function} cb The function that should be called with the maximum number of payments in a series of the plate payments.
188 */
189 this.MaxPaymentsInSeries = function(requestData, cb) {
190 cb(0);
191 };
192
193 /**
194 * A function that run a function from the second argument with an name of a brand.
195 * @since 2
196 *
197 * @param {object} requestData An object with a request data.
198 * @param {function} cb The function that should be called with the name of a brand.
199 */
200 this.MerchantBrandName = function(requestData, cb) {
201 cb(false);
202 };
203
204 /**
205 * A function that is to run when the payment is successfully completed.
206 */
207 this.OnFinishedPayment = function() {
208 console.log("Finished some payment.");
209 };
210
211 /**
212 * A function to handle the status returned by Corporate Node during the operation of acceptance of the plate payments series.
213 * @since 2
214 */
215 this.OnReceivedPlatePaymentSeriesStatus = function() {};
216
217 /**
218 * A function that is to run when the plate payment is successfully accepted.
219 * @since 2
220 */
221 this.OnAcceptedPlatePaymentSeries = function() {};
222
223};
224
225/**
226 * Checks if variable is function.
227 *
228 * @private
229 * @author Billon sp. z o.o.
230 * @param func The variable to check
231 * @return {boolean} True if variable is function, otherwise false.
232 */
233var isFunction = function(func) {
234 if (typeof func !== "function") {
235 return false;
236 }
237
238 return true;
239};
240
241var deliveryOptions = {
242 "NOT_NEEDED": 0,
243 "OPTIONAL": 1,
244 "OBLIGATORY": 2
245};
246
247var uids = [];
248
249var taskTracker = {};
250
251/**
252 * Returns a name for merchant's brand from the second argument if exists or the domain of a page that has sent the request otherwise
253 * @since 2
254 *
255 * @private
256 * @author Billon sp. z o.o.
257 * @param {object} headers The Sails.js headers in request.
258 * @param {(string|undefined|null|false)} mbn The name for merchant's brand.
259 * @return {string} The name for merchant's brand.
260 */
261var getMerchantBrandName = function(headers, mbn) {
262 if (mbn) {
263 return mbn;
264 } else {
265 var url = require('url');
266 return url.parse(headers['origin'] ? headers['origin'] : headers['referer']).hostname;
267 }
268};
269
270/**
271 * Validates a peer location and adds it to parameters of a request if peer location is correct.
272 *
273 * @private
274 * @author Billon sp. z o.o.
275 * @param {object} user The peer location.
276 * @param {object} params The parameters of a payment request or request of start of payment series.
277 */
278var addPeerLocationIfAvailable = function(user, params) {
279 if (typeof user.confirmationCode1 != 'undefined' && user.confirmationCode1 != null && typeof user.confirmationCode2 != 'undefined' && user.confirmationCode2 != null) {
280 if (!user.userLocation || !user.userLocation.machineIdHex || !user.userLocation.ip || !user.userLocation.tcp || !user.userLocation.udp) {
281 user.userLocation = null;
282 }
283 if (!user.buddyLocation || !user.buddyLocation.machineIdHex || !user.buddyLocation.ip || !user.buddyLocation.tcp || !user.buddyLocation.udp) {
284 user.buddyLocation = null;
285 }
286 params.peerLocation = user;
287 }
288};
289
290// ERRORS
291var errs = {
292 ERR_INVALID_BODY: {
293 err: "ERR_INVALID_BODY",
294 description: "Missing body."
295 },
296 ERR_INVALID_QUERY: {
297 err: "ERR_INVALID_QUERY",
298 description: "Missing query."
299 },
300 ERR_INVALID_QUERY_DATA: {
301 err: "ERR_INVALID_QUERY_DATA",
302 description: "Data must be an object."
303 },
304 ERR_INVALID_PRODUCTS: {
305 err: "ERR_INVALID_PRODUCTS",
306 description: "Data.products must be an object."
307 },
308 ERR_INVALID_USER: {
309 err: "ERR_INVALID_USER",
310 description: "Data.user must be an object."
311 },
312 ERR_INVALID_WUI: {
313 err: "ERR_INVALID_WUI",
314 description: "Data.cNode must be an object."
315 },
316 ERR_INVALID_USER_USERNAME: {
317 err: "ERR_INVALID_USER_USERNAME",
318 description: "Data.user.userName must be a string with minimum 4 characters length."
319 },
320 ERR_INVALID_TASKID: {
321 err: "ERR_INVALID_TASKID",
322 description: "Invalid taskId sent."
323 },
324 ERR_INVALID_UID: {
325 err: "ERR_INVALID_UID",
326 description: "Invalid uid sent."
327 },
328 ERR_TASK_DOES_NOT_EXIST: {
329 err: "ERR_TASK_DOES_NOT_EXIST",
330 description: "Task does not exist."
331 },
332 ERR_CANNOT_DOWNLOAD: {
333 err: "ERR_CANNOT_DOWNLOAD",
334 description: "Cannot download file."
335 },
336 ERR_INVALID_AMOUNT: {
337 err: "ERR_INVALID_AMOUNT",
338 description: "Invalid amount."
339 }
340};
341
342var plateColors = {'PLATE_ALPHA': '44B905', 'PLATE_BETA': '00ADFF', 'PLATE_GAMMA': 'B466CB', 'PLATE_DELTA': 'F6891C', 'PLATE_EPSILON': 'EC2B41'};
343
344Billon.Payment.prototype = {
345
346 /**
347 * Sets a function that run a function from the fourth argument with an object with a merchant data.
348 *
349 * @param {function} func The function with four arguments:
350 * an object with a request data, an array with products,
351 * a delivery data and the function, which should be called with the object with a merchant data.
352 * @return {(Billon.Payment|false)} The object of this method.
353 */
354 merchant: function(func) {
355 if (!isFunction(func)) {
356 console.log("Payment.merchant parameter must be a function.");
357 return false;
358 }
359
360 this.Merchant = func;
361 return this;
362 },
363
364 /**
365 * Sets a function that run a function from the fourth argument with API key of the user of the service ‘billon.me’
366 * or an object with username with which the application 24/7 is signed in and address on which the application 24/7 listens.
367 *
368 * @param {function} func The function with four arguments:
369 * an object with a request data, an array with products,
370 * a delivery data and the function, which should be called with API key of the user of the service ‘billon.me’
371 * or an object with username with which the application 24/7 is signed in and address on which the application 24/7 listens.
372 * @return {(Billon.Payment|false)} The object of this method.
373 */
374 cNode: function(func) {
375 if (!isFunction(func)) {
376 console.log("Payment.cNode parameter must be a function.");
377 return false;
378 }
379
380 this.CNode = func;
381 return this;
382 },
383
384 /**
385 * Sets a function that run a function from the fourth argument with API key of the user of the service ‘billon.me’
386 * or an object with username with which the application 24/7 is signed in and address on which the application 24/7 listens.
387 * @deprecated since version 2.5
388 *
389 * @param {function} func The function with four arguments:
390 * an object with a request data, an array with products,
391 * a delivery data and the function, which should be called with API key of the user of the service ‘billon.me’
392 * or an object with username with which the application 24/7 is signed in and address on which the application 24/7 listens.
393 * @return {(Billon.Payment|false)} The object of this method.
394 */
395 app24: function(func) {
396 return this.cNode(func);
397 },
398
399 /**
400 * Sets a function that is to run after receiving response to SOAP request.
401 * @since 2.1
402 *
403 * @param {function} func The function with four arguments:
404 * name of the SOAP message, parameters of the SOAP message, Corporate Node response, errors when sending SOAP request.
405 * @return {(Billon.Payment|false)} The object of this method.
406 */
407 onRequestSend: function(func) {
408 if (!isFunction(func)) {
409 console.log("Payment.onRequestSend parameter must be a function.");
410 return this;
411 }
412
413 this.OnRequestSend = func;
414 return this;
415 },
416
417 /**
418 * Sets a function that run a function from the second argument with the object ‘peerLocation’.
419 *
420 * @param {function} func The function with two arguments:
421 * an object with a request data and the function, which should be called with the object ‘peerLocation’.
422 * @return {(Billon.Payment|false)} The object of this method.
423 */
424 user: function(func) {
425 if (!isFunction(func)) {
426 console.log("Payment.user parameter must be a function.");
427 return false;
428 }
429
430 this.User = func;
431 return this;
432 },
433
434 /**
435 * Sets a function that run a function from the second argument with an array of product ids.
436 *
437 * @param {function} func The function with two arguments:
438 * an object with a request data and the function, which should be called with the array of product ids.
439 * @return {(Billon.Payment|false)} The object of this method.
440 */
441 products: function(func) {
442 if (!isFunction(func)) {
443 console.log("Payment.products parameter must be a function.");
444 return false;
445 }
446
447 this.Products = func;
448 return this;
449 },
450
451 /**
452 * Sets a function that run a function from the third argument with a product data or an amount expressed in an object with product data.
453 *
454 * @param {function} func The function with two arguments:
455 * an object with a request data
456 * and the function,
457 * which should be called with an object with the product data or the amount expressed in an object with product data.
458 * @return {(Billon.Payment|false)} The object of this method.
459 */
460 product: function(func) {
461 if (!isFunction(func)) {
462 console.log("Payment.product parameter must be a function.");
463 return false;
464 }
465
466 this.Product = func;
467 return this;
468 },
469
470 /**
471 * Sets a function that run a function from the third argument with a product data or an amount expressed in an object with product data.
472 *
473 * @param {function} func The function with three arguments:
474 * an object with a request data, a product data
475 * and the function,
476 * which should be called with an object with the product data or the amount expressed in an object with product data.
477 * @return {(Billon.Payment|false)} The object of this method.
478 */
479 productBillon: function(func) {
480 if (!isFunction(func)) {
481 console.log("Payment.productBillon parameter must be a function.");
482 return false;
483 }
484
485 this.ProductBillon = func;
486 return this;
487 },
488
489 /**
490 * Sets a function that run a function from the third argument with a delivery data.
491 *
492 * @param {function} func The function with three arguments:
493 * an object with a request data, an object with product data
494 * and the function, which should be called with an object with the delivery data.
495 * @return {(Billon.Payment|false)} The object of this method.
496 */
497 productDelivery: function(func) {
498 if (!isFunction(func)) {
499 console.log("Payment.productDelivery parameter must be a function.");
500 return false;
501 }
502
503 this.ProductDelivery = func;
504 return this;
505 },
506
507 /**
508 * Sets a function that run a function from the fourth argument with an array with a path of file to download.
509 *
510 * @param {function} func The function with four arguments:
511 * an object with a request data, an object with product data, a payment document,
512 * and the function, which should be called with an object with the path of file to download.
513 * @return {(Billon.Payment|false)} The object of this method.
514 */
515 productDownload: function(func) {
516 if (!isFunction(func)) {
517 console.log("Payment.productDownload parameter must be a function.");
518 return false;
519 }
520
521 this.ProductDownload = func;
522 return this;
523 },
524
525 /**
526 * Sets a function that run a function from the second argument with ISO 4217 code of the currency.
527 *
528 * @param {function} func The function with two arguments:
529 * an object with a request data and the function, which should be called with ISO 4217 code of the currency.
530 * @return {(Billon.Payment|false)} The object of this method.
531 */
532 currency: function(func) {
533 if (!isFunction(func)) {
534 console.log("Payment.currency parameter must be a function.");
535 return this;
536 }
537
538 this.Currency = func;
539 return this;
540 },
541
542 /**
543 * Sets a function that run a function from the second argument with an identifier of series and the type of plate.
544 * @since 2
545 *
546 * @param {function} func The function with two arguments:
547 * an object with a request data and the function, which should be called with an identifier of series and the type of plate.
548 * @return {(Billon.Payment|false)} The object of this method.
549 */
550 platePayment: function(func) {
551 if (!isFunction(func)) {
552 console.log("Payment.platePayment parameter must be a function.");
553 return this;
554 }
555
556 this.PlatePayment = func;
557 return this;
558 },
559
560 /**
561 * Sets a function that run a function from the third argument with false or a changed payment document.
562 *
563 * @param {function} func The function with three arguments:
564 * an object with a request data, the payment document
565 * and the function, which should be called with false or the changed payment document.
566 * @return {(Billon.Payment|false)} The object of this method.
567 */
568 documentParse: function(func) {
569 if (!isFunction(func)) {
570 console.log("Payment.documentParse parameter must be a function.");
571 return false;
572 }
573
574 this.DocumentParse = func;
575 return this;
576 },
577
578 /**
579 * Sets a function that run a function from the fourth argument with the payment title.
580 *
581 * @param {function} func The function with four arguments:
582 * an object with a request data, an array with products,
583 * a delivery data and the function, which should be called with the payment title.
584 * @return {(Billon.Payment|false)} The object of this method.
585 */
586 paymentTitle: function(func) {
587 if (!isFunction(func)) {
588 console.log("Payment.paymentTitle parameter must be a function.");
589 return false;
590 }
591
592 this.PaymentTitle = func;
593 return this;
594 },
595
596 /**
597 * Sets a function that run a function from the second argument with prices of plates.
598 * @since 2
599 *
600 * @param {function} func The function with two arguments:
601 * an object with a request data and the function, which should be called with the prices of the plates as arguments.
602 * @return {(Billon.Payment|false)} The object of this method.
603 */
604 plates: function(func) {
605 if (!isFunction(func)) {
606 console.log("Payment.plates parameter must be a function.");
607 return this;
608 }
609
610 this.Plates = func;
611 return this;
612 },
613
614 /**
615 * Sets a function that run a function from the second argument with the maximum amount of the plate payments in series.
616 *
617 * @param {function} func The function with two arguments:
618 * an object with a request data
619 * and the function, which should be called with the maximum amount,
620 * which is expressed in the number of thousandths of a basic monetary unit, of the plate payments in series.
621 * @return {(Billon.Payment|false)} The object of this method.
622 */
623 maxTotalAmount: function(func) {
624 if (!isFunction(func)) {
625 console.log("Payment.maxTotalAmount parameter must be a function.");
626 return this;
627 }
628
629 this.MaxTotalAmount = func;
630 return this;
631 },
632
633 /**
634 * Sets a function that run a function from the second argument with the duration of the series the plate payments in seconds.
635 * @since 2
636 *
637 * @param {function} func The function with two arguments:
638 * an object with a request data
639 * and the function, which should be called with the duration of the series the plate payments in seconds.
640 * @return {(Billon.Payment|false)} The object of this method.
641 */
642 duration: function(func) {
643 if (!isFunction(func)) {
644 console.log("Payment.duration parameter must be a function.");
645 return this;
646 }
647
648 this.Duration = func;
649 return this;
650 },
651
652 /**
653 * Sets a function that run a function from second argument with the maximum number of payments in a series of the plate payments.
654 * @since 2
655 *
656 * @param {function} func The function with two arguments:
657 * an object with a request data
658 * and the function, which should be called with the maximum number of payments in a series of the plate payments.
659 * @return {(Billon.Payment|false)} The object of this method.
660 */
661 maxPaymentsInSeries: function(func) {
662 if (!isFunction(func)) {
663 console.log("Payment.maxPaymentsInSeries parameter must be a function.");
664 return this;
665 }
666
667 this.MaxPaymentsInSeries = func;
668 return this;
669 },
670
671 /**
672 * Sets a function that run a function from the second argument with an name of a brand.
673 * @since 2
674 *
675 * @param {function} func The function with two arguments:
676 * an object with a request data and the function, which should be called with the name of a brand.
677 * @return {(Billon.Payment|false)} The object of this method.
678 */
679 merchantBrandName: function(func) {
680 if (!isFunction(func)) {
681 console.log("Payment.merchantBrandName parameter must be a function.");
682 return this;
683 }
684
685 this.MerchantBrandName = func;
686 return this;
687 },
688
689 /**
690 * Sets a function that is to run when the payment is successfully completed.
691 *
692 * @param {function} func The function with four arguments: products, a delevery data, a purchase docuemnt and a request data.
693 * @return {(Billon.Payment|false)} The object of this method.
694 */
695 onFinishedPayment: function(func) {
696 if (!isFunction(func)) {
697 console.log("Payment.onFinishedPayment parameter must be a function.");
698 return false;
699 }
700
701 this.OnFinishedPayment = func;
702 return this;
703 },
704
705 /**
706 * Sets a function to handle the status returned by Corporate Node during the operation of acceptance of the plate payments series.
707 * @since 2
708 *
709 * @param {function} func The function with an object with the response as argument.
710 * @return {(Billon.Payment|false)} The object of this method.
711 */
712 onReceivedPlatePaymentSeriesStatus: function(func) {
713 if (!isFunction(func)) {
714 console.log("Payment.onReceivedPlatePaymentSeriesStatus parameter must be a function.");
715 return false;
716 }
717
718 this.OnReceivedPlatePaymentSeriesStatus = func;
719 return this;
720 },
721
722 /**
723 * Sets a function that is to run when the plate payment is successfully accepted.
724 * @since 2
725 *
726 * @param {function} func The function with an object with the payment data as argument.
727 * @return {(Billon.Payment|false)} The object of this method.
728 */
729 onAcceptedPlatePaymentSeries: function(func) {
730 if (!isFunction(func)) {
731 console.log("Payment.onAcceptedPlatePaymentSeries parameter must be a function.");
732 return false;
733 }
734
735 this.OnAcceptedPlatePaymentSeries = func;
736 return this;
737 },
738
739 /**
740 * Initiates and listen to donation for user's object and value sended by POST.
741 *
742 * @param {Request} req The first parameter of a function of Sails.js controller, Sails.js incoming request object.
743 * @param {Response} res The second parameter of a function of Sails.js controller, Sails.js outgoing response object.
744 */
745 donateInitiation: function(req, res) {
746 var self = this;
747
748 if (typeof req.body !== "object") {
749 return res.send(errs.ERR_INVALID_QUERY);
750 }
751
752 var requestData = req.body;
753
754 if (typeof requestData.user !== "object") {
755 return res.send(errs.ERR_INVALID_USER);
756 }
757
758 if (typeof requestData.amount !== "number") {
759 return res.send(errs.ERR_INVALID_AMOUNT);
760 }
761
762 if (typeof requestData.user.userName !== "string" || requestData.user.userName.length < 4) {
763 return res.send(errs.ERR_INVALID_USER_USERNAME);
764 }
765
766 var paymentData = {
767 user: requestData.user,
768 amount: requestData.amount
769 };
770
771 var requestInvoiceData = "NOT_NEEDED";
772 var requestDeliveryData = "NOT_NEEDED";
773 self.CNode(requestData, null, null, function(wui) {
774 var document = DocumentScheme();
775 self.DocumentParse(requestData, document, function(parsedDocument) {
776 if (parsedDocument !== false) {
777 document = parsedDocument;
778 }
779
780 // Wczytanie danych sprzedawcy.
781 self.Merchant(requestData, document.sales_document_data.items, document.sales_document_data.delivery_option, function(merchant) {
782 var uid = Billon.uniqueId();
783 document.sales_document_data.seller_data = merchant;
784 document.sales_document_data.sales_document_id = uid;
785
786 // Ustalenie daty.
787 document.sales_document_data.sales_document_date = new Date().getTime();
788 document.sales_document_data.trade_date = new Date().getTime();
789 document.sales_document_data.total_amount_gross = paymentData.amount;
790
791 self.PaymentTitle(requestData, document.sales_document_data.items, document.sales_document_data.delivery_option, function(title) {
792 self.Currency(requestData, function(currency) {
793 self.MerchantBrandName(requestData, function(mbn) {
794 var data = {
795 cNode: wui,
796 params: {
797 type: "NORMAL",
798 amount: {
799 amount: paymentData.amount,
800 currency: currency
801 },
802 requestData: {
803 username: paymentData.user.userName,
804 uniqueTransferId: document.sales_document_data.sales_document_id,
805 title: title,
806 merchantBrandName: getMerchantBrandName(req.headers, mbn),
807 requestInvoiceData: requestInvoiceData,
808 requestDeliveryData: requestDeliveryData,
809 description: document ? JSON.stringify(document) : null
810 }
811 }
812 };
813 addPeerLocationIfAvailable(paymentData.user, data.params);
814 Billon.SoapService.onRequestSend = self.OnRequestSend;
815 Billon.SoapService.call.requestPaymentInitiation(data, function(requestResponse) {
816 var copy = _.clone(requestResponse);
817 if (requestResponse.requestStatus === "SUCCESS") {
818 taskTracker[uid] = {
819 taskId: requestResponse.taskId,
820 cNode: wui,
821 paymentData: paymentData
822 };
823 var interval = setInterval(function() {
824 Billon.SoapService.onRequestSend = self.OnRequestSend;
825 Billon.SoapService.call.getTaskStatus({
826 cNode: wui,
827 params: {
828 taskId: requestResponse.taskId
829 }
830 }, function(taskResponse) {
831 if (taskResponse.requestStatus !== "SUCCESS") {
832 setTimeout(function() {
833 delete taskTracker[uid];
834 }, 30000);
835 return clearInterval(interval);
836 }
837
838 if (taskResponse.status.split("_")[0] === "FINISHED" || taskResponse.progressPercent === 100 || taskResponse.progressPercent === "100") {
839 clearInterval(interval);
840 setTimeout(function() {
841 delete taskTracker[uid];
842 }, 30000);
843 }
844
845 if (taskResponse.status === "FINISHED_OK") {
846 document.sales_document_data.items = paymentData;
847 document.additionalInfo = taskResponse.additionalInfo;
848 document.taskId = requestResponse.taskId;
849 self.OnFinishedPayment(document.sales_document_data.items, document.sales_document_data.delivery_option, document, requestData);
850 }
851
852 });
853 }, 5000);
854 copy.taskId = uid;
855 }
856
857 res.json(copy);
858 });
859 });
860 });
861 });
862 });
863 });
864 });
865 },
866
867 /**
868 * Initiates and listen to payment.
869 *
870 * @param {Request} req The first parameter of a function of Sails.js controller, Sails.js incoming request object.
871 * @param {Response} res The second parameter of a function of Sails.js controller, Sails.js outgoing response object.
872 */
873 paymentInitiation: function(req, res) {
874 var self = this;
875 if (typeof req.body !== "object") {
876 return res.send(errs.ERR_INVALID_BODY);
877 }
878
879 var requestData = req.body,
880 paymentData = {};
881
882 self.User(requestData, function(user) {
883 if (typeof user !== "object") {
884 return res.send(errs.ERR_INVALID_USER);
885 }
886
887 if (typeof user.userName !== "string" || user.userName.length < 4) {
888 return res.send(errs.ERR_INVALID_USER_USERNAME);
889 }
890
891 paymentData.user = user;
892
893 self.Products(requestData, function(products) {
894 if (products && typeof products !== "object") {
895 return res.send(errs.ERR_INVALID_PRODUCTS);
896 }
897
898 paymentData.products = products;
899
900 var document = DocumentScheme();
901
902 self.DocumentParse(requestData, document, function(parsedDocument) {
903 if (parsedDocument !== false) {
904 document = parsedDocument;
905 }
906
907 var requestInvoiceData = "NOT_NEEDED";
908 var requestDeliveryData = "NOT_NEEDED";
909
910 // Wczytanie produktów.
911 var itemsLoaded = 0;
912 paymentData.items = [];
913 var productsLength = 1;
914 var onItemReceived = function(item) {
915 paymentData.items.push(item);
916 self.ProductBillon(requestData, item, function(currentItem) {
917 if (typeof currentItem == "object") {
918 currentItem.unit_price_net = parseInt(currentItem.unit_price_net * 1000);
919 currentItem.amount_net = currentItem.unit_price_net * currentItem.quantity;
920 document.sales_document_data.total_amount_net += currentItem.amount_net;
921 currentItem.amount_gross = currentItem.amount_gross * 1000;
922
923 // Sprawdzenie czy potrzeba danych do faktury lub dostawy.
924 if (deliveryOptions[currentItem.requestInvoiceData] > deliveryOptions[requestInvoiceData]) {
925 requestInvoiceData = currentItem.requestInvoiceData;
926 }
927
928 if (deliveryOptions[currentItem.requestDeliveryData] > deliveryOptions[requestDeliveryData]) {
929 requestDeliveryData = currentItem.requestDeliveryData;
930 }
931
932 if (currentItem.vat && currentItem.vat.amount >= 0) {
933 currentItem.vat.amount *= 1000;
934 }
935 // Dodanie produktu do listy.
936 document.sales_document_data.items.push(currentItem);
937 document.sales_document_data.total_amount_gross += currentItem.amount_gross *
938 (currentItem.quantity || currentItem.quantity === 0 ?
939 currentItem.quantity : 1);
940 }
941 else {
942 document.sales_document_data.items.push({amount_gross: currentItem});
943 document.sales_document_data.total_amount_gross += currentItem;
944 }
945
946 itemsLoaded++;
947 if (itemsLoaded === productsLength) {
948 onItemsLoaded();
949 }
950 });
951 };
952 if (paymentData.products) {
953 productsLength = paymentData.products.length;
954 for (var i = 0; i < productsLength; i++) {
955 var itemId = paymentData.products[i];
956 self.Product(requestData, itemId, onItemReceived);
957 }
958 }
959 else {
960 self.Product(requestData, undefined, onItemReceived);
961 }
962 function onItemsLoaded() {
963
964 // Wczytanie opcji dostawy.
965 self.ProductDelivery(requestData, document.sales_document_data.items, function(delivery) {
966 document.sales_document_data.delivery_option = delivery;
967
968 // Wczytanie danych sprzedawcy.
969 self.Merchant(requestData, document.sales_document_data.items, document.sales_document_data.delivery_option, function(merchant) {
970 var uid = Billon.uniqueId();
971 document.sales_document_data.seller_data = merchant;
972 document.sales_document_data.sales_document_id = uid;
973
974 // Ustalenie daty.
975 document.sales_document_data.sales_document_date = new Date().getTime();
976 document.sales_document_data.trade_date = new Date().getTime();
977
978 self.CNode(requestData, document.sales_document_data.items, document.sales_document_data.delivery_option, function(wui) {
979 if (!wui) {
980 return res.send(errs.ERR_INVALID_WUI);
981 }
982 self.PaymentTitle(requestData, document.sales_document_data.items, document.sales_document_data.delivery_option, function(title) {
983 self.Currency(requestData, function(c) {
984 self.PlatePayment(requestData, function(spid, t) {
985 self.MerchantBrandName(requestData, function(mbn) {
986 var keyCodeArr = [];
987 var counter = 0;
988 var keyCodeItems = _.filter(paymentData.items, function(item) {
989 return item.KeyCodes;
990 });
991 var keyCodeItemsLength = keyCodeItems.length;
992
993 var errorCalled = false;
994 var onKeyCodeDownload = function(download) {
995 if (errorCalled) {
996 return;
997 }
998
999 if (download.err) {
1000 errorCalled = true;
1001 return res.json(errs.ERR_CANNOT_DOWNLOAD);
1002 }
1003
1004 if (!download || download.length === 0) {
1005 return res.json(errs.ERR_CANNOT_DOWNLOAD);
1006 }
1007
1008 // TODO: Obsłużyć wiele kodów jako 1 produkt.
1009 KeyCode.update({
1010 id: download[0].id
1011 }, {
1012 Status: "blocked"
1013 }).exec(function(err, updated) {
1014 if (err) {
1015 console.log(err);
1016 return;
1017 }
1018
1019 if (typeof updated !== "undefined") {
1020 keyCodeArr.push(updated[0]);
1021 }
1022
1023 counter++;
1024 if (keyCodeItemsLength === counter) {
1025 onDownloadedFinished();
1026 }
1027 });
1028 };
1029
1030 if (keyCodeItemsLength === 0) {
1031 return self.ProductDownload(requestData, paymentData.items, delivery, document, onDownloadedFinished);
1032 }
1033
1034 for (var i = 0; i < keyCodeItemsLength; i++) {
1035 self.ProductDownload(requestData, paymentData.items, delivery, document, onKeyCodeDownload);
1036 }
1037
1038 function onDownloadedFinished(downloadArr) {
1039 if (t) {
1040 t = t.toUpperCase();
1041 if (t == 'ALPHA' || t == 'BETA' || t == 'GAMMA' || t == 'DELTA' || t == 'EPSILON') {
1042 t = 'PLATE_' + t;
1043 }
1044 }
1045 var data = {
1046 cNode: wui,
1047 params: {
1048 type: t ? t : "NORMAL",
1049 amount: {
1050 amount: document.sales_document_data.total_amount_gross,
1051 currency: c
1052 },
1053 requestData: {
1054 username: paymentData.user.userName,
1055 uniqueTransferId: uid,
1056 title: title,
1057 merchantBrandName: getMerchantBrandName(req.headers, mbn),
1058 requestInvoiceData: requestInvoiceData,
1059 requestDeliveryData: requestDeliveryData,
1060 description: JSON.stringify(document)
1061 }
1062 }
1063 };
1064 if (t && t.indexOf('PLATE_') == 0) {
1065 data.params.requestData.plateColorHex = plateColors[t];
1066 }
1067 if (spid) {
1068 data.params.seriesId = spid;
1069 }
1070 addPeerLocationIfAvailable(paymentData.user, data.params);
1071 Billon.SoapService.onRequestSend = self.OnRequestSend;
1072 Billon.SoapService.call.requestPaymentInitiation(data, function(requestResponse) {
1073 var onUpdated = function(err, updated) {
1074 if (err) {
1075 console.log(err);
1076 }
1077 };
1078
1079 var unBlockKeyCodes = function() {
1080 for (var i = 0; i < keyCodeArr.length; i++) {
1081 var keyCode = keyCodeArr[i];
1082 KeyCode.update({
1083 id: keyCode.id
1084 }, {
1085 Status: "available"
1086 }).exec(onUpdated);
1087 }
1088 };
1089
1090 if (requestResponse.err || requestResponse.requestStatus !== "SUCCESS") {
1091 unBlockKeyCodes();
1092 }
1093
1094 var copy = _.clone(requestResponse);
1095 if (requestResponse.requestStatus === "SUCCESS") {
1096 taskTracker[uid] = {
1097 requestData: requestData,
1098 taskId: requestResponse.taskId,
1099 cNode: wui,
1100 items: paymentData.items,
1101 delivery: document.sales_document_data.delivery_option,
1102 document: document,
1103 download: downloadArr,
1104 keyCodes: keyCodeArr
1105 };
1106
1107 var interval = setInterval(function() {
1108 Billon.SoapService.onRequestSend = self.OnRequestSend;
1109 Billon.SoapService.call.getTaskStatus({
1110 cNode: wui,
1111 params: {
1112 taskId: requestResponse.taskId
1113 }
1114 }, function(taskResponse) {
1115 if (taskResponse.requestStatus !== "SUCCESS") {
1116 clearInterval(interval);
1117 setTimeout(function() {
1118 delete taskTracker[uid];
1119 }, 30000);
1120
1121 unBlockKeyCodes();
1122 return;
1123 }
1124
1125 var onUpdatedKey = function(err, updated) {
1126 if (err) {
1127 console.log(err);
1128 }
1129 };
1130
1131 var keyCodeUsed;
1132
1133 if (taskResponse.status.split("_")[0] === "FINISHED" || taskResponse.progressPercent === 100
1134 || taskResponse.progressPercent === "100") {
1135 clearInterval(interval);
1136 setTimeout(function() {
1137 delete taskTracker[uid];
1138 }, 30000);
1139
1140 if (taskResponse.status !== "FINISHED_OK") {
1141 for (var j = 0; j < keyCodeArr.length; j++) {
1142 keyCodeUsed = keyCodeArr[j];
1143 KeyCode.update({
1144 id: keyCodeUsed.id
1145 }, {
1146 Status: "available"
1147 }).exec(onUpdatedKey);
1148 }
1149 }
1150
1151 }
1152
1153 if (taskResponse.status === "FINISHED_OK") {
1154 for (var k = 0; k < keyCodeArr.length; k++) {
1155 keyCodeUsed = keyCodeArr[k];
1156 console.log("keyCodeUsed");
1157 console.log(keyCodeUsed);
1158 KeyCode.update({
1159 id: keyCodeUsed.id
1160 }, {
1161 Status: "sold"
1162 }).exec(onUpdatedKey);
1163 }
1164
1165 document.additionalInfo = taskResponse.additionalInfo;
1166 document.taskId = requestResponse.taskId;
1167 self.OnFinishedPayment(document.sales_document_data.items, document.sales_document_data.delivery_option, document, requestData);
1168 }
1169
1170 });
1171 }, 5000);
1172 copy.taskId = uid;
1173 }
1174
1175 res.json(copy);
1176
1177 });
1178 }
1179 });
1180 });
1181 });
1182 });
1183 });
1184 });
1185 });
1186 }
1187 });
1188 });
1189 });
1190 },
1191
1192 /**
1193 * Outputs information about a tariff of plate payments.
1194 * @since 2.1
1195 *
1196 * @param {Response} req The second parameter of a function of Sails.js controller, Sails.js outgoing response object.
1197 * @param {Response} res The second parameter of a function of Sails.js controller, Sails.js outgoing response object.
1198 */
1199 tariff: function(req, res) {
1200 var self = this;
1201 if (self.tariff.arguments.length == 1) {
1202 res = req;
1203 }
1204 self.Plates({}, function(alpha, beta, gamma, delta, epsilon) {
1205 self.Currency({}, function(c) {
1206 self.Duration({}, function(d) {
1207 self.MaxTotalAmount({}, function(mta) {
1208 self.MerchantBrandName({}, function(mbn) {
1209 res.json({amounts: [alpha, beta, gamma, delta, epsilon], currency: c, duration: d, maxTotalAmount: mta, merchantBrandName: mbn});
1210 });
1211 });
1212 });
1213 });
1214 });
1215 },
1216
1217 /**
1218 * Outputs information about a tariff of plate payments.
1219 * @deprecated since version 2.1
1220 * @since 2
1221 *
1222 *
1223 * @param {Response} req The second parameter of a function of Sails.js controller, Sails.js outgoing response object.
1224 * @param {Response} res The second parameter of a function of Sails.js controller, Sails.js outgoing response object.
1225 */
1226 platesList: function(req, res) {
1227 if (this.platesList.arguments.length == 1) {
1228 this.tariff(req, req);
1229 }
1230 else {
1231 this.tariff(null, res);
1232 }
1233 },
1234
1235 /**
1236 * Initiates and listen to start of series of plate payments.
1237 * @since 2
1238 *
1239 * @param {Request} req The first parameter of a function of Sails.js controller, Sails.js incoming request object.
1240 * @param {Response} res The second parameter of a function of Sails.js controller, Sails.js outgoing response object.
1241 */
1242 platePaymentSeriesStart: function(req, res) {
1243 var self = this;
1244 if (typeof req.body !== "object") {
1245 return res.send(errs.ERR_INVALID_BODY);
1246 }
1247 var requestData = req.body,
1248 paymentData = {};
1249 self.User(requestData, function(user) {
1250 if (typeof user !== "object") {
1251 return res.send(errs.ERR_INVALID_USER);
1252 }
1253
1254 if (typeof user.userName !== "string" || user.userName.length < 4) {
1255 return res.send(errs.ERR_INVALID_USER_USERNAME);
1256 }
1257 paymentData.user = user;
1258 self.Plates(requestData, function(alpha, beta, gamma, delta, epsilon) {
1259 var cpc = _.clone(plateColors);
1260 if (!beta) {
1261 beta = alpha;
1262 cpc.PLATE_BETA = cpc.PLATE_ALPHA;
1263 alpha = 0;
1264 }
1265 if (!gamma) {
1266 gamma = beta;
1267 beta = alpha;
1268 cpc.PLATE_GAMMA = cpc.PLATE_BETA;
1269 cpc.PLATE_BETA = cpc.PLATE_ALPHA;
1270 alpha = 0;
1271 }
1272 if (!delta) {
1273 delta = gamma;
1274 gamma = beta;
1275 beta = alpha;
1276 cpc.PLATE_DELTA = cpc.PLATE_GAMMA;
1277 cpc.PLATE_GAMMA = cpc.PLATE_BETA;
1278 cpc.PLATE_BETA = cpc.PLATE_ALPHA;
1279 alpha = 0;
1280 }
1281 if (!epsilon) {
1282 epsilon = delta;
1283 delta = gamma;
1284 gamma = beta;
1285 beta = alpha;
1286 cpc.PLATE_EPSILON = cpc.PLATE_DELTA;
1287 cpc.PLATE_DELTA = cpc.PLATE_GAMMA;
1288 cpc.PLATE_GAMMA = cpc.PLATE_BETA;
1289 cpc.PLATE_BETA = cpc.PLATE_ALPHA;
1290 alpha = 0;
1291 }
1292 var plates = {'alpha-price': alpha, 'beta-price': beta, 'gamma-price': gamma, 'delta-price': delta, 'epsilon-price': epsilon,
1293 'alpha-color': cpc.PLATE_ALPHA, 'beta-color': cpc.PLATE_BETA, 'gamma-color': cpc.PLATE_GAMMA,
1294 'delta-color': cpc.PLATE_DELTA, 'epsilon-color': cpc.PLATE_EPSILON};
1295 self.CNode(requestData, plates, null, function(wui) {
1296 if (!wui) {
1297 return res.send(errs.ERR_INVALID_WUI);
1298 }
1299 self.Currency(requestData, function(c) {
1300 self.MaxTotalAmount(requestData, function(mta) {
1301 self.Duration(requestData, function(d) {
1302 self.MaxPaymentsInSeries(requestData, function(mp) {
1303 self.MerchantBrandName(requestData, function(t) {
1304 var title = getMerchantBrandName(req.headers, t);
1305 var uid = Billon.uniqueId();
1306 data = {cNode: wui,
1307 params: {seriesData: {
1308 description: ' ',
1309 username: paymentData.user.userName,
1310 maxTotalAmount: {amount: mta, currency: c, colour: 0},
1311 maxPaymentsInSeries: mp,
1312 seriesSecondDuration: d,
1313 plateParameters: plates},
1314 type: 'PLATE_PAYMENT_SERIES',
1315 requestData: {
1316 username: paymentData.user.userName,
1317 uniqueTransferId: uid,
1318 title: title,
1319 merchantBrandName: title,
1320 requestInvoiceData: 'NOT_NEEDED',
1321 requestDeliveryData: 'NOT_NEEDED',
1322 description: ' ',
1323 channelInfo: ' ',
1324 antiSpamCode: ' '}}};
1325 addPeerLocationIfAvailable(paymentData.user, data.params);
1326 Billon.SoapService.onRequestSend = self.OnRequestSend;
1327 Billon.SoapService.call.startSeriesPayment(data, function(requestResponse) {
1328 var copy = _.clone(requestResponse);
1329 if (requestResponse.requestStatus === "SUCCESS") {
1330 taskTracker[uid] = {
1331 taskId: requestResponse.taskId,
1332 cNode: wui,
1333 paymentData: paymentData
1334 };
1335 var interval = setInterval(function() {
1336 Billon.SoapService.onRequestSend = self.OnRequestSend;
1337 Billon.SoapService.call.getTaskStatus({
1338 cNode: wui,
1339 params: {
1340 taskId: requestResponse.taskId
1341 }
1342 }, function(taskResponse) {
1343 self.OnReceivedPlatePaymentSeriesStatus(taskResponse);
1344 if (taskResponse.requestStatus !== "SUCCESS") {
1345 setTimeout(function() {
1346 delete taskTracker[uid];
1347 }, 30000);
1348 return clearInterval(interval);
1349 }
1350 var PaymentAccepted = taskResponse.status === "TRANSFERRING" || taskResponse.status === "TRANSFERING"
1351 || taskResponse.status === "SERIES_ACCEPTED";
1352 if (PaymentAccepted || taskResponse.status.split("_")[0] === "FINISHED" ||
1353 taskResponse.progressPercent === 100 || taskResponse.progressPercent === "100") {
1354 clearInterval(interval);
1355 setTimeout(function() {
1356 delete taskTracker[uid];
1357 }, 30000);
1358 }
1359 if (PaymentAccepted) {
1360 self.OnAcceptedPlatePaymentSeries(paymentData);
1361 }
1362
1363 });
1364 }, 5000);
1365 copy.taskId = uid;
1366 }
1367 res.json(copy);
1368 });
1369 });
1370 });
1371 });
1372 });
1373 });
1374 });
1375 });
1376 });
1377 },
1378
1379 /**
1380 * Checks status of a payment or a start of plate payment series.
1381 *
1382 * @param {string} $uid An identifier of the task.
1383 * @param {function} $cb A function, which is to be called with a response of Corporate Node or a service 'billon.me'.
1384 */
1385 paymentStatus: function(uid, cb) {
1386 if (typeof uid !== "string") {
1387 return cb(errs.ERR_INVALID_UID);
1388 }
1389
1390 var self = this;
1391 var taskData = taskTracker[uid];
1392 if (typeof taskData === "undefined") {
1393 return cb(errs.ERR_TASK_DOES_NOT_EXIST);
1394 }
1395
1396 Billon.SoapService.onRequestSend = self.OnRequestSend;
1397 Billon.SoapService.call.getTaskStatus({
1398 cNode: taskData.cNode ? taskData.cNode : taskData.WUI,
1399 params: {
1400 taskId: taskData.taskId
1401 }
1402 }, function(taskResponse) {
1403
1404 if (typeof taskResponse.status === "string" && taskResponse.status === "FINISHED_OK") {
1405 var publicCodes = [];
1406 if (taskData && taskData.keyCodes) {
1407 for (var i = 0; i < taskData.keyCodes.length; i++) {
1408 publicCodes.push(taskData.keyCodes[i].Value);
1409 }
1410 }
1411 taskResponse.agent = {
1412 download: taskData.download,
1413 keyCodes: publicCodes
1414 };
1415
1416 if (cb) {
1417 cb(taskResponse);
1418 }
1419 } else if (cb) {
1420 cb(taskResponse);
1421 }
1422 });
1423 }
1424};
1425
1426Billon.Shop = Billon.Payment;
1427billon = Billon;
1428
1429module.exports = Billon;