BalanceChange.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. <?php
  2. /**
  3. * Author: 芸众商城 www.yunzshop.com
  4. * Date: 2017/5/24
  5. * Time: 下午5:08
  6. */
  7. namespace app\common\services\finance;
  8. use app\common\events\member\MemberBalanceChangeEvent;
  9. use app\common\events\member\MemberBalanceDeficiencyEvent;
  10. use app\common\events\MessageEvent;
  11. use app\common\exceptions\AppException;
  12. use app\common\models\finance\Balance;
  13. use app\common\models\Member;
  14. use app\common\services\credit\ConstService;
  15. use app\common\services\credit\Credit;
  16. use app\common\models\notice\MinAppTemplateMessage;
  17. use app\common\services\MessageService as MsgService;
  18. use app\common\models\notice\MessageTemp;
  19. use app\common\services\notice\official\BalanceChangeNotice;
  20. use app\common\services\notice\official\BalanceDeficiencyNotice;
  21. use app\common\services\txyunsms\SmsSingleSender;
  22. class BalanceChange extends Credit
  23. {
  24. private $new_value;
  25. private $balanceSet = array();
  26. /**
  27. * 实现基类中的抽象方法
  28. * 通过基类 data 中的 member_id 获取会员信息
  29. * @return mixed
  30. */
  31. public function getMemberModel()
  32. {
  33. return $this->memberModel = Member::select('uid', 'avatar', 'mobile', 'nickname', 'realname', 'credit2')->where('uid', $this->data['member_id'])->lockForUpdate()->first() ?: false;
  34. }
  35. /**
  36. * 实现基类中的抽象方法
  37. * 记录数据写入
  38. * @return bool|\Illuminate\Support\MessageBag|string
  39. */
  40. public function recordSave()
  41. {
  42. $recordModel = new Balance();
  43. $recordModel->fill($this->getRecordData());
  44. $validator = $recordModel->validator();
  45. if ($validator->fails()) {
  46. return $validator->messages();
  47. }
  48. return $recordModel->save() ? true : '明细记录写入出错';
  49. }
  50. /**
  51. * 实现基类中的抽项方法
  52. * @return bool|string
  53. */
  54. public function updateMemberCredit()
  55. {
  56. $this->memberModel->credit2 = $this->new_value;
  57. if ($this->memberModel->save()) {
  58. $this->sendSmsMessage();
  59. $this->sendMessage();
  60. event(new MemberBalanceChangeEvent($this->memberModel,$this->new_value,$this->change_value,$this->source, $this->recordData));
  61. return true;
  62. }
  63. return '写入会员余额失败';
  64. //return $this->memberModel->save() ? true : '写入会员余额失败';
  65. }
  66. /**
  67. * @return bool
  68. * @throws AppException
  69. */
  70. public function validatorData()
  71. {
  72. $this->new_value = bcadd($this->memberModel->credit2, $this->change_value, 2);
  73. if ($this->new_value < 0) {
  74. throw new AppException("用户({$this->memberModel->uid})余额({$this->memberModel->credit2})不足({$this->change_value})");
  75. }
  76. if (!$this->relation()) {
  77. throw new AppException('该订单已经提交过,不能重复使用');
  78. }
  79. return true;
  80. }
  81. /**
  82. * 实现基类中的抽项方法
  83. * @return bool
  84. * @throws AppException
  85. */
  86. public function validatorOzy()
  87. {
  88. return true;
  89. }
  90. public function transfer(array $data)
  91. {
  92. if (!$data['recipient']) {
  93. throw new AppException('被转让者不存在');
  94. }
  95. $result = parent::transfer($data);
  96. $data['member_id'] = $data['recipient'];
  97. return $result === true ? $this->addition($data) : $result;
  98. }
  99. //通用
  100. public function universal(array $data)
  101. {
  102. if (!isset($data['source']) || !isset($data['type'])) {
  103. throw new AppException('变动类型、业务类型必须设置');
  104. }
  105. $this->source = $data['source'];
  106. // 1为收入 2为支出
  107. return $data['type'] == 1 ? $this->addition($data) : $this->subtraction($data);
  108. }
  109. /**
  110. *
  111. * 直播打赏
  112. * @param array $data
  113. * @return bool|string
  114. * @throws AppException
  115. */
  116. public function roomReward(array $data)
  117. {
  118. if (!$data['recipient']) {
  119. throw new AppException('被转让者不存在');
  120. }
  121. $result = parent::RoomRewardTransfer($data);
  122. $data['member_id'] = $data['recipient'];
  123. $money = floor(($data['change_value'] * ($data['code_proportion']/100))*100)/100;
  124. $data['change_value'] = $money;
  125. return $result === true ? parent::RoomRewardRecipient($data) : $result;
  126. }
  127. public function incomeWithdrawAward(array $data)
  128. {
  129. $this->source = ConstService::SOURCE_INCOME_WITHDRAW_AWARD;
  130. return $this->addition($data);
  131. }
  132. public function pointTransfer(array $data)
  133. {
  134. $this->source = ConstService::SOURCE_POINT_TRANSFER;
  135. return $this->addition($data);
  136. }
  137. public function parentPayment(array $data)
  138. {
  139. $this->source = ConstService::PARENT_PAYMENT_REWARD;
  140. return $this->addition($data);
  141. }
  142. public function groupWorkAward(array $data)
  143. {
  144. $this->source = ConstService::GROUP_WORK_AWARD;
  145. return $this->addition($data);
  146. }
  147. public function groupWorkHeadAward(array $data)
  148. {
  149. $this->source = ConstService::GROUP_WORK_HEAD_AWARD;
  150. return $this->addition($data);
  151. }
  152. public function groupWorkParentAward(array $data)
  153. {
  154. $this->source = ConstService::GROUP_WORK_PARENT_AWARD;
  155. return $this->addition($data);
  156. }
  157. public function ownerOrder(array $data)
  158. {
  159. $this->source = ConstService::OWNER_ORDER_WITHHOLD;
  160. return $this->subtraction($data);
  161. }
  162. public function ownerOrderSettle(array $data)
  163. {
  164. $this->source = ConstService::OWNER_ORDER_SETTLE;
  165. return $this->addition($data);
  166. }
  167. public function convert(array $data)
  168. {
  169. $result = parent::convert($data);
  170. return $result;
  171. }
  172. public function convertCancel(array $data)
  173. {
  174. $result = parent::convertCancel($data);
  175. return $result;
  176. }
  177. public function deduct(array $data)
  178. {
  179. $result = parent::consume($data);
  180. return $result;
  181. }
  182. /**
  183. * 检测单号是否可用,为空则生成唯一单号
  184. * @return bool|string
  185. */
  186. private function relation()
  187. {
  188. if ($this->data['relation']) {
  189. $result = Balance::ofOrderSn($this->data['relation'])->ofSource($this->source)->ofMemberId($this->data['member_id'])->first();
  190. //dd($result);
  191. if ($result) {
  192. return false;
  193. }
  194. return $this->data['relation'];
  195. }
  196. return $this->createOrderSN();
  197. }
  198. /**
  199. * 生成唯一单号
  200. * @return string
  201. */
  202. public function createOrderSN()
  203. {
  204. $ordersn = createNo('BC', true);
  205. while (1) {
  206. if (!Balance::ofOrderSn($ordersn)->first()) {
  207. break;
  208. }
  209. $ordersn = createNo('BC', true);
  210. }
  211. return $ordersn;
  212. }
  213. protected $recordData;
  214. /**
  215. * 明细记录 data 数组
  216. * @return array
  217. */
  218. private function getRecordData()
  219. {
  220. $thirdStatus = empty($this->data['thirdStatus']) ? 1 : $this->data['thirdStatus'];
  221. $this->recordData = [
  222. 'uniacid' => \YunShop::app()->uniacid,
  223. 'member_id' => $this->memberModel->uid,
  224. 'old_money' => $this->memberModel->credit2 ?: 0,
  225. 'change_money' => $this->change_value,
  226. 'new_money' => $this->new_value,
  227. 'type' => $this->type,
  228. 'service_type' => $this->source,
  229. 'serial_number' => $this->relation(),
  230. 'operator' => $this->data['operator'],
  231. 'operator_id' => $this->data['operator_id'],
  232. 'remark' => $this->data['remark'],
  233. 'thirdStatus' => $thirdStatus
  234. ];
  235. return $this->recordData;
  236. }
  237. /**
  238. * 余额变动消息通知
  239. */
  240. private function sendMessage()
  241. {
  242. date_default_timezone_set('PRC');
  243. if($this->change_value == 0){
  244. //余额变动为0,无需发送消息
  245. return;
  246. }
  247. $balanceNotice = new BalanceChangeNotice($this->memberModel,$this->new_value,$this->change_value,$this->source);
  248. $balanceNotice->sendMessage();
  249. $this->balanceSet = \Setting::get('finance.balance');
  250. //检查余额是否达到下限
  251. if ($this->balanceSet['blance_floor'] > $this->new_value && $this->balanceSet['blance_floor_on'] == 1) {
  252. $this->checkBalanceFloor();
  253. }
  254. return ;
  255. if ($this->change_value == 0) {
  256. return;
  257. }
  258. $template_id = \Setting::get('shop.notice')['balance_change'];
  259. \Log::info('余额变动通知', $template_id);
  260. $params = [
  261. ['name' => '商城名称', 'value' => \Setting::get('shop.shop')['name']],
  262. ['name' => '昵称', 'value' => $this->memberModel->nickname],
  263. ['name' => '时间', 'value' => date('Y-m-d H:i', time())],
  264. ['name' => '余额变动金额', 'value' => $this->change_value],
  265. ['name' => '余额变动类型', 'value' => (new ConstService(''))->sourceComment()[$this->source]],
  266. ['name' => '变动后余额数值', 'value' => $this->new_value]
  267. ];
  268. $news_link = MessageTemp::find($template_id)->news_link;
  269. $news_link = $news_link ?: '';
  270. event(new MessageEvent($this->memberModel->uid, $template_id, $params, $url = $news_link));
  271. //小程序消息通知
  272. $is_open = MinAppTemplateMessage::getTitle('账户余额提醒');
  273. if (!$is_open->is_open) {
  274. return;
  275. }
  276. $miniParams = [
  277. 'keyword1' => ['value' => $this->memberModel->nickname],// 会员昵称
  278. 'keyword2' => ['value' => date('Y-m-d H:i', time())],//变动时间
  279. 'keyword3' => ['value' => $this->change_value],// 变动金额
  280. 'keyword4' => ['value' => $this->new_value],// 当前余额
  281. 'keyword5' => ['value' => (new ConstService(''))->sourceComment()[$this->source]],// 变动类型
  282. ];
  283. $this->miniSendToShops($is_open->template_id, $miniParams, $this->memberModel->uid);
  284. }
  285. protected function miniSendToShops($templateId, $msg, $uid)
  286. {
  287. if (empty($templateId)) {
  288. return;
  289. }
  290. \Log::debug('===============', [$templateId]);
  291. MsgService::MiniNotice($templateId, $msg, $uid);
  292. }
  293. //余额下限消息通知
  294. public function checkBalanceFloor()
  295. {
  296. if (!$this->balanceSet['blance_floor']) {
  297. return true;
  298. }
  299. //未设置直接报错
  300. if (empty($this->balanceSet['balance_message_type'])) {
  301. return true;
  302. }
  303. //只有三种情况
  304. if (in_array($this->balanceSet['balance_message_type'], [1, 2, 3]) != true) {
  305. return true;
  306. }
  307. //指定会员等级
  308. if ($this->balanceSet['balance_message_type'] == 2) {
  309. if ($this->memberModel->yzMember->level_id != $this->balanceSet['level_limit']) {
  310. return true;
  311. }
  312. }
  313. //指定会员
  314. if ($this->balanceSet['balance_message_type'] == 1) {
  315. if (in_array($this->memberModel->uid, explode(',', $this->balanceSet['uids'])) != true) {
  316. return true;
  317. }
  318. }
  319. //指定会员分组
  320. if ($this->balanceSet['balance_message_type'] == 3) {
  321. if ($this->memberModel->yzMember->group_id != $this->balanceSet['group_type']) {
  322. return true;
  323. }
  324. }
  325. event(new MemberBalanceDeficiencyEvent($this->memberModel,$this->balanceSet,$this->new_value)); //会员余额不足事件
  326. $template_id = \Setting::get('shop.notice')['balance_deficiency'];
  327. if (!$template_id) {
  328. return true;
  329. }
  330. $balanceNotice = new BalanceDeficiencyNotice($this->memberModel,$this->balanceSet,$this->new_value);
  331. $balanceNotice->sendMessage();
  332. // $params = [
  333. // ['name' => '商城名称', 'value' => \Setting::get('shop.shop')['name']],
  334. // ['name' => '昵称', 'value' => $this->memberModel->nickname],
  335. // ['name' => '时间', 'value' => date('Y-m-d H:i', time())],
  336. // ['name' => '通知额度', 'value' => $this->balanceSet['blance_floor']],
  337. // ['name' => '当前余额', 'value' => $this->new_value]
  338. // ];
  339. // $news_link = MessageTemp::find($template_id)->news_link;
  340. // $news_link = $news_link ?: '';
  341. // event(new MessageEvent($this->memberModel->uid, $template_id, $params, $url = $news_link));
  342. }
  343. /**
  344. * 充值短信
  345. * @return bool
  346. */
  347. private function sendSmsMessage()
  348. {
  349. try {
  350. if ($this->source != 1) {
  351. \Log::debug('不是充值不需要发送短信');
  352. return true;
  353. }
  354. if (!$this->memberModel->mobile) {
  355. \Log::debug('未获取到该会员手机号');
  356. return true;
  357. }
  358. $name = \Setting::get('shop.shop')['name'];
  359. $data = Array( // 短信模板中字段的值
  360. 'preshop' => $name,
  361. 'date' => date("m月d日", time()),
  362. 'amount' => $this->change_value,
  363. 'amounts' => $this->new_value,
  364. 'endshop' => $name,
  365. );
  366. app('sms')->sendMemberRecharge($this->memberModel->mobile, $data);
  367. return true;
  368. } catch (\Exception $e) {
  369. \Log::debug($e->getMessage());
  370. return true;
  371. }
  372. }
  373. }