Browse Source

业务流程逻辑:各省定价不同 & 分成:2/8分,跟代理,1:1分

1557492053 1 year ago
parent
commit
fd8db383a7

+ 4 - 1
application/admin/controller/Area.php

@@ -67,7 +67,6 @@ class Area extends Backend
         return $this->view->fetch();
     }
 
-
     public function selectpage()
     {
         $where = [
@@ -83,6 +82,10 @@ class Area extends Backend
         return $this->c_selectpage($where);
     }
 
+    public function indexv2()
+    {
+        return parent::selectpage();
+    }
 
 }
 

+ 94 - 4
application/admin/controller/service/Service.php

@@ -2,6 +2,7 @@
 
 namespace app\admin\controller\service;
 
+use app\admin\model\Area;
 use app\common\controller\Backend;
 use think\Db;
 use think\exception\PDOException;
@@ -61,7 +62,7 @@ class Service extends Backend
                 ->paginate($limit);
 
             foreach ($list as $row) {
-                $row->visible(['id', 'name', 'cover_image', 'description', 'real_price', 'duration_minute', 'introduce_images', 'hot', 'sift', 'count', 'sort', 'status', 'updatetime']);
+                $row->visible(['id', 'name', 'cover_image', 'province_name', 'description', 'real_price', 'duration_minute', 'introduce_images', 'hot', 'sift', 'count', 'sort', 'status', 'updatetime']);
                 $row->visible(['category']);
                 $row->getRelation('category')->visible(['name']);
             }
@@ -75,13 +76,102 @@ class Service extends Backend
 
     public function add()
     {
-        return parent::c_add(["type" => \E_SERVICE_TYPE::App]);
+        if (false === $this->request->isPost()) {
+            return $this->view->fetch();
+        }
+        $params = $this->request->post('row/a');
+        if (empty($params)) {
+            $this->error(__('Parameter %s can not be empty', ''));
+        }
+        $params = $this->preExcludeFields($params);
+
+        $area = Area::get($params['p_code']);
+        if (!$area) {
+            $this->error('所属省份选择错误');
+        }
+        foreach (["type" => \E_SERVICE_TYPE::App, 'p_code' => $area['area_code'], 'province_name' => $area['name']] as $key => $value) {
+            $params[$key] = $value;
+        }
+        if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
+            $params[$this->dataLimitField] = $this->auth->id;
+        }
+        $result = false;
+        Db::startTrans();
+        try {
+            //是否采用模型验证
+            if ($this->modelValidate) {
+                $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
+                $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
+                $this->model->validateFailException()->validate($validate);
+            }
+            $result = $this->model->allowField(true)->save($params);
+            Db::commit();
+        } catch (ValidateException|PDOException|\Exception $e) {
+            Db::rollback();
+            $this->error($e->getMessage());
+        }
+        if ($result === false) {
+            $this->error(__('No rows were inserted'));
+        }
+        $this->success();
     }
 
-    public function commonselect() {
-       return $this->c_selectpage([["type", "=", \E_SERVICE_TYPE::App]]);
+    public function edit($ids = null)
+    {
+        $row = $this->model->get($ids);
+        if (!$row) {
+            $this->error(__('No Results were found'));
+        }
+        $adminIds = $this->getDataLimitAdminIds();
+        if (is_array($adminIds) && !in_array($row[$this->dataLimitField], $adminIds)) {
+            $this->error(__('You have no permission'));
+        }
+        if (false === $this->request->isPost()) {
+            $this->view->assign('row', $row);
+            return $this->view->fetch();
+        }
+        $params = $this->request->post('row/a');
+        if (empty($params)) {
+            $this->error(__('Parameter %s can not be empty', ''));
+        }
+        $params = $this->preExcludeFields($params);
+
+        $area = Area::get($params['p_code']);
+        if (!$area) {
+            $this->error('所属省份选择错误');
+        }
+        foreach (["type" => \E_SERVICE_TYPE::App, 'p_code' => $area['area_code'], 'province_name' => $area['name']] as $key => $value) {
+            $params[$key] = $value;
+        }
+
+        $result = false;
+        Db::startTrans();
+        try {
+            //是否采用模型验证
+            if ($this->modelValidate) {
+                $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
+                $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate;
+                $row->validateFailException()->validate($validate);
+            }
+            $result = $row->allowField(true)->save($params);
+
+            Db::commit();
+        } catch (ValidateException | PDOException | Exception $e) {
+            Db::rollback();
+            $this->error($e->getMessage());
+        }
+        if (false === $result) {
+            $this->error(__('No rows were updated'));
+        }
+        $this->success();
     }
 
 
 
+    public function commonselect()
+    {
+        return $this->c_selectpage([["type", "=", \E_SERVICE_TYPE::App]]);
+    }
+
+
 }

