BxCreditsModule.php 38 KB

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