BxPaymentProviderStripeV3.php 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup Payment Payment
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. require_once('BxPaymentProviderStripeBasic.php');
  12. class BxPaymentProviderStripeV3 extends BxPaymentProviderStripeBasic implements iBxBaseModPaymentProvider
  13. {
  14. protected $_oStripe;
  15. protected $_iAmountPrecision;
  16. function __construct($aConfig)
  17. {
  18. parent::__construct($aConfig);
  19. $this->_aIncludeJs = array(
  20. 'stripe_v3.js'
  21. );
  22. $this->_oStripe = null;
  23. $this->_iAmountPrecision = 2;
  24. }
  25. public function actionGetSessionRecurring()
  26. {
  27. $aClient = $this->_oModule->getProfileInfo();
  28. $aParams = array(
  29. 'seller_id' => (int)bx_get('seller_id'),
  30. 'seller_provider' => bx_process_input(bx_get('seller_provider')),
  31. 'module_id' => (int)bx_get('module_id'),
  32. 'item_id' => (int)bx_get('item_id'),
  33. 'item_count' => (int)bx_get('item_count'),
  34. 'item_addons' => '',
  35. 'redirect' => bx_process_input(bx_get('redirect')),
  36. 'custom' => bx_process_input(bx_get('custom')),
  37. );
  38. if(($mixedItemAddons = bx_get('item_addons')) !== false) {
  39. $mixedItemAddons = bx_process_input($mixedItemAddons);
  40. if(!is_array($mixedItemAddons))
  41. $mixedItemAddons = strpos($mixedItemAddons, ',') !== false ? explode(',', $mixedItemAddons) : [$mixedItemAddons];
  42. $aParams['item_addons'] = $this->_oModule->_oConfig->a2s($mixedItemAddons);
  43. }
  44. $aItems = array($this->_oModule->_oConfig->descriptorA2S(array(
  45. 'seller_id' => $aParams['seller_id'],
  46. 'module_id' => $aParams['module_id'],
  47. 'item_id' => $aParams['item_id'],
  48. 'item_count' => $aParams['item_count'],
  49. 'item_addons' => $aParams['item_addons'],
  50. )));
  51. $oCart = $this->_oModule->getObjectCart();
  52. $aCartInfo = $oCart->getInfo(BX_PAYMENT_TYPE_RECURRING, $aClient['id'], $aParams['seller_id'], $aItems);
  53. if(empty($aCartInfo) || !is_array($aCartInfo))
  54. return echoJson(array('msg' => _t('_bx_payment_err_nothing_selected')));
  55. $aItem = reset($aCartInfo['items']);
  56. $aSessionParams = array(
  57. 'cancel_url' => $aItem['url'],
  58. 'success_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_SUBSCRIBE_JSON'), array_merge($aParams, array(
  59. 'session_id' => '{CHECKOUT_SESSION_ID}'
  60. )), false)
  61. );
  62. $mixedSession = $this->_createSession(BX_PAYMENT_TYPE_RECURRING, $aSessionParams, $aClient, $aCartInfo);
  63. if($mixedSession === false)
  64. return echoJson(array('msg' => _t('_bx_payment_err_cannot_perform')));
  65. $sJsObject = $this->getJsObject(array(
  66. 'iModuleId' => $aParams['module_id'],
  67. 'iSellerId' => $aParams['seller_id'],
  68. 'iItemId' => $aParams['item_id']
  69. ));
  70. return echoJson(array(
  71. 'code' => 0,
  72. 'session_id' => $mixedSession['id'],
  73. 'eval' => $sJsObject . '.onSubscribe(oData);'
  74. ));
  75. }
  76. public function authorizeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
  77. {
  78. $sSessionId = bx_process_input(bx_get('session_id'));
  79. if(empty($aCartInfo['items']) || !is_array($aCartInfo['items']))
  80. return $this->_sLangsPrefix . 'err_empty_items';
  81. $aClient = $this->_oModule->getProfileInfo();
  82. $aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
  83. $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
  84. if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
  85. return $this->_sLangsPrefix . 'err_already_processed';
  86. switch($aPending['type']) {
  87. case BX_PAYMENT_TYPE_SINGLE:
  88. $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_SINGLE, $sSessionId);
  89. if($mixedResult === false)
  90. return $this->_sLangsPrefix . 'err_cannot_perform';
  91. return [
  92. 'code' => BX_PAYMENT_RESULT_SUCCESS,
  93. 'redirect' => $this->getReturnDataUrl($aVendor['id'], array(
  94. 'mode' => $mixedResult['mode'],
  95. 'order_id' => $mixedResult['order_id'],
  96. 'customer_id' => $mixedResult['customer_id'],
  97. 'pending_id' => $aPending['id'],
  98. 'redirect' => $sRedirect
  99. ))
  100. ];
  101. case BX_PAYMENT_TYPE_RECURRING:
  102. return $this->_sLangsPrefix . 'err_not_supported';
  103. }
  104. }
  105. public function captureAuthorizedCheckout($sOrderAuth, $mixedPending, $aInfo)
  106. {
  107. $aPending = is_array($mixedPending) ? $mixedPending : $this->_oModule->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$mixedPending]);
  108. if(empty($aPending) || !is_array($aPending))
  109. return ['code' => 2, 'message' => $this->_sLangsPrefix . 'err_empty_order'];
  110. $bPaid = false;
  111. $sOrder = '';
  112. switch($aPending['type']) {
  113. case BX_PAYMENT_TYPE_SINGLE:
  114. $oPaymentIntent = $this->_createPaymentIntent($sOrderAuth, $aInfo['items_price'], $aInfo['vendor_currency_code']);
  115. if($oPaymentIntent === false)
  116. return ['code' => 3, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
  117. $aPaymentIntent = $oPaymentIntent->jsonSerialize();
  118. if(empty($aPaymentIntent) || !is_array($aPaymentIntent))
  119. return ['code' => 3, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
  120. $bPaid = $aPaymentIntent['status'] == 'succeeded';
  121. $sOrder = $aPaymentIntent['id'];
  122. break;
  123. case BX_PAYMENT_TYPE_RECURRING:
  124. return ['code' => 1, 'message' => $this->_sLangsPrefix . 'err_not_supported'];
  125. }
  126. $aResult = [
  127. 'code' => BX_PAYMENT_RESULT_SUCCESS,
  128. 'message' => $this->_sLangsPrefix . 'strp_msg_charged',
  129. 'pending_id' => $aPending['id'],
  130. 'paid' => $bPaid
  131. ];
  132. //--- Update pending transaction
  133. $this->_oModule->_oDb->updateOrderPending($aResult['pending_id'], [
  134. 'order' => $sOrder,
  135. 'error_code' => $aResult['code'],
  136. 'error_msg' => _t($aResult['message']),
  137. ]);
  138. return $aResult;
  139. }
  140. public function initializeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
  141. {
  142. $sSessionId = bx_process_input(bx_get('session_id'));
  143. if(empty($aCartInfo['items']) || !is_array($aCartInfo['items']))
  144. return $this->_sLangsPrefix . 'err_empty_items';
  145. $aClient = $this->_oModule->getProfileInfo();
  146. $aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
  147. $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
  148. if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
  149. return $this->_sLangsPrefix . 'err_already_processed';
  150. switch($aPending['type']) {
  151. case BX_PAYMENT_TYPE_SINGLE:
  152. $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_SINGLE, $sSessionId);
  153. if($mixedResult === false || $mixedResult['status'] != 'paid')
  154. return $this->_sLangsPrefix . 'err_cannot_perform';
  155. break;
  156. case BX_PAYMENT_TYPE_RECURRING:
  157. $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_RECURRING, $sSessionId);
  158. if($mixedResult === false)
  159. return $this->_sLangsPrefix . 'err_cannot_perform';
  160. break;
  161. }
  162. $aProcessed = $this->_oModule->_oDb->getOrderPending(['type' => 'order', 'order' => $mixedResult['order_id']]);
  163. if(!empty($aProcessed) && is_array($aProcessed) && (int)$aProcessed['processed'] != 0 && $aProcessed['id'] != $iPendingId)
  164. return $this->_sLangsPrefix . 'err_already_processed';
  165. $aData = [
  166. 'mode' => $mixedResult['mode'],
  167. 'order_id' => $mixedResult['order_id'],
  168. 'customer_id' => $mixedResult['customer_id'],
  169. 'pending_id' => $aPending['id'],
  170. 'redirect' => $sRedirect
  171. ];
  172. if(bx_is_api())
  173. return $this->_oModule->serviceFinalizeCheckout($this->_sName, $aVendor['id'], $aData);
  174. header("Location: " . $this->getReturnDataUrl($aVendor['id'], $aData));
  175. exit;
  176. }
  177. public function finalizeCheckout(&$aData)
  178. {
  179. $sMode = bx_process_input($aData['mode']);
  180. $sOrderId = bx_process_input($aData['order_id']);
  181. $sCustomerId = bx_process_input($aData['customer_id']);
  182. $iPendingId = bx_process_input($aData['pending_id'], BX_DATA_INT);
  183. if(empty($iPendingId))
  184. return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_wrong_data');
  185. $sRedirect = bx_process_input($aData['redirect']);
  186. $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
  187. if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
  188. return array('code' => 3, 'message' => $this->_sLangsPrefix . 'err_already_processed');
  189. $aResult = array(
  190. 'code' => BX_PAYMENT_RESULT_SUCCESS,
  191. 'message' => '',
  192. 'pending_id' => $iPendingId,
  193. 'customer_id' => '',
  194. 'subscription_id' => '',
  195. 'client_name' => '',
  196. 'client_email' => '',
  197. 'authorized' => false,
  198. 'paid' => false,
  199. 'trial' => false,
  200. 'redirect' => $sRedirect
  201. );
  202. switch($aPending['type']) {
  203. case BX_PAYMENT_TYPE_SINGLE:
  204. $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_SINGLE, $sCustomerId);
  205. if($oCustomer === false)
  206. return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
  207. $aCustomer = $oCustomer->jsonSerialize();
  208. if(empty($aCustomer) || !is_array($aCustomer))
  209. return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
  210. $sMessage = '';
  211. $bPaid = $bAuthorized = false;
  212. switch($sMode) {
  213. case 'setup':
  214. $oSetupIntent = $this->_retrieveSetupIntent($sOrderId);
  215. if($oSetupIntent === false)
  216. return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
  217. $aSetupIntent = $oSetupIntent->jsonSerialize();
  218. if(empty($aSetupIntent) || !is_array($aSetupIntent))
  219. return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
  220. $sMessage = $this->_sLangsPrefix . 'strp_msg_authorized';
  221. $bAuthorized = $aSetupIntent['status'] == 'succeeded';
  222. break;
  223. case 'payment':
  224. $oPaymentIntent = $this->_retrievePaymentIntent($sOrderId);
  225. if($oPaymentIntent === false)
  226. return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
  227. $aPaymentIntent = $oPaymentIntent->jsonSerialize();
  228. if(empty($aPaymentIntent) || !is_array($aPaymentIntent))
  229. return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
  230. $sMessage = $this->_sLangsPrefix . 'strp_msg_charged';
  231. $bPaid = $aPaymentIntent['status'] == 'succeeded';
  232. break;
  233. }
  234. $aResult = array_merge($aResult, array(
  235. 'message' => $sMessage,
  236. 'client_email' => $aCustomer['email'],
  237. 'authorized' => $bAuthorized,
  238. 'paid' => $bPaid,
  239. ));
  240. break;
  241. case BX_PAYMENT_TYPE_RECURRING:
  242. $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_RECURRING, $sCustomerId);
  243. $oSubscription = $this->_retrieveSubscription($sCustomerId, $sOrderId);
  244. if($oCustomer === false || $oSubscription === false)
  245. return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
  246. $aCustomer = $oCustomer->jsonSerialize();
  247. $aSubscription = $oSubscription->jsonSerialize();
  248. if(empty($aCustomer) || !is_array($aCustomer) || empty($aSubscription) || !is_array($aSubscription))
  249. return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
  250. $aResult = array_merge($aResult, [
  251. 'message' => $this->_sLangsPrefix . 'strp_msg_subscribed',
  252. 'customer_id' => $sCustomerId,
  253. 'subscription_id' => $sOrderId,
  254. 'client_email' => $aCustomer['email'],
  255. 'trial' => $this->isSubscriptionStatus(BX_PAYMENT_SBS_STATUS_TRIAL, $aSubscription)
  256. ]);
  257. $aPaymentPending = $this->_oModule->_oDb->getStrpPaymentPending($sOrderId);
  258. if(empty($aPaymentPending) || !is_array($aPaymentPending))
  259. break;
  260. if($this->_bCheckAmount && ((float)$aPending['amount'] != (float)$aPaymentPending['amount'] || strcasecmp($this->_oModule->_oConfig->getDefaultCurrencyCode(), $aPaymentPending['currency']) !== 0))
  261. break;
  262. $aResult['paid'] = true;
  263. break;
  264. }
  265. //--- Update pending transaction ---//
  266. $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
  267. 'order' => $sOrderId,
  268. 'error_code' => $aResult['code'],
  269. 'error_msg' => _t($aResult['message'])
  270. ));
  271. return $aResult;
  272. }
  273. public function getButtonSingle($iClientId, $iVendorId, $aParams = array())
  274. {
  275. if(!isset($aParams['sAction']))
  276. return '';
  277. return $aParams['sAction'] . parent::getButtonSingle($iClientId, $iVendorId, $aParams);
  278. }
  279. public function overwriteCheckoutParamsSingle($aParams, &$oGrid)
  280. {
  281. $aClient = $this->_oModule->getProfileInfo();
  282. $oCart = $this->_oModule->getObjectCart();
  283. $aCartInfo = $oCart->getInfo(BX_PAYMENT_TYPE_SINGLE, $aClient['id'], $aParams['seller_id'], $aParams['items']);
  284. if(empty($aCartInfo) || !is_array($aCartInfo))
  285. return array('msg' => _t('_bx_payment_err_nothing_selected'));
  286. $aSessionParams = array(
  287. 'cancel_url' => $oCart->serviceGetCartUrl($aParams['seller_id']),
  288. 'success_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_CART_CHECKOUT'), array_merge($aParams, array(
  289. 'session_id' => '{CHECKOUT_SESSION_ID}'
  290. )), false)
  291. );
  292. $mixedSession = $this->_createSession(BX_PAYMENT_TYPE_SINGLE, $aSessionParams, $aClient, $aCartInfo);
  293. if($mixedSession === false)
  294. return array('msg' => _t('_bx_payment_err_cannot_perform'));
  295. return array(
  296. 'eval' => $this->_oModule->_oConfig->getJsObject($this->_sName) . '.onCartCheckout(oData);',
  297. 'session_id' => $mixedSession['id']
  298. );
  299. }
  300. /**
  301. * Note. Isn't used for now in default version.
  302. */
  303. public function createSessionAuthorize($sType, $iClientId, $iSellerId, $sItems, $aSessionParams = [])
  304. {
  305. $aClient = $this->_oModule->getProfileInfo($iClientId);
  306. $oCart = $this->_oModule->getObjectCart();
  307. $aCartInfo = $oCart->getInfo($sType, $aClient['id'], $iSellerId, $sItems);
  308. if(empty($aCartInfo) || !is_array($aCartInfo))
  309. return false;
  310. $aSessionParams = array_merge([
  311. 'cancel_url' => $oCart->serviceGetCartUrl($iSellerId),
  312. 'success_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_AUTHORIZE') . $sType . '/', [
  313. 'provider' => $this->_sName,
  314. 'seller_id' => $iSellerId,
  315. 'items' => $sItems,
  316. 'session_id' => '{CHECKOUT_SESSION_ID}'
  317. ], false)
  318. ], $aSessionParams);
  319. $mixedSession = $this->_createSession('authorize', $aSessionParams, $aClient, $aCartInfo);
  320. if($mixedSession === false)
  321. return false;
  322. return $mixedSession['id'];
  323. }
  324. /*
  325. * https://stripe.com/docs/checkout/embedded/quickstart?client=react&lang=php
  326. */
  327. public function createSessionPaymentEmbedded($sType, $iClientId, $iSellerId, $sItems, $aSessionParams = [])
  328. {
  329. $aClient = $this->_oModule->getProfileInfo($iClientId);
  330. $oCart = $this->_oModule->getObjectCart();
  331. $aCartInfo = $oCart->getInfo($sType, $aClient['id'], $iSellerId, $sItems);
  332. if(empty($aCartInfo) || !is_array($aCartInfo))
  333. return false;
  334. $aSessionParams = array_merge([
  335. 'ui_mode' => 'embedded',
  336. 'return_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_CART_CHECKOUT'), [
  337. 'provider' => $this->_sName,
  338. 'seller_id' => $iSellerId,
  339. 'items' => $sItems,
  340. 'session_id' => '{CHECKOUT_SESSION_ID}'
  341. ], false)
  342. ], $aSessionParams);
  343. if(strpos($aSessionParams['return_url'], 'session_id') === false)
  344. $aSessionParams['return_url'] .= '&session_id={CHECKOUT_SESSION_ID}';
  345. $mixedSession = $this->_createSession($sType, $aSessionParams, $aClient, $aCartInfo);
  346. if($mixedSession === false)
  347. return false;
  348. return $mixedSession['client_secret'];
  349. }
  350. public function createTax($sName, $fPercentage, $bInclusive = false)
  351. {
  352. $oTax = null;
  353. $aTax = [
  354. 'display_name' => $sName,
  355. 'percentage' => $fPercentage,
  356. 'inclusive' => $bInclusive,
  357. ];
  358. /**
  359. * @hooks
  360. * @hookdef hook-bx_payment-stripe_v3_create_tax 'bx_payment', 'stripe_v3_create_tax' - hook to override tax data redurned by payment provider
  361. * - $unit_name - equals `bx_payment`
  362. * - $action - equals `stripe_v3_create_tax`
  363. * - $object_id - pending transaction id
  364. * - $sender_id - not used
  365. * - $extra_params - array of additional params with the following array keys:
  366. * - `tax_object` - [object] by ref, an instance of tax, redurned by payment provider, can be overridden in hook processing
  367. * - `tax_params` - [array] by ref, array with tax parameters, can be overridden in hook processing
  368. * @hook @ref hook-bx_payment-stripe_v3_create_tax
  369. */
  370. bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_tax', 0, false, [
  371. 'tax_object' => &$oTax,
  372. 'tax_params' => &$aTax,
  373. 'tax_params_ref' => &$aTax,
  374. ]);
  375. try {
  376. if(empty($oTax))
  377. $oTax = $this->_getStripe()->taxRates->create($aTax);
  378. }
  379. catch (Exception $oException) {
  380. return $this->_processException('Create Tax Error: ', $oException);
  381. }
  382. $aResult = $oTax->jsonSerialize();
  383. if(empty($aResult) || !is_array($aResult))
  384. return false;
  385. return $aResult['id'];
  386. }
  387. public function retrieveTax($sId)
  388. {
  389. $oTax = null;
  390. /**
  391. * @hooks
  392. * @hookdef hook-bx_payment-stripe_v3_retrieve_tax 'bx_payment', 'stripe_v3_retrieve_tax' - hook to override tax data retrieved from payment provider
  393. * - $unit_name - equals `bx_payment`
  394. * - $action - equals `stripe_v3_retrieve_tax`
  395. * - $object_id - not used
  396. * - $sender_id - not used
  397. * - $extra_params - array of additional params with the following array keys:
  398. * - `tax_id` - [string] by ref, unique tax id, can be overridden in hook processing
  399. * - `tax_object` - [object] by ref, an instance of tax, redurned by payment provider, can be overridden in hook processing
  400. * @hook @ref hook-bx_payment-stripe_v3_retrieve_tax
  401. */
  402. bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_tax', 0, false, [
  403. 'tax_id' => &$sId,
  404. 'tax_object' => &$oTax
  405. ]);
  406. try {
  407. if(empty($oTax))
  408. $oTax = $this->_getStripe()->taxRates->retrieve($sId);
  409. }
  410. catch (Exception $oException) {
  411. return $this->_processException('Retrieve Tax Error: ', $oException);
  412. }
  413. return $oTax;
  414. }
  415. public function getVerificationCodeSession($iVendorId, $iCustomerId, $fAmount, $sCurrency)
  416. {
  417. $sCode = $this->_getVerificationCodeSession($iVendorId, $iCustomerId, $fAmount, $sCurrency);
  418. /**
  419. * @hooks
  420. * @hookdef hook-bx_payment-stripe_v3_get_code_session 'bx_payment', 'stripe_v3_get_code_session' - hook to override session verification code
  421. * - $unit_name - equals `bx_payment`
  422. * - $action - equals `stripe_v3_get_code_session`
  423. * - $object_id - not used
  424. * - $sender_id - not used
  425. * - $extra_params - array of additional params with the following array keys:
  426. * - `provider` - [object] an instance of provider, @see BxBaseModPaymentProvider
  427. * - `vendor_id` - [int] vendor (seller) profile id
  428. * - `customer_id` - [int] customer (buyer) profile id
  429. * - `amount` - [float] session amount
  430. * - `currency` - [string] session currency code
  431. * - `override_result` - [string] by ref, verification code, can be overridden in hook processing
  432. * @hook @ref hook-bx_payment-stripe_v3_get_code_session
  433. */
  434. bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_code_session', 0, false, [
  435. 'provider' => $this,
  436. 'vendor_id' => $iVendorId,
  437. 'customer_id' => $iCustomerId,
  438. 'amount' => $fAmount,
  439. 'currency' => $sCurrency,
  440. 'override_result' => &$sCode
  441. ]);
  442. return $sCode;
  443. }
  444. public function checkVerificationCodeSession($iVendorId, $iCustomerId, $aResult)
  445. {
  446. $bCheckResult = $this->_checkVerificationCodeSession($iVendorId, $iCustomerId, $aResult);
  447. /**
  448. * @hooks
  449. * @hookdef hook-bx_payment-stripe_v3_verify_session 'bx_payment', 'stripe_v3_verify_session' - hook to override checking of session verification code
  450. * - $unit_name - equals `bx_payment`
  451. * - $action - equals `stripe_v3_verify_session`
  452. * - $object_id - not used
  453. * - $sender_id - not used
  454. * - $extra_params - array of additional params with the following array keys:
  455. * - `provider` - [object] an instance of provider, @see BxBaseModPaymentProvider
  456. * - `vendor_id` - [int] vendor (seller) profile id
  457. * - `customer_id` - [int] customer (buyer) profile id
  458. * - `result` - [array] results array received from payment provider
  459. * - `override_result` - [boolean] by ref, is verification passed or not, can be overridden in hook processing
  460. * @hook @ref hook-bx_payment-stripe_v3_verify_session
  461. */
  462. bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_verify_session', 0, false, [
  463. 'provider' => $this,
  464. 'vendor_id' => $iVendorId,
  465. 'customer_id' => $iCustomerId,
  466. 'result' => $aResult,
  467. 'override_result' => &$bCheckResult
  468. ]);
  469. return $bCheckResult;
  470. }
  471. protected function _getStripe()
  472. {
  473. if(empty($this->_oStripe))
  474. $this->_oStripe = new \Stripe\StripeClient($this->_getSecretKey());
  475. return $this->_oStripe;
  476. }
  477. /*
  478. * Related Docs: https://stripe.com/docs/api/customers/retrieve
  479. */
  480. protected function _retrieveCustomer($sType, $sId)
  481. {
  482. $oCustomer = null;
  483. /**
  484. * @hooks
  485. * @hookdef hook-bx_payment-stripe_v3_retrieve_customer 'bx_payment', 'stripe_v3_retrieve_customer' - hook to override customer data retrieved from payment provider
  486. * It's equivalent to @ref hook-bx_payment-stripe_retrieve_customer
  487. * @hook @ref hook-bx_payment-stripe_v3_retrieve_customer
  488. */
  489. bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_customer', 0, false, [
  490. 'type' => $sType,
  491. 'customer_id' => &$sId,
  492. 'customer_object' => &$oCustomer
  493. ]);
  494. try {
  495. if(empty($oCustomer))
  496. $oCustomer = $this->_getStripe()->customers->retrieve($sId);
  497. }
  498. catch (Exception $oException) {
  499. return $this->_processException('Retrieve Customer Error: ', $oException);
  500. }
  501. return $oCustomer;
  502. }
  503. /*
  504. * Related Docs: https://stripe.com/docs/api/checkout/sessions/create
  505. */
  506. protected function _createSession($sType, $aParams, &$aClient, &$aCartInfo)
  507. {
  508. $sMode = '';
  509. $aLineItems = $aMetaItems = [];
  510. $bVerify = true;
  511. switch($sType) {
  512. case 'authorize':
  513. $sMode = 'setup';
  514. $bVerify = false;
  515. foreach($aCartInfo['items'] as $aItem) {
  516. $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aItem['module_id'], $aItem['id']]);
  517. if(!empty($aItem['addons']) && is_array($aItem['addons']))
  518. foreach($aItem['addons'] as $aAddon)
  519. $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aAddon['module_id'], $aAddon['id']]);
  520. }
  521. $aParams['customer_creation'] = 'always';
  522. break;
  523. case BX_PAYMENT_TYPE_SINGLE:
  524. $sMode = 'payment';
  525. foreach($aCartInfo['items'] as $aItem) {
  526. list($_aLineItems, $_aMetaItems) = $this->_getLineItems($sType, $aItem, [
  527. 'vendor_currency_code' => $aCartInfo['vendor_currency_code']
  528. ]);
  529. $aLineItems = array_merge($aLineItems, $_aLineItems);
  530. $aMetaItems = array_merge($aMetaItems, $_aMetaItems);
  531. }
  532. $aParams['customer_creation'] = 'always';
  533. break;
  534. case BX_PAYMENT_TYPE_RECURRING:
  535. $sMode = 'subscription';
  536. $iTrial = 0;
  537. foreach($aCartInfo['items'] as $aItem) {
  538. list($_aLineItems, $_aMetaItems) = $this->_getLineItems($sType, $aItem, [
  539. 'vendor_currency_code' => $aCartInfo['vendor_currency_code']
  540. ]);
  541. $aLineItems = array_merge($aLineItems, $_aLineItems);
  542. $aMetaItems = array_merge($aMetaItems, $_aMetaItems);
  543. if((int)$aItem['trial_recurring'] > 0)
  544. $iTrial = (int)$aItem['trial_recurring'];
  545. }
  546. if($iTrial > 0) {
  547. $bVerify = false;
  548. $aParams['subscription_data'] = [
  549. 'trial_period_days' => $iTrial
  550. ];
  551. }
  552. break;
  553. }
  554. $oSession = null;
  555. $aSession = array_merge([
  556. 'mode' => $sMode,
  557. 'payment_method_types' => ['card'],
  558. 'customer_email' => !empty($aClient['email']) ? $aClient['email'] : ''
  559. ], $aParams);
  560. $bLineItems = !empty($aLineItems);
  561. $aSession['line_items'] = $aLineItems;
  562. $bMetaData = !empty($aMetaItems);
  563. if($bMetaData) {
  564. $aSession['metadata'] = [
  565. 'vendor' => $aCartInfo['vendor_id'],
  566. 'client' => $aClient['id'],
  567. 'type' => $sType,
  568. 'items' => $this->_oModule->_oConfig->descriptorsA2S($aMetaItems)
  569. ];
  570. if($bVerify) {
  571. $fAmount = 100 * round((float)$aCartInfo['items_price'], $this->_iAmountPrecision);
  572. $aSession['metadata']['verification'] = $this->getVerificationCodeSession($aCartInfo['vendor_id'], $aClient['id'], $fAmount, $aCartInfo['vendor_currency_code']);
  573. }
  574. }
  575. /**
  576. * @hooks
  577. * @hookdef hook-bx_payment-stripe_v3_create_session 'bx_payment', 'stripe_v3_create_session' - hook to override session data redurned by payment provider
  578. * - $unit_name - equals `bx_payment`
  579. * - $action - equals `stripe_v3_create_session`
  580. * - $object_id - pending transaction id
  581. * - $sender_id - not used
  582. * - $extra_params - array of additional params with the following array keys:
  583. * - `session_object` - [object] by ref, an instance of session, redurned by payment provider, can be overridden in hook processing
  584. * - `session_params` - [array] by ref, array with session parameters, can be overridden in hook processing
  585. * @hook @ref hook-bx_payment-stripe_v3_create_session
  586. */
  587. bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_session', 0, false, [
  588. 'session_object' => &$oSession,
  589. 'session_params' => &$aSession
  590. ]);
  591. try {
  592. if(empty($oSession))
  593. $oSession = $this->_getStripe()->checkout->sessions->create($aSession);
  594. }
  595. catch (Exception $oException) {
  596. return $this->_processException('Create Session Error: ', $oException);
  597. }
  598. $aResult = $oSession->jsonSerialize();
  599. if(empty($aResult) || !is_array($aResult))
  600. return false;
  601. if($bVerify && !$this->checkVerificationCodeSession($aCartInfo['vendor_id'], $aClient['id'], $aResult))
  602. return false;
  603. return $aResult;
  604. }
  605. protected function _getSession($sType, $sId)
  606. {
  607. $oSession = $this->_retrieveSession($sId);
  608. if($oSession === false)
  609. return false;
  610. $aSession = $oSession->jsonSerialize();
  611. if(empty($aSession) || !is_array($aSession))
  612. return array();
  613. $sMode = 'payment';
  614. if(!empty($aSession['mode']))
  615. $sMode = $aSession['mode'];
  616. $aResult = array(
  617. 'id' => $aSession['id'],
  618. 'mode' => $sMode,
  619. 'order_id' => '',
  620. 'customer_id' => $aSession['customer'],
  621. 'status' => $aSession['payment_status']
  622. );
  623. switch($sType) {
  624. case BX_PAYMENT_TYPE_SINGLE:
  625. $aResult['order_id'] = $aSession[($sMode == 'setup' ? 'setup' : 'payment') . '_intent'];
  626. break;
  627. case BX_PAYMENT_TYPE_RECURRING:
  628. $aResult['order_id'] = $aSession['subscription'];
  629. break;
  630. }
  631. return $aResult;
  632. }
  633. /*
  634. * Related Docs: https://stripe.com/docs/api/checkout/sessions/retrieve
  635. */
  636. protected function _retrieveSession($sId)
  637. {
  638. $oSession = null;
  639. /**
  640. * @hooks
  641. * @hookdef hook-bx_payment-stripe_v3_retrieve_session 'bx_payment', 'stripe_v3_retrieve_session' - hook to override session data retrieved from payment provider
  642. * - $unit_name - equals `bx_payment`
  643. * - $action - equals `stripe_v3_retrieve_session`
  644. * - $object_id - not used
  645. * - $sender_id - not used
  646. * - $extra_params - array of additional params with the following array keys:
  647. * - `session_id` - [string] by ref, unique session id, can be overridden in hook processing
  648. * - `session_object` - [object] by ref, an instance of session, redurned by payment provider, can be overridden in hook processing
  649. * @hook @ref hook-bx_payment-stripe_v3_retrieve_session
  650. */
  651. bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_session', 0, false, [
  652. 'session_id' => &$sId,
  653. 'session_object' => &$oSession
  654. ]);
  655. try {
  656. if(empty($oSession))
  657. $oSession = $this->_getStripe()->checkout->sessions->retrieve($sId);
  658. }
  659. catch (Exception $oException) {
  660. return $this->_processException('Retrieve Session Error: ', $oException);
  661. }
  662. return $oSession;
  663. }
  664. /*
  665. * Related Docs: https://stripe.com/docs/api/setup_intents/retrieve
  666. */
  667. protected function _retrieveSetupIntent($sId)
  668. {
  669. $oSetupIntent = null;
  670. /**
  671. * @hooks
  672. * @hookdef hook-bx_payment-stripe_v3_retrieve_setup_intent 'bx_payment', 'stripe_v3_retrieve_setup_intent' - hook to override SetupIntent data retrieved from payment provider
  673. * - $unit_name - equals `bx_payment`
  674. * - $action - equals `stripe_v3_retrieve_setup_intent`
  675. * - $object_id - not used
  676. * - $sender_id - not used
  677. * - $extra_params - array of additional params with the following array keys:
  678. * - `setup_intent_id` - [string] by ref, unique SetupIntent id, can be overridden in hook processing
  679. * - `setup_intent_object` - [object] by ref, an instance of SetupIntent, redurned by payment provider, can be overridden in hook processing
  680. * @hook @ref hook-bx_payment-stripe_v3_retrieve_setup_intent
  681. */
  682. bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_setup_intent', 0, false, [
  683. 'setup_intent_id' => &$sId,
  684. 'setup_intent_object' => &$oSetupIntent
  685. ]);
  686. try {
  687. if(empty($oSetupIntent))
  688. $oSetupIntent = $this->_getStripe()->setupIntents->retrieve($sId);
  689. }
  690. catch (Exception $oException) {
  691. return $this->_processException('Retrieve Setup Intent Error: ', $oException);
  692. }
  693. return $oSetupIntent;
  694. }
  695. /*
  696. * Related Docs: https://stripe.com/docs/api/payment_intents/create
  697. */
  698. protected function _createPaymentIntent($sSetupIntentId, $fAmount, $sCurrency, $bConfirm = true)
  699. {
  700. $oPaymentIntent = null;
  701. /**
  702. * @hooks
  703. * @hookdef hook-bx_payment-stripe_v3_create_payment_intent 'bx_payment', 'stripe_v3_create_payment_intent' - hook to override PaymentIntent data redurned by payment provider
  704. * - $unit_name - equals `bx_payment`
  705. * - $action - equals `stripe_v3_create_payment_intent`
  706. * - $object_id - not used
  707. * - $sender_id - not used
  708. * - $extra_params - array of additional params with the following array keys:
  709. * - `setup_intent_id` - [string] by ref, unique SetupIntent id, can be overridden in hook processing
  710. * - `payment_intent_object` - [object] by ref, an instance of PaymentIntent, redurned by payment provider, can be overridden in hook processing
  711. * @hook @ref hook-bx_payment-stripe_v3_create_payment_intent
  712. */
  713. bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_payment_intent', 0, false, [
  714. 'setup_intent_id' => &$sSetupIntentId,
  715. 'payment_intent_object' => &$oPaymentIntent
  716. ]);
  717. try {
  718. if(empty($oPaymentIntent)) {
  719. $oSetupIntent = $this->_retrieveSetupIntent($sSetupIntentId);
  720. if($oSetupIntent === false)
  721. return false;
  722. $aSetupIntent = $oSetupIntent->jsonSerialize();
  723. if(empty($aSetupIntent) || !is_array($aSetupIntent))
  724. return false;
  725. $oPaymentIntent = $this->_getStripe()->paymentIntents->create([
  726. 'amount' => 100 * round($fAmount, $this->_iAmountPrecision),
  727. 'currency' => strtolower($sCurrency),
  728. 'customer' => $aSetupIntent['customer'],
  729. 'payment_method' => $aSetupIntent['payment_method'],
  730. 'confirm' => $bConfirm
  731. ]);
  732. }
  733. }
  734. catch (Exception $oException) {
  735. return $this->_processException('Retrieve Payment Intent Error: ', $oException);
  736. }
  737. return $oPaymentIntent;
  738. }
  739. /*
  740. * Related Docs: https://stripe.com/docs/api/payment_intents/retrieve
  741. */
  742. protected function _retrievePaymentIntent($sId)
  743. {
  744. $oPaymentIntent = null;
  745. /**
  746. * @hooks
  747. * @hookdef hook-bx_payment-stripe_v3_retrieve_payment_intent 'bx_payment', 'stripe_v3_retrieve_payment_intent' - hook to override PaymentIntent data retrieved from payment provider
  748. * - $unit_name - equals `bx_payment`
  749. * - $action - equals `stripe_v3_retrieve_payment_intent`
  750. * - $object_id - not used
  751. * - $sender_id - not used
  752. * - $extra_params - array of additional params with the following array keys:
  753. * - `payment_intent_id` - [string] by ref, unique PaymentIntent id, can be overridden in hook processing
  754. * - `payment_intent_object` - [object] by ref, an instance of PaymentIntent, redurned by payment provider, can be overridden in hook processing
  755. * @hook @ref hook-bx_payment-stripe_v3_retrieve_payment_intent
  756. */
  757. bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_payment_intent', 0, false, [
  758. 'payment_intent_id' => &$sId,
  759. 'payment_intent_object' => &$oPaymentIntent
  760. ]);
  761. try {
  762. if(empty($oPaymentIntent))
  763. $oPaymentIntent = $this->_getStripe()->paymentIntents->retrieve($sId);
  764. }
  765. catch (Exception $oException) {
  766. return $this->_processException('Retrieve Payment Intent Error: ', $oException);
  767. }
  768. return $oPaymentIntent;
  769. }
  770. /*
  771. * Related Docs: https://stripe.com/docs/api/subscriptions/retrieve
  772. */
  773. protected function _retrieveSubscription($sCustomerId, $sSubscriptionId)
  774. {
  775. $oSubscription = null;
  776. /**
  777. * @hooks
  778. * @hookdef hook-bx_payment-stripe_v3_retrieve_subscription 'bx_payment', 'stripe_v3_retrieve_subscription' - hook to override subscription data retrieved from payment provider
  779. * - $unit_name - equals `bx_payment`
  780. * - $action - equals `stripe_v3_retrieve_subscription`
  781. * - $object_id - not used
  782. * - $sender_id - not used
  783. * - $extra_params - array of additional params with the following array keys:
  784. * - `subscription_id` - [string] by ref, unique subscription id, can be overridden in hook processing
  785. * - `subscription_object` - [object] by ref, an instance of subscription, redurned by payment provider, can be overridden in hook processing
  786. * @hook @ref hook-bx_payment-stripe_v3_retrieve_subscription
  787. */
  788. bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_subscription', 0, false, [
  789. 'subscription_id' => &$sSubscriptionId,
  790. 'subscription_object' => &$oSubscription
  791. ]);
  792. try {
  793. if(empty($oSubscription))
  794. $oSubscription = $this->_getStripe()->subscriptions->retrieve($sSubscriptionId);
  795. }
  796. catch (Exception $oException) {
  797. return $this->_processException('Retrieve Subscription Error: ', $oException);
  798. }
  799. return $oSubscription;
  800. }
  801. /*
  802. * Related Docs: https://stripe.com/docs/api/tokens/create_card
  803. */
  804. protected function _createToken($aCard)
  805. {
  806. try {
  807. $oToken = $this->_getStripe()->tokens->create(['card' => $aCard]);
  808. }
  809. catch (Stripe\Error\Base $oException) {
  810. return $this->_processException('Create Token Error: ', $oException);
  811. }
  812. return $oToken->jsonSerialize();
  813. }
  814. /*
  815. * Related Docs: https://stripe.com/docs/api/cards/create
  816. */
  817. protected function _createCard($sType, $sCustomerId, $sToken)
  818. {
  819. try {
  820. $oCard = $this->_getStripe()->customers->createSource($sCustomerId, [
  821. 'source' => $sToken
  822. ]);
  823. }
  824. catch (Stripe\Error\Base $oException) {
  825. return $this->_processException('Create Card Error: ', $oException);
  826. }
  827. return $oCard->jsonSerialize();
  828. }
  829. protected function _retrieveCard($sCustomerId, $sCardId = '')
  830. {
  831. try {
  832. $oCustomer = $this->_getStripe()->customers->retrieve($sCustomerId);
  833. if(empty($sCardId))
  834. $sCardId = $oCustomer->default_source;
  835. if(empty($sCardId))
  836. return false;
  837. $oCard = $this->_getStripe()->customers->retrieveSource($sCustomerId, $sCardId);
  838. }
  839. catch (Exception $oException) {
  840. return $this->_processException('Retrieve Card Error: ', $oException);
  841. }
  842. return $oCard;
  843. }
  844. /*
  845. * Related Docs: https://stripe.com/docs/api/payment_methods/retrieve
  846. */
  847. protected function _retrievePaymentMethod($sPaymentMethodId)
  848. {
  849. try {
  850. $oPaymentMethod = $this->_getStripe()->paymentMethods->retrieve($sPaymentMethodId);
  851. }
  852. catch (Exception $oException) {
  853. return $this->_processException('Retrieve Payment Method Error: ', $oException);
  854. }
  855. return $oPaymentMethod;
  856. }
  857. protected function _getButton($sType, $iClientId, $iVendorId, $aParams = array())
  858. {
  859. list($sJsCode, $sJsMethod) = $this->_getButtonJs($sType, $iClientId, $iVendorId, $aParams);
  860. if($sType == BX_PAYMENT_TYPE_SINGLE)
  861. return $sJsCode;
  862. return parent::_getButton($sType, $iClientId, $iVendorId);
  863. }
  864. protected function _getButtonJs($sType, $iClientId, $iVendorId, $aParams = array())
  865. {
  866. $sClientEmail = '';
  867. if(!empty($iClientId) && ($oClient = BxDolProfile::getInstance($iClientId)) !== false)
  868. $sClientEmail = $oClient->getAccountObject()->getEmail();
  869. $sPublicKey = '';
  870. $sConnectedAccountId = '';
  871. /**
  872. * @hooks
  873. * @hookdef hook-bx_payment-stripe_v3_get_button 'bx_payment', 'stripe_v3_get_button' - hook to override checkout/subscibe button
  874. * - $unit_name - equals `bx_payment`
  875. * - $action - equals `stripe_v3_get_button`
  876. * - $object_id - not used
  877. * - $sender_id - client (buyer) profile id
  878. * - $extra_params - array of additional params with the following array keys:
  879. * - `type` - [string] by ref, payment type ('single' or 'recurring'), can be overridden in hook processing
  880. * - `public_key` - [string] by ref, public key from Stripe account, can be overridden in hook processing
  881. * @hook @ref hook-bx_payment-stripe_v3_get_button
  882. */
  883. bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_button', 0, $iClientId, [
  884. 'client_id' => $iClientId,
  885. 'vendor_id' => $iVendorId,
  886. 'type' => &$sType,
  887. 'public_key' => &$sPublicKey,
  888. 'connected_account_id' => &$sConnectedAccountId,
  889. 'type_ref' => &$sType,
  890. 'public_key_ref' => &$sPublicKey,
  891. 'connected_account_id_ref' => &$sConnectedAccountId,
  892. ]);
  893. $sJsMethod = '';
  894. $sJsObject = $this->getJsObject($aParams);
  895. switch($sType) {
  896. case BX_PAYMENT_TYPE_SINGLE:
  897. $sJsMethod = 'void(0)';
  898. break;
  899. case BX_PAYMENT_TYPE_RECURRING:
  900. $sJsMethod = $sJsObject . '.subscribe(this)';
  901. break;
  902. }
  903. return [$this->_oModule->_oTemplate->getJsCode($this->_sName, array_merge([
  904. 'js_object' => $sJsObject,
  905. 'sProvider' => $this->_sName,
  906. 'sPublicKey' => !empty($sPublicKey) ? $sPublicKey : $this->_getPublicKey(),
  907. 'sConnectedAccountId' => $sConnectedAccountId,
  908. 'sVendorName' => '',
  909. 'sVendorCurrency' => '',
  910. 'sVendorIcon' => '',
  911. 'sClientEmail' => $sClientEmail,
  912. ], $aParams)), $sJsMethod];
  913. }
  914. protected function _getVerificationCodeSession($iVendorId, $iCustomerId, $fAmount, $sCurrency)
  915. {
  916. return md5(implode('#-#', array(
  917. (int)$iVendorId,
  918. (int)$iCustomerId,
  919. (float)$fAmount,
  920. strtoupper($sCurrency)
  921. )));
  922. }
  923. protected function _checkVerificationCodeSession($iVendorId, $iCustomerId, $aResult)
  924. {
  925. return !empty($aResult['metadata']['verification']) && $aResult['metadata']['verification'] == $this->getVerificationCodeSession($iVendorId, $iCustomerId, $aResult['amount_total'], $aResult['currency']);
  926. }
  927. protected function _getLineItems($sType, $aItem, $aParams = [])
  928. {
  929. $aLineItems = $aMetaItems = [];
  930. $bRecurring = $sType == BX_PAYMENT_TYPE_RECURRING;
  931. $sCurrency = ($sKey = 'vendor_currency_code') && !empty($aParams[$sKey]) ? $aParams[$sKey] : $this->_oModule->_oConfig->getDefaultCurrencyCode();
  932. $aProductData = [
  933. 'name' => $aItem['title']
  934. ];
  935. if(!empty($aItem['description']))
  936. $aProductData['description'] = strmaxtextlen(strip_tags($aItem['description']), 60, '...');
  937. $aLineItem = [
  938. 'price_data' => [
  939. 'currency' => $sCurrency,
  940. 'product_data' => $aProductData,
  941. 'unit_amount' => 100 * $this->_oModule->_oConfig->getPrice($sType, $aItem, $this->_iAmountPrecision),
  942. ],
  943. 'quantity' => $aItem['quantity'],
  944. ];
  945. if($bRecurring && ($mixedPeriod = $this->_oModule->_oConfig->getPeriod($sType, $aItem)) !== false) {
  946. list($iPeriod, $sPeriodUnit) = $mixedPeriod;
  947. $aLineItem['price_data']['recurring'] = [
  948. 'interval' => $sPeriodUnit,
  949. 'interval_count' => $iPeriod
  950. ];
  951. }
  952. $aLineItems[] = $aLineItem;
  953. $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aItem['module_id'], $aItem['id']]);
  954. if(!empty($aItem['addons']) && is_array($aItem['addons']))
  955. foreach($aItem['addons'] as $aAddon) {
  956. $aAddonData = [
  957. 'name' => $aAddon['title']
  958. ];
  959. if(!empty($aAddon['description']))
  960. $aAddonData['description'] = strmaxtextlen(strip_tags($aAddon['description']), 60, '...');
  961. $aLineItem = [
  962. 'price_data' => [
  963. 'currency' => $sCurrency,
  964. 'product_data' => $aAddonData,
  965. 'unit_amount' => 100 * $this->_oModule->_oConfig->getPrice($sType, $aAddon, $this->_iAmountPrecision),
  966. ],
  967. 'quantity' => $aAddon['quantity'],
  968. ];
  969. if($bRecurring && ($mixedPeriod = $this->_oModule->_oConfig->getPeriod($sType, $aAddon)) !== false) {
  970. list($iPeriod, $sPeriodUnit) = $mixedPeriod;
  971. $aLineItem['price_data']['recurring'] = [
  972. 'interval' => $sPeriodUnit,
  973. 'interval_count' => $iPeriod
  974. ];
  975. }
  976. $aLineItems[] = $aLineItem;
  977. $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aAddon['module_id'], $aAddon['id']]);
  978. }
  979. return [$aLineItems, $aMetaItems];
  980. }
  981. protected function _processException($sMessage, &$oException)
  982. {
  983. if(method_exists($oException, 'getError') && ($oError = $oException->getError())) {
  984. $sError = $oError->message;
  985. $aError = $oError->toArray();
  986. }
  987. else {
  988. $sError = $oException->getMessage();
  989. $aError = array();
  990. }
  991. $this->log($sMessage . $sError, '', BX_LOG_ERR);
  992. if(!empty($aError))
  993. $this->log($aError, '', BX_LOG_ERR);
  994. return false;
  995. }
  996. }
  997. /** @} */