+ 40 - 13
application/admin/view/service/service/add.html

@@ -6,6 +6,16 @@
             <input id="c-name" class="form-control" name="row[name]" type="text" value="">
         </div>
     </div>
+
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">所属省份:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-p_code" data-rule="required" data-source="area/indexv2"
+                   class="form-control selectpage" data-params='{"custom[level]": "1"}' name="row[p_code]" type="text" value="">
+        </div>
+    </div>
+
+
     <div class="form-group">
         <label class="control-label col-xs-12 col-sm-2">{:__('星级')}:</label>
         <div class="col-xs-12 col-sm-8">
@@ -16,10 +26,16 @@
         <label class="control-label col-xs-12 col-sm-2">{:__('Cover_image')}:</label>
         <div class="col-xs-12 col-sm-8">
             <div class="input-group">
-                <input id="c-cover_image" data-rule="required" class="form-control" size="50" name="row[cover_image]" type="text">
+                <input id="c-cover_image" data-rule="required" class="form-control" size="50" name="row[cover_image]"
+                       type="text">
                 <div class="input-group-addon no-border no-padding">
-                    <span><button type="button" id="faupload-cover_image" class="btn btn-danger faupload" data-input-id="c-cover_image" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="false" data-preview-id="p-cover_image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
-                    <span><button type="button" id="fachoose-cover_image" class="btn btn-primary fachoose" data-input-id="c-cover_image" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
+                    <span><button type="button" id="faupload-cover_image" class="btn btn-danger faupload"
+                                  data-input-id="c-cover_image"
+                                  data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp"
+                                  data-multiple="false" data-preview-id="p-cover_image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
+                    <span><button type="button" id="fachoose-cover_image" class="btn btn-primary fachoose"
+                                  data-input-id="c-cover_image" data-mimetype="image/*" data-multiple="false"><i
+                            class="fa fa-list"></i> {:__('Choose')}</button></span>
                 </div>
                 <span class="msg-box n-right" for="c-cover_image"></span>
             </div>
@@ -41,7 +57,8 @@
     <div class="form-group">
         <label class="control-label col-xs-12 col-sm-2">{:__('Duration_minute')}:</label>
         <div class="col-xs-12 col-sm-8">
-            <input id="c-duration_minute" data-rule="required" class="form-control" name="row[duration_minute]" type="number" value="60">
+            <input id="c-duration_minute" data-rule="required" class="form-control" name="row[duration_minute]"
+                   type="number" value="60">
         </div>
     </div>
     <div class="form-group">
@@ -50,8 +67,13 @@
             <div class="input-group">
                 <input id="c-introduce_images" class="form-control" size="50" name="row[introduce_images]" type="text">
                 <div class="input-group-addon no-border no-padding">
