LuckyCalc.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <?php
  2. namespace crmeb\services\async;
  3. use app\admin\model\user\User;
  4. use app\admin\model\user\UserBill;
  5. use app\models\store\StoreOrder;
  6. use app\models\store\StoreOrderCartInfo;
  7. use app\models\user\UserNotice;
  8. use crmeb\basic\BaseModel;
  9. use think\facade\Config;
  10. use think\facade\Log;
  11. use ActivityCalc;
  12. class LuckyCalc {
  13. protected static $NAME = 'lucky';
  14. private function searchActiveInSuk($suk) {
  15. $parts = explode(",", $suk);
  16. if (count($parts) <= 0) {
  17. return false;
  18. }
  19. foreach ($parts as $part) {
  20. $t = trim($part);
  21. if ($t == 20 || $t == 21) {
  22. return $t;
  23. }
  24. }
  25. return false;
  26. }
  27. public function calc() {
  28. $lucky_cate_id = Config::get('activity.lucky_cate_id');
  29. $products = ActivityCalc::getOrders($lucky_cate_id);
  30. if (count($products) <= 1) {
  31. Log::info('not enough order, stop lucky activity');
  32. return;
  33. }
  34. // split win & lose
  35. shuffle($products);
  36. shuffle($products);
  37. $left = [];
  38. $right = [];
  39. $left_spent = 0.0;
  40. $right_spent = 0.0;
  41. $orders = [];
  42. foreach ($products as &$p) {
  43. $ci = json_decode($p['cart_info'], true);
  44. $num = $ci['num']; // 购买个数
  45. $productInfo = isset($ci['productInfo']) ? $ci['productInfo'] : [];
  46. $attrInfo = isset($productInfo['attrInfo']) ? $productInfo['attrInfo'] : [];
  47. $price = isset($attrInfo['price']) ? $attrInfo['price'] : 0.0;
  48. $cost = isset($attrInfo['cost']) ? $attrInfo['cost'] : 0.0;
  49. $ppaid = bcmul($num, $price, 2);// product paid
  50. $pcost = bcmul($num, $cost, 2);
  51. $oid = $p['id'];
  52. $p['paid'] = $ppaid;
  53. $p['cost'] = $pcost;
  54. if (!isset($orders[$oid])) {
  55. $orders[$oid] = 1;
  56. } else {
  57. $orders[$oid] += 1;
  58. }
  59. if ($ppaid <= 1.0) {
  60. Log::warning("impossible price, order: ". $p['id']);
  61. continue;
  62. }
  63. if ($cost <= 0.1) {
  64. Log::warning("impossible cost, order: ". $p['id']);
  65. continue;
  66. }
  67. $suk = isset($attrInfo['suk']) ? $attrInfo['suk'] : 'any';
  68. $flag = $this->searchActiveInSuk($suk);
  69. if ($flag == 20) {
  70. $left[] = $p;
  71. $left_spent = bcadd($left_spent, $ppaid, 2);
  72. } else if ($flag == 21) {
  73. $right[] = $p;
  74. $right_spent = bcadd($right_spent, $ppaid, 2);
  75. } else {
  76. Log::error('cant find suk in lucky field. id=' . $oid);
  77. continue;
  78. }
  79. }// foreach
  80. $products = [];
  81. $diff_money = bcsub($left_spent, $right_spent, 2);
  82. if ($diff_money < 0.0) {
  83. $diff_money = -$diff_money;
  84. }
  85. $open = 20;
  86. $winners = $left;
  87. $losers = $right;
  88. if ($left_spent > $right_spent) {
  89. $open = 21;
  90. $winners = $right;
  91. $losers = $left;
  92. }
  93. // 结果处置
  94. foreach($winners as $p) {
  95. $single = $orders[$p['id']] == 1;
  96. $this->execute($p, $single, true);
  97. }
  98. foreach($losers as $p) {
  99. $single = $orders[$p['id']] == 1;
  100. $this->execute($p, $single, false);
  101. }
  102. } // calc
  103. /**
  104. * 奖励分配
  105. *
  106. * @param $product 获奖订单中的商品
  107. * @param bool $single 是否是单种商品构成的订单
  108. * @param bool $win 是否中奖
  109. */
  110. protected function execute($product, $single=true, $win=true) {
  111. BaseModel::beginTrans();
  112. $result = 0;
  113. $reparation = 0.0;
  114. if ($win) {
  115. $result = 1;
  116. $reparation = bcmul(bcsub($product['paid'], $product['cost'], 2), 0.1, 2);
  117. }
  118. // 标记商品为已参与活动
  119. $r1 = StoreOrderCartInfo::where('oid', $product['id'])
  120. ->where('product_id', $product['product_id'])
  121. ->update([
  122. 'activity' => self::$NAME,
  123. 'result' => $result,
  124. 'reparation' => $reparation,
  125. ]);
  126. if (!$win) {
  127. return;
  128. }
  129. $refund_price = bcadd($product['paid'], $reparation, 2);
  130. // 订单全部商品都中奖的退单
  131. $r2 = true;
  132. if ($single) {
  133. $r2 = StoreOrder::where('id', $product['id'])->update([
  134. 'refund_price' => $refund_price,
  135. 'refund_status' => 2,
  136. ]);
  137. }
  138. // 中奖的 退款并赔款返回到佣金
  139. $r3 = UserBill::income('參加活动', $product['uid'], 'now_money', 'brokerage',
  140. $refund_price, $product['id'], bcadd($product['now_money'], $refund_price, 2),
  141. '订单退款' . $product['paid'] . '+' . $reparation . '元');
  142. $r4 = User::bcInc($product['uid'], 'brokerage_price', $refund_price, 'uid');
  143. $ok = $r1 && $r2 && $r3 && $r4;
  144. BaseModel::checkTrans($ok);
  145. if ($ok) {
  146. // 中奖用户发送中奖消息.
  147. UserNotice::sendNoticeTo($product['uid'], '您的订单已退款',
  148. '您好,由于活动商品库存有限,您的订单 ' . $product['store_name']
  149. . ' 未能成功分配. 该商品付款' . $product['paid'] . '元已如数退还, 并赔付您' . $reparation
  150. . '元作为补偿, 对您造成的不便我们深感抱歉. 同时感谢您对美天旺的喜爱和信任, 美天旺活动场将永远为您守候. 顺祝生活愉快.');
  151. }
  152. }
  153. }