Преглед изворни кода

作业计费逻辑变更及测试变更

Zhouzhendong пре 5 година
родитељ
комит
450e5e0930

+ 8 - 2
app/Http/Controllers/TestController.php

@@ -44,6 +44,7 @@ use App\Services\OrderTrackingService;
 use App\Services\OwnerService;
 use App\Services\StoreService;
 use App\Services\WarehouseService;
+use App\Unit;
 use App\User;
 use App\Warehouse;
 use Carbon\Carbon;
@@ -52,6 +53,7 @@ use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Cache;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Redis;
 use Illuminate\Support\Str;
 use Maatwebsite\Excel\Facades\Excel;
 use Ramsey\Collection\Collection;
@@ -92,8 +94,12 @@ class TestController extends Controller
         }
     }
     public function test4(){
-        $a = new FeatureService();
-        dd($a->matchFeature("1&2&3",[],[]));
+        $units = Unit::get();
+        //dd($units);
+        foreach ($units as $index => $unit){
+            if ($index!=1)unset($units[$index]);
+        }
+        dd($units);
     }
 
     public function updateLaborRemark(){

+ 50 - 8
app/Services/FeatureService.php

@@ -196,31 +196,43 @@ Class FeatureService
      *      $vale : 特征简述 例: "1&2|(3|4)"
      *      $columnMapping : 列映射 例:["商品名称"=>"commodity_name"]
      *      $matchObject : 被匹配对象,必须存在列映射所指定字段 例:["commodity_name"=>"衣服"]
+     *      $isMultiMatching 是否开启多重匹配 开启将匹配对象视为二维数组深层寻找商品(入库需要)
      *      bool true匹配成功 false匹配失败
      *
      * @param string $value
      * @param array $columnMapping
      * @param array $matchObject
+     * @param bool $isMultiMatching
      * @return bool
      */
-    public function matchFeature($value, $columnMapping, $matchObject) :bool
+    public function matchFeature($value, $columnMapping, $matchObject, $isMultiMatching = false) :bool
     {
         preg_match_all('/\d+|[\&\|\(\)]/',$value,$result);
         if (implode("",$result[0]) != $value)return false;
 
-        preg_match_all('/\d+/',$value,$ids);
-        if ($ids[0])$fs = Feature::query()->whereIn("id",$ids[0])->get();
-        else return false;
-        $features = [];
-        foreach ($fs as $f){
-            $features[$f->id] = $f;
-        }
+        $features = app(CacheService::class)->getOrExecute($value,function ()use($value){
+            preg_match_all('/\d+/',$value,$ids);
+            if ($ids[0])$fs = Feature::query()->whereIn("id",$ids[0])->get();
+            else return false;
+            $features = [];
+            foreach ($fs as $f){
+                $features[$f->id] = $f;
+            }
+            return $features;
+        });
+
 
         foreach ($result[0] as &$str) {
             if (is_numeric($str) && isset($features[$str])) {
                 $column = $features[$str]["type"];
                 $logic = $features[$str]["logic"];
                 $describe = $features[$str]["describe"];
+                if ($column == '商品名称' && $isMultiMatching){
+                    $packageColumn = $columnMapping["packages"] ?? "packages";
+                    $packages = $matchObject[$packageColumn] ?? [];
+                    $str = $this->multiMatching($packages,$logic,$describe,$columnMapping[$column] ?? '');
+                    continue;
+                }
                 $value = isset($columnMapping[$column]) ? $matchObject[$columnMapping[$column]] : '';
                 switch ($logic) {
                     case "包含":
@@ -247,4 +259,34 @@ Class FeatureService
         return eval("return $is;");
     }
 
+    /**
+     * 多重子项匹配
+     *
+     * @param array $packages
+     * @param string $logic
+     * @param string $describe
+     * @param string $column
+     * @return string           //"true" || "false"
+     */
+    private function multiMatching($packages, $logic, $describe, $column):string
+    {
+        if(!$column)return 'false';
+
+        foreach ($packages as $package){
+            $value = $package[$column] ?? '';
+            switch ($logic) {
+                case "包含":
+                    if (mb_strpos($value,$describe)!==false)return 'true';
+                    break;
+                case "不包含":
+                    if (mb_strpos($value,$describe) === false)return 'true';
+                    break;
+                case "等于":
+                    if ($value == $describe)return 'true';
+                    break;
+            }
+        }
+        return "false";
+    }
+
 }

+ 0 - 1
app/Services/LogService.php

@@ -7,7 +7,6 @@ namespace App\Services;
 use App\Log;
 use Exception;
 use Illuminate\Support\Facades\Redis;
-use Illuminate\Support\Facades\Request;
 
 class LogService
 {

+ 89 - 81
app/Services/OwnerPriceOperationService.php

@@ -97,26 +97,26 @@ Class OwnerPriceOperationService
     /** 参数顺序: 数量 匹配对象 列映射 货主ID 单位ID 类型 SKU .
      *  匹配顺序: 类型 货主 策略 单位 特征                    ..多对多匹配规则废弃,1对1,设单位必定为件,对应规则必然只有一项存在
      *  单位匹配: 件,箱,单 由小到大,依次换算匹配           .
-     * @param int $amount
+     *
+     *  2:没有总数量存在,都为子项内数量
+     *
      * @param array|object $matchObject  key-val
      * @param array $columnMapping       key-val
      * @param string $owner_id
      * @param string $type
      * @param string $sku
      * @return double
-     * 错误代码: -1:非法数量 -2:无计费模型 -3:未知单位 -4:sku为空 -5:货主未找到 -6:无箱规 -7:未匹配到计费模型
+     * 错误代码: -1:无匹配对象 -2:无计费模型 -3:未知单位 -4:sku为空 -5:货主未找到 -6:无箱规 -7:未匹配到计费模型
      */
-    public function matchRule($amount, $matchObject, $columnMapping, $owner_id, $sku = null, $type = '出库')
+    public function matchRule($matchObject, $columnMapping, $owner_id, $sku = null, $type = '出库')
     {
-        if ($amount <= 0 )return -1;
-
         $unitModels = Unit::query()->whereIn("name",["件","箱","单"])->get();
         $units = [];
         foreach ($unitModels as $unitModel)$units[$unitModel->id] = $unitModel->name;
 
         $withs = $type=='出库' ? ['ownerOutStorageRules'=>function($query){
             /** @var Builder $query */
-            $query->orderByRaw("CASE strategy  WHEN '默认' THEN 1 WHEN '特征' THEN 2 WHEN '起步' THEN 3 END DESC,priority DESC");
+            $query->orderByRaw("CASE strategy  WHEN '起步' THEN 1 WHEN '默认' THEN 2 WHEN '特征' THEN 3 END DESC,priority DESC");
         }] : ['ownerInStorageRule'] ;
         $rules = OwnerPriceOperation::query()->with($withs)
             ->where("operation_type",$type)
@@ -128,7 +128,15 @@ Class OwnerPriceOperationService
         if (!$rules)return -2;
 
         if ($type == '入库'){
-            foreach ($rules as $index => $rule){
+            $amountColumn = $columnMapping["amount"] ?? "amount";
+            $packageColumn = $columnMapping["packages"] ?? "packages";
+            $packages = $matchObject[$packageColumn] ?? false;
+            if (!$packages)return -1;
+
+            $amount = 0;
+            foreach ($packages as $package)$amount += $package[$amountColumn] ?? 0;
+            if (!$amount)return -1;
+            foreach ($rules as $rule){
                 $sum = $amount;
                 if (!$rule->ownerInStorageRule)continue;
                 if ($rule->strategy == '特征'){
@@ -137,10 +145,7 @@ Class OwnerPriceOperationService
                         if (!isset($units[$rule->ownerInStorageRule->unit_id])) return -3;
                         if ($units[$rule->ownerInStorageRule->unit_id] == '箱'){ //为箱时同步商品寻找箱规
                             $sum = $this->changeUnit($sum,$owner_id,$sku);
-                            if ($sum<0){
-                                if ($index == count($rules)-1)return $sum;
-                                continue;
-                            }
+                            if ($sum<0)return $sum;
                         }
                         if ($units[$rule->ownerInStorageRule->unit_id] == '单')$sum = 1; //为单时数量设为1;
                         return ceil($sum/$rule->ownerInStorageRule->amount)*$rule->ownerInStorageRule->unit_price;
@@ -149,10 +154,7 @@ Class OwnerPriceOperationService
                     if (!isset($units[$rule->ownerInStorageRule->unit_id])) return -3;
                     if ($units[$rule->ownerInStorageRule->unit_id] == '箱'){ //为箱时同步商品寻找箱规
                         $sum = $this->changeUnit($sum,$owner_id,$sku);
-                        if ($sum<0){
-                            if ($index == count($rules)-1)return $sum;
-                            continue;
-                        }
+                        if ($sum<0)return $sum;
                     }
                     if ($units[$rule->ownerInStorageRule->unit_id] == '单')$sum = 1; //为单时数量设为1;
                     return ceil($sum/$rule->ownerInStorageRule->amount)*$rule->ownerInStorageRule->unit_price;
@@ -166,11 +168,11 @@ Class OwnerPriceOperationService
             if ($rule->strategy == '特征'){
                 $bool = app("FeatureService")->matchFeature($rule->feature,$columnMapping,$matchObject);//匹配特征
                 if ($bool === true){
-                    $money = $this->matchOutStorage($amount,$rule->ownerOutStorageRules,$columnMapping,$matchObject,$units,$owner_id,$sku);
+                    $money = $this->matchOutStorage($rule->ownerOutStorageRules,$columnMapping,$matchObject,$units,$owner_id,$sku);
                     if ($money>0)return $money;
                 };
             }else{
-                $money = $this->matchOutStorage($amount,$rule->ownerOutStorageRules,$columnMapping,$matchObject,$units,$owner_id,$sku);
+                $money = $this->matchOutStorage($rule->ownerOutStorageRules,$columnMapping,$matchObject,$units,$owner_id,$sku);
                 if ($money>0)return $money;
             };
         }
@@ -183,87 +185,93 @@ Class OwnerPriceOperationService
         if (!$pack)return -6;
         return ceil($amount/$pack);
     }
-    private function matchOutStorage($amount, $rules, $columnMapping, $matchObject, $units, $owner_id, $sku)
+
+    private function matchOutStorage($rules, $columnMapping, $matchObject, $units, $owner_id, $sku)
     {
-        $money = 0;
-        foreach ($rules as $index => $rule){
-            $sum = $amount;
-            switch ($rule->strategy){
-                case "起步":
-                    $money = $rule->amount * $rule->unit_price;
-                    if ($units[$rule->unit_id] == '箱') { //为箱时同步商品寻找箱规
-                        if (!$sku)return -4;
-                        $pack = app("CommodityService")->getPack($owner_id,$sku);
-                        if (!$pack)return -6;
-                        $rule->amount *= $pack;
-                    }
+        $amountColumn = $columnMapping["amount"] ?? "amount";
+        $packageColumn = $columnMapping["packages"] ?? "packages";
+        $packages = $matchObject[$packageColumn] ?? false;
+        $commodityColumn = $columnMapping["商品名称"] ?? 'commodity';
+        if (!$packages)return -1;
 
-                    if ($amount < $rule->amount)$amount = $rule->amount;
-                    else $amount -= $rule->amount;
-                    break;
+        $unitName = "";
+        foreach ($rules as $rule){
+            switch ($rule->strategy){
                 case "特征":
-                    if (app("FeatureService")->matchFeature($rule->feature,$columnMapping,$matchObject)){
-                        if (!isset($units[$rule->unit_id]) || $units[$rule->unit_id] == '单') return -3;
+                    foreach ($packages as &$package){
+                        if ($package["price"] ?? false)continue;
+                        if (!app("FeatureService")->matchFeature($rule->feature,["商品名称"=>"commodity"],["commodity"=>$package[$commodityColumn] ?? ''])) continue;
+
+                        if (!$unitName)$unitName = $units[$rule->unit_id];
+                        else {
+                            if ($unitName != $units[$rule->unit_id])
+                                return -3;
+                        }
+                        $package["price"] = $rule->unit_price;
+                        if (!isset($units[$rule->unit_id]) || $units[$rule->unit_id] == '单')return -3;
                         if ($units[$rule->unit_id] == '箱'){ //为箱时同步商品寻找箱规
-                            $sum = $this->changeUnit($sum,$owner_id,$sku);
-                            if ($sum<0){
-                                if ($index == count($rules)-1)return $sum;
-                                break;
-                            }
+                            $amount = $this->changeUnit($package[$amountColumn],$owner_id,$sku);
+                            if ($amount<0)return $amount;
+                            $package[$amountColumn] = $amount;
                         }
-                        return (ceil($sum/$rule->amount)*$rule->unit_price)+$money;
-                    };
+                    }
                     break;
                 case "默认":
-                    if (!isset($units[$rule->unit_id]) || $units[$rule->unit_id] == '单') return -3;
-                    if ($units[$rule->unit_id] == '箱'){ //为箱时同步商品寻找箱规
-                        $sum = $this->changeUnit($sum,$owner_id,$sku);
-                        if ($sum<0){
-                            if ($index == count($rules)-1)return $sum;
-                            break;
+                    foreach ($packages as &$package){
+                        if ($package["price"] ?? false)continue; //校验是否已匹配到
+                        if (!$unitName)$unitName = $units[$rule->unit_id]; //校验单位是否一致
+                        else {
+                            if ($unitName != $units[$rule->unit_id])
+                                return -3;
+                        }
+
+                        $package["price"] = $rule->unit_price;
+                        if (!isset($units[$rule->unit_id]) || $units[$rule->unit_id] == '单')return -3;
+                        if ($units[$rule->unit_id] == '箱'){ //为箱时同步商品寻找箱规
+                            $amount = $this->changeUnit($package[$amountColumn],$owner_id,$sku);
+                            if ($amount<0)return $amount;
+                            $package[$amountColumn] = $amount;
                         }
                     }
-                    return (ceil($sum/$rule->amount)*$rule->unit_price)+$money;
                     break;
+                default:
+                    if ($unitName && $unitName != $units[$rule->unit_id])return -3; //校验单位是否一致
+
+                    $money = $rule->amount * $rule->unit_price;
+                    $startNumber = $rule->amount;
+                    $packages = $this->settingCount($packages,$amountColumn,$startNumber);
+                    if ($packages){
+                        foreach ($packages as $package){
+                            $money += $package[$amountColumn] * $package["price"];
+                        }
+                    }
+                    return $money;
             }
         }
         return -7;
     }
-
-    private function matchInStorage($amount, $matchObject, $columnMapping, $owner_id, $unit_id, $rules, $sku, $units = null, $isMatch = false)
+    //设置数量
+    private function settingCount($packages,$amountColumn,$startNumber)
     {
-        /*foreach ($rules as $rule){
-            if ($unit_id != $rule->ownerInStorageRule->unit_id)continue;
-            else{
-                if ($rule->strategy == '特征'){
-                    $bool = app("FeatureService")->matchFeature($rule->feature,$columnMapping,$matchObject);
-                    if ($bool === true){
-                        return ceil($amount/$rule->ownerInStorageRule->amount)*$rule->ownerInStorageRule->unit_price;
-                    };
-                }else{
-                    return ceil($amount/$rule->ownerInStorageRule->amount)*$rule->ownerInStorageRule->unit_price;
-                };
+        if (!$packages) return null;
+        $maxPrice = 0;
+        $index = null;
+        foreach ($packages as $i => $package){
+            if ($package[$amountColumn] <= 0){
+                unset($packages[$i]);continue;
+            }
+            if ($package["price"] > $maxPrice){
+                $maxPrice = $package["price"];
+                $index = $i;
             }
         }
-        //单位换算
-        if (!$units){
-            $unitModels = Unit::query()->whereIn("name",["件","箱","单"])->get();
-            if (!$unitModels) return null;
-            foreach ($unitModels as $unitModel)$units[$unitModel->name] = $unitModel->id;
+        if ($packages[$index][$amountColumn] >= $startNumber){
+            $packages[$index][$amountColumn] -= $startNumber;
+            return $packages;
+        }else{
+            unset($packages[$index]);
+            $startNumber -= $packages[$index][$amountColumn];
+            $this->settingCount($packages,$amountColumn,$startNumber);
         }
-        $name = array_search($unit_id,$units);
-        //递归匹配
-        switch ($name){
-            case "件"://布尔值校验是否匹配过件来确保箱只匹配一次件
-                return $this->matchInStorage($amount, $matchObject, $columnMapping, $owner_id, $units["箱"], $rules, $sku, $units, true);
-            case "箱"://箱存在向下向上转换
-                if ($isMatch){
-                    return $this->matchInStorage($amount, $matchObject, $columnMapping, $owner_id, $units["单"], $rules, $sku, $units);
-                }else{
-                    return $this->matchInStorage($amount, $matchObject, $columnMapping, $owner_id, $units["件"], $rules, $sku, $units);
-                }
-            case "单"://三次匹配皆无,返回null
-                return null;
-        }*/
     }
 }

+ 2 - 2
resources/views/maintenance/priceModel/operation/_addFeature.blade.php

@@ -27,12 +27,12 @@
                         </label>
                         <label class="col-2">
                             <select class="form-control form-control-sm" v-model="feature.type">
-                                <option v-for="t in type" :value="t">@{{ t }}</option>
+                                <option v-for="t in type" :value="t" v-if="(thisIndex == '-1' && t != '商品名称') || (thisIndex != '-1' && t=='商品名称')">@{{ t }}</option>
                             </select>
                         </label>
                         <label class="col-1">
                             <select class="form-control form-control-sm" v-model="feature.logic">
-                                <option v-for="l in logic" :value="l">@{{ l }}</option>
+                                <option v-for="l in logic" :value="l" v-if="thisIndex == '-1' || l != '不包含'">@{{ l }}</option>
                             </select>
                         </label>
                         <label class="col-4">

+ 2 - 1
resources/views/maintenance/priceModel/operation/create.blade.php

@@ -80,7 +80,8 @@
                         <div class="row">
                             <div class="col-4 form-inline">
                                 <label for="amount"><span v-if="model.operation_type=='出库'">起步数:</span><span v-else>计量:</span></label>
-                                <input id="amount" type="number" :class="errors['rules.'+i+'.amount'] ? 'is-invalid' : ''" v-model="rule.amount" class="form-control" required>
+                                <input id="amount" :readonly="(model.operation_type=='出库' && rule.strategy=='起步') || model.operation_type!='出库' ? false : true"
+                                       type="number" :class="errors['rules.'+i+'.amount'] ? 'is-invalid' : ''" v-model="rule.amount" class="form-control" required>
                                 <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors['rules.'+i+'.amount']">
                                     <strong>必须为整数</strong>
                                 </span>

+ 8 - 0
tests/Services/FeatureService/FeatureServiceTest.php

@@ -133,11 +133,19 @@ class FeatureServiceTest extends TestCase
         $this->data["models"][] = $model1->toArray();
         $this->data["models"][] = $model2->toArray();
         $this->data["models"][] = $model3->toArray();
+
         $columnMapping = ["商品名称"=>"commodity","订单类型"=>"order","店铺类型"=>"shop"];
         $matchObject = ["commodity"=>Str::random(2).$model1->describe,"order"=>$model1->describe,"shop"=>$model3->describe];
         $value = $model1->id."&(".$model2->id."&".$model3->id.")";
         $result = $this->service->matchFeature($value,$columnMapping,$matchObject);
         $this->assertEquals(true,$result);
+
+        $columnMapping = ["商品名称"=>"commodity","订单类型"=>"order","店铺类型"=>"shop","packages"=>"ps"];
+        $matchObject = ["ps"=>[["a"=>1,"commodity"=>Str::random(2).$model1->describe]],"order"=>$model1->describe,"shop"=>$model3->describe];
+        $value = $model1->id."&(".$model2->id."&".$model3->id.")";
+        $result = $this->service->matchFeature($value,$columnMapping,$matchObject,true);
+        $this->assertEquals(true,$result);
+
         $matchObject = ["commodity"=>$model1->describe.Str::random(2),"order"=>$model2->describe.Str::random(2),"shop"=>"1"];
         $result = $this->service->matchFeature($value,$columnMapping,$matchObject);
         $this->assertEquals(false,$result);

+ 16 - 14
tests/Services/OwnerPriceOperationService/OwnerPriceOperationServiceTest.php

@@ -75,41 +75,37 @@ class OwnerPriceOperationServiceTest extends  TestCase
             "owner_price_operation_id"          => $model3->id,
             "strategy"                          =>"起步",
             "amount"                            =>6,
-            "unit_id"                           => $pieces->id,
+            "unit_id"                           => $box->id,
             "unit_price"                        => 2.22,
         ]);
         $out4 = factory(OwnerOutStorageRule::class)->create([
             "owner_price_operation_id"          => $model3->id,
             "strategy"                          => "默认",
-            "amount"                            => 6,
             "unit_id"                           => $box->id,
             "unit_price"                        => 3.22,
         ]);
         $out5 = factory(OwnerOutStorageRule::class)->create([
             "owner_price_operation_id"          => $model3->id,
             "strategy"                          =>"特征",
-            "amount"                            => 6,
-            "unit_id"                           => $single->id,
+            "unit_id"                           => $box->id,
             "unit_price"                        => 4.22,
         ]);
         $out6 = factory(OwnerOutStorageRule::class)->create([
             "owner_price_operation_id"          => $model4->id,
             "strategy"                          =>"起步",
             "amount"                            => 6,
-            "unit_id"                           => $pieces->id,
+            "unit_id"                           => $box->id,
             "unit_price"                        => 5.1,
         ]);
         $out7 = factory(OwnerOutStorageRule::class)->create([
             "owner_price_operation_id"          => $model4->id,
             "strategy"                          => "默认",
-            "amount"                            => 6,
-            "unit_id"                           => $pieces->id,
+            "unit_id"                           => $box->id,
             "unit_price"                        => 5.2,
         ]);
         $out8 = factory(OwnerOutStorageRule::class)->create([
             "owner_price_operation_id"          => $model4->id,
             "strategy"                          =>"特征",
-            "amount"                            => 6,
             "unit_id"                           => $box->id,
             "unit_price"                        => 5.3,
         ]);
@@ -141,14 +137,20 @@ class OwnerPriceOperationServiceTest extends  TestCase
             /** @var Mock $mock */
             $mock->shouldReceive("matchFeature")->andReturn(true);
         });
-        $result = $this->service->matchRule(55,[],[],$this->data["owners"][0]["id"],$this->data["commodities"][0]["sku"],"入库");
+        $result = $this->service->matchRule(["packages"=>[["commodity"=>"测试","amount"=>55]]],[],$this->data["owners"][0]["id"],$this->data["commodities"][0]["sku"],"入库");
         $this->assertEquals(12.88,$result);
-        $result = $this->service->matchRule(56,[],[],$this->data["owners"][0]["id"],null,"入库");
+        $result = $this->service->matchRule(["packages"=>[["commodity"=>"测试","amount"=>57]]],[],$this->data["owners"][0]["id"],$this->data["commodities"][0]["sku"],"出库");
+        $this->assertEquals(99.5,$result);
+    }
+    /**
+     * @group customer
+     */
+    public function testMatchRule1()
+    {
+        $result = $this->service->matchRule(["packages"=>[["commodity"=>"测试","amount"=>56]]],[],$this->data["owners"][0]["id"],$this->data["commodities"][0]["sku"],"入库");
         $this->assertEquals(26.64,$result);
-        $result = $this->service->matchRule(57,[],[],$this->data["owners"][0]["id"],$this->data["commodities"][0]["sku"],"出库");
-        $this->assertEquals(46.5,$result);
-        $result = $this->service->matchRule(58,[],[],$this->data["owners"][0]["id"],null,"出库");
-        $this->assertEquals(77.4,$result);
+        $result = $this->service->matchRule(["packages"=>[["commodity"=>"测试","amount"=>58]]],[],$this->data["owners"][0]["id"],$this->data["commodities"][0]["sku"],"出库");
+        $this->assertEquals(58.4,$result);
     }
 
     public function tearDown(): void