-                    <span><button type="button" id="faupload-introduce_images" class="btn btn-danger faupload" data-input-id="c-introduce_images" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="true" data-preview-id="p-introduce_images"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
-                    <span><button type="button" id="fachoose-introduce_images" class="btn btn-primary fachoose" data-input-id="c-introduce_images" data-mimetype="image/*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
+                    <span><button type="button" id="faupload-introduce_images" class="btn btn-danger faupload"
+                                  data-input-id="c-introduce_images"
+                                  data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp"
+                                  data-multiple="true" data-preview-id="p-introduce_images"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
+                    <span><button type="button" id="fachoose-introduce_images" class="btn btn-primary fachoose"
+                                  data-input-id="c-introduce_images" data-mimetype="image/*" data-multiple="true"><i
+                            class="fa fa-list"></i> {:__('Choose')}</button></span>
                 </div>
                 <span class="msg-box n-right" for="c-introduce_images"></span>
             </div>
@@ -61,7 +83,8 @@
     <div class="form-group">
         <label class="control-label col-xs-12 col-sm-2">{:__('Category_id')}:</label>
         <div class="col-xs-12 col-sm-8">
-            <input id="c-category_id" data-rule="required" data-source="service/category" class="form-control selectpage" name="row[category_id]" type="text" value="">
+            <input id="c-category_id" data-rule="required" data-source="service/category"
+                   class="form-control selectpage" name="row[category_id]" type="text" value="">
         </div>
     </div>
     <div class="form-group">
@@ -69,7 +92,8 @@
         <div class="col-xs-12 col-sm-8">
             <div class="radio">
                 {foreach name="boolList" item="vo"}
-                <label for="row[hot]-{$key}"><input id="row[hot]-{$key}" name="row[hot]" type="radio" value="{$key}" {in name="key" value="0"}checked{/in} /> {$vo}</label>
+                <label for="row[hot]-{$key}"><input id="row[hot]-{$key}" name="row[hot]" type="radio" value="{$key}" {in
+                                                    name="key" value="0" }checked{/in} /> {$vo}</label>
                 {/foreach}
             </div>
         </div>
@@ -79,7 +103,8 @@
         <div class="col-xs-12 col-sm-8">
             <div class="radio">
                 {foreach name="boolList" item="vo"}
-                <label for="row[sift]-{$key}"><input id="row[sift]-{$key}" name="row[sift]" type="radio" value="{$key}" {in name="key" value="0"}checked{/in} /> {$vo}</label>
+                <label for="row[sift]-{$key}"><input id="row[sift]-{$key}" name="row[sift]" type="radio" value="{$key}"
+                                                     {in name="key" value="0" }checked{/in} /> {$vo}</label>
                 {/foreach}
             </div>
         </div>
@@ -99,11 +124,13 @@
     <div class="form-group">
         <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
         <div class="col-xs-12 col-sm-8">
-            
+
             <div class="radio">
-            {foreach name="statusList" item="vo"}
-            <label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio" value="{$key}" {in name="key" value="normal"}checked{/in} /> {$vo}</label>
-            {/foreach}
+                {foreach name="statusList" item="vo"}
+                <label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio"
+                                                       value="{$key}" {in name="key" value="normal" }checked{/in} />
+                    {$vo}</label>
+                {/foreach}
             </div>
 
         </div>

+ 27 - 0
application/api/controller/Card.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace app\api\controller;
+
+class Card
+{
+    private $type;
+
+    private $number;
+
+
+    public function __construct($type, $num)
+    {
+        $this->type = $type;
+        $this->number = $type + $num;
+    }
+
+    public function getType() {
+        return $this->type;
+    }
+
+    public function getNumber() {
+        return $this->number - $this->type;
+    }
+
+
+}

+ 26 - 0
application/api/controller/Service.php

@@ -65,6 +65,32 @@ class Service extends Api
         ]);
     }
 
