ParentReward.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. <?php
  2. /****************************************************************
  3. * Author: king -- LiBaoJia
  4. * Date: 2020/7/7 11:53 AM
  5. * Email: livsyitian@163.com
  6. * QQ: 995265288
  7. * IDE: PhpStorm
  8. * User: 芸众商城 www.yunzshop.com
  9. ****************************************************************/
  10. namespace app\common\services\point;
  11. use app\common\exceptions\ShopException;
  12. use app\common\facades\Setting;
  13. use app\common\models\Goods;
  14. use app\common\models\Member;
  15. use app\common\models\point\ParentRewardLog;
  16. use app\common\services\finance\PointService;
  17. use app\common\services\goods\SaleGoods;
  18. use Carbon\Carbon;
  19. use Illuminate\Support\Facades\DB;
  20. use Yunshop\StoreCashier\common\models\CashierGoods;
  21. use Yunshop\StoreCashier\common\models\StoreOrder;
  22. use Yunshop\StoreCashier\common\models\StoreSetting;
  23. class ParentReward
  24. {
  25. public $order;
  26. public $parent;
  27. public $grand;
  28. public $base_setting;
  29. public $point_setting;
  30. public $event;
  31. /**
  32. * @param $order
  33. * @param $event
  34. * @return void
  35. * 上级赠送积分
  36. */
  37. public function handle($order, $event)
  38. {
  39. $this->point_setting = Setting::get('point.set');
  40. $this->order = $order;
  41. $this->getMemberParent();
  42. $this->getBaseSetting();
  43. $this->event = $event;
  44. if (!$this->parent) {
  45. $this->debug('会员不存在上级');
  46. return;
  47. }
  48. $this->order->orderGoods->each(function ($v) {
  49. if ($v->isRefund()) {
  50. $this->debug('已售后订单商品不赠送上级积分', $v->id);
  51. return;
  52. }
  53. $goods_setting = $this->goodsSetting($v);
  54. if (!$goods_setting['base_amount']) {
  55. $this->debug('利润或实付金额为0', $v->id);
  56. return;
  57. }
  58. $res1 = $this->createCommission($goods_setting, $v, 1);
  59. $res2 = $this->createCommission($goods_setting, $v, 2);
  60. if ($res1 || $res2) {
  61. $this->award($this->order->id);
  62. }
  63. });
  64. }
  65. /**
  66. * @param $goods_setting
  67. * @param $order_goods
  68. * @param $level
  69. * @return bool
  70. * 生成奖励记录
  71. */
  72. protected function createCommission($goods_setting, $order_goods, $level)
  73. {
  74. if (ParentRewardLog::uniacid()->where('level', $level)->where('order_goods_id', $order_goods->id)->first()) {
  75. $this->debug('重复奖励', $order_goods->id);
  76. return false;
  77. }
  78. if ($goods_setting['point_type'] == 2) {
  79. if ($this->event != 'pay') {
  80. $this->debug('支付后赠送且当前非支付事件', $order_goods->id);
  81. return false;
  82. }
  83. if ($this->order->status < 1) {
  84. $this->debug('支付后赠送且订单未支付', $order_goods->id);
  85. return false;
  86. }
  87. }
  88. if ($goods_setting['point_type'] == 1) {
  89. if ($this->event != 'receive') {
  90. $this->debug('每月赠送且当前非完成事件', $order_goods->id);
  91. return false;
  92. }
  93. if ($this->order->status < 3) {
  94. $this->debug('每月赠送且订单未完成', $order_goods->id);
  95. return false;
  96. }
  97. }
  98. if ($goods_setting['point_type'] == 0) {
  99. if ($this->event != 'receive') {
  100. $this->debug('完成后赠送且当前非完成事件', $order_goods->id);
  101. return false;
  102. }
  103. if ($this->order->status < 3) {
  104. $this->debug('完成后赠送且订单未完成', $order_goods->id);
  105. return false;
  106. }
  107. }
  108. $member = $level == 1 ? $this->parent : $this->grand;
  109. if (!$member) {
  110. $this->debug($level . '级上级不存在', $order_goods->id);
  111. return false;
  112. }
  113. $type_key = ($level == 1 ? 'first' : 'second') . '_type';
  114. $number_key = ($level == 1 ? 'first' : 'second') . '_number';
  115. if ($goods_setting[$type_key] == 1) {
  116. $point = bcmul($goods_setting['base_amount'], bcdiv($goods_setting[$number_key], 100, 8), 2);
  117. } else {
  118. $point = bcmul($goods_setting[$number_key], $order_goods->total, 2);
  119. }
  120. $point = bccomp($point, 0, 2) == 1 ? $point : 0;
  121. if (!$point) {
  122. $this->debug($level . '级上级奖励积分为0', $order_goods->id);
  123. return false;
  124. }
  125. $create_data = [
  126. 'uniacid' => \YunShop::app()->uniacid,
  127. 'uid' => $member->uid,
  128. 'order_id' => $this->order->id,
  129. 'order_goods_id' => $order_goods->id,
  130. 'expect_reward_time' => 0,
  131. 'status' => 0,
  132. 'level' => $level,
  133. 'point' => $point,
  134. ];
  135. if ($goods_setting['point_type'] == 1) { //每月初发放
  136. if (bccomp($goods_setting['max_once_point'], 0, 2) != 1) {
  137. $this->debug('每月赠送积分为0', $order_goods->id);
  138. return false;
  139. }
  140. $insert_data = [];
  141. $time = time();
  142. do {
  143. $this_point = bccomp($goods_setting['max_once_point'], $create_data['point'], 2) == 1 ? $create_data['point'] : $goods_setting['max_once_point'];
  144. $create_data['point'] = bcsub($create_data['point'], $this_point, 2);
  145. $time = Carbon::createFromTimestamp($time)->endOfMonth()->timestamp + 1;
  146. $insert_data[] = array_merge($create_data, [
  147. 'point' => $this_point,
  148. 'expect_reward_time' => $time,
  149. ]);
  150. } while ($create_data['point'] > 0);
  151. if ($insert_data) {
  152. $insert_data = array_chunk($insert_data, 500);
  153. foreach ($insert_data as $insert) {
  154. ParentRewardLog::insert($insert);
  155. }
  156. }
  157. } else { //立刻发放
  158. ParentRewardLog::create($create_data);
  159. }
  160. return true;
  161. }
  162. /**
  163. * @return void
  164. * 获取2层内上级
  165. */
  166. protected function getMemberParent()
  167. {
  168. $this->parent = null;
  169. $this->grand = null;
  170. $member = Member::uniacid()->with('yzMember')->find($this->order->uid);
  171. if ($member->yzMember->parent_id) {
  172. $this->parent = Member::uniacid()->with('yzMember')->find($member->yzMember->parent_id);
  173. }
  174. if ($this->parent && $this->parent->yzMember->parent_id) {
  175. $this->grand = Member::uniacid()->find($this->parent->yzMember->parent_id);
  176. }
  177. }
  178. /**
  179. * @return int[]
  180. * 获取奖励基础设置
  181. */
  182. protected function getBaseSetting()
  183. {
  184. $setting = $this->analysisSetting($this->point_setting['first_parent_point'], $this->point_setting['second_parent_point']);
  185. if ($this->order->plugin_id == 32) {
  186. if (app('plugins')->isEnabled('store-cashier')
  187. && ($store_id = StoreOrder::where('order_id', $this->order->id)->value('store_id'))
  188. && $store_setting = StoreSetting::where('store_id', $store_id)->where('key', 'point')->first()
  189. ) {
  190. $store_setting = $store_setting->value['set'] ? : [];
  191. $setting = $this->formSetting($this->analysisSetting($store_setting['first_parent_point'], $store_setting['second_parent_point']), $setting);
  192. }
  193. }
  194. // elseif ($this->order->plugin_id == 31) {
  195. // if (!app('plugins')->isEnabled('store-cashier')) {
  196. // return $this->analysisSetting(0, 0);
  197. // }
  198. // $goods_id = $this->order->orderGoods->first()->goods_id;
  199. // $setting = $this->formSetting($this->goodsSetting($goods_id), $setting, 1);
  200. // }
  201. $this->base_setting = $setting;
  202. return $this->base_setting;
  203. }
  204. /**
  205. * @param $setting
  206. * @param $base_setting
  207. * @param $form_type
  208. * @return mixed
  209. * 组装设置
  210. */
  211. protected function formSetting($setting, $base_setting, $form_type = 0)
  212. {
  213. if ($setting['first_number']) {
  214. $base_setting['first_number'] = $setting['first_number'];
  215. $base_setting['first_type'] = $setting['first_type'];
  216. }
  217. if ($setting['second_number']) {
  218. $base_setting['second_number'] = $setting['second_number'];
  219. $base_setting['second_type'] = $setting['second_type'];
  220. }
  221. if ($form_type == 1) {
  222. if (!$setting['first_number']) {
  223. $base_setting['first_number'] = 0;
  224. }
  225. if (!$setting['second_number']) {
  226. $base_setting['second_number'] = 0;
  227. }
  228. }
  229. if ($form_type == 2) {
  230. if ($setting['first_number'] === 0 || $setting['first_number'] === '0') {
  231. $base_setting['first_number'] = 0;
  232. }
  233. if ($setting['second_number'] === 0 || $setting['second_number'] === '0') {
  234. $base_setting['second_number'] = 0;
  235. }
  236. }
  237. return $base_setting;
  238. }
  239. /**
  240. * @param $order_goods
  241. * @return int|mixed|string
  242. * 获取奖励基础金额
  243. */
  244. protected function getBaseAmount($order_goods)
  245. {
  246. if ($this->point_setting['give_type'] == 1) { //利润
  247. $base_amount = 0;
  248. switch ($this->order->plugin_id) {
  249. case 31:
  250. if (app('plugins')->isEnabled('store-cashier')) {
  251. $cashier_goods = CashierGoods::where('goods_id', $order_goods->goods_id)->first();
  252. if (bccomp($cashier_goods->shop_commission, 0, 8) == 1) {
  253. $base_amount = bcmul($order_goods->payment_amount, bcdiv($cashier_goods->shop_commission, 100, 8), 2);
  254. }
  255. }
  256. break;
  257. case 32:
  258. if (app('plugins')->isEnabled('store-cashier')) {
  259. $store_id = StoreOrder::where('order_id', $this->order->id)->value('store_id');
  260. $store_setting = StoreSetting::where('store_id', $store_id)->where('key', 'store')->first();
  261. $percent = $store_setting->value['shop_commission'] ?: 0;
  262. if (bccomp($percent, 0, 8) == 1) {
  263. $base_amount = bcmul($order_goods->payment_amount, bcdiv($percent, 100, 8), 2);
  264. }
  265. }
  266. break;
  267. default:
  268. $base_amount = bcsub($order_goods->payment_amount, $order_goods->goods_cost_price, 2);
  269. }
  270. } else { //实付价格
  271. $base_amount = $order_goods->payment_amount;
  272. }
  273. return bccomp($base_amount, 0, 2) == 1 ? $base_amount : 0;
  274. }
  275. /**
  276. * @param $order_goods
  277. * @return mixed
  278. * 获取商品独立设置
  279. */
  280. protected function goodsSetting($order_goods)
  281. {
  282. $goods_id = $order_goods->goods_id;
  283. $goods_sale = SaleGoods::where('goods_id', $goods_id)->first();
  284. $setting = $this->base_setting;
  285. if ($goods_sale) {
  286. $goods_setting = $this->analysisSetting($goods_sale->first_parent_point, $goods_sale->second_parent_point, 1);
  287. $setting = $this->formSetting($goods_setting, $setting, $this->order->plugin_id == 31 ? 1 : 2);
  288. }
  289. $setting['point_type'] = $goods_sale->point_type ?: 0;
  290. $setting['max_once_point'] = $goods_sale->max_once_point && bccomp($goods_sale->max_once_point, 0, 2) == 1 ? $goods_sale->max_once_point : 0;
  291. $setting['base_amount'] = $this->getBaseAmount($order_goods);
  292. return $setting;
  293. }
  294. /**
  295. * @param $first_percent
  296. * @param $second_percent
  297. * @return int[]
  298. * 解析设置
  299. */
  300. protected function analysisSetting($first_percent = '', $second_percent = '', $type = 0)
  301. {
  302. $setting = [
  303. 'first_number' => 0,
  304. 'second_number' => 0,
  305. 'first_type' => 1,
  306. 'second_type' => 1,
  307. ];
  308. foreach (['first', 'second'] as $v) {
  309. $percent_key = $v . '_percent';
  310. if ($type == 1 && !$$percent_key && $$percent_key !== 0 && $$percent_key !== '0') {
  311. $setting[$v . '_number'] = '';
  312. } elseif (floatval($$percent_key) && bccomp(floatval($$percent_key), 0, 2) == 1) {
  313. if (strstr($$percent_key, '%') === false) {
  314. $setting[$v . '_type'] = 2;
  315. }
  316. $setting[$v . '_number'] = floatval($$percent_key);
  317. }
  318. }
  319. return $setting;
  320. // if (floatval($first_percent) && bccomp(floatval($first_percent), 0, 2) == 1) {
  321. // if (strstr($first_percent, '%') === false) {
  322. // $setting['first_type'] = 2;
  323. // }
  324. // $setting['first_number'] = floatval($first_percent);
  325. // }
  326. }
  327. /**
  328. * @param $order_id
  329. * @param $order_goods_id
  330. * @return void
  331. * 上级赠送积分回滚
  332. */
  333. public function refund($order_id = 0, $order_goods_id = 0)
  334. {
  335. $query = ParentRewardLog::uniacid()->where('status', '>=', 0);
  336. if (empty($order_id) && empty($order_goods_id)) {
  337. return;
  338. }
  339. if ($order_id) {
  340. $function = is_array($order_id) ? 'whereIn' : 'where';
  341. $query->$function('order_id', $order_id);
  342. }
  343. if ($order_goods_id) {
  344. $function = is_array($order_id) ? 'whereIn' : 'where';
  345. $query->$function('order_goods_id', $order_goods_id);
  346. }
  347. $list = $query->get();
  348. if ($list->isNotEmpty()) {
  349. $list->each(function ($v) {
  350. if ($v->status == 0) {
  351. $v->status = -1;
  352. $v->save();
  353. } elseif ($v->status == 1) {
  354. try {
  355. $data = [
  356. 'point_income_type' => PointService::POINT_INCOME_LOSE,
  357. 'member_id' => $v->uid,
  358. 'point_mode' => $v->level == 1 ? PointService::POINT_MODE_FIRST_PARENT_REFUND : PointService::POINT_MODE_SECOND_PARENT_REFUND,
  359. 'point' => bcsub(0, $v->point, 2),
  360. 'remark' => "购物赠送上级({$v->level}级)回退,订单ID{$v->order_id},订单商品表ID{$v->order_goods_id},记录ID{$v->id}",
  361. ];
  362. $pointService = new PointService($data);
  363. $res = $pointService->changePoint($v->id);
  364. if ($res === false) {
  365. throw new ShopException('未知错误');
  366. }
  367. $v->status = -1;
  368. $v->save();
  369. DB::commit();
  370. } catch (ShopException $e) {
  371. DB::rollBack();
  372. \Log::debug('积分上级赠送回滚失败', $v->id);
  373. }
  374. }
  375. });
  376. }
  377. }
  378. /**
  379. * @param $order_id
  380. * @return void
  381. * 发放奖励
  382. */
  383. public function award($order_id = 0)
  384. {
  385. $query = ParentRewardLog::uniacid()
  386. ->where('status', 0)
  387. ->where('expect_reward_time', '<', time());
  388. if ($order_id) {
  389. $query->where('order_id', $order_id);
  390. } else {
  391. $query->limit(500);
  392. }
  393. $list = $query->get();
  394. if ($list->isNotEmpty()) {
  395. $list->each(function ($v) {
  396. try {
  397. DB::beginTransaction();
  398. $data = [
  399. 'point_income_type' => PointService::POINT_INCOME_GET,
  400. 'member_id' => $v->uid,
  401. 'point_mode' => $v->level == 1 ? PointService::POINT_MODE_FIRST_PARENT_REWARD : PointService::POINT_MODE_SECOND_PARENT_REWARD,
  402. 'point' => $v->point,
  403. 'remark' => "购物赠送上级({$v->level}级),订单ID{$v->order_id},订单商品表ID{$v->order_goods_id},记录ID{$v->id}",
  404. ];
  405. $pointService = new PointService($data);
  406. $res = $pointService->changePoint($v->id);
  407. if ($res === false) {
  408. throw new ShopException('未知错误');
  409. }
  410. $v->status = 1;
  411. $v->actual_reward_time = time();
  412. $v->save();
  413. DB::commit();
  414. } catch (ShopException $e) {
  415. DB::rollBack();
  416. $this->debug('发放积分失败,' . $e->getMessage(), $v->id);
  417. }
  418. });
  419. }
  420. }
  421. public function debug($msg = '', $data = '')
  422. {
  423. $base_msg = $this->order->id ? "上级赠送积分异常,订单{$this->order->id},原因:" : "上级赠送积分异常,原因:";
  424. \Log::debug($base_msg . $msg, $data);
  425. }
  426. }