BxCreditsModule.php 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191
  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 Credits Credits
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. define('BX_CREDITS_TRANSFER_TYPE_PURCHASE', 'purchase');
  12. define('BX_CREDITS_TRANSFER_TYPE_CHECKOUT', 'checkout');
  13. define('BX_CREDITS_TRANSFER_TYPE_CANCELLATION', 'cancellation');
  14. define('BX_CREDITS_TRANSFER_TYPE_GRANT', 'grant');
  15. define('BX_CREDITS_TRANSFER_TYPE_SEND', 'send');
  16. define('BX_CREDITS_TRANSFER_TYPE_WITHDRAW', 'withdraw');
  17. define('BX_CREDITS_TRANSFER_TYPE_SERVICE', 'service');
  18. define('BX_CREDITS_DIRECTION_IN', 'in');
  19. define('BX_CREDITS_DIRECTION_OUT', 'out');
  20. define('BX_CREDITS_ORDER_TYPE_SINGLE', 'single'); //--- one-time payment
  21. define('BX_CREDITS_ORDER_TYPE_RECURRING', 'recurring'); //--- recurring payment (subscription)
  22. class BxCreditsModule extends BxBaseModGeneralModule
  23. {
  24. function __construct(&$aModule)
  25. {
  26. parent::__construct($aModule);
  27. }
  28. public function actionGetProfiles()
  29. {
  30. $sTerm = bx_get('term');
  31. $a = BxDolService::call('system', 'profiles_search', array($sTerm), 'TemplServiceProfiles');
  32. echoJson($a);
  33. }
  34. public function actionCheckBundleName()
  35. {
  36. $CNF = &$this->_oConfig->CNF;
  37. $sName = bx_process_input(bx_get('name'));
  38. if(empty($sName))
  39. return echoJson(array());
  40. $sResult = '';
  41. $iId = (int)bx_get('id');
  42. if(!empty($iId)) {
  43. $aBundle = $this->_oDb->getBundle(array('type' => 'id', 'id' => $iId));
  44. if(strcmp($sName, $aBundle[$CNF['FIELD_NAME']]) == 0)
  45. $sResult = $sName;
  46. }
  47. echoJson(array(
  48. 'name' => !empty($sResult) ? $sResult : $this->_oConfig->getBundleName($sName)
  49. ));
  50. }
  51. public function actionCheckout()
  52. {
  53. $iBuyerId = bx_get_logged_profile_id();
  54. if(!$iBuyerId)
  55. return echoJson(['code' => 1, 'msg' => _t('_bx_credits_err_unknown_buyer')]);
  56. $sErrIncorrectData = _t('_bx_credits_err_incorrect_data');
  57. $aData = $this->_oConfig->getCheckoutData();
  58. if(empty($aData) || !is_array($aData))
  59. return echoJson(['code' => 2, 'msg' => $sErrIncorrectData]);
  60. $fConversion = $this->_oConfig->getConversionRateUse();
  61. $iPrecision = $this->_oConfig->getPrecision();
  62. $iSellerId = (int)$aData['seller'];
  63. $fAmount = (float)$aData['amount'];
  64. $aCustomData = $this->_oConfig->deconstructCheckoutCustomData($aData['custom']);
  65. $oPayments = BxDolPayments::getInstance();
  66. $aPpOrders = $oPayments->getPendingOrdersInfo(['id' => (int)$aCustomData[1]]);
  67. if(!empty($aPpOrders) && is_array($aPpOrders)) {
  68. $aPpOrder = reset($aPpOrders);
  69. if(empty($aPpOrder) || !is_array($aPpOrder) || (int)$aPpOrder['seller_id'] != $iSellerId)
  70. return echoJson(['code' => 3, 'msg' => $sErrIncorrectData]);
  71. $fAmountM = (float)$aPpOrder['amount'];
  72. $sCurrencyDefault = $oPayments->getCurrencyCode();
  73. if(strcmp($aPpOrder['currency'], $sCurrencyDefault) != 0)
  74. $fAmountM = $oPayments->convert ($fAmountM, $aPpOrder['currency'], $sCurrencyDefault);
  75. if($this->_oConfig->convertM2C($fAmountM, $fConversion, $iPrecision) != $fAmount)
  76. return echoJson(['code' => 3, 'msg' => $sErrIncorrectData]);
  77. }
  78. $fBalance = (float)$this->_oDb->getProfile(['type' => 'balance', 'id' => $iBuyerId]);
  79. if($fAmount > $fBalance)
  80. return echoJson(['code' => 4, 'msg' => _t('_bx_credits_err_low_balance')]);
  81. $sOrder = $this->_oConfig->getOrder();
  82. $sInfo = '_bx_credits_txt_history_info_checkout';
  83. $sData = serialize([
  84. 'conversion' => $fConversion,
  85. 'precision' => $iPrecision
  86. ]);
  87. $this->updateProfileBalance($iBuyerId, $iSellerId, -$fAmount, BX_CREDITS_TRANSFER_TYPE_CHECKOUT, $sOrder, $sInfo, $sData);
  88. $this->updateProfileBalance($iSellerId, $iBuyerId, $fAmount, BX_CREDITS_TRANSFER_TYPE_CHECKOUT, $sOrder, $sInfo, $sData);
  89. bx_alert($this->getName(), 'checkout', 0, false, [
  90. 'seller' => $iSellerId,
  91. 'buyer' => $iBuyerId,
  92. 'amount' => $fAmount,
  93. 'order' => $sOrder
  94. ]);
  95. return echoJson([
  96. 'code' => 0,
  97. 'redirect' => bx_append_url_params($aData['return_data_url'], ['o' => $sOrder, 'c' => $aData['custom']])
  98. ]);
  99. }
  100. public function actionSubscribe()
  101. {
  102. $iBuyerId = bx_get_logged_profile_id();
  103. if(!$iBuyerId)
  104. return echoJson(array('code' => 1, 'msg' => _t('_bx_credits_err_unknown_buyer')));
  105. $aData = $this->_oConfig->getCheckoutData();
  106. if(empty($aData) || !is_array($aData))
  107. return echoJson(array('code' => 2, 'msg' => _t('_bx_credits_err_incorrect_data')));
  108. $iSellerId = (int)$aData['seller'];
  109. $fAmount = (float)$aData['amount'];
  110. $fBalance = (float)$this->_oDb->getProfile(array('type' => 'balance', 'id' => $iBuyerId));
  111. if($fAmount > $fBalance)
  112. return echoJson(array('code' => 3, 'msg' => _t('_bx_credits_err_low_balance')));
  113. $sUnique = $this->_oConfig->getOrder(9);
  114. $sCustomer = 'bx_cus_' . $sUnique;
  115. $sSubscription = 'bx_sub_' . $sUnique;
  116. bx_alert($this->getName(), 'subscribe', 0, false, array(
  117. 'seller' => $iSellerId,
  118. 'buyer' => $iBuyerId,
  119. 'amount' => $fAmount,
  120. 'trial' => $aData['trial'],
  121. 'customer' => $sCustomer,
  122. 'subscription' => $sSubscription
  123. ));
  124. return echoJson(array(
  125. 'code' => 0,
  126. 'redirect' => bx_append_url_params($aData['return_data_url'], array(
  127. 'cs' => $sCustomer,
  128. 'sb' => $sSubscription,
  129. 'tr' => $aData['trial'],
  130. 'c' => $aData['custom']
  131. ))
  132. ));
  133. }
  134. public function serviceGetSafeServices()
  135. {
  136. return array (
  137. 'GetBlockBundles' => '',
  138. 'GetBlockOrders' => '',
  139. 'GetBlockHistory' => '',
  140. );
  141. }
  142. public function serviceGetCheckoutUrl()
  143. {
  144. return $this->_oConfig->getCheckoutUrl();
  145. }
  146. public function serviceConvertMoneyToCredits($fMoney, $fRate = false, $iPrecision = false)
  147. {
  148. return $this->_oConfig->convertM2C($fMoney, $fRate, $iPrecision);
  149. }
  150. public function serviceConvertCreditsToMoney($fCredits, $fRate = false, $iPrecision = false)
  151. {
  152. return $this->_oConfig->convertC2M($fCredits, $fRate, $iPrecision);
  153. }
  154. public function serviceValidateCheckout($iSeller, $iBuyer, $fAmount, $sOrder)
  155. {
  156. $fAmount = (float)$fAmount;
  157. $aOut = $this->_oDb->getHistory(array('type' => 'row_by', 'by' => array('first_pid' => $iBuyer, 'direction' => BX_CREDITS_DIRECTION_OUT, 'order' => $sOrder)));
  158. if(empty($aOut) || !is_array($aOut) || (int)$aOut['second_pid'] != (int)$iSeller)
  159. return false;
  160. $aDataOut = unserialize($aOut['data']);
  161. if($this->_oConfig->convertM2C($fAmount, $aDataOut['conversion'], $aDataOut['precision']) != (float)$aOut['amount'])
  162. return false;
  163. $aIn = $this->_oDb->getHistory(array('type' => 'row_by', 'by' => array('first_pid' => $iSeller, 'direction' => BX_CREDITS_DIRECTION_IN, 'order' => $sOrder)));
  164. if(empty($aIn) || !is_array($aIn) || (int)$aIn['second_pid'] != (int)$iBuyer)
  165. return false;
  166. $aDataIn = unserialize($aIn['data']);
  167. if($this->_oConfig->convertM2C($fAmount, $aDataIn['conversion'], $aDataIn['precision']) != (float)$aIn['amount'])
  168. return false;
  169. return true;
  170. }
  171. public function serviceGetBlockCheckout()
  172. {
  173. $oBuyer = BxDolProfile::getInstance();
  174. if(!$oBuyer)
  175. return MsgBox(_t('_bx_credits_err_unknown_buyer'));
  176. $iSeller = (int)bx_get('seller');
  177. $oSeller = BxDolProfile::getInstance($iSeller);
  178. if(!$oSeller)
  179. return MsgBox(_t('_bx_credits_err_unknown_seller'));
  180. $fAmountM = $fAmountMInDef = (float)bx_get('amount');
  181. $oPayments = BxDolPayments::getInstance();
  182. $sCurrency = bx_process_input(bx_get('currency_code'));
  183. $sCurrencyDefault = $oPayments->getCurrencyCode();
  184. if(strcmp($sCurrency, $sCurrencyDefault) != 0)
  185. $fAmountMInDef = $oPayments->convert($fAmountM, $sCurrency, $sCurrencyDefault);
  186. $fAmountC = $this->_oConfig->convertM2C($fAmountMInDef);
  187. $aData = [
  188. 'seller' => $iSeller,
  189. 'currency' => [
  190. 'code' => $sCurrency,
  191. 'sign' => bx_process_input(bx_get('currency_sign')),
  192. ],
  193. 'amountm' => $fAmountM,
  194. 'amountc' => $fAmountC
  195. ];
  196. $iItemsCount = (int)bx_get('items_count');
  197. for($i = 0; $i < $iItemsCount; $i++) {
  198. $aData['items'][] = [
  199. 'title' => bx_process_input(bx_get('item_title_' . $i)),
  200. 'quantity' => (int)bx_get('item_quantity_' . $i)
  201. ];
  202. }
  203. $this->_oConfig->setCheckoutData([
  204. 'seller' => $iSeller,
  205. 'amount' => $fAmountC,
  206. 'custom' => bx_process_input(bx_get('custom')),
  207. 'return_data_url' => bx_process_input(bx_get('return_data_url')),
  208. ]);
  209. return $this->_oTemplate->getBlockCheckout($oBuyer, $oSeller, $aData);
  210. }
  211. public function serviceGetPopupSubscribe($aData)
  212. {
  213. $oBuyer = BxDolProfile::getInstance();
  214. if(!$oBuyer)
  215. return ['msg' => _t('_bx_credits_err_unknown_buyer')];
  216. $iSeller = (int)$aData['seller'];
  217. $oSeller = BxDolProfile::getInstance($iSeller);
  218. if(!$oSeller)
  219. return ['msg' => _t('_bx_credits_err_unknown_seller')];
  220. $fAmountM = $fAmountMInDef = (float)$aData['amount'];
  221. $oPayments = BxDolPayments::getInstance();
  222. $sCurrency = $aData['currency_code'];
  223. $sCurrencyDefault = $oPayments->getCurrencyCode();
  224. if(strcmp($sCurrency, $sCurrencyDefault) != 0)
  225. $fAmountMInDef = $oPayments->convert($fAmountM, $sCurrency, $sCurrencyDefault);
  226. $fAmountC = $this->_oConfig->convertM2C($fAmountMInDef);
  227. $aData = array_merge($aData, [
  228. 'currency' => [
  229. 'code' => $sCurrency,
  230. 'sign' => $aData['currency_sign'],
  231. ],
  232. 'amountm' => $fAmountM,
  233. 'amountc' => $fAmountC
  234. ]);
  235. $this->_oConfig->setCheckoutData([
  236. 'seller' => $iSeller,
  237. 'amount' => $fAmountC,
  238. 'trial' => (int)$aData['trial'] > 0,
  239. 'custom' => bx_process_input($aData['custom']),
  240. 'return_data_url' => bx_process_input($aData['return_data_url']),
  241. ]);
  242. return $this->_oTemplate->getPopupSubscribe($oBuyer, $oSeller, $aData);
  243. }
  244. public function serviceGetMenuItemAddonAmount()
  245. {
  246. $iProfileId = bx_get_logged_profile_id();
  247. if(!$iProfileId)
  248. return '';
  249. return array(
  250. 'unit' => $this->_oTemplate->getUnit(),
  251. 'value' => $this->convertC2S($this->_oDb->getProfile(array('type' => 'balance', 'id' => $iProfileId)), false)
  252. );
  253. }
  254. /**
  255. * @page service Service Calls
  256. * @section bx_credits Credits
  257. * @subsection bx_credits-page_blocks Page Blocks
  258. * @subsubsection bx_credits-get_block_bundles get_block_bundles
  259. *
  260. * @code bx_srv('bx_credits', 'get_block_bundles'); @endcode
  261. *
  262. * Get page block with bundles
  263. *
  264. * @see BxCreditsModule::serviceGetBlockBundles
  265. */
  266. /**
  267. * @ref bx_credits-get_block_bundles "get_block_bundles"
  268. */
  269. public function serviceGetBlockBundles()
  270. {
  271. return $this->_oTemplate->getBlockBundles();
  272. }
  273. /**
  274. * @page service Service Calls
  275. * @section bx_credits Credits
  276. * @subsection bx_credits-page_blocks Page Blocks
  277. * @subsubsection bx_credits-get_block_orders_note get_block_orders_note
  278. *
  279. * @code bx_srv('bx_credits', 'get_block_orders_note', [...]); @endcode
  280. *
  281. * Get page block with a notice for orders usage.
  282. *
  283. * @return HTML string with block content to display on the site.
  284. *
  285. * @see BxCreditsModule::serviceBlockLicensesNote
  286. */
  287. /**
  288. * @ref bx_credits-get_block_orders_note "get_block_orders_note"
  289. */
  290. public function serviceGetBlockOrdersNote()
  291. {
  292. return MsgBox(_t('_bx_credits_page_block_content_orders_common_note'));
  293. }
  294. /**
  295. * @page service Service Calls
  296. * @section bx_credits Credits
  297. * @subsection bx_credits-page_blocks Page Blocks
  298. * @subsubsection bx_credits-get_block_orders get_block_orders
  299. *
  300. * @code bx_srv('bx_credits', 'get_block_orders', [...]); @endcode
  301. *
  302. * Get page block with a list of orders purchased by currently logged member.
  303. *
  304. * @return an array describing a block to display on the site or false if there is no enough input data. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
  305. *
  306. * @see BxCreditsModule::serviceGetBlockOrders
  307. */
  308. /**
  309. * @ref bx_credits-get_block_orders "get_block_orders"
  310. */
  311. public function serviceGetBlockOrders($sType = 'common')
  312. {
  313. return $this->_getBlockOrders($sType);
  314. }
  315. /**
  316. * @page service Service Calls
  317. * @section bx_credits Credits
  318. * @subsection bx_credits-page_blocks Page Blocks
  319. * @subsubsection bx_credits-get_block_history get_block_history
  320. *
  321. * @code bx_srv('bx_credits', 'get_block_history', [...]); @endcode
  322. *
  323. * Get page block with a list of all changes with credits.
  324. *
  325. * @return an array describing a block to display on the site or false if there is no enough input data. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
  326. *
  327. * @see BxCreditsModule::serviceGetBlockHistory
  328. */
  329. /**
  330. * @ref bx_credits-get_block_history "get_block_history"
  331. */
  332. public function serviceGetBlockHistory($sType = 'common')
  333. {
  334. return $this->_getBlockHistory($sType);
  335. }
  336. /**
  337. * @page service Service Calls
  338. * @section bx_credits Credits
  339. * @subsection bx_credits-page_blocks Page Blocks
  340. * @subsubsection bx_credits-get_block_profiles get_block_profiles
  341. *
  342. * @code bx_srv('bx_credits', 'get_block_profiles', [...]); @endcode
  343. *
  344. * Get page block with a list of profiles for managing their parameters.
  345. *
  346. * @return an array describing a block to display on the site or false if there is no enough input data. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
  347. *
  348. * @see BxCreditsModule::serviceGetBlockProfiles
  349. */
  350. /**
  351. * @ref bx_credits-get_block_profiles "get_block_profiles"
  352. */
  353. public function serviceGetBlockProfiles($sType = 'common')
  354. {
  355. return $this->_getBlockProfiles($sType);
  356. }
  357. /**
  358. * @page service Service Calls
  359. * @section bx_credits Credits
  360. * @subsection bx_credits-payments Payments
  361. * @subsubsection bx_credits-get_payment_data get_payment_data
  362. *
  363. * @code bx_srv('bx_credits', 'get_payment_data', [...]); @endcode
  364. *
  365. * Get an array with module's description. Is needed for payments processing module.
  366. *
  367. * @return an array with module's description.
  368. *
  369. * @see BxCreditsModule::serviceGetPaymentData
  370. */
  371. /**
  372. * @ref bx_credits-get_payment_data "get_payment_data"
  373. */
  374. public function serviceGetPaymentData()
  375. {
  376. $CNF = &$this->_oConfig->CNF;
  377. $oPermalink = BxDolPermalinks::getInstance();
  378. $aResult = $this->_aModule;
  379. $aResult['url_browse_order_common'] = bx_absolute_url($oPermalink->permalink($CNF['URL_ORDERS_COMMON'], array('filter' => '{order}')));
  380. $aResult['url_browse_order_administration'] = bx_absolute_url($oPermalink->permalink($CNF['URL_ORDERS_ADMINISTRATION'], array('filter' => '{order}')));
  381. return $aResult;
  382. }
  383. /**
  384. * @page service Service Calls
  385. * @section bx_credits Credits
  386. * @subsection bx_credits-payments Payments
  387. * @subsubsection bx_credits-get_cart_item get_cart_item
  388. *
  389. * @code bx_srv('bx_credits', 'get_cart_item', [...]); @endcode
  390. *
  391. * Get an array with prodict's description. Is used in Shopping Cart in payments processing module.
  392. *
  393. * @param $iItemId product's ID.
  394. * @return an array with prodict's description. Empty array is returned if something is wrong.
  395. *
  396. * @see BxCreditsModule::serviceGetCartItem
  397. */
  398. /**
  399. * @ref bx_credits-get_cart_item "get_cart_item"
  400. */
  401. public function serviceGetCartItem($iItemId)
  402. {
  403. $CNF = &$this->_oConfig->CNF;
  404. if(!$iItemId)
  405. return array();
  406. $aItem = $this->_oDb->getBundle(array('type' => 'id', 'id' => $iItemId));
  407. if(empty($aItem) || !is_array($aItem))
  408. return array();
  409. return array (
  410. 'id' => $aItem[$CNF['FIELD_ID']],
  411. 'author_id' => $this->_oConfig->getAuthor(),
  412. 'name' => $aItem[$CNF['FIELD_NAME']],
  413. 'title' => _t($aItem[$CNF['FIELD_TITLE']]),
  414. 'description' => $this->_oConfig->getBundleDescription($aItem),
  415. 'url' => $this->_oConfig->getBundleUrl($aItem),
  416. 'price_single' => $aItem[$CNF['FIELD_PRICE']],
  417. 'price_recurring' => '',
  418. 'period_recurring' => 1,
  419. 'period_unit_recurring' => '',
  420. 'trial_recurring' => ''
  421. );
  422. }
  423. /**
  424. * @page service Service Calls
  425. * @section bx_credits Credits
  426. * @subsection bx_credits-payments Payments
  427. * @subsubsection bx_credits-get_cart_items get_cart_items
  428. *
  429. * @code bx_srv('bx_credits', 'get_cart_items', [...]); @endcode
  430. *
  431. * Get an array with prodicts' descriptions by seller. Is used in Manual Order Processing in payments processing module.
  432. *
  433. * @param $iSellerId seller ID.
  434. * @return an array with prodicts' descriptions. Empty array is returned if something is wrong or seller doesn't have any products.
  435. *
  436. * @see BxCreditsModule::serviceGetCartItems
  437. */
  438. /**
  439. * @ref bx_credits-get_cart_items "get_cart_items"
  440. */
  441. public function serviceGetCartItems($iSellerId)
  442. {
  443. $CNF = &$this->_oConfig->CNF;
  444. $iAuthorId = $this->_oConfig->getAuthor();
  445. if($iSellerId != $iAuthorId && !BxDolAcl::getInstance()->isMemberLevelInSet([MEMBERSHIP_ID_ADMINISTRATOR], $iSellerId))
  446. return array();
  447. $aItems = $this->_oDb->getBundle(array('type' => 'all', 'active' => 1));
  448. $aResult = array();
  449. foreach($aItems as $aItem)
  450. $aResult[] = array(
  451. 'id' => $aItem[$CNF['FIELD_ID']],
  452. 'author_id' => $iAuthorId,
  453. 'name' => $aItem[$CNF['FIELD_NAME']],
  454. 'title' => _t($aItem[$CNF['FIELD_TITLE']]),
  455. 'description' => $this->_oConfig->getBundleDescription($aItem),
  456. 'url' => $this->_oConfig->getBundleUrl($aItem),
  457. 'price_single' => $aItem[$CNF['FIELD_PRICE']],
  458. 'price_recurring' => '',
  459. 'period_recurring' => 1,
  460. 'period_unit_recurring' => '',
  461. 'trial_recurring' => ''
  462. );
  463. return $aResult;
  464. }
  465. /**
  466. * @page service Service Calls
  467. * @section bx_credits Credits
  468. * @subsection bx_credits-payments Payments
  469. * @subsubsection bx_credits-register_cart_item register_cart_item
  470. *
  471. * @code bx_srv('bx_credits', 'register_cart_item', [...]); @endcode
  472. *
  473. * Register a processed single time payment inside the Credits module. Is called with payment processing module after the payment was registered there.
  474. *
  475. * @param $iClientId client ID.
  476. * @param $iSellerId seller ID
  477. * @param $iItemId item ID.
  478. * @param $iItemCount the number of purchased items.
  479. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  480. * @param $sLicense license number genereted with payment processing module for internal usage
  481. * @return an array with purchased prodict's description. Empty array is returned if something is wrong.
  482. *
  483. * @see BxCreditsModule::serviceRegisterCartItem
  484. */
  485. /**
  486. * @ref bx_credits-register_cart_item "register_cart_item"
  487. */
  488. public function serviceRegisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
  489. {
  490. return $this->_serviceRegisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, BX_CREDITS_ORDER_TYPE_SINGLE);
  491. }
  492. /**
  493. * @page service Service Calls
  494. * @section bx_credits Credits
  495. * @subsection bx_credits-payments Payments
  496. * @subsubsection bx_credits-register_subscription_item register_subscription_item
  497. *
  498. * @code bx_srv('bx_credits', 'register_subscription_item', [...]); @endcode
  499. *
  500. * Register a processed subscription (recurring payment) inside the Credits module. Is called with payment processing module after the subscription was registered there.
  501. *
  502. * @param $iClientId client ID.
  503. * @param $iSellerId seller ID
  504. * @param $iItemId item ID.
  505. * @param $iItemCount the number of purchased items.
  506. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  507. * @param $sLicense license number genereted with payment processing module for internal usage
  508. * @return an array with subscribed prodict's description. Empty array is returned if something is wrong.
  509. *
  510. * @see BxCreditsModule::serviceRegisterSubscriptionItem
  511. */
  512. /**
  513. * @ref bx_credits-register_subscription_item "register_subscription_item"
  514. */
  515. public function serviceRegisterSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
  516. {
  517. return $this->_serviceRegisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, BX_CREDITS_ORDER_TYPE_RECURRING);
  518. }
  519. /**
  520. * @page service Service Calls
  521. * @section bx_credits Credits
  522. * @subsection bx_credits-payments Payments
  523. * @subsubsection bx_credits-reregister_cart_item reregister_cart_item
  524. *
  525. * @code bx_srv('bx_credits', 'reregister_cart_item', [...]); @endcode
  526. *
  527. * Reregister a single time payment inside the Credits module. Is called with payment processing module after the payment was reregistered there.
  528. *
  529. * @param $iClientId client ID.
  530. * @param $iSellerId seller ID
  531. * @param $iItemIdOld old item ID.
  532. * @param $iItemIdNew new item ID.
  533. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  534. * @return an array with purchased prodict's description. Empty array is returned if something is wrong.
  535. *
  536. * @see BxCreditsModule::serviceReregisterCartItem
  537. */
  538. /**
  539. * @ref bx_credits-reregister_cart_item "reregister_cart_item"
  540. */
  541. public function serviceReregisterCartItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
  542. {
  543. return array();
  544. }
  545. /**
  546. * @page service Service Calls
  547. * @section bx_credits Credits
  548. * @subsection bx_credits-payments Payments
  549. * @subsubsection bx_credits-reregister_subscription_item reregister_subscription_item
  550. *
  551. * @code bx_srv('bx_credits', 'reregister_subscription_item', [...]); @endcode
  552. *
  553. * Reregister a subscription (recurring payment) inside the Credits module. Is called with payment processing module after the subscription was reregistered there.
  554. *
  555. * @param $iClientId client ID.
  556. * @param $iSellerId seller ID
  557. * @param $iItemIdOld old item ID.
  558. * @param $iItemIdNew new item ID.
  559. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  560. * @return an array with subscribed prodict's description. Empty array is returned if something is wrong.
  561. *
  562. * @see BxCreditsModule::serviceReregisterSubscriptionItem
  563. */
  564. /**
  565. * @ref bx_credits-reregister_subscription_item "reregister_subscription_item"
  566. */
  567. public function serviceReregisterSubscriptionItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
  568. {
  569. return array();
  570. }
  571. /**
  572. * @page service Service Calls
  573. * @section bx_credits Credits
  574. * @subsection bx_credits-payments Payments
  575. * @subsubsection bx_credits-unregister_cart_item unregister_cart_item
  576. *
  577. * @code bx_srv('bx_credits', 'unregister_cart_item', [...]); @endcode
  578. *
  579. * Unregister an earlier processed single time payment inside the Credits module. Is called with payment processing module after the payment was unregistered there.
  580. *
  581. * @param $iClientId client ID.
  582. * @param $iSellerId seller ID
  583. * @param $iItemId item ID.
  584. * @param $iItemCount the number of purchased items.
  585. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  586. * @param $sLicense license number genereted with payment processing module for internal usage
  587. * @return boolean value determining where the payment was unregistered or not.
  588. *
  589. * @see BxCreditsModule::serviceUnregisterCartItem
  590. */
  591. /**
  592. * @ref bx_credits-unregister_cart_item "unregister_cart_item"
  593. */
  594. public function serviceUnregisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
  595. {
  596. return $this->_serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, BX_CREDITS_ORDER_TYPE_SINGLE);
  597. }
  598. /**
  599. * @page service Service Calls
  600. * @section bx_credits Credits
  601. * @subsection bx_credits-payments Payments
  602. * @subsubsection bx_credits-unregister_subscription_item unregister_subscription_item
  603. *
  604. * @code bx_srv('bx_credits', 'unregister_subscription_item', [...]); @endcode
  605. *
  606. * Unregister an earlier processed subscription (recurring payment) inside the Credits module. Is called with payment processing module after the subscription was unregistered there.
  607. *
  608. * @param $iClientId client ID.
  609. * @param $iSellerId seller ID
  610. * @param $iItemId item ID.
  611. * @param $iItemCount the number of purchased items.
  612. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  613. * @param $sLicense license number genereted with payment processing module for internal usage
  614. * @return boolean value determining where the subscription was unregistered or not.
  615. *
  616. * @see BxCreditsModule::serviceUnregisterSubscriptionItem
  617. */
  618. /**
  619. * @ref bx_credits-unregister_subscription_item "unregister_subscription_item"
  620. */
  621. public function serviceUnregisterSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
  622. {
  623. return $this->_serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, BX_CREDITS_ORDER_TYPE_RECURRING);
  624. }
  625. /**
  626. * @page service Service Calls
  627. * @section bx_credits Credits
  628. * @subsection bx_credits-payments Payments
  629. * @subsubsection bx_credits-cancel_subscription_item cancel_subscription_item
  630. *
  631. * @code bx_srv('bx_credits', 'cancel_subscription_item', [...]); @endcode
  632. *
  633. * Cancel an earlier processed subscription (recurring payment) inside the Credits module. Is called with payment processing module after the subscription was canceled there.
  634. *
  635. * @param $iClientId client ID.
  636. * @param $iSellerId seller ID
  637. * @param $iItemId item ID.
  638. * @param $iItemCount the number of purchased items.
  639. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  640. * @return boolean value determining where the subscription was canceled or not.
  641. *
  642. * @see BxCreditsModule::serviceCancelSubscriptionItem
  643. */
  644. /**
  645. * @ref bx_credits-cancel_subscription_item "cancel_subscription_item"
  646. */
  647. public function serviceCancelSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder)
  648. {
  649. return true;
  650. }
  651. public function serviceGetProfileBalance($iProfileId = 0)
  652. {
  653. return $this->getProfileBalance($iProfileId);
  654. }
  655. public function serviceUpdateProfileBalance($iFirstPid, $fAmount, $iSecondPid = 0, $sOrder = '', $sInfo = '')
  656. {
  657. if(empty($sInfo))
  658. $sInfo = '_bx_credits_txt_history_info_service';
  659. return $this->updateProfileBalance($iFirstPid, $iSecondPid, $fAmount, BX_CREDITS_TRANSFER_TYPE_SERVICE, $sOrder, $sInfo);
  660. }
  661. public function serviceMakePayment($iBuyerPid, $fAmount, $iSellerPid, $sOrder = '')
  662. {
  663. $sInfo = '_bx_credits_txt_history_info_checkout';
  664. if(!$this->updateProfileBalance($iBuyerPid, $iSellerPid, -$fAmount, BX_CREDITS_TRANSFER_TYPE_CHECKOUT, $sOrder, $sInfo))
  665. return false;
  666. if(!$this->updateProfileBalance($iSellerPid, $iBuyerPid, $fAmount, $sOrder, BX_CREDITS_TRANSFER_TYPE_CHECKOUT, $sInfo)) {
  667. $this->updateProfileBalance($iBuyerPid, 0, $fAmount, BX_CREDITS_TRANSFER_TYPE_CANCELLATION, $sOrder, '_bx_credits_txt_history_info_cancellation');
  668. return false;
  669. }
  670. return true;
  671. }
  672. /**
  673. * Delete all content by profile
  674. * @param $iProfileId profile id
  675. * @return number of deleted items
  676. */
  677. public function serviceDeleteEntitiesByAuthor ($iProfileId)
  678. {
  679. $this->_oDb->deleteProfile(array('id' => $iProfileId));
  680. $this->_oDb->deleteHistory(array('first_pid' => $iProfileId));
  681. }
  682. /*
  683. * Common methods
  684. */
  685. public function convertC2S($fCredits, $bWithUnit = true)
  686. {
  687. $sResult = '';
  688. if($bWithUnit)
  689. $sResult .= $this->_oTemplate->getUnit();
  690. $iPrecision = $this->_oConfig->getPrecision();
  691. $sResult .= sprintf("%01." . $iPrecision . "f", round((float)$fCredits, $iPrecision));
  692. return $sResult;
  693. }
  694. public function getProfileBalance($iProfileId = 0)
  695. {
  696. if(empty($iProfileId))
  697. $iProfileId = bx_get_logged_profile_id();
  698. if(empty($iProfileId))
  699. return 0;
  700. return (float)$this->_oDb->getProfile(array('type' => 'balance', 'id' => $iProfileId));
  701. }
  702. public function getProfileBalanceCleared($iProfileId = 0)
  703. {
  704. if(empty($iProfileId))
  705. $iProfileId = bx_get_logged_profile_id();
  706. if(empty($iProfileId))
  707. return 0;
  708. $fCleared = (float)$this->_oDb->getHistory(['type' => 'cleared', 'profile' => $iProfileId]);
  709. $fSpent = (float)$this->_oDb->getHistory(['type' => 'spent', 'profile' => $iProfileId]);
  710. return $fCleared > $fSpent ? $fCleared - $fSpent : 0;
  711. }
  712. public function updateProfileBalance($iFirstPid, $iSecondPid, $fAmount, $sType, $sOrder = '', $sInfo = '', $sData = '')
  713. {
  714. $CNF = &$this->_oConfig->CNF;
  715. if(empty($sOrder))
  716. $sOrder = $this->_oConfig->getOrder();
  717. if(empty($sData))
  718. $sData = serialize(array(
  719. 'conversion' => $this->_oConfig->getConversionRateUse(),
  720. 'precision' => $this->_oConfig->getPrecision()
  721. ));
  722. if(!$this->_oDb->updateProfileBalance($iFirstPid, $fAmount))
  723. return false;
  724. $fAmountAbs = abs($fAmount);
  725. $sDirection = $fAmount > 0 ? BX_CREDITS_DIRECTION_IN : BX_CREDITS_DIRECTION_OUT;
  726. $iHistoryId = $this->_oDb->insertHistory([
  727. 'first_pid' => $iFirstPid,
  728. 'second_pid' => $iSecondPid,
  729. 'amount' => $fAmountAbs,
  730. 'type' => $sType,
  731. 'direction' => $sDirection,
  732. 'order' => $sOrder,
  733. 'data' => $sData,
  734. 'info' => $sInfo,
  735. 'date' => time()
  736. ]);
  737. if(!$iHistoryId)
  738. return false;
  739. bx_alert($this->getName(), 'update_balance', 0, false, array(
  740. 'first_pid' => $iFirstPid,
  741. 'second_pid' => $iSecondPid,
  742. 'amount' => $fAmountAbs,
  743. 'type' => $sType,
  744. 'direction' => $sDirection,
  745. 'order' => $sOrder,
  746. ));
  747. $oSecondProfile = BxDolProfile::getInstanceMagic($iSecondPid);
  748. sendMailTemplate($CNF['ETEMPLATE_' . strtoupper($sDirection)], 0, $iFirstPid, array(
  749. 'second_profile_name' => $oSecondProfile->getDisplayName(),
  750. 'amount' => $fAmountAbs,
  751. ));
  752. return $iHistoryId;
  753. }
  754. public function processGrant($iUserId, $iProfileId, $fAmount, $sMessage = '')
  755. {
  756. $CNF = &$this->_oConfig->CNF;
  757. $oProfile = BxDolProfile::getInstance($iProfileId);
  758. if(!$oProfile)
  759. return ['code' => 2, 'msg' => '_bx_credits_err_profile_not_found'];
  760. $sInfo = '_bx_credits_txt_history_info_grant';
  761. $iHistoryId = $this->updateProfileBalance($iProfileId, 0, $fAmount, BX_CREDITS_TRANSFER_TYPE_GRANT, '', $sInfo);
  762. if(!$iHistoryId)
  763. return ['code' => 3, 'msg' => '_bx_credits_err_cannot_update_balance'];
  764. sendMailTemplate($CNF['ETEMPLATE_GRANTED'], 0, $iProfileId, [
  765. 'amount' => $fAmount,
  766. 'message' => $sMessage
  767. ]);
  768. bx_alert($this->getName(), 'granted', 0, false, [
  769. 'profile' => $iProfileId,
  770. 'amount' => $fAmount,
  771. ]);
  772. return ['code' => 0, 'id' => $iHistoryId];
  773. }
  774. public function processSend($iUserId, $iProfileId, $fAmount, $sMessage = '')
  775. {
  776. $CNF = &$this->_oConfig->CNF;
  777. $fAmountAvail = $this->getProfileBalance($iUserId);
  778. if($fAmount > $fAmountAvail)
  779. return ['code' => 1, 'msg' => '_bx_credits_err_low_balance'];
  780. $oProfile = null;
  781. if(!$iProfileId || !($oProfile = BxDolProfile::getInstance($iProfileId)))
  782. return ['code' => 2, 'msg' => '_bx_credits_err_profile_not_found'];
  783. $sOrder = $this->_oConfig->getOrder();
  784. $sInfo = !empty($sMessage) ? $sMessage : '_bx_credits_txt_history_info_send';
  785. $iHistoryId = $this->updateProfileBalance($iUserId, $iProfileId, -$fAmount, BX_CREDITS_TRANSFER_TYPE_SEND, $sOrder, $sInfo);
  786. if(!$iHistoryId)
  787. return ['code' => 3, 'msg' => '_bx_credits_err_cannot_update_balance'];
  788. if(!$this->updateProfileBalance($iProfileId, $iUserId, $fAmount, BX_CREDITS_TRANSFER_TYPE_SEND, $sOrder, $sInfo)) {
  789. $sInfo = '_bx_credits_txt_history_info_cancellation';
  790. $iHistoryId = $this->updateProfileBalance($iUserId, 0, $fAmount, BX_CREDITS_TRANSFER_TYPE_CANCELLATION, $sOrder, $sInfo);
  791. return ['code' => 3, 'id' => $iHistoryId, 'msg' => '_bx_credits_err_cannot_update_balance'];
  792. }
  793. $oUser = BxDolProfile::getInstance($iUserId);
  794. sendMailTemplate($CNF['ETEMPLATE_RECEIVED'], 0, $iProfileId, [
  795. 'performer_id' => $iUserId,
  796. 'performer_name' => $oUser->getDisplayName(),
  797. 'performer_link' => $oUser->getUrl(),
  798. 'amount' => $fAmount,
  799. 'order' => $sOrder,
  800. 'message' => $sMessage
  801. ]);
  802. bx_alert($this->getName(), 'sent', 0, $iUserId, [
  803. 'performer' => $iUserId,
  804. 'profile' => $iProfileId,
  805. 'amount' => $fAmount,
  806. 'order' => $sOrder,
  807. ]);
  808. return ['code' => 0, 'id' => $iHistoryId];
  809. }
  810. public function processWithdrawRequest($iUserId, $iProfileId, $fAmount, $sMessage = '')
  811. {
  812. $CNF = &$this->_oConfig->CNF;
  813. if(empty($iProfileId))
  814. $iProfileId = bx_get_logged_profile_id ();
  815. if(empty($iProfileId))
  816. return ['code' => 1, 'msg' => '_bx_credits_err_login_required'];
  817. $oProfile = BxDolProfile::getInstance($iProfileId);
  818. if(!$oProfile)
  819. return ['code' => 1, 'msg' => '_bx_credits_err_login_required'];
  820. $fBalanceCleared = $this->getProfileBalanceCleared($iProfileId);
  821. if($fAmount > $fBalanceCleared)
  822. return ['code' => 2, 'msg' => '_bx_credits_err_low_balance'];
  823. $aProfileInfo = $this->_oDb->getProfile(['type' => 'id', 'id' => $iProfileId]);
  824. $iWithdrawMinimum = !empty($aProfileInfo['wdw_minimum']) ? (int)$aProfileInfo['wdw_minimum'] : (int)getParam($CNF['PARAM_WITHDRAW_MINIMUM']);
  825. if($fAmount < $iWithdrawMinimum)
  826. return ['code' => 3, 'msg' => _t('_bx_credits_err_withdraw_minimum', $iWithdrawMinimum)];
  827. $fBalance = $this->getProfileBalance($iProfileId);
  828. $iWithdrawRemaining = !empty($aProfileInfo['wdw_remaining']) ? (int)$aProfileInfo['wdw_remaining'] : (int)getParam($CNF['PARAM_WITHDRAW_REMAINING']);
  829. if(($fBalance - $fAmount) < $iWithdrawRemaining)
  830. return ['code' => 4, 'msg' => _t('_bx_credits_err_withdraw_remaining', $iWithdrawRemaining)];
  831. $aResult = ['code' => 5, 'msg' => '_bx_credits_err_cannot_send'];
  832. $fRate = $this->_oConfig->getConversionRateWithdraw();
  833. $aTemplateVars = [
  834. 'profile_link' => $oProfile->getUrl(),
  835. 'profile_name' => $oProfile->getDisplayName(),
  836. 'amount' => $fAmount,
  837. 'rate' => $fRate,
  838. 'message' => $sMessage,
  839. 'confirm_url' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_HISTORY_ADMINISTRATION']))
  840. ];
  841. $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($CNF['ETEMPLATE_WITHDRAW_REQUESTED'], $aTemplateVars);
  842. if(!$aTemplate)
  843. return $aResult;
  844. $sEmail = $this->_oConfig->getWithdrawEmail();
  845. if(!sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, [], BX_EMAIL_SYSTEM, 'html', false, [], true))
  846. return $aResult;
  847. bx_alert($this->getName(), 'withdraw_requested', 0, $iProfileId, [
  848. 'profile' => $iProfileId,
  849. 'amount' => $fAmount,
  850. 'rate' => $fRate
  851. ]);
  852. return ['code' => 0];
  853. }
  854. public function processWithdrawConfirm($iUserId, $iProfileId, $fAmount, $sMessage = '')
  855. {
  856. $CNF = &$this->_oConfig->CNF;
  857. $oProfile = BxDolProfile::getInstance($iProfileId);
  858. if(!$oProfile)
  859. return ['code' => 1, 'msg' => '_bx_credits_err_profile_not_found'];
  860. $fBalance = $this->getProfileBalance($iProfileId);
  861. if($fAmount > $fBalance)
  862. return ['code' => 2, 'msg' => '_bx_credits_err_low_balance'];
  863. $sInfo = '_bx_credits_txt_history_info_withdraw';
  864. $iHistoryId = $this->updateProfileBalance($iProfileId, 0, -$fAmount, BX_CREDITS_TRANSFER_TYPE_WITHDRAW, '', $sInfo);
  865. if(!$iHistoryId)
  866. return ['code' => 3, 'msg' => '_bx_credits_err_cannot_update_balance'];
  867. sendMailTemplate($CNF['ETEMPLATE_WITHDRAW_SENT'], 0, $iProfileId, [
  868. 'amount' => $fAmount,
  869. 'message' => $sMessage
  870. ]);
  871. bx_alert($this->getName(), 'withdraw_sent', 0, $iUserId, [
  872. 'performer' => $iUserId,
  873. 'profile' => $iProfileId,
  874. 'amount' => $fAmount,
  875. ]);
  876. return ['code' => 0, 'id' => $iHistoryId];
  877. }
  878. public function processClearing()
  879. {
  880. $CNF = &$this->_oConfig->CNF;
  881. $aItems = $this->_oDb->getHistory(['type' => 'clearing', 'clearing' => $this->_oConfig->getWithdrawClearing()]);
  882. if(empty($aItems) || !is_array($aItems))
  883. return;
  884. $iNow = time();
  885. foreach($aItems as $aItem) {
  886. $this->_oDb->updateHistory([$CNF['FIELD_H_CLEARED'] => $iNow], [$CNF['FIELD_H_ID'] => $aItem['id']]);
  887. //TODO: Some action(s) related to clearing can be performed here.
  888. }
  889. }
  890. /*
  891. * Internal methods
  892. */
  893. protected function _serviceRegisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType)
  894. {
  895. $CNF = &$this->_oConfig->CNF;
  896. $aItem = $this->serviceGetCartItem($iItemId);
  897. if(empty($aItem) || !is_array($aItem))
  898. return array();
  899. $aBundle = $this->_oDb->getBundle(array('type' => 'id', 'id' => $iItemId));
  900. if(empty($aBundle) || !is_array($aBundle))
  901. return array();
  902. $iTrial = 0;
  903. $sDuration = '';
  904. $sAction = 'register';
  905. if($sType == BX_CREDITS_ORDER_TYPE_RECURRING && isset($CNF['FIELD_DURATION_RECURRING'], $CNF['FIELD_TRIAL_RECURRING'])) {
  906. $iTrial = $aBundle[$CNF['FIELD_TRIAL_RECURRING']];
  907. $sDuration = $aBundle[$CNF['FIELD_DURATION_RECURRING']];
  908. if($this->_oDb->isOrderByPbo($iClientId, $iItemId, $sOrder))
  909. $sAction = 'prolong';
  910. }
  911. if(!$this->_oDb->{$sAction . 'Order'}($iClientId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType, $sDuration, $iTrial))
  912. return array();
  913. $sInfo = '_bx_credits_txt_history_info_purchase';
  914. $fAmount = ((float)$aBundle[$CNF['FIELD_AMOUNT']] + (float)$aBundle[$CNF['FIELD_BONUS']]) * $iItemCount;
  915. if(!$this->updateProfileBalance($iClientId, 0, $fAmount, BX_CREDITS_TRANSFER_TYPE_PURCHASE, '', $sInfo))
  916. return array();
  917. bx_alert($this->getName(), 'order_' . $sAction, 0, false, array(
  918. 'profile_id' => $iClientId,
  919. 'bundle_id' => $iItemId,
  920. 'product_id' => $iItemId, //--- Alias for 'bundle_id'
  921. 'count' => $iItemCount,
  922. 'order' => $sOrder,
  923. 'license' => $sLicense,
  924. 'type' => $sType,
  925. 'duration' => $sDuration,
  926. 'trial' => $iTrial
  927. ));
  928. $oClient = BxDolProfile::getInstanceMagic($iClientId);
  929. $oSeller = BxDolProfile::getInstanceMagic($iSellerId);
  930. $sSellerUrl = $oSeller->getUrl();
  931. $sSellerName = $oSeller->getDisplayName();
  932. sendMailTemplate($CNF['ETEMPLATE_PURCHASED'], 0, $iClientId, array(
  933. 'client_name' => $oClient->getDisplayName(),
  934. 'bundle_name' => $aBundle[$CNF['FIELD_NAME']],
  935. 'bundle_title' => _t($aBundle[$CNF['FIELD_TITLE']]),
  936. 'bundle_url' => $this->_oConfig->getBundleUrl($aBundle),
  937. 'vendor_url' => $sSellerUrl,
  938. 'vendor_name' => $sSellerName,
  939. 'order' => $sOrder,
  940. 'license' => $sLicense,
  941. 'notes' => _t('_bx_credits_txt_purchased_note', $sSellerUrl, $sSellerName),
  942. ));
  943. return $aItem;
  944. }
  945. protected function _serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType)
  946. {
  947. $CNF = &$this->_oConfig->CNF;
  948. $aBundle = $this->_oDb->getBundle(array('type' => 'id', 'id' => $iItemId));
  949. if(empty($aBundle) || !is_array($aBundle))
  950. return false;
  951. if(!$this->_oDb->unregisterOrder($iClientId, $iItemId, $sOrder, $sLicense, $sType))
  952. return false;
  953. $fAmount = (float)$aBundle[$CNF['FIELD_AMOUNT']] + (float)$aBundle[$CNF['FIELD_BONUS']];
  954. $aProfile = $this->_oDb->getProfile(array('type' => 'id', 'id' => $iClientId));
  955. if(!empty($aProfile) && is_array($aProfile))
  956. $this->_oDb->updateProfile(array('balance' => (float)$aProfile['balance'] - $fAmount), array('id' => $aProfile['id']));
  957. bx_alert($this->getName(), 'order_unregister', 0, false, array(
  958. 'profile_id' => $iClientId,
  959. 'bundle_id' => $iItemId,
  960. 'product_id' => $iItemId, //--- Alias for 'bundle_id'
  961. 'count' => $iItemCount,
  962. 'order' => $sOrder,
  963. 'license' => $sLicense,
  964. 'type' => $sType,
  965. ));
  966. return true;
  967. }
  968. protected function _getBlockOrders($sType)
  969. {
  970. $CNF = &$this->_oConfig->CNF;
  971. $sGrid = $CNF['OBJECT_GRID_ORDERS_' . strtoupper($sType)];
  972. $oGrid = BxDolGrid::getObjectInstance($sGrid);
  973. if(!$oGrid)
  974. return '';
  975. return [
  976. 'content' => $oGrid->getCode(),
  977. 'menu' => $CNF['OBJECT_MENU_MANAGE_SUBMENU']
  978. ];
  979. }
  980. protected function _getBlockHistory($sType)
  981. {
  982. $CNF = &$this->_oConfig->CNF;
  983. $sGrid = $CNF['OBJECT_GRID_HISTORY_' . strtoupper($sType)];
  984. $oGrid = BxDolGrid::getObjectInstance($sGrid);
  985. if(!$oGrid)
  986. return '';
  987. return [
  988. 'content' => $oGrid->getCode(),
  989. 'menu' => $CNF['OBJECT_MENU_MANAGE_SUBMENU']
  990. ];
  991. }
  992. protected function _getBlockProfiles($sType)
  993. {
  994. $CNF = &$this->_oConfig->CNF;
  995. $sKey = 'OBJECT_GRID_PROFILES_' . strtoupper($sType);
  996. if(empty($CNF[$sKey]))
  997. return '';
  998. $sGrid = $CNF[$sKey];
  999. $oGrid = BxDolGrid::getObjectInstance($sGrid);
  1000. if(!$oGrid)
  1001. return '';
  1002. return [
  1003. 'content' => $oGrid->getCode(),
  1004. 'menu' => $CNF['OBJECT_MENU_MANAGE_SUBMENU']
  1005. ];
  1006. }
  1007. }
  1008. /** @} */