1
0

BxCreditsModule.php 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621
  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. define('BX_CREDITS_WITHDRAWAL_STATUS_REQUESTED', 'requested');
  23. define('BX_CREDITS_WITHDRAWAL_STATUS_CANCELED', 'canceled');
  24. define('BX_CREDITS_WITHDRAWAL_STATUS_CONFIRMED', 'confirmed');
  25. class BxCreditsModule extends BxBaseModGeneralModule
  26. {
  27. function __construct(&$aModule)
  28. {
  29. parent::__construct($aModule);
  30. }
  31. public function actionGetProfiles()
  32. {
  33. $sTerm = bx_get('term');
  34. $a = BxDolService::call('system', 'profiles_search', array($sTerm), 'TemplServiceProfiles');
  35. echoJson($a);
  36. }
  37. public function actionCheckBundleName()
  38. {
  39. $CNF = &$this->_oConfig->CNF;
  40. $sName = bx_process_input(bx_get('name'));
  41. if(empty($sName))
  42. return echoJson(array());
  43. $sResult = '';
  44. $iId = (int)bx_get('id');
  45. if(!empty($iId)) {
  46. $aBundle = $this->_oDb->getBundle(array('type' => 'id', 'id' => $iId));
  47. if(strcmp($sName, $aBundle[$CNF['FIELD_NAME']]) == 0)
  48. $sResult = $sName;
  49. }
  50. echoJson(array(
  51. 'name' => !empty($sResult) ? $sResult : $this->_oConfig->getBundleName($sName)
  52. ));
  53. }
  54. public function actionCheckout()
  55. {
  56. return echoJson($this->serviceCheckout());
  57. }
  58. public function actionSubscribe()
  59. {
  60. return echoJson($this->serviceSubscribe());
  61. }
  62. public function serviceGetSafeServices()
  63. {
  64. return [
  65. 'GetBlockBundles' => '',
  66. 'GetBlockOrders' => '',
  67. 'GetBlockHistory' => '',
  68. 'AddToCart' => '',
  69. 'Checkout' => '',
  70. 'Subscribe' => ''
  71. ];
  72. }
  73. public function serviceCheckout()
  74. {
  75. $iBuyerId = bx_get_logged_profile_id();
  76. if(!$iBuyerId)
  77. return ['code' => 1, 'msg' => _t('_bx_credits_err_unknown_buyer')];
  78. $sErrIncorrectData = _t('_bx_credits_err_incorrect_data');
  79. $aData = $this->_oConfig->getCheckoutData();
  80. if(empty($aData) || !is_array($aData))
  81. return ['code' => 2, 'msg' => $sErrIncorrectData];
  82. $fConversion = $this->_oConfig->getConversionRateUse();
  83. $iPrecision = $this->_oConfig->getPrecision();
  84. $iSellerId = (int)$aData['seller'];
  85. $fAmount = (float)$aData['amount'];
  86. $aCustomData = $this->_oConfig->deconstructCheckoutCustomData($aData['custom']);
  87. $oPayments = BxDolPayments::getInstance();
  88. $aPpOrders = $oPayments->getPendingOrdersInfo(['id' => (int)$aCustomData[1]]);
  89. if(!empty($aPpOrders) && is_array($aPpOrders)) {
  90. $aPpOrder = reset($aPpOrders);
  91. if(empty($aPpOrder) || !is_array($aPpOrder) || (int)$aPpOrder['seller_id'] != $iSellerId)
  92. return ['code' => 3, 'msg' => $sErrIncorrectData];
  93. $fAmountM = (float)$aPpOrder['amount'];
  94. $sCurrencyDefault = $oPayments->getCurrencyCode();
  95. if(strcmp($aPpOrder['currency'], $sCurrencyDefault) != 0)
  96. $fAmountM = $oPayments->convert ($fAmountM, $aPpOrder['currency'], $sCurrencyDefault);
  97. if($this->_oConfig->convertM2C($fAmountM, $fConversion, $iPrecision) != $fAmount)
  98. return ['code' => 3, 'msg' => $sErrIncorrectData];
  99. }
  100. $fBalance = (float)$this->_oDb->getProfile(['type' => 'balance', 'id' => $iBuyerId]);
  101. if($fAmount > $fBalance)
  102. return ['code' => 4, 'msg' => _t('_bx_credits_err_low_balance')];
  103. $sOrder = $this->_oConfig->getOrder();
  104. $sInfo = '_bx_credits_txt_history_info_checkout';
  105. $sData = serialize([
  106. 'conversion' => $fConversion,
  107. 'precision' => $iPrecision
  108. ]);
  109. $this->updateProfileBalance($iBuyerId, $iSellerId, -$fAmount, BX_CREDITS_TRANSFER_TYPE_CHECKOUT, $sOrder, $sInfo, $sData);
  110. $this->updateProfileBalance($iSellerId, $iBuyerId, $fAmount, BX_CREDITS_TRANSFER_TYPE_CHECKOUT, $sOrder, $sInfo, $sData);
  111. /**
  112. * @hooks
  113. * @hookdef hook-bx_credits-checkout 'bx_credits', 'checkout' - hook after checkout with creadits was performed
  114. * - $unit_name - equals `bx_credits`
  115. * - $action - equals `checkout`
  116. * - $object_id - not used
  117. * - $sender_id - not used
  118. * - $extra_params - array of additional params with the following array keys:
  119. * - `seller` - [int] seller profile id
  120. * - `buyer` - [int] buyer profile id
  121. * - `amount` - [float] amount was paid
  122. * - `order` - [string] order number for processed checkout action
  123. * @hook @ref hook-bx_credits-checkout
  124. */
  125. bx_alert($this->getName(), 'checkout', 0, false, [
  126. 'seller' => $iSellerId,
  127. 'buyer' => $iBuyerId,
  128. 'amount' => $fAmount,
  129. 'order' => $sOrder
  130. ]);
  131. $aParams = [
  132. 'o' => $sOrder,
  133. 'c' => $aData['custom']
  134. ];
  135. return $this->_bIsApi ? [
  136. 'code' => 0,
  137. 'request_url' => $aData['return_data_url'] . '&params[]=' . json_encode($aParams)
  138. ] : [
  139. 'code' => 0,
  140. 'redirect' => bx_append_url_params($aData['return_data_url'], $aParams)
  141. ];
  142. }
  143. public function serviceSubscribe()
  144. {
  145. $iBuyerId = bx_get_logged_profile_id();
  146. if(!$iBuyerId)
  147. return ['code' => 1, 'msg' => _t('_bx_credits_err_unknown_buyer')];
  148. $aData = $this->_oConfig->getCheckoutData();
  149. if(empty($aData) || !is_array($aData))
  150. return ['code' => 2, 'msg' => _t('_bx_credits_err_incorrect_data')];
  151. $iSellerId = (int)$aData['seller'];
  152. $fAmount = (float)$aData['amount'];
  153. $fBalance = (float)$this->_oDb->getProfile(array('type' => 'balance', 'id' => $iBuyerId));
  154. if($fAmount > $fBalance)
  155. return ['code' => 3, 'msg' => _t('_bx_credits_err_low_balance')];
  156. $sUnique = $this->_oConfig->getOrder(9);
  157. $sCustomer = 'bx_cus_' . $sUnique;
  158. $sSubscription = 'bx_sub_' . $sUnique;
  159. /**
  160. * @hooks
  161. * @hookdef hook-bx_credits-subscribe 'bx_credits', 'subscribe' - hook after subscription was registered
  162. * - $unit_name - equals `bx_credits`
  163. * - $action - equals `subscribe`
  164. * - $object_id - not used
  165. * - $sender_id - not used
  166. * - $extra_params - array of additional params with the following array keys:
  167. * - `seller` - [int] seller profile id
  168. * - `buyer` - [int] buyer profile id
  169. * - `amount` - [float] amount was paid
  170. * - `trial` - [boolean] if trial period is available or not
  171. * - `customer` - [string] unique customer id for newly registered subscription
  172. * - `subscription` - [string] unique subscription id
  173. * @hook @ref hook-bx_credits-subscribe
  174. */
  175. bx_alert($this->getName(), 'subscribe', 0, false, [
  176. 'seller' => $iSellerId,
  177. 'buyer' => $iBuyerId,
  178. 'amount' => $fAmount,
  179. 'trial' => $aData['trial'],
  180. 'customer' => $sCustomer,
  181. 'subscription' => $sSubscription
  182. ]);
  183. $aParams = [
  184. 'cs' => $sCustomer,
  185. 'sb' => $sSubscription,
  186. 'tr' => $aData['trial'],
  187. 'c' => $aData['custom']
  188. ];
  189. return $this->_bIsApi ? [
  190. 'code' => 0,
  191. 'request_url' => $aData['return_data_url'] . '&params[]=' . json_encode($aParams)
  192. ] : [
  193. 'code' => 0,
  194. 'redirect' => bx_append_url_params($aData['return_data_url'], $aParams)
  195. ];
  196. }
  197. public function serviceGetCheckoutUrl()
  198. {
  199. return $this->_oConfig->getCheckoutUrl();
  200. }
  201. public function serviceConvertMoneyToCredits($fMoney, $fRate = false, $iPrecision = false)
  202. {
  203. return $this->_oConfig->convertM2C($fMoney, $fRate, $iPrecision);
  204. }
  205. public function serviceConvertCreditsToMoney($fCredits, $fRate = false, $iPrecision = false)
  206. {
  207. return $this->_oConfig->convertC2M($fCredits, $fRate, $iPrecision);
  208. }
  209. public function serviceValidateCheckout($iSeller, $iBuyer, $fAmount, $sOrder)
  210. {
  211. $fAmount = (float)$fAmount;
  212. $aOut = $this->_oDb->getHistory(array('type' => 'row_by', 'by' => array('first_pid' => $iBuyer, 'direction' => BX_CREDITS_DIRECTION_OUT, 'order' => $sOrder)));
  213. if(empty($aOut) || !is_array($aOut) || (int)$aOut['second_pid'] != (int)$iSeller)
  214. return false;
  215. $aDataOut = unserialize($aOut['data']);
  216. if($this->_oConfig->convertM2C($fAmount, $aDataOut['conversion'], $aDataOut['precision']) != (float)$aOut['amount'])
  217. return false;
  218. $aIn = $this->_oDb->getHistory(array('type' => 'row_by', 'by' => array('first_pid' => $iSeller, 'direction' => BX_CREDITS_DIRECTION_IN, 'order' => $sOrder)));
  219. if(empty($aIn) || !is_array($aIn) || (int)$aIn['second_pid'] != (int)$iBuyer)
  220. return false;
  221. $aDataIn = unserialize($aIn['data']);
  222. if($this->_oConfig->convertM2C($fAmount, $aDataIn['conversion'], $aDataIn['precision']) != (float)$aIn['amount'])
  223. return false;
  224. return true;
  225. }
  226. public function serviceGetBlockCheckout()
  227. {
  228. $oBuyer = BxDolProfile::getInstance();
  229. if(!$oBuyer)
  230. return ($sMsg = _t('_bx_credits_err_unknown_buyer')) && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : MsgBox($sMsg);
  231. $iSeller = (int)bx_get('seller');
  232. $oSeller = BxDolProfile::getInstance($iSeller);
  233. if(!$oSeller)
  234. return ($sMsg = _t('_bx_credits_err_unknown_seller')) && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : MsgBox($sMsg);
  235. $fAmountM = $fAmountMInDef = (float)bx_get('amount');
  236. $oPayments = BxDolPayments::getInstance();
  237. $sCurrency = bx_process_input(bx_get('currency_code'));
  238. $sCurrencyDefault = $oPayments->getCurrencyCode();
  239. if(strcmp($sCurrency, $sCurrencyDefault) != 0)
  240. $fAmountMInDef = $oPayments->convert($fAmountM, $sCurrency, $sCurrencyDefault);
  241. $fAmountC = $this->_oConfig->convertM2C($fAmountMInDef);
  242. $aData = [
  243. 'seller' => $iSeller,
  244. 'currency' => [
  245. 'code' => $sCurrency,
  246. 'sign' => bx_process_input(bx_get('currency_sign')),
  247. ],
  248. 'amountm' => $fAmountM,
  249. 'amountc' => $fAmountC
  250. ];
  251. $iItemsCount = (int)bx_get('items_count');
  252. for($i = 0; $i < $iItemsCount; $i++) {
  253. $aData['items'][] = [
  254. 'title' => bx_process_input(bx_get('item_title_' . $i)),
  255. 'quantity' => (int)bx_get('item_quantity_' . $i)
  256. ];
  257. }
  258. $this->_oConfig->setCheckoutData([
  259. 'seller' => $iSeller,
  260. 'amount' => $fAmountC,
  261. 'custom' => bx_process_input(bx_get('custom')),
  262. 'return_data_url' => bx_process_input(bx_get('return_data_url')),
  263. ]);
  264. $mixedResult = $this->_oTemplate->getBlockCheckout($oBuyer, $oSeller, $aData);
  265. return $this->_bIsApi ? [bx_api_get_block('credits_checkout', $mixedResult)] : $mixedResult;
  266. }
  267. public function serviceGetPopupSubscribe($aData)
  268. {
  269. $oBuyer = BxDolProfile::getInstance();
  270. if(!$oBuyer)
  271. return ['msg' => _t('_bx_credits_err_unknown_buyer')];
  272. $iSeller = (int)$aData['seller'];
  273. $oSeller = BxDolProfile::getInstance($iSeller);
  274. if(!$oSeller)
  275. return ['msg' => _t('_bx_credits_err_unknown_seller')];
  276. $fAmountM = $fAmountMInDef = (float)$aData['amount'];
  277. $oPayments = BxDolPayments::getInstance();
  278. $sCurrency = $aData['currency_code'];
  279. $sCurrencyDefault = $oPayments->getCurrencyCode();
  280. if(strcmp($sCurrency, $sCurrencyDefault) != 0)
  281. $fAmountMInDef = $oPayments->convert($fAmountM, $sCurrency, $sCurrencyDefault);
  282. $fAmountC = $this->_oConfig->convertM2C($fAmountMInDef);
  283. $aData = array_merge($aData, [
  284. 'currency' => [
  285. 'code' => $sCurrency,
  286. 'sign' => $aData['currency_sign'],
  287. ],
  288. 'amountm' => $fAmountM,
  289. 'amountc' => $fAmountC
  290. ]);
  291. $this->_oConfig->setCheckoutData([
  292. 'seller' => $iSeller,
  293. 'amount' => $fAmountC,
  294. 'trial' => (int)$aData['trial'] > 0,
  295. 'custom' => bx_process_input($aData['custom']),
  296. 'return_data_url' => bx_process_input($aData['return_data_url']),
  297. ]);
  298. return $this->_oTemplate->getPopupSubscribe($oBuyer, $oSeller, $aData);
  299. }
  300. public function serviceGetMenuItemAddonAmount()
  301. {
  302. $iProfileId = bx_get_logged_profile_id();
  303. if(!$iProfileId)
  304. return '';
  305. return array(
  306. 'unit' => $this->_oTemplate->getUnit(),
  307. 'value' => $this->convertC2S($this->_oDb->getProfile(array('type' => 'balance', 'id' => $iProfileId)), false)
  308. );
  309. }
  310. /**
  311. * @page service Service Calls
  312. * @section bx_credits Credits
  313. * @subsection bx_credits-page_blocks Page Blocks
  314. * @subsubsection bx_credits-get_block_bundles get_block_bundles
  315. *
  316. * @code bx_srv('bx_credits', 'get_block_bundles'); @endcode
  317. *
  318. * Get page block with bundles
  319. *
  320. * @see BxCreditsModule::serviceGetBlockBundles
  321. */
  322. /**
  323. * @ref bx_credits-get_block_bundles "get_block_bundles"
  324. */
  325. public function serviceGetBlockBundles()
  326. {
  327. $mixedResult = $this->_oTemplate->getBlockBundles();
  328. if($this->_bIsApi)
  329. return [
  330. bx_api_get_block('bundles', $mixedResult)
  331. ];
  332. return $mixedResult;
  333. }
  334. /**
  335. * @page service Service Calls
  336. * @section bx_credits Credits
  337. * @subsection bx_credits-page_blocks Page Blocks
  338. * @subsubsection bx_credits-get_block_orders_note get_block_orders_note
  339. *
  340. * @code bx_srv('bx_credits', 'get_block_orders_note', [...]); @endcode
  341. *
  342. * Get page block with a notice for orders usage.
  343. *
  344. * @return HTML string with block content to display on the site.
  345. *
  346. * @see BxCreditsModule::serviceBlockLicensesNote
  347. */
  348. /**
  349. * @ref bx_credits-get_block_orders_note "get_block_orders_note"
  350. */
  351. public function serviceGetBlockOrdersNote()
  352. {
  353. return MsgBox(_t('_bx_credits_page_block_content_orders_common_note'));
  354. }
  355. /**
  356. * @page service Service Calls
  357. * @section bx_credits Credits
  358. * @subsection bx_credits-page_blocks Page Blocks
  359. * @subsubsection bx_credits-get_block_orders get_block_orders
  360. *
  361. * @code bx_srv('bx_credits', 'get_block_orders', [...]); @endcode
  362. *
  363. * Get page block with a list of orders purchased by currently logged member.
  364. *
  365. * @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.
  366. *
  367. * @see BxCreditsModule::serviceGetBlockOrders
  368. */
  369. /**
  370. * @ref bx_credits-get_block_orders "get_block_orders"
  371. */
  372. public function serviceGetBlockOrders($sType = 'common')
  373. {
  374. return $this->_getBlockOrders($sType);
  375. }
  376. /**
  377. * @page service Service Calls
  378. * @section bx_credits Credits
  379. * @subsection bx_credits-page_blocks Page Blocks
  380. * @subsubsection bx_credits-get_block_history get_block_history
  381. *
  382. * @code bx_srv('bx_credits', 'get_block_history', [...]); @endcode
  383. *
  384. * Get page block with a list of all changes with credits.
  385. *
  386. * @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.
  387. *
  388. * @see BxCreditsModule::serviceGetBlockHistory
  389. */
  390. /**
  391. * @ref bx_credits-get_block_history "get_block_history"
  392. */
  393. public function serviceGetBlockHistory($sType = 'common')
  394. {
  395. return $this->_getBlockHistory($sType);
  396. }
  397. /**
  398. * @page service Service Calls
  399. * @section bx_credits Credits
  400. * @subsection bx_credits-page_blocks Page Blocks
  401. * @subsubsection bx_credits-get_block_withdrawals get_block_withdrawals
  402. *
  403. * @code bx_srv('bx_credits', 'get_block_withdrawals', [...]); @endcode
  404. *
  405. * Get page block with a list of all credits withdrawals.
  406. *
  407. * @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.
  408. *
  409. * @see BxCreditsModule::serviceGetBlockHistory
  410. */
  411. /**
  412. * @ref bx_credits-get_block_withdrawals "get_block_withdrawals"
  413. */
  414. public function serviceGetBlockWithdrawals($sType = 'common')
  415. {
  416. if(!$this->_oConfig->isWithdraw())
  417. return MsgBox (_t('_bx_credits_msg_action_withdrawals_disabled'));
  418. return $this->_getBlockWithdrawals($sType);
  419. }
  420. /**
  421. * @page service Service Calls
  422. * @section bx_credits Credits
  423. * @subsection bx_credits-page_blocks Page Blocks
  424. * @subsubsection bx_credits-get_block_profiles get_block_profiles
  425. *
  426. * @code bx_srv('bx_credits', 'get_block_profiles', [...]); @endcode
  427. *
  428. * Get page block with a list of profiles for managing their parameters.
  429. *
  430. * @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.
  431. *
  432. * @see BxCreditsModule::serviceGetBlockProfiles
  433. */
  434. /**
  435. * @ref bx_credits-get_block_profiles "get_block_profiles"
  436. */
  437. public function serviceGetBlockProfiles($sType = 'common')
  438. {
  439. return $this->_getBlockProfiles($sType);
  440. }
  441. /**
  442. * @page service Service Calls
  443. * @section bx_credits Credits
  444. * @subsection bx_credits-payments Payments
  445. * @subsubsection bx_credits-get_payment_data get_payment_data
  446. *
  447. * @code bx_srv('bx_credits', 'get_payment_data', [...]); @endcode
  448. *
  449. * Get an array with module's description. Is needed for payments processing module.
  450. *
  451. * @return an array with module's description.
  452. *
  453. * @see BxCreditsModule::serviceGetPaymentData
  454. */
  455. /**
  456. * @ref bx_credits-get_payment_data "get_payment_data"
  457. */
  458. public function serviceGetPaymentData()
  459. {
  460. $CNF = &$this->_oConfig->CNF;
  461. $oPermalink = BxDolPermalinks::getInstance();
  462. return array_merge($this->_aModule, [
  463. 'url_browse_order_common' => bx_absolute_url(bx_append_url_params($oPermalink->permalink($CNF['URL_ORDERS_COMMON']), ['filter' => '{order}'], false)),
  464. 'url_browse_order_administration' => bx_absolute_url(bx_append_url_params($oPermalink->permalink($CNF['URL_ORDERS_ADMINISTRATION']), ['filter' => '{order}'], false))
  465. ]);
  466. }
  467. /**
  468. * @page service Service Calls
  469. * @section bx_credits Credits
  470. * @subsection bx_credits-payments Payments
  471. * @subsubsection bx_credits-add_to_cart add_to_cart
  472. *
  473. * @code bx_srv('bx_credits', 'add_to_cart', [...]); @endcode
  474. *
  475. * Adds an item in Shopping Cart. Is needed for payments processing module.
  476. *
  477. * @return an array with module's description.
  478. *
  479. * @see BxCreditsModule::serviceAddToCart
  480. */
  481. /**
  482. * @ref bx_credits-add_to_cart "add_to_cart"
  483. */
  484. public function serviceAddToCart($iItemId)
  485. {
  486. $iVendor = $this->_oConfig->getAuthor();
  487. $oPayments = BxDolPayments::getInstance();
  488. $aResult = $oPayments->addToCart($iVendor, $this->_oConfig->getName(), $iItemId, 1, true);
  489. if(isset($aResult['code']) && (int)$aResult['code'] != 0)
  490. return $this->_bIsApi ? [bx_api_get_msg($aResult['message'])] : $aResult;
  491. return $this->_bIsApi ? [
  492. 'url' => $oPayments->getCartUrl($iVendor)
  493. ] : $aResult;
  494. }
  495. /**
  496. * @page service Service Calls
  497. * @section bx_credits Credits
  498. * @subsection bx_credits-payments Payments
  499. * @subsubsection bx_credits-get_cart_item get_cart_item
  500. *
  501. * @code bx_srv('bx_credits', 'get_cart_item', [...]); @endcode
  502. *
  503. * Get an array with prodict's description. Is used in Shopping Cart in payments processing module.
  504. *
  505. * @param $iItemId product's ID.
  506. * @return an array with prodict's description. Empty array is returned if something is wrong.
  507. *
  508. * @see BxCreditsModule::serviceGetCartItem
  509. */
  510. /**
  511. * @ref bx_credits-get_cart_item "get_cart_item"
  512. */
  513. public function serviceGetCartItem($iItemId)
  514. {
  515. $CNF = &$this->_oConfig->CNF;
  516. if(!$iItemId)
  517. return array();
  518. $aItem = $this->_oDb->getBundle(array('type' => 'id', 'id' => $iItemId));
  519. if(empty($aItem) || !is_array($aItem))
  520. return array();
  521. return array (
  522. 'id' => $aItem[$CNF['FIELD_ID']],
  523. 'author_id' => $this->_oConfig->getAuthor(),
  524. 'name' => $aItem[$CNF['FIELD_NAME']],
  525. 'title' => _t($aItem[$CNF['FIELD_TITLE']]),
  526. 'description' => $this->_oConfig->getBundleDescription($aItem),
  527. 'url' => $this->_oConfig->getBundleUrl($aItem),
  528. 'price_single' => $aItem[$CNF['FIELD_PRICE']],
  529. 'price_recurring' => '',
  530. 'period_recurring' => 1,
  531. 'period_unit_recurring' => '',
  532. 'trial_recurring' => ''
  533. );
  534. }
  535. /**
  536. * @page service Service Calls
  537. * @section bx_credits Credits
  538. * @subsection bx_credits-payments Payments
  539. * @subsubsection bx_credits-get_cart_items get_cart_items
  540. *
  541. * @code bx_srv('bx_credits', 'get_cart_items', [...]); @endcode
  542. *
  543. * Get an array with prodicts' descriptions by seller. Is used in Manual Order Processing in payments processing module.
  544. *
  545. * @param $iSellerId seller ID.
  546. * @return an array with prodicts' descriptions. Empty array is returned if something is wrong or seller doesn't have any products.
  547. *
  548. * @see BxCreditsModule::serviceGetCartItems
  549. */
  550. /**
  551. * @ref bx_credits-get_cart_items "get_cart_items"
  552. */
  553. public function serviceGetCartItems($iSellerId)
  554. {
  555. $CNF = &$this->_oConfig->CNF;
  556. $iAuthorId = $this->_oConfig->getAuthor();
  557. if($iSellerId != $iAuthorId && !BxDolAcl::getInstance()->isMemberLevelInSet([MEMBERSHIP_ID_ADMINISTRATOR], $iSellerId))
  558. return array();
  559. $aItems = $this->_oDb->getBundle(array('type' => 'all', 'active' => 1));
  560. $aResult = array();
  561. foreach($aItems as $aItem)
  562. $aResult[] = array(
  563. 'id' => $aItem[$CNF['FIELD_ID']],
  564. 'author_id' => $iAuthorId,
  565. 'name' => $aItem[$CNF['FIELD_NAME']],
  566. 'title' => _t($aItem[$CNF['FIELD_TITLE']]),
  567. 'description' => $this->_oConfig->getBundleDescription($aItem),
  568. 'url' => $this->_oConfig->getBundleUrl($aItem),
  569. 'price_single' => $aItem[$CNF['FIELD_PRICE']],
  570. 'price_recurring' => '',
  571. 'period_recurring' => 1,
  572. 'period_unit_recurring' => '',
  573. 'trial_recurring' => ''
  574. );
  575. return $aResult;
  576. }
  577. /**
  578. * @page service Service Calls
  579. * @section bx_credits Credits
  580. * @subsection bx_credits-payments Payments
  581. * @subsubsection bx_credits-register_cart_item register_cart_item
  582. *
  583. * @code bx_srv('bx_credits', 'register_cart_item', [...]); @endcode
  584. *
  585. * Register a processed single time payment inside the Credits module. Is called with payment processing module after the payment was registered there.
  586. *
  587. * @param $iClientId client ID.
  588. * @param $iSellerId seller ID
  589. * @param $iItemId item ID.
  590. * @param $iItemCount the number of purchased items.
  591. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  592. * @param $sLicense license number genereted with payment processing module for internal usage
  593. * @return an array with purchased prodict's description. Empty array is returned if something is wrong.
  594. *
  595. * @see BxCreditsModule::serviceRegisterCartItem
  596. */
  597. /**
  598. * @ref bx_credits-register_cart_item "register_cart_item"
  599. */
  600. public function serviceRegisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
  601. {
  602. return $this->_serviceRegisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, BX_CREDITS_ORDER_TYPE_SINGLE);
  603. }
  604. /**
  605. * @page service Service Calls
  606. * @section bx_credits Credits
  607. * @subsection bx_credits-payments Payments
  608. * @subsubsection bx_credits-register_subscription_item register_subscription_item
  609. *
  610. * @code bx_srv('bx_credits', 'register_subscription_item', [...]); @endcode
  611. *
  612. * Register a processed subscription (recurring payment) inside the Credits module. Is called with payment processing module after the subscription was registered there.
  613. *
  614. * @param $iClientId client ID.
  615. * @param $iSellerId seller ID
  616. * @param $iItemId item ID.
  617. * @param $iItemCount the number of purchased items.
  618. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  619. * @param $sLicense license number genereted with payment processing module for internal usage
  620. * @return an array with subscribed prodict's description. Empty array is returned if something is wrong.
  621. *
  622. * @see BxCreditsModule::serviceRegisterSubscriptionItem
  623. */
  624. /**
  625. * @ref bx_credits-register_subscription_item "register_subscription_item"
  626. */
  627. public function serviceRegisterSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
  628. {
  629. return $this->_serviceRegisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, BX_CREDITS_ORDER_TYPE_RECURRING);
  630. }
  631. /**
  632. * @page service Service Calls
  633. * @section bx_credits Credits
  634. * @subsection bx_credits-payments Payments
  635. * @subsubsection bx_credits-reregister_cart_item reregister_cart_item
  636. *
  637. * @code bx_srv('bx_credits', 'reregister_cart_item', [...]); @endcode
  638. *
  639. * Reregister a single time payment inside the Credits module. Is called with payment processing module after the payment was reregistered there.
  640. *
  641. * @param $iClientId client ID.
  642. * @param $iSellerId seller ID
  643. * @param $iItemIdOld old item ID.
  644. * @param $iItemIdNew new item ID.
  645. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  646. * @return an array with purchased prodict's description. Empty array is returned if something is wrong.
  647. *
  648. * @see BxCreditsModule::serviceReregisterCartItem
  649. */
  650. /**
  651. * @ref bx_credits-reregister_cart_item "reregister_cart_item"
  652. */
  653. public function serviceReregisterCartItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
  654. {
  655. return array();
  656. }
  657. /**
  658. * @page service Service Calls
  659. * @section bx_credits Credits
  660. * @subsection bx_credits-payments Payments
  661. * @subsubsection bx_credits-reregister_subscription_item reregister_subscription_item
  662. *
  663. * @code bx_srv('bx_credits', 'reregister_subscription_item', [...]); @endcode
  664. *
  665. * Reregister a subscription (recurring payment) inside the Credits module. Is called with payment processing module after the subscription was reregistered there.
  666. *
  667. * @param $iClientId client ID.
  668. * @param $iSellerId seller ID
  669. * @param $iItemIdOld old item ID.
  670. * @param $iItemIdNew new item ID.
  671. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  672. * @return an array with subscribed prodict's description. Empty array is returned if something is wrong.
  673. *
  674. * @see BxCreditsModule::serviceReregisterSubscriptionItem
  675. */
  676. /**
  677. * @ref bx_credits-reregister_subscription_item "reregister_subscription_item"
  678. */
  679. public function serviceReregisterSubscriptionItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
  680. {
  681. return array();
  682. }
  683. /**
  684. * @page service Service Calls
  685. * @section bx_credits Credits
  686. * @subsection bx_credits-payments Payments
  687. * @subsubsection bx_credits-unregister_cart_item unregister_cart_item
  688. *
  689. * @code bx_srv('bx_credits', 'unregister_cart_item', [...]); @endcode
  690. *
  691. * Unregister an earlier processed single time payment inside the Credits module. Is called with payment processing module after the payment was unregistered there.
  692. *
  693. * @param $iClientId client ID.
  694. * @param $iSellerId seller ID
  695. * @param $iItemId item ID.
  696. * @param $iItemCount the number of purchased items.
  697. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  698. * @param $sLicense license number genereted with payment processing module for internal usage
  699. * @return boolean value determining where the payment was unregistered or not.
  700. *
  701. * @see BxCreditsModule::serviceUnregisterCartItem
  702. */
  703. /**
  704. * @ref bx_credits-unregister_cart_item "unregister_cart_item"
  705. */
  706. public function serviceUnregisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
  707. {
  708. return $this->_serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, BX_CREDITS_ORDER_TYPE_SINGLE);
  709. }
  710. /**
  711. * @page service Service Calls
  712. * @section bx_credits Credits
  713. * @subsection bx_credits-payments Payments
  714. * @subsubsection bx_credits-unregister_subscription_item unregister_subscription_item
  715. *
  716. * @code bx_srv('bx_credits', 'unregister_subscription_item', [...]); @endcode
  717. *
  718. * Unregister an earlier processed subscription (recurring payment) inside the Credits module. Is called with payment processing module after the subscription was unregistered there.
  719. *
  720. * @param $iClientId client ID.
  721. * @param $iSellerId seller ID
  722. * @param $iItemId item ID.
  723. * @param $iItemCount the number of purchased items.
  724. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  725. * @param $sLicense license number genereted with payment processing module for internal usage
  726. * @return boolean value determining where the subscription was unregistered or not.
  727. *
  728. * @see BxCreditsModule::serviceUnregisterSubscriptionItem
  729. */
  730. /**
  731. * @ref bx_credits-unregister_subscription_item "unregister_subscription_item"
  732. */
  733. public function serviceUnregisterSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
  734. {
  735. return $this->_serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, BX_CREDITS_ORDER_TYPE_RECURRING);
  736. }
  737. /**
  738. * @page service Service Calls
  739. * @section bx_credits Credits
  740. * @subsection bx_credits-payments Payments
  741. * @subsubsection bx_credits-cancel_subscription_item cancel_subscription_item
  742. *
  743. * @code bx_srv('bx_credits', 'cancel_subscription_item', [...]); @endcode
  744. *
  745. * Cancel an earlier processed subscription (recurring payment) inside the Credits module. Is called with payment processing module after the subscription was canceled there.
  746. *
  747. * @param $iClientId client ID.
  748. * @param $iSellerId seller ID
  749. * @param $iItemId item ID.
  750. * @param $iItemCount the number of purchased items.
  751. * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
  752. * @return boolean value determining where the subscription was canceled or not.
  753. *
  754. * @see BxCreditsModule::serviceCancelSubscriptionItem
  755. */
  756. /**
  757. * @ref bx_credits-cancel_subscription_item "cancel_subscription_item"
  758. */
  759. public function serviceCancelSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder)
  760. {
  761. return true;
  762. }
  763. /**
  764. * @page service Service Calls
  765. * @section bx_credits Credits
  766. * @subsection bx_credits-other Other
  767. * @subsubsection bx_credits-get_analytics_revenue get_analytics_revenue
  768. *
  769. * @code bx_srv('bx_credits', 'get_analytics_revenue', [['from' => 1700000000, 'to' => 1702592000, 'starts' => [...], 'limit' => 10]]); @endcode
  770. *
  771. * The credits economy for the Analytics module's revenue reports: credits bought, spent on
  772. * checkouts, granted, sent, moved by other modules and withdrawn in a period, with a series
  773. * per time bucket, the top spenders, and the credits members hold now (a liability).
  774. * Analytics finds this service in every installed module, so the module is never named there.
  775. *
  776. * @param $aParams array with:
  777. * a. from - period start (unix time)
  778. * b. to - period end, exclusive (unix time)
  779. * c. starts - bucket starts (unix times, ascending) for the series; a row goes to the latest start before it
  780. * d. limit - rows in top lists
  781. * e. meta - when true, only the title and the unit are returned
  782. * @return array with title (language key), unit (credits), metrics (key => title, value, count, money, series [start => value]), lists (top_spenders => title, rows [profile_id, value]) and snapshot (balance => title, value, holders, money_default)
  783. *
  784. * @see BxCreditsModule::serviceGetAnalyticsRevenue
  785. */
  786. /**
  787. * @ref bx_credits-get_analytics_revenue "get_analytics_revenue"
  788. */
  789. public function serviceGetAnalyticsRevenue($aParams = [])
  790. {
  791. $aResult = [
  792. 'title' => '_bx_credits',
  793. 'unit' => 'credits',
  794. ];
  795. if(!is_array($aParams) || !empty($aParams['meta']))
  796. return $aResult;
  797. $iFrom = isset($aParams['from']) ? (int)$aParams['from'] : 0;
  798. $iTo = isset($aParams['to']) ? (int)$aParams['to'] : time();
  799. $aStarts = isset($aParams['starts']) && is_array($aParams['starts']) ? $aParams['starts'] : [];
  800. $iLimit = isset($aParams['limit']) ? (int)$aParams['limit'] : 10;
  801. // metric => [transfer type, direction]
  802. $aMetrics = [
  803. 'bought' => [BX_CREDITS_TRANSFER_TYPE_PURCHASE, BX_CREDITS_DIRECTION_IN],
  804. 'spent' => [BX_CREDITS_TRANSFER_TYPE_CHECKOUT, BX_CREDITS_DIRECTION_OUT],
  805. 'granted' => [BX_CREDITS_TRANSFER_TYPE_GRANT, BX_CREDITS_DIRECTION_IN],
  806. 'sent' => [BX_CREDITS_TRANSFER_TYPE_SEND, BX_CREDITS_DIRECTION_OUT],
  807. 'service_in' => [BX_CREDITS_TRANSFER_TYPE_SERVICE, BX_CREDITS_DIRECTION_IN],
  808. 'service_out' => [BX_CREDITS_TRANSFER_TYPE_SERVICE, BX_CREDITS_DIRECTION_OUT],
  809. 'withdrawn' => [BX_CREDITS_TRANSFER_TYPE_WITHDRAW, BX_CREDITS_DIRECTION_OUT],
  810. ];
  811. $aTotals = [];
  812. foreach($this->_oDb->getAnalyticsTotals($iFrom, $iTo) as $aRow)
  813. $aTotals[$aRow['type'] . '|' . $aRow['direction']] = $aRow;
  814. $aSeries = [];
  815. foreach($this->_oDb->getAnalyticsSeries($iFrom, $iTo, $aStarts) as $aRow)
  816. $aSeries[$aRow['type'] . '|' . $aRow['direction']][(int)$aRow['bucket']] = (float)$aRow['amount'];
  817. $aWithdrawn = $this->_oDb->getAnalyticsWithdrawn($iFrom, $iTo);
  818. $aResult['metrics'] = [];
  819. foreach($aMetrics as $sMetric => list($sType, $sDirection)) {
  820. $sKey = $sType . '|' . $sDirection;
  821. $fValue = isset($aTotals[$sKey]) ? (float)$aTotals[$sKey]['amount'] : 0;
  822. $aValues = [];
  823. foreach($aStarts as $iStart)
  824. $aValues[(int)$iStart] = isset($aSeries[$sKey][(int)$iStart]) ? $aSeries[$sKey][(int)$iStart] : 0;
  825. $aResult['metrics'][$sMetric] = [
  826. 'title' => '_bx_credits_txt_analytics_' . $sMetric,
  827. 'value' => $fValue,
  828. 'count' => isset($aTotals[$sKey]) ? (int)$aTotals[$sKey]['count'] : 0,
  829. // withdrawals are paid out at their own rate
  830. 'money' => $sMetric == 'withdrawn' ? (float)$aWithdrawn['money'] : $this->_oConfig->convertC2M($fValue),
  831. 'series' => $aValues,
  832. ];
  833. }
  834. $aSpenders = [];
  835. foreach($this->_oDb->getAnalyticsTopSpenders($iFrom, $iTo, $iLimit) as $aRow)
  836. $aSpenders[] = ['profile_id' => (int)$aRow['profile_id'], 'value' => (float)$aRow['amount']];
  837. $aResult['lists'] = [
  838. 'top_spenders' => [
  839. 'title' => '_bx_credits_txt_analytics_top_spenders',
  840. 'rows' => $aSpenders,
  841. ],
  842. ];
  843. $aBalance = $this->_oDb->getAnalyticsBalance();
  844. $aResult['snapshot'] = [
  845. 'balance' => [
  846. 'title' => '_bx_credits_txt_analytics_balance',
  847. 'value' => (float)$aBalance['balance'],
  848. 'holders' => (int)$aBalance['holders'],
  849. 'money_default' => $this->_oConfig->convertC2M((float)$aBalance['balance']),
  850. ],
  851. ];
  852. return $aResult;
  853. }
  854. public function serviceGetProfileBalance($iProfileId = 0)
  855. {
  856. return $this->getProfileBalance($iProfileId);
  857. }
  858. public function serviceUpdateProfileBalance($iFirstPid, $fAmount, $iSecondPid = 0, $sOrder = '', $sInfo = '')
  859. {
  860. if(empty($sInfo))
  861. $sInfo = '_bx_credits_txt_history_info_service';
  862. return $this->updateProfileBalance($iFirstPid, $iSecondPid, $fAmount, BX_CREDITS_TRANSFER_TYPE_SERVICE, $sOrder, $sInfo);
  863. }
  864. public function serviceMakePayment($iBuyerPid, $fAmount, $iSellerPid, $sOrder = '')
  865. {
  866. $sInfo = '_bx_credits_txt_history_info_checkout';
  867. if(!$this->updateProfileBalance($iBuyerPid, $iSellerPid, -$fAmount, BX_CREDITS_TRANSFER_TYPE_CHECKOUT, $sOrder, $sInfo))
  868. return false;
  869. if(!$this->updateProfileBalance($iSellerPid, $iBuyerPid, $fAmount, $sOrder, BX_CREDITS_TRANSFER_TYPE_CHECKOUT, $sInfo)) {
  870. $this->updateProfileBalance($iBuyerPid, 0, $fAmount, BX_CREDITS_TRANSFER_TYPE_CANCELLATION, $sOrder, '_bx_credits_txt_history_info_cancellation');
  871. return false;
  872. }
  873. return true;
  874. }
  875. /**
  876. * Delete all content by profile
  877. * @param $iProfileId profile id
  878. * @return number of deleted items
  879. */
  880. public function serviceDeleteEntitiesByAuthor ($iProfileId)
  881. {
  882. $this->_oDb->deleteProfile(array('id' => $iProfileId));
  883. $this->_oDb->deleteHistory(array('first_pid' => $iProfileId));
  884. }
  885. /*
  886. * Common methods
  887. */
  888. public function convertC2S($fCredits, $bWithUnit = true)
  889. {
  890. $sResult = '';
  891. if($bWithUnit)
  892. $sResult .= $this->_oTemplate->getUnit();
  893. $iPrecision = $this->_oConfig->getPrecision();
  894. $sResult .= sprintf("%01." . $iPrecision . "f", round((float)$fCredits, $iPrecision));
  895. return $sResult;
  896. }
  897. public function getProfileLimits($iProfileId = 0)
  898. {
  899. if(empty($iProfileId))
  900. $iProfileId = bx_get_logged_profile_id();
  901. $aResults = [
  902. 'wdw_clearing' => $this->_oConfig->getWithdrawClearing(),
  903. 'wdw_minimum' => $this->_oConfig->getWithdrawMinimum(),
  904. 'wdw_remaining' => $this->_oConfig->getWithdrawRemaining(),
  905. ];
  906. if(empty($iProfileId))
  907. return $aResults;
  908. $aProfile = $this->_oDb->getProfile(['type' => 'id', 'id' => $iProfileId]);
  909. foreach($aResults as $sKey => $mixedValue)
  910. if(!empty($aProfile[$sKey]))
  911. $aResults[$sKey] = $aProfile[$sKey];
  912. return $aResults;
  913. }
  914. public function getProfileBalance($iProfileId = 0)
  915. {
  916. if(empty($iProfileId))
  917. $iProfileId = bx_get_logged_profile_id();
  918. if(empty($iProfileId))
  919. return 0;
  920. return (float)$this->_oDb->getProfile(array('type' => 'balance', 'id' => $iProfileId));
  921. }
  922. public function getProfileBalanceCleared($iProfileId = 0)
  923. {
  924. if(empty($iProfileId))
  925. $iProfileId = bx_get_logged_profile_id();
  926. if(empty($iProfileId))
  927. return 0;
  928. $fCleared = (float)$this->_oDb->getHistory(['type' => 'cleared', 'profile' => $iProfileId]);
  929. $fSpent = (float)$this->_oDb->getHistory(['type' => 'spent', 'profile' => $iProfileId]);
  930. return $fCleared > $fSpent ? round($fCleared - $fSpent, 2) : 0;
  931. }
  932. public function updateProfileBalance($iFirstPid, $iSecondPid, $fAmount, $sType, $sOrder = '', $sInfo = '', $sData = '')
  933. {
  934. $CNF = &$this->_oConfig->CNF;
  935. if(empty($sOrder))
  936. $sOrder = $this->_oConfig->getOrder();
  937. if(empty($sData))
  938. $sData = serialize(array(
  939. 'conversion' => $this->_oConfig->getConversionRateUse(),
  940. 'precision' => $this->_oConfig->getPrecision()
  941. ));
  942. if(!$this->_oDb->updateProfileBalance($iFirstPid, $fAmount))
  943. return false;
  944. $fAmountAbs = abs($fAmount);
  945. $sDirection = $fAmount > 0 ? BX_CREDITS_DIRECTION_IN : BX_CREDITS_DIRECTION_OUT;
  946. $iHistoryId = $this->_oDb->insertHistory([
  947. 'first_pid' => $iFirstPid,
  948. 'second_pid' => $iSecondPid,
  949. 'amount' => $fAmountAbs,
  950. 'type' => $sType,
  951. 'direction' => $sDirection,
  952. 'order' => $sOrder,
  953. 'data' => $sData,
  954. 'info' => $sInfo,
  955. 'date' => time()
  956. ]);
  957. if(!$iHistoryId)
  958. return false;
  959. /**
  960. * @hooks
  961. * @hookdef hook-bx_credits-update_balance 'bx_credits', 'update_balance' - hook after profile's credits balance was updated (credits were transferred from one profile to another)
  962. * - $unit_name - equals `bx_credits`
  963. * - $action - equals `update_balance`
  964. * - $object_id - not used
  965. * - $sender_id - not used
  966. * - $extra_params - array of additional params with the following array keys:
  967. * - `first_pid` - [int] first profile id
  968. * - `second_pid` - [int] second profile id
  969. * - `amount` - [float] amount was transferred
  970. * - `type` - [string] transfer type: purchase, checkout, cancellation, grant, send, withdraw, service
  971. * - `direction` - [string] transfer direction: in or out
  972. * - `order` - [string] unique order number associated with the transfer
  973. * @hook @ref hook-bx_credits-update_balance
  974. */
  975. bx_alert($this->getName(), 'update_balance', 0, false, [
  976. 'first_pid' => $iFirstPid,
  977. 'second_pid' => $iSecondPid,
  978. 'amount' => $fAmountAbs,
  979. 'type' => $sType,
  980. 'direction' => $sDirection,
  981. 'order' => $sOrder,
  982. ]);
  983. $oSecondProfile = BxDolProfile::getInstanceMagic($iSecondPid);
  984. sendMailTemplate($CNF['ETEMPLATE_' . strtoupper($sDirection)], 0, $iFirstPid, array(
  985. 'second_profile_name' => $oSecondProfile->getDisplayName(),
  986. 'amount' => $fAmountAbs,
  987. ));
  988. return $iHistoryId;
  989. }
  990. public function processGrant($iUserId, $iProfileId, $fAmount, $sMessage = '')
  991. {
  992. $CNF = &$this->_oConfig->CNF;
  993. $oProfile = BxDolProfile::getInstance($iProfileId);
  994. if(!$oProfile)
  995. return ['code' => 2, 'msg' => '_bx_credits_err_profile_not_found'];
  996. $sInfo = '_bx_credits_txt_history_info_grant';
  997. $iHistoryId = $this->updateProfileBalance($iProfileId, 0, $fAmount, BX_CREDITS_TRANSFER_TYPE_GRANT, '', $sInfo);
  998. if(!$iHistoryId)
  999. return ['code' => 3, 'msg' => '_bx_credits_err_cannot_update_balance'];
  1000. sendMailTemplate($CNF['ETEMPLATE_GRANTED'], 0, $iProfileId, [
  1001. 'amount' => $fAmount,
  1002. 'message' => $sMessage
  1003. ]);
  1004. /**
  1005. * @hooks
  1006. * @hookdef hook-bx_credits-granted 'bx_credits', 'granted' - hook after some amount of credits was granted to a profile
  1007. * - $unit_name - equals `bx_credits`
  1008. * - $action - equals `granted`
  1009. * - $object_id - not used
  1010. * - $sender_id - not used
  1011. * - $extra_params - array of additional params with the following array keys:
  1012. * - `profile` - [int] recipient profile id
  1013. * - `amount` - [float] amount was granted
  1014. * @hook @ref hook-bx_credits-granted
  1015. */
  1016. bx_alert($this->getName(), 'granted', 0, false, [
  1017. 'profile' => $iProfileId,
  1018. 'amount' => $fAmount,
  1019. ]);
  1020. return ['code' => 0, 'id' => $iHistoryId];
  1021. }
  1022. public function processSend($iUserId, $iProfileId, $fAmount, $sMessage = '')
  1023. {
  1024. $CNF = &$this->_oConfig->CNF;
  1025. $fAmountAvail = $this->getProfileBalance($iUserId);
  1026. if($fAmount > $fAmountAvail)
  1027. return ['code' => 1, 'msg' => '_bx_credits_err_low_balance'];
  1028. $oProfile = null;
  1029. if(!$iProfileId || !($oProfile = BxDolProfile::getInstance($iProfileId)))
  1030. return ['code' => 2, 'msg' => '_bx_credits_err_profile_not_found'];
  1031. $sOrder = $this->_oConfig->getOrder();
  1032. $sInfo = !empty($sMessage) ? $sMessage : '_bx_credits_txt_history_info_send';
  1033. $iHistoryId = $this->updateProfileBalance($iUserId, $iProfileId, -$fAmount, BX_CREDITS_TRANSFER_TYPE_SEND, $sOrder, $sInfo);
  1034. if(!$iHistoryId)
  1035. return ['code' => 3, 'msg' => '_bx_credits_err_cannot_update_balance'];
  1036. if(!$this->updateProfileBalance($iProfileId, $iUserId, $fAmount, BX_CREDITS_TRANSFER_TYPE_SEND, $sOrder, $sInfo)) {
  1037. $sInfo = '_bx_credits_txt_history_info_cancellation';
  1038. $iHistoryId = $this->updateProfileBalance($iUserId, 0, $fAmount, BX_CREDITS_TRANSFER_TYPE_CANCELLATION, $sOrder, $sInfo);
  1039. return ['code' => 3, 'id' => $iHistoryId, 'msg' => '_bx_credits_err_cannot_update_balance'];
  1040. }
  1041. $oUser = BxDolProfile::getInstance($iUserId);
  1042. sendMailTemplate($CNF['ETEMPLATE_RECEIVED'], 0, $iProfileId, [
  1043. 'performer_id' => $iUserId,
  1044. 'performer_name' => $oUser->getDisplayName(),
  1045. 'performer_link' => $oUser->getUrl(),
  1046. 'amount' => $fAmount,
  1047. 'order' => $sOrder,
  1048. 'message' => $sMessage
  1049. ]);
  1050. /**
  1051. * @hooks
  1052. * @hookdef hook-bx_credits-sent 'bx_credits', 'sent' - hook after some amount of credits was sent from one profile to another
  1053. * - $unit_name - equals `bx_credits`
  1054. * - $action - equals `sent`
  1055. * - $object_id - not used
  1056. * - $sender_id - sender profile id
  1057. * - $extra_params - array of additional params with the following array keys:
  1058. * - `performer` - [int] sender profile id
  1059. * - `profile` - [int] recipient profile id
  1060. * - `amount` - [float] amount was sent
  1061. * - `order` - [string] unique order number associated with 'sent' action
  1062. * @hook @ref hook-bx_credits-sent
  1063. */
  1064. bx_alert($this->getName(), 'sent', 0, $iUserId, [
  1065. 'performer' => $iUserId,
  1066. 'profile' => $iProfileId,
  1067. 'amount' => $fAmount,
  1068. 'order' => $sOrder,
  1069. ]);
  1070. return ['code' => 0, 'id' => $iHistoryId];
  1071. }
  1072. public function processWithdrawRequest($iUserId, $iProfileId, $fAmount, $sMessage = '')
  1073. {
  1074. $CNF = &$this->_oConfig->CNF;
  1075. if(empty($iProfileId))
  1076. $iProfileId = bx_get_logged_profile_id ();
  1077. if(empty($iProfileId))
  1078. return ['code' => 1, 'msg' => '_bx_credits_err_login_required'];
  1079. $oProfile = BxDolProfile::getInstance($iProfileId);
  1080. if(!$oProfile)
  1081. return ['code' => 1, 'msg' => '_bx_credits_err_login_required'];
  1082. $fBalanceCleared = $this->getProfileBalanceCleared($iProfileId);
  1083. if($fAmount > $fBalanceCleared)
  1084. return ['code' => 2, 'msg' => '_bx_credits_err_low_balance'];
  1085. $aProfileInfo = $this->_oDb->getProfile(['type' => 'id', 'id' => $iProfileId]);
  1086. $iWithdrawMinimum = !empty($aProfileInfo['wdw_minimum']) ? (int)$aProfileInfo['wdw_minimum'] : (int)getParam($CNF['PARAM_WITHDRAW_MINIMUM']);
  1087. if($fAmount < $iWithdrawMinimum)
  1088. return ['code' => 3, 'msg' => _t('_bx_credits_err_withdraw_minimum', $iWithdrawMinimum)];
  1089. $fBalance = $this->getProfileBalance($iProfileId);
  1090. $iWithdrawRemaining = !empty($aProfileInfo['wdw_remaining']) ? (int)$aProfileInfo['wdw_remaining'] : (int)getParam($CNF['PARAM_WITHDRAW_REMAINING']);
  1091. if(($fBalance - $fAmount) < $iWithdrawRemaining)
  1092. return ['code' => 4, 'msg' => _t('_bx_credits_err_withdraw_remaining', $iWithdrawRemaining)];
  1093. $aResult = ['code' => 5, 'msg' => '_bx_credits_err_cannot_send'];
  1094. $fRate = $this->_oConfig->getConversionRateWithdraw();
  1095. $iId = $this->_oDb->insertWithdrawal([
  1096. 'profile_id' => $iProfileId,
  1097. 'amount' => $fAmount,
  1098. 'rate' => $fRate,
  1099. 'message' => $sMessage,
  1100. 'added' => time()
  1101. ]);
  1102. if(!$iId)
  1103. return $aResult;
  1104. $aTemplateVars = [
  1105. 'profile_link' => $oProfile->getUrl(),
  1106. 'profile_name' => $oProfile->getDisplayName(),
  1107. 'amount' => $fAmount,
  1108. 'rate' => $fRate,
  1109. 'message' => $sMessage,
  1110. 'confirm_url' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_HISTORY_ADMINISTRATION']))
  1111. ];
  1112. $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($CNF['ETEMPLATE_WITHDRAW_REQUESTED'], $aTemplateVars);
  1113. if(!$aTemplate)
  1114. return $aResult;
  1115. $sEmail = $this->_oConfig->getWithdrawEmail();
  1116. if(!sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, [], BX_EMAIL_SYSTEM))
  1117. return $aResult;
  1118. /**
  1119. * @hooks
  1120. * @hookdef hook-bx_credits-withdraw_requested 'bx_credits', 'withdraw_requested' - hook after a profile requested to withdraw some amount of credits from his balance
  1121. * - $unit_name - equals `bx_credits`
  1122. * - $action - equals `withdraw_requested`
  1123. * - $object_id - not used
  1124. * - $sender_id - performer profile id
  1125. * - $extra_params - array of additional params with the following array keys:
  1126. * - `profile` - [int] performer profile id
  1127. * - `amount` - [float] amount to withdraw
  1128. * - `rate` - [float] withdraw conversion rate
  1129. * @hook @ref hook-bx_credits-withdraw_requested
  1130. */
  1131. bx_alert($this->getName(), 'withdraw_requested', 0, $iProfileId, [
  1132. 'profile' => $iProfileId,
  1133. 'amount' => $fAmount,
  1134. 'rate' => $fRate
  1135. ]);
  1136. return ['code' => 0, 'id' => $iId];
  1137. }
  1138. public function processWithdrawCancel($iId)
  1139. {
  1140. $CNF = &$this->_oConfig->CNF;
  1141. $aWithdrawal = $this->_oDb->getWithdrawal(['type' => 'id', 'id' => $iId]);
  1142. if(empty($aWithdrawal) || !is_array($aWithdrawal))
  1143. return ['code' => 1, 'msg' => '_bx_credits_err_withdrawal_not_found'];
  1144. $iProfileId = (int)$aWithdrawal['profile_id'];
  1145. $oProfile = BxDolProfile::getInstance($iProfileId);
  1146. if(!$oProfile)
  1147. return ['code' => 2, 'msg' => '_bx_credits_err_profile_not_found'];
  1148. $aResult = ['code' => 3, 'msg' => '_bx_credits_err_cannot_cancel_withdrawal'];
  1149. $aTemplateVars = [
  1150. 'profile_link' => $oProfile->getUrl(),
  1151. 'profile_name' => $oProfile->getDisplayName(),
  1152. 'amount' => $aWithdrawal['amount'],
  1153. 'manage_url' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_WITHDRAWALS_ADMINISTRATION']))
  1154. ];
  1155. $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($CNF['ETEMPLATE_WITHDRAW_CANCELED'], $aTemplateVars);
  1156. if(!$aTemplate)
  1157. return $aResult;
  1158. $sEmail = $this->_oConfig->getWithdrawEmail();
  1159. if(!sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, [], BX_EMAIL_SYSTEM))
  1160. return $aResult;
  1161. if(!$this->_oDb->updateWithdrawal(['status' => BX_CREDITS_WITHDRAWAL_STATUS_CANCELED], ['id' => $iId]))
  1162. return $aResult;
  1163. /**
  1164. * @hooks
  1165. * @hookdef hook-bx_credits-withdraw_canceled 'bx_credits', 'withdraw_canceled' - hook after a profile canceled his withdrawal request
  1166. * - $unit_name - equals `bx_credits`
  1167. * - $action - equals `withdraw_canceled`
  1168. * - $object_id - not used
  1169. * - $sender_id - performer profile id
  1170. * - $extra_params - array of additional params with the following array keys:
  1171. * - `profile` - [int] performer profile id
  1172. * - `amount` - [float] amount to withdraw
  1173. * - `rate` - [float] withdraw conversion rate
  1174. * @hook @ref hook-bx_credits-withdraw_canceled
  1175. */
  1176. bx_alert($this->getName(), 'withdraw_canceled', $iId, $iProfileId, [
  1177. 'profile' => $iProfileId,
  1178. 'amount' => $aWithdrawal['amount'],
  1179. ]);
  1180. return ['code' => 0, 'id' => $iId];
  1181. }
  1182. public function processWithdrawConfirm($iUserId, $iWithdrawalId)
  1183. {
  1184. $CNF = &$this->_oConfig->CNF;
  1185. $aWithdrawal = $this->_oDb->getWithdrawal(['type' => 'id', 'id' => $iWithdrawalId]);
  1186. if(empty($aWithdrawal) || !is_array($aWithdrawal))
  1187. return ['code' => 1, 'msg' => '_bx_credits_err_withdrawal_not_found'];
  1188. $iProfileId = (int)$aWithdrawal['profile_id'];
  1189. $oProfile = BxDolProfile::getInstance($iProfileId);
  1190. if(!$oProfile)
  1191. return ['code' => 2, 'msg' => '_bx_credits_err_profile_not_found'];
  1192. $fAmount = (float)$aWithdrawal['amount'];
  1193. $fBalance = $this->getProfileBalance($iProfileId);
  1194. if($fAmount > $fBalance)
  1195. return ['code' => 3, 'msg' => '_bx_credits_err_low_balance'];
  1196. $sInfo = '_bx_credits_txt_history_info_withdraw';
  1197. $iHistoryId = $this->updateProfileBalance($iProfileId, 0, -$fAmount, BX_CREDITS_TRANSFER_TYPE_WITHDRAW, '', $sInfo);
  1198. if(!$iHistoryId)
  1199. return ['code' => 4, 'msg' => '_bx_credits_err_cannot_update_balance'];
  1200. $aHistory = $this->_oDb->getHistory(['type' => 'id', 'id' => $iHistoryId]);
  1201. if(!$this->_oDb->updateWithdrawal(['performer_id' => $iUserId, 'order' => $aHistory['order'], 'confirmed' => time(), 'status' => BX_CREDITS_WITHDRAWAL_STATUS_CONFIRMED], ['id' => $iWithdrawalId]))
  1202. return $aResult;
  1203. sendMailTemplate($CNF['ETEMPLATE_WITHDRAW_SENT'], 0, $iProfileId, [
  1204. 'amount' => $fAmount
  1205. ], BX_EMAIL_SYSTEM);
  1206. /**
  1207. * @hooks
  1208. * @hookdef hook-bx_credits-withdraw_sent 'bx_credits', 'withdraw_sent' - hook after the amount of credits requested to withdraw was sent
  1209. * - $unit_name - equals `bx_credits`
  1210. * - $action - equals `withdraw_sent`
  1211. * - $object_id - not used
  1212. * - $sender_id - performer profile id
  1213. * - $extra_params - array of additional params with the following array keys:
  1214. * - `profile` - [int] performer profile id
  1215. * - `amount` - [float] amount to withdraw
  1216. * - `rate` - [float] withdraw conversion rate
  1217. * @hook @ref hook-bx_credits-withdraw_sent
  1218. */
  1219. bx_alert($this->getName(), 'withdraw_sent', $iWithdrawalId, $iUserId, [
  1220. 'performer' => $iUserId,
  1221. 'profile' => $iProfileId,
  1222. 'amount' => $fAmount,
  1223. ]);
  1224. return ['code' => 0, 'id' => $iWithdrawalId];
  1225. }
  1226. public function processClearing()
  1227. {
  1228. $CNF = &$this->_oConfig->CNF;
  1229. $aItems = $this->_oDb->getHistory(['type' => 'clearing', 'clearing' => $this->_oConfig->getWithdrawClearing()]);
  1230. if(empty($aItems) || !is_array($aItems))
  1231. return;
  1232. $iNow = time();
  1233. foreach($aItems as $aItem) {
  1234. $this->_oDb->updateHistory([$CNF['FIELD_H_CLEARED'] => $iNow], [$CNF['FIELD_H_ID'] => $aItem['id']]);
  1235. //TODO: Some action(s) related to clearing can be performed here.
  1236. }
  1237. }
  1238. /*
  1239. * Internal methods
  1240. */
  1241. protected function _serviceRegisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType)
  1242. {
  1243. $CNF = &$this->_oConfig->CNF;
  1244. $aItem = $this->serviceGetCartItem($iItemId);
  1245. if(empty($aItem) || !is_array($aItem))
  1246. return array();
  1247. $aBundle = $this->_oDb->getBundle(array('type' => 'id', 'id' => $iItemId));
  1248. if(empty($aBundle) || !is_array($aBundle))
  1249. return array();
  1250. $iTrial = 0;
  1251. $sDuration = '';
  1252. $sAction = 'register';
  1253. if($sType == BX_CREDITS_ORDER_TYPE_RECURRING && isset($CNF['FIELD_DURATION_RECURRING'], $CNF['FIELD_TRIAL_RECURRING'])) {
  1254. $iTrial = $aBundle[$CNF['FIELD_TRIAL_RECURRING']];
  1255. $sDuration = $aBundle[$CNF['FIELD_DURATION_RECURRING']];
  1256. if($this->_oDb->isOrderByPbo($iClientId, $iItemId, $sOrder))
  1257. $sAction = 'prolong';
  1258. }
  1259. if(!$this->_oDb->{$sAction . 'Order'}($iClientId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType, $sDuration, $iTrial))
  1260. return array();
  1261. $sInfo = '_bx_credits_txt_history_info_purchase';
  1262. $fAmount = ((float)$aBundle[$CNF['FIELD_AMOUNT']] + (float)$aBundle[$CNF['FIELD_BONUS']]) * $iItemCount;
  1263. if(!$this->updateProfileBalance($iClientId, 0, $fAmount, BX_CREDITS_TRANSFER_TYPE_PURCHASE, '', $sInfo))
  1264. return array();
  1265. /**
  1266. * @hooks
  1267. * @hookdef hook-bx_credits-order_register 'bx_credits', 'order_register' - hook after the payment for a bundle of credits was processed with payment processing module
  1268. * - $unit_name - equals `bx_credits`
  1269. * - $action - equals `order_register`
  1270. * - $object_id - not used
  1271. * - $sender_id - not used
  1272. * - $extra_params - array of additional params with the following array keys:
  1273. * - `profile_id` - [int] client (buyer) profile id
  1274. * - `bundle_id` - [int] bundle id
  1275. * - `product_id` - [int] bundle id
  1276. * - `count` - [int] number of items in order
  1277. * - `order` - [string] order number provided with payment processing module
  1278. * - `license` - [string] license number provided with payment processing module
  1279. * - `type` - [string] payment type ('single' or 'recurring'), current version supports 'single' type payments for bundles only
  1280. * - `duration` - [string] isn't supported
  1281. * - `trial` - [string] isn't supported
  1282. * @hook @ref hook-bx_credits-order_register
  1283. */
  1284. /**
  1285. * @hooks
  1286. * @hookdef hook-bx_credits-order_prolong 'bx_credits', 'order_prolong' - hook isn't currently used because 'single' type payments for bundles are only supported
  1287. * It's equivalent to @ref hook-bx_credits-order_register
  1288. * @hook @ref hook-bx_credits-order_prolong
  1289. */
  1290. bx_alert($this->getName(), 'order_' . $sAction, 0, false, [
  1291. 'profile_id' => $iClientId,
  1292. 'bundle_id' => $iItemId,
  1293. 'product_id' => $iItemId, //--- Alias for 'bundle_id'
  1294. 'count' => $iItemCount,
  1295. 'order' => $sOrder,
  1296. 'license' => $sLicense,
  1297. 'type' => $sType,
  1298. 'duration' => $sDuration,
  1299. 'trial' => $iTrial
  1300. ]);
  1301. $oClient = BxDolProfile::getInstanceMagic($iClientId);
  1302. $oSeller = BxDolProfile::getInstanceMagic($iSellerId);
  1303. $sSellerUrl = $oSeller->getUrl();
  1304. $sSellerName = $oSeller->getDisplayName();
  1305. sendMailTemplate($CNF['ETEMPLATE_PURCHASED'], 0, $iClientId, array(
  1306. 'client_name' => $oClient->getDisplayName(),
  1307. 'bundle_name' => $aBundle[$CNF['FIELD_NAME']],
  1308. 'bundle_title' => _t($aBundle[$CNF['FIELD_TITLE']]),
  1309. 'bundle_url' => $this->_oConfig->getBundleUrl($aBundle),
  1310. 'vendor_url' => $sSellerUrl,
  1311. 'vendor_name' => $sSellerName,
  1312. 'order' => $sOrder,
  1313. 'license' => $sLicense,
  1314. 'notes' => _t('_bx_credits_txt_purchased_note', $sSellerUrl, $sSellerName),
  1315. ));
  1316. return $aItem;
  1317. }
  1318. protected function _serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType)
  1319. {
  1320. $CNF = &$this->_oConfig->CNF;
  1321. $aBundle = $this->_oDb->getBundle(array('type' => 'id', 'id' => $iItemId));
  1322. if(empty($aBundle) || !is_array($aBundle))
  1323. return false;
  1324. if(!$this->_oDb->unregisterOrder($iClientId, $iItemId, $sOrder, $sLicense, $sType))
  1325. return false;
  1326. $fAmount = (float)$aBundle[$CNF['FIELD_AMOUNT']] + (float)$aBundle[$CNF['FIELD_BONUS']];
  1327. $aProfile = $this->_oDb->getProfile(array('type' => 'id', 'id' => $iClientId));
  1328. if(!empty($aProfile) && is_array($aProfile))
  1329. $this->_oDb->updateProfile(array('balance' => (float)$aProfile['balance'] - $fAmount), array('id' => $aProfile['id']));
  1330. /**
  1331. * @hooks
  1332. * @hookdef hook-bx_credits-order_unregister 'bx_credits', 'order_unregister' - hook after the payment for a bundle of credits was refunded with payment processing module
  1333. * - $unit_name - equals `bx_credits`
  1334. * - $action - equals `order_unregister`
  1335. * - $object_id - not used
  1336. * - $sender_id - not used
  1337. * - $extra_params - array of additional params with the following array keys:
  1338. * - `profile_id` - [int] client (buyer) profile id
  1339. * - `bundle_id` - [int] bundle id
  1340. * - `product_id` - [int] bundle id
  1341. * - `count` - [int] number of items in order
  1342. * - `order` - [string] order number provided with payment processing module
  1343. * - `license` - [string] license number provided with payment processing module
  1344. * - `type` - [string] payment type ('single' or 'recurring'), current version supports 'single' type payments for bundles only
  1345. * @hook @ref hook-bx_credits-order_unregister
  1346. */
  1347. bx_alert($this->getName(), 'order_unregister', 0, false, [
  1348. 'profile_id' => $iClientId,
  1349. 'bundle_id' => $iItemId,
  1350. 'product_id' => $iItemId, //--- Alias for 'bundle_id'
  1351. 'count' => $iItemCount,
  1352. 'order' => $sOrder,
  1353. 'license' => $sLicense,
  1354. 'type' => $sType,
  1355. ]);
  1356. return true;
  1357. }
  1358. protected function _getBlockOrders($sType)
  1359. {
  1360. $CNF = &$this->_oConfig->CNF;
  1361. return $this->_getBlockGrid($CNF['OBJECT_GRID_ORDERS_' . strtoupper($sType)]);
  1362. }
  1363. protected function _getBlockHistory($sType)
  1364. {
  1365. $CNF = &$this->_oConfig->CNF;
  1366. return $this->_getBlockGrid($CNF['OBJECT_GRID_HISTORY_' . strtoupper($sType)]);
  1367. }
  1368. protected function _getBlockWithdrawals($sType)
  1369. {
  1370. $CNF = &$this->_oConfig->CNF;
  1371. return $this->_getBlockGrid($CNF['OBJECT_GRID_WITHDRAWALS_' . strtoupper($sType)]);
  1372. }
  1373. protected function _getBlockProfiles($sType)
  1374. {
  1375. $CNF = &$this->_oConfig->CNF;
  1376. return $this->_getBlockGrid($CNF['OBJECT_GRID_PROFILES_' . strtoupper($sType)]);
  1377. }
  1378. protected function _getBlockGrid($sGrid)
  1379. {
  1380. $CNF = &$this->_oConfig->CNF;
  1381. $oGrid = null;
  1382. if(!$sGrid || !($oGrid = BxDolGrid::getObjectInstance($sGrid)))
  1383. return $this->_bIsApi ? [] : '';
  1384. $sMenu = $CNF['OBJECT_MENU_MANAGE_SUBMENU'];
  1385. return $this->_bIsApi ? [
  1386. 'content' => [bx_api_get_block('grid', $oGrid->getCodeAPI())],
  1387. 'menu' => ($oMenu = BxTemplMenu::getObjectInstance($sMenu)) ? $oMenu->getCodeAPI() : ''
  1388. ] : [
  1389. 'content' => $oGrid->getCode(),
  1390. 'menu' => $sMenu
  1391. ];
  1392. }
  1393. }
  1394. /** @} */