/modules/sale/lib/internals/userbudgetpool.php

https://gitlab.com/alexprowars/bitrix · PHP · 328 lines · 228 code · 50 blank · 50 comment · 30 complexity · 2d952350c28eab4af34fc565575f65e2 MD5 · raw file

  1. <?php
  2. namespace Bitrix\Sale\Internals;
  3. use Bitrix\Main\Localization\Loc;
  4. use Bitrix\Sale;
  5. use Bitrix\Main;
  6. Loc::loadMessages(__FILE__);
  7. class UserBudgetPool
  8. {
  9. private const STATUS_LOCKED_NOW = 1;
  10. private const STATUS_LOCKED_EARLIER = -1;
  11. private const STATUS_NOT_LOCKED = 0;
  12. private $statusLock = self::STATUS_NOT_LOCKED;
  13. private $userId;
  14. protected static $userBudgetPool = [];
  15. protected $items = [];
  16. const BUDGET_TYPE_ORDER_CANCEL_PART = 'ORDER_CANCEL_PART';
  17. const BUDGET_TYPE_ORDER_UNPAY = 'ORDER_UNPAY';
  18. const BUDGET_TYPE_ORDER_PART_RETURN = 'ORDER_PART_RETURN';
  19. const BUDGET_TYPE_OUT_CHARGE_OFF = 'OUT_CHARGE_OFF';
  20. const BUDGET_TYPE_EXCESS_SUM_PAID = 'EXCESS_SUM_PAID';
  21. const BUDGET_TYPE_MANUAL = 'MANUAL';
  22. const BUDGET_TYPE_ORDER_PAY = 'ORDER_PAY';
  23. const BUDGET_TYPE_ORDER_PAY_PART = 'ORDER_PAY_PART';
  24. protected function __construct($userId)
  25. {
  26. $this->userId = $userId;
  27. }
  28. /**
  29. * @param $sum
  30. * @param $budgetType
  31. * @param Sale\Order $order
  32. * @param Sale\Payment|null $payment
  33. * @throws Main\Db\SqlQueryException
  34. */
  35. public function add($sum, $budgetType, Sale\Order $order, Sale\Payment $payment = null)
  36. {
  37. if (!$this->isLocked())
  38. {
  39. $this->lock();
  40. }
  41. if ($this->isStatusLockEarlier())
  42. {
  43. return;
  44. }
  45. $fields = [
  46. "SUM" => $sum,
  47. "CURRENCY" => $order->getCurrency(),
  48. "TYPE" => $budgetType,
  49. "ORDER" => $order,
  50. ];
  51. if ($payment !== null)
  52. {
  53. $fields['PAYMENT'] = $payment;
  54. }
  55. $this->items[] = $fields;
  56. }
  57. /**
  58. * @throws Main\Db\SqlQueryException
  59. */
  60. protected function lock()
  61. {
  62. if ($this->statusLock === self::STATUS_NOT_LOCKED)
  63. {
  64. $connection = Main\Application::getConnection();
  65. $name = $connection->getSqlHelper()->forSql($this->getUniqLockName());
  66. $dbRes = $connection->query("SELECT GET_LOCK('{$name}', 0) as L");
  67. $result = $dbRes->fetch();
  68. if ($result['L'] === '0')
  69. {
  70. $this->statusLock = self::STATUS_LOCKED_EARLIER;
  71. return;
  72. }
  73. $this->statusLock = self::STATUS_LOCKED_NOW;
  74. }
  75. }
  76. private function getUniqLockName() : string
  77. {
  78. return "user_budget_{$this->userId}";
  79. }
  80. /**
  81. * @throws Main\Db\SqlQueryException
  82. * @return void
  83. */
  84. protected function unlock()
  85. {
  86. if ($this->statusLock === self::STATUS_LOCKED_NOW)
  87. {
  88. $connection = Main\Application::getConnection();
  89. $name = $connection->getSqlHelper()->forSql($this->getUniqLockName());
  90. $connection->query("SELECT RELEASE_LOCK('{$name}')");
  91. $this->statusLock = self::STATUS_NOT_LOCKED;
  92. }
  93. }
  94. protected function isLocked()
  95. {
  96. return
  97. $this->statusLock === self::STATUS_LOCKED_EARLIER
  98. || $this->statusLock === self::STATUS_LOCKED_NOW
  99. ;
  100. }
  101. protected function isStatusLockEarlier()
  102. {
  103. return $this->statusLock === self::STATUS_LOCKED_EARLIER;
  104. }
  105. /**
  106. * @return array|false
  107. */
  108. public function get()
  109. {
  110. if (isset($this->items))
  111. {
  112. return $this->items;
  113. }
  114. return false;
  115. }
  116. /**
  117. * @param $index
  118. * @return bool
  119. * @throws Main\Db\SqlQueryException
  120. */
  121. public function delete($index)
  122. {
  123. if (isset($this->items) && isset($this->items[$index]))
  124. {
  125. unset($this->items[$index]);
  126. if (count($this->items) === 0)
  127. {
  128. $this->unlock();
  129. }
  130. return true;
  131. }
  132. return false;
  133. }
  134. /**
  135. * @param $userId
  136. * @return UserBudgetPool
  137. */
  138. public static function getUserBudgetPool($userId)
  139. {
  140. if (!isset(static::$userBudgetPool[$userId]))
  141. {
  142. static::$userBudgetPool[$userId] = new static($userId);
  143. }
  144. return static::$userBudgetPool[$userId];
  145. }
  146. /**
  147. * @param Sale\Order $order
  148. * @param $value
  149. * @param $type
  150. * @param Sale\Payment|null $payment
  151. * @throws Main\Db\SqlQueryException
  152. */
  153. public static function addPoolItem(Sale\Order $order, $value, $type, Sale\Payment $payment = null)
  154. {
  155. if (floatval($value) == 0)
  156. return;
  157. $userId = $order->getUserId();
  158. $pool = static::getUserBudgetPool($userId);
  159. $pool->add($value, $type, $order, $payment);
  160. }
  161. /**
  162. * @param $userId
  163. * @return Sale\Result
  164. */
  165. public static function onUserBudgetSave($userId)
  166. {
  167. $result = new Sale\Result();
  168. $pool = static::getUserBudgetPool($userId);
  169. if ($pool->isStatusLockEarlier())
  170. {
  171. return $result->addError(
  172. new Sale\ResultError(
  173. Loc::getMessage('SALE_PROVIDER_USER_BUDGET_LOCKED')
  174. )
  175. );
  176. }
  177. foreach ($pool->get() as $key => $budgetDat)
  178. {
  179. $orderId = null;
  180. $paymentId = null;
  181. if (isset($budgetDat['ORDER'])
  182. && ($budgetDat['ORDER'] instanceof Sale\OrderBase))
  183. {
  184. $orderId = $budgetDat['ORDER']->getId();
  185. }
  186. if (isset($budgetDat['PAYMENT'])
  187. && ($budgetDat['PAYMENT'] instanceof Sale\Payment))
  188. {
  189. $paymentId = $budgetDat['PAYMENT']->getId();
  190. }
  191. if (!\CSaleUserAccount::UpdateAccount($userId, $budgetDat['SUM'], $budgetDat['CURRENCY'], $budgetDat['TYPE'], $orderId, '', $paymentId))
  192. {
  193. $result->addError( new Sale\ResultError(Loc::getMessage("SALE_PROVIDER_USER_BUDGET_".$budgetDat['TYPE']."_ERROR"), "SALE_PROVIDER_USER_BUDGET_".$budgetDat['TYPE']."_ERROR") );
  194. }
  195. $pool->delete($key);
  196. }
  197. return $result;
  198. }
  199. /**
  200. * @param Sale\Order $order
  201. * @return int
  202. */
  203. public static function getUserBudgetTransForOrder(Sale\Order $order)
  204. {
  205. $ignoreTypes = array(
  206. static::BUDGET_TYPE_ORDER_PAY
  207. );
  208. $sumTrans = 0;
  209. if ($order->getId() > 0)
  210. {
  211. $resTrans = \CSaleUserTransact::GetList(
  212. array("TRANSACT_DATE" => "DESC"),
  213. array(
  214. "ORDER_ID" => $order->getId(),
  215. ),
  216. false,
  217. false,
  218. array("AMOUNT", "CURRENCY", "DEBIT")
  219. );
  220. while ($transactDat = $resTrans->Fetch())
  221. {
  222. if ($transactDat['DEBIT'] == "Y")
  223. {
  224. $sumTrans += $transactDat['AMOUNT'];
  225. }
  226. else
  227. {
  228. $sumTrans -= $transactDat['AMOUNT'];
  229. }
  230. }
  231. }
  232. if ($userBudgetPool = static::getUserBudgetPool($order->getUserId()))
  233. {
  234. foreach ($userBudgetPool->get() as $userBudgetDat)
  235. {
  236. if (in_array($userBudgetDat['TYPE'], $ignoreTypes))
  237. continue;
  238. $sumTrans += $userBudgetDat['SUM'];
  239. }
  240. }
  241. return $sumTrans;
  242. }
  243. /**
  244. * @param Sale\Order $order
  245. * @return int
  246. */
  247. public static function getUserBudgetByOrder(Sale\Order $order)
  248. {
  249. $budget = static::getUserBudget($order->getUserId(), $order->getCurrency());
  250. if ($userBudgetPool = static::getUserBudgetPool($order->getUserId()))
  251. {
  252. foreach ($userBudgetPool->get() as $userBudgetDat)
  253. {
  254. $budget += $userBudgetDat['SUM'];
  255. }
  256. }
  257. return $budget;
  258. }
  259. /**
  260. * @param $userId
  261. * @param $currency
  262. * @return float|null
  263. */
  264. public static function getUserBudget($userId, $currency)
  265. {
  266. $budget = null;
  267. if ($userAccount = \CSaleUserAccount::GetByUserId($userId, $currency))
  268. {
  269. if ($userAccount['LOCKED'] != 'Y')
  270. $budget = floatval($userAccount['CURRENT_BUDGET']);
  271. }
  272. return $budget;
  273. }
  274. public function __destruct()
  275. {
  276. $this->unlock();
  277. }
  278. }