| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- <?php
- namespace crmeb\services\async;
- use app\models\user\UserNotice;
- use app\admin\model\user\UserBill;
- use app\admin\model\user\User;
- use app\models\store\StoreOrder;
- use app\models\store\StoreOrderCartInfo;
- use crmeb\basic\BaseModel;
- use think\facade\Config;
- use think\facade\Log;
- /**
- * 抢清仓活动
- *
- * 玩法:
- * 指定一个清仓分类. 该分类下的所有商品在一个周期内一起开奖,
- * 中奖的退款并赔款, 未中奖的安排发货.
- *
- * 在宣传中, 抢到的发货, 未抢到的退款并赔款.
- *
- * Class ClearanceCalc
- * @package crmeb\services\async
- */
- class ClearanceCalc {
- // 活动代号
- protected static $NAME = 'clr';
- public function calc() {
- $clearance_cate_id = Config::get('activity.clearance_cate_id');
- // 找到清仓场次中未参加活动的订单
- $products = StoreOrderCartInfo::alias('ci')
- ->join('store_order o', 'o.id=ci.oid')
- ->join('store_product p', 'ci.product_id=p.id')
- ->join('user u', 'u.uid = o.uid')
- ->where('o.paid', 1)
- ->where('o.status', '>=', 0)
- ->where('o.refund_status', 0)
- ->where('o.is_del', 0)
- ->where('o.is_system_del', 0)
- ->where('p.cart_id', $clearance_cate_id)
- ->where('ci.activity', '')
- ->field('o.id, o.pay_price, ci.product_id, ci.cart_info, u.uid, u.now_money, p.store_name')->select();
- $products = $products ? $products->toArray() : [];
- if (count($products) <= 1) {
- Log::info('not enough order, stop clearance activity');
- return;
- }
- // 按商品处理订单
- $counter = 0;
- $left = [];
- $right = [];
- $left_spent = 0;
- $right_spent = 0;
- shuffle($products);
- shuffle($products);
- // 标记有多件商品的订单
- $orders = [];
- foreach($products as $p) {
- $counter += 1;
- $ci = json_decode($p['cart_info'], true);
- $num = $ci['num']; // 购买个数
- $productInfo = isset($ci['productInfo']) ? $ci['productInfo'] : [];
- $attrInfo = isset($productInfo['attrInfo']) ? $productInfo['attrInfo'] : [];
- $price = isset($attrInfo['price']) ? $attrInfo['price'] : 0.0;
- $cost = isset($attrInfo['cost']) ? $attrInfo['cost'] : 0.0;
- $ppaid = bcmul($num, $price, 2);// product paid
- $pcost = bcmul($num, $cost, 2);
- $oid = $p['id'];
- $p['paid'] = $ppaid;
- $p['cost'] = $pcost;
- if (!isset($orders[$oid])) {
- $orders[$oid] = 1;
- } else {
- $orders[$oid] += 1;
- }
- if ($ppaid <= 1.0) {
- Log::warning("impossible price, order: ". $p['id']);
- continue;
- }
- if ($cost <= 0.1) {
- Log::warning("impossible cost, order: ". $p['id']);
- continue;
- }
- if ($counter % 2) {
- $left[] = $p;
- $left_spent = bcadd($left_spent, $ppaid, 2);
- } else {
- $right[] = $p;
- $right_spent = bcadd($right_spent, $ppaid, 2);
- }
- }
- // free memory
- $products = [];
- // 定输赢
- $diff_money = bcsub($left_spent, $right_spent, 2);
- if ($diff_money < 0.0) {
- $diff_money = -$diff_money;
- }
- $winners = $left;
- $losers = $right;
- if ($left_spent > $right_spent) {
- $winners = $right;
- $losers = $left;
- }
- // 结果处置
- $single = 0;
- foreach($winners as $p) {
- $single = $orders[$p['id']] == 1;
- $this->execute($p, $single, true);
- }
- foreach($losers as $p) {
- $single = $orders[$p['id']] == 1;
- $this->execute($p, $single, false);
- }
- }
- /**
- * 奖励分配
- *
- * @param $product 获奖订单中的商品
- * @param bool $single 是否是单种商品构成的订单
- * @param bool $win 是否中奖
- */
- protected function execute($product, $single=true, $win=true) {
- BaseModel::beginTrans();
- $result = 0;
- $reparation = 0.0;
- if ($win) {
- $result = 1;
- $reparation = bcmul(bcsub($product['paid'], $product['cost'], 2), 0.1, 2);
- }
- // 标记商品为已参与活动
- $r1 = StoreOrderCartInfo::where('oid', $product['id'])
- ->where('product_id', $product['product_id'])
- ->update([
- 'activity' => self::$NAME,
- 'result' => $result,
- 'reparation' => $reparation,
- ]);
- if (!$win) {
- return;
- }
- $refund_price = bcadd($product['paid'], $reparation, 2);
- // 订单全部商品都中奖的退单
- $r2 = true;
- if ($single) {
- $r2 = StoreOrder::where('id', $product['id'])->update([
- 'refund_price' => $refund_price,
- 'refund_status' => 2,
- ]);
- }
- // 中奖的 退款并赔款返回到佣金
- $r3 = UserBill::income('參加活动', $product['uid'], 'now_money', 'brokerage',
- $refund_price, $product['id'], bcadd($product['now_money'], $refund_price, 2),
- '订单退款' . $product['paid'] . '+' . $reparation . '元');
- $r4 = User::bcInc($product['uid'], 'brokerage_price', $refund_price, 'uid');
- $ok = $r1 && $r2 && $r3 && $r4;
- BaseModel::checkTrans($ok);
- if ($ok) {
- // 中奖用户发送中奖消息. TODO
- UserNotice::sendNoticeTo($product['uid'], '您的订单已退款',
- '您好,由于活动商品库存有限,您的订单 ' . $product['store_name']
- . ' 未能成功分配. 该商品付款' . $product['paid'] . '元已如数退还, 并赔付您' . $reparation
- . '元作为补偿, 对您造成的不便我们深感抱歉. 同时感谢您对美天旺的喜爱和信任, 美天旺活动场将永远等您. 顺祝生活愉快.');
- }
- }
- }
|