+
+
+    /// 根据地区筛选
+    public function fetchAppV2()
+    {
+        $params = (new BaseApiValidate([
+            'p_code' => "require|number",
+            'category_id' => "number",
+            'hot' => "number"
+        ]))->checkBody();
+        $user = $this->auth->getUser();
+
+        list($page, $size) = [$params['page'] ?? 1, $params['size'] ?? 10];
+        $paginate = $this->serviceModel->fetchServicesV2(\E_SERVICE_TYPE::App, $params, $page, $size, $user);
+        $items = collection($paginate->items())->toArray();
+
+        $membership_discount_rate = config("site.membership_discount_rate") / 100;
+        foreach ($items as &$item) {
+            $item["membership_discount_price"] = fixed2Float($item["real_price"] * $membership_discount_rate);
+        }
+        $this->success([
+            $items,
+            $paginate->total()
+        ]);
+    }
+
     /**
      * 获取球房服务分类
      */

+ 4 - 4
application/api/controller/Test.php

@@ -25,9 +25,6 @@ class Test extends Api
         var_dump($result);
     }
 
-    public function test2()
-    {
-    }
 
     /**
      * 获取证书
@@ -197,7 +194,10 @@ class Test extends Api
 }
 
 
-
+/**
+ * 各省定价不相同 获取服务时候 根据位置获取服务
+ * 抽成比例更换
+ */
 
 
 

+ 25 - 0
application/api/model/service/Service.php

@@ -42,5 +42,30 @@ class Service extends BaseModel
             ->paginate($size);
     }
 
+    public function fetchServicesV2($type, $params, $page = 1, $size = 10, $user = null)
+    {
+        $where = [
+            'type' => $type,
+            'status' => \E_BASE_STATUS::Normal,
+            'p_code' => $params['p_code']
+        ];
+        if (isset($params['category_id']) && $params['category_id'] > 0)
+            $where['category_id'] = $params['category_id'];
+        if (isset($params['hot']) && $params['hot'])
+            $where['hot'] = 1;
+        if (isset($params['store_id']) && $params['store_id'] > 0)
+            $where['store_id'] = $params['store_id'];
+        if (isset($params["sift"]) && $params['sift'])
+            $where['sift'] = 1;
+        if (!isset($params["is_add_clock"]) || $params["is_add_clock"] != 1) {
+            $where['is_add_clock'] = 0;
+        }
+        return $this->where($where)
+            ->order('sort', 'desc')
+            ->order('real_price', 'ASC')
+            ->page($page)
+            ->paginate($size);
+    }
+
 
 }

+ 185 - 2
application/api/service/ProfitService.php

@@ -5,10 +5,8 @@ namespace app\api\service;
 
 use app\admin\model\Admin;
 use app\admin\model\profit\Bill;
-use app\api\model\Channel;
 use app\api\model\massager\Massager;
 use app\api\model\massager\Wallet;
-use app\api\model\massager\Work;
 use app\api\model\Store;
 use app\api\model\User;
 use redis\RedLock;
@@ -338,6 +336,191 @@ class ProfitService extends BaseService
         }
     }
 
+
+    public function profitV2($order, $user, $unusual = false)
+    {
+        $platform = $this->adminModel->where("id", "=", 1)->find();
+        if (!$platform)
+            return $this->fail("Admin不存在!");
+        $massager = $this->massagerModel->getMassager($order->massager_id);
+        if ($order["massager_id"] > 0) {
+            if (!$massager)
+                return $this->fail("助教信息不存在!");
+        }
+        $agency = $this->adminModel->findAgency($order->city_code);
+        $redLock = new RedLock();
+        $agencyLock = false;
+        $sLock = false;
+        $mLock = false;
+        if ($agency) {
+            $agencyLock = $redLock->lock(Admin::AgencyKey($agency->id));
+            if (!is_array($agencyLock))
+                return $this->fail("请稍后再试!");
+        }
+        // 平台抽成比例
+        $platform_rate = 10;
+        // 代理商抽成比例
+        $agency_rate = 0;
+        $store = $this->storeModel->findById($order->store_id ?? -1);
+        $self_rate = 0;
+        if ($order["store_id"] > 0) { // 球房分润标准
+        } else { // 线上分润标准
+            $mLock = $redLock->lock(\app\api\model\massager\Wallet::MWKey($order->massager_id));
+            if (!is_array($mLock))
+                return $this->fail("请稍后再试");
+            // 本人比例
+            $self_rate = 80;
+            if ($agency) {
+                $agency_rate = 10;
+            } else {
+                // 如果代理商不存在 则剩余部分 全部归于平台;
+                $platform_rate = 20;
+            }
+        }
+
+
+        if (fixed2Float(($platform_rate + $agency_rate + $self_rate)) != 100) {
+            return $this->fail("比例计算错误!");
+        }
+        $pLock = $redLock->lock(Admin::PlatformKey());
+        if (!is_array($pLock))
+            return $this->fail("请稍后再试!");
+        $mWallet = $this->mWalletModel->getWallet($order->massager_id);
+        $locks = [$pLock, $agencyLock, $sLock, $mLock];
+        $trip_amount = $order->trip_amount;
+        // 实际支付金额 - 出行费 = 订单分润金额
+        $total_profit_amount = $order->total_real_amount - $trip_amount;
+        if ($unusual && $order["is_refund_trip"] == 1) {
+            $trip_amount = 0;
+        }
+        if ($unusual) { // 管理员终止
+            $total_profit_amount = $order->total_real_amount - $order->refund_amount - $trip_amount;
+        }
+
+        if ($total_profit_amount <= 0)
+            return $this->fail("分润金额小于0");
+
+        $p_profit_amount = fixed2Float($total_profit_amount * ($platform_rate / 100));
+        $a_profit_amount = $agency_rate > 0 ? fixed2Float($total_profit_amount * ($agency_rate / 100)) : 0;
+        $self_profit_amount = fixed2Float($total_profit_amount * ($self_rate / 100));
+
+        Db::startTrans();
+        try {
+            $profit_bills = [
+                [
+                    "identity_type" => \E_IDENTITY_TYPE::Platform,
+                    "target_id" => 1,
+                    "target_name" => "平台",
+                    "change_type" => \E_PROFIT_BILL_CHANGE_TYPE::Profit,
+                    "order_no" => $order->no,
+                    "total_amount" => $total_profit_amount,
+                    "rate" => $platform_rate,
+                    "change" => $p_profit_amount,
+                    "before" => $platform->profit_amount,
+                    "after" => fixed2Float($platform->profit_amount + $p_profit_amount),
+                    "createtime" => time(),
+                    "city_code" => $order->city_code
+                ]
+            ];
+            if ($order->store_id > 0) { // 门店
+                $after = fixed2Float($store->profit_amount + $self_profit_amount);
+                $profit_bills[] = [
+                    "identity_type" => \E_IDENTITY_TYPE::Store,
+                    "target_id" => $store->id,
+                    "target_name" => $store->name,
+                    "change_type" => \E_PROFIT_BILL_CHANGE_TYPE::Profit,
+                    "order_no" => $order->no,
+                    "total_amount" => $total_profit_amount,
+                    "rate" => $self_rate,
+                    "change" => $self_profit_amount,
+                    "before" => $store->profit_amount,
+                    "after" => $after,
+                    "createtime" => time(),
+                    "city_code" => $order->city_code
+                ];
+                $this->storeModel->where("id", $store->id)->setInc("profit_amount", $self_profit_amount);
+            } else { // 助教
+                $after = fixed2Float($mWallet->profit_amount + $self_profit_amount);
+                $profit_bills[] = [
+                    "identity_type" => \E_IDENTITY_TYPE::Massager,
+                    "target_id" => $massager->id,
+                    "target_name" => $massager->name,
+                    "change_type" => \E_PROFIT_BILL_CHANGE_TYPE::Profit,
+                    "order_no" => $order->no,
+                    "total_amount" => $total_profit_amount,
+                    "rate" => $self_rate,
+                    "change" => $self_profit_amount,
+                    "before" => $mWallet->profit_amount,
+                    "after" => $after,
+                    "createtime" => time(),
+                    "city_code" => $order->city_code
+                ];
+                $m_bills = [
+                    [
+                        "massager_id" => $massager->id,
+                        "currency_type" => \E_USER_BILL_CURRENCY_TYPE::Money,
+                        "change_type" => \E_M_BILL_CHANGE_TYPE::Profit,
+                        "change" => $self_profit_amount,
+                        "before" => $mWallet->profit_amount,
+                        "after" => $after,
+                        "reason" => "服务费用",
+                        "relation_no" => $order->no,
+                        "createtime" => time()
+                    ]
+                ];
+
+                if ($trip_amount > 0) {
+                    $m_bills[] = [
+                        "massager_id" => $massager->id,
+                        "currency_type" => \E_USER_BILL_CURRENCY_TYPE::Money,
+                        "change_type" => \E_M_BILL_CHANGE_TYPE::Travel,
+                        "change" => $trip_amount,
+                        "before" => $after,
+                        "after" => $after + $trip_amount,
+                        "reason" => "出行费用",
+                        "relation_no" => $order->no,
+                        "createtime" => time()
+                    ];
+                }
+                $this->mWalletModel->where("id", $mWallet->id)->setInc(
+                    "profit_amount",
+                    ($self_profit_amount + $trip_amount)
+                );
+                $this->mBillModel->insertAll($m_bills);
+            }
+            if ($agency && $a_profit_amount > 0) {
+                $profit_bills[] = [
+                    "identity_type" => \E_IDENTITY_TYPE::Agency,
+                    "target_id" => $agency->id,
+                    "target_name" => $agency->nickname,
+                    "change_type" => \E_PROFIT_BILL_CHANGE_TYPE::Profit,
+                    "order_no" => $order->no,
+                    "total_amount" => $total_profit_amount,
+                    "rate" => $agency_rate,
+                    "change" => $a_profit_amount,
+                    "before" => $agency->profit_amount,
+                    "after" => fixed2Float($agency->profit_amount + $a_profit_amount),
+                    "createtime" => time(),
+                    "city_code" => $order->city_code
+                ];
+                $this->adminModel->where("id", $agency->id)->setInc("profit_amount", $a_profit_amount);
+            }
+            $this->adminModel->where("id", 1)->setInc("profit_amount", $p_profit_amount);
+            $this->pBillModel->insertAll($profit_bills);
+            Db::commit();
+            return $this->ok(true);
+        } catch (Exception $e) {
+            Db::rollback();
+            return $this->fail($e->getMessage());
+        } finally {
+            foreach ($locks as $lock) {
+                if (is_array($lock))
+                    $redLock->unlock($lock);
+            }
+        }
+    }
+
+
 }
 
 

+ 4 - 2
public/assets/js/backend/service/service.js

@@ -21,13 +21,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
             table.bootstrapTable({
                 url: $.fn.bootstrapTable.defaults.extend.index_url,
                 pk: 'id',
-                sortName: 'id',
+                sortName: 'level',
+                sortOrder: 'ASC',
                 fixedColumns: true,
                 fixedRightNumber: 1,
                 columns: [
                     [
                         {checkbox: true},
                         {field: 'id', title: __('Id')},
+                        {field: 'province_name', title: '所属省份', operate: 'LIKE'},
                         {field: 'category.name', title: __('分类名称'), operate: 'LIKE'},
                         {field: 'name', title: __('Name'), operate: 'LIKE'},
                         {
@@ -49,7 +51,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                         {field: 'hot', title: __('Hot'), formatter: (value) => ["否", "是"][value]},
                         {field: 'sift', title: __('Sift'), formatter: (value) => ["否", "是"][value]},
                         {field: 'count', title: __('Count')},
-                        {field: 'sort', title: __('Sort')},
+                        {field: 'sort', title: __('Sort'), sortable:true},
                         {
                             field: 'status',
                             title: __('Status'),