Kaynağa Gözat

项目管理-快递阶梯计费

Zhouzhendong 5 yıl önce
ebeveyn
işleme
1b77113245

+ 2 - 3
app/Commodity.php

@@ -2,7 +2,6 @@
 
 namespace App;
 
-use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use App\Traits\ModelTimeFormat;
 
@@ -13,9 +12,9 @@ class Commodity extends Model
     use ModelLogChanging;
 
     use ModelTimeFormat;
-    protected $fillable=['name','sku','owner_id','created_at','length','width','height','volumn',"type","pack_spec",'updated_at'];
+    protected $fillable=['name','sku','owner_id','created_at','length',
+        'width','height','volumn',"type","pack_spec",'updated_at',"remark"];
     protected $appends=['barcode'];
-//    protected $appends=['barcode','owner_name','owner_code'];
 
     public function setNameAttribute($value){
         $this->attributes['name']=str_replace(PHP_EOL,'',$value);

+ 22 - 2
app/Feature.php

@@ -16,14 +16,34 @@ class Feature extends Model
         "describe", //特征
     ];
 
-    const type = [
+    const TYPE = [
         0 => "商品名称",  //二级
         1 => "订单类型",
         2 => "承运商",
         3 => "店铺类型",
         4 => "波次类型",
-        5 => "商品备注",
+        5 => "商品备注",  //二级
         6 => "长",       //二级
         7 => "订单备注",
     ];
+    const TYPE_NODE = [0,5,6]; //标注二级类型
+    const MAPPING = [
+        "store" => [
+            0 => "storeItems.name",
+            1 => "stored_method",
+            5 => "storeItems.commodity.remark",
+            6 => "storeItems.commodity.length",
+            7 => "remark",
+        ],
+        "order" => [
+            0 => "packages.commodities.commodity.name",
+            1 => "order_type",
+            2 => "logistic.name",
+            3 => "shop.name",
+            4 => "batch.wms_type",
+            5 => "packages.commodities.commodity.remark",
+            6 => "packages.commodities.commodity.length",
+            7 => "remark",
+        ]
+    ];
 }

+ 5 - 2
app/Http/Controllers/CommodityController.php

@@ -232,7 +232,7 @@ class CommodityController extends Controller
         $commodities = $commodityService->getOwnerCommodities(['owner_id' => $owner_id, 'sku'=>$skus]);
         $updateCommodities = [];
         $updateCommodities[] = [
-            'id', 'sku', 'name', 'length', 'width', 'height', 'volumn',"pack_spec"
+            'id', 'sku', 'name', 'length', 'width', 'height', 'volumn',"pack_spec","remark"
         ];
         $barcodeMap = [];
         $commoditiesId = [];
@@ -254,6 +254,7 @@ class CommodityController extends Controller
                     'height' => $wms->skuhigh,
                     'volumn' => $wms->cube,
                     "pack_spec"  => $wms->packid == 'STANDARD' ? 0 : explode("/",$wms->packid)[1],
+                    'remark' => $wms->notes,
                 ];
             }
             if ($wms->alternate_sku1){
@@ -316,6 +317,7 @@ class CommodityController extends Controller
                 'height' => $wms->skuhigh,
                 'volumn' => $wms->cube,
                 "pack_spec"  => $wms->packid == 'STANDARD' ? 0 : explode("/",$wms->packid)[1],
+                'remark' => $wms->notes,
                 "created_at" => $today,
             ];
             $barcodeMap[$wms->sku] = [];
@@ -340,7 +342,7 @@ class CommodityController extends Controller
             $commodities = $commodityService->ownerBarcodeSeekCommodityGet(['id'=>$owner_id], $barcodes);
             $updateCommodities = [];
             $updateCommodities[] = [
-                'id', 'sku', 'name', 'length', 'width', 'height', 'volumn',
+                'id', 'sku', 'name', 'length', 'width', 'height', 'volumn','pack_spec','remark'
             ];
             foreach ($commodities as $commodity){
                 foreach ($commodity->barcodes as $code){
@@ -356,6 +358,7 @@ class CommodityController extends Controller
                             'height' => $goods['height'],
                             'volumn' => $goods['volumn'],
                             "pack_spec" => $goods["pack_spec"],
+                            'remark' => $goods["notes"],
                         ];
                         unset($createCommodities[$barcodeIndex[$code->code]]);
                         break;

+ 7 - 10
app/Http/Controllers/PriceModelController.php

@@ -116,7 +116,8 @@ class PriceModelController extends Controller
             'using_type'=>['required'],
             'minimum_area'=>['nullable','numeric','min:0'],
             'discount_value'=>['nullable','numeric','min:0'],
-            'price'=>['required','numeric','min:0'],
+            'price.*'=>['required','numeric','min:0'],
+            'amount_interval.*'=>['required','integer','min:0'],
             'discount_type'=>['required'],
             'unit_id'=>['required','integer'],
             'time_unit_id'=>['required','integer'],
@@ -129,7 +130,8 @@ class PriceModelController extends Controller
             'counting_type' =>"计费类型",
             'using_type'    =>"用仓类型",
             'minimum_area'  =>"最低起租面积",
-            'price'         =>"单价",
+            'price.*'       =>"单价",
+            'amount_interval.*'=>"数量区间",
             'discount_type' =>"减免类型",
             'discount_value'=>"减免值",
             'unit_id'       =>"单位",
@@ -1144,6 +1146,7 @@ class PriceModelController extends Controller
             "discount_value"    => request("discount_value") ?? 0,
             "unit_id"           => request("unit_id"),
             "time_unit_id"      => request("time_unit_id"),
+            "amount_interval"   => request("amount_interval") ?? null,
         ];
         if (request("id")){
             $model = app('OwnerStoragePriceModelService')->find(request("id"));
@@ -1183,6 +1186,7 @@ class PriceModelController extends Controller
             "operation_type"    => request("operation_type"),
             "strategy"          => request("strategy"),
             "feature"           => request("feature"),
+            "type_mark"         => request()->has("type_mark") ? \request("type_mark") : null,
             "remark"            => request("remark"),
             "discount_count"    => implode(",",request("discount_count")),
             "total_price"       => request("total_price"),
@@ -1219,14 +1223,7 @@ class PriceModelController extends Controller
                 if ($delete)app("OwnerPriceOperationItemService")->destroy($delete);
                 if (count($update) > 1)app(BatchUpdateService::class)->batchUpdate("owner_price_operation_items",$update);
                 if ($insert)app("OwnerPriceOperationItemService")->insert($insert);
-            }else{
-                foreach ($params["items"] as &$item){
-                    unset($item["id"]);
-                    $item["feature"] = $item["feature"] ?? null;
-                    $item["discount_price"] = implode(",",$item["discount_price"] ?? []);
-                }
-                $model = app("OwnerPriceOperationService")->copy($model,$operation,null,$params["items"],false);
-            }
+            }else $model = app("OwnerPriceOperationService")->copy($model,$operation,null,$params["items"],false);
         }else{
             DB::transaction(function ()use(&$model,$params,$operation){
                 $model = app('OwnerPriceOperationService')->create($operation);

+ 2 - 0
app/Http/Controllers/RejectedController.php

@@ -3,6 +3,7 @@
 namespace App\Http\Controllers;
 
 use App\Imports\RejectedImport;
+use App\Jobs\RejectedBillCreateInstantBill;
 use App\Logistic;
 use App\Owner;
 use App\QualityLabel;
@@ -307,6 +308,7 @@ class RejectedController extends Controller
             if (!$re){
                 return ['success'=>'false','fail_info'=>"数据 {$rejected['id']} 更新失败"];
             }
+            dispatch(new RejectedBillCreateInstantBill($rejected));
         });
         app('LogService')->log(__METHOD__,__FUNCTION__,json_encode($request->toArray()),Auth::user()['id']);
         return ['success'=>'true'];

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

@@ -123,6 +123,7 @@ use Illuminate\Support\Facades\Hash;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Support\Facades\Redis;
 use Illuminate\Support\Facades\Storage;
+use Illuminate\Support\Facades\Validator;
 use Illuminate\Support\Str;
 use Maatwebsite\Excel\Facades\Excel;
 use Mockery\Mock;
@@ -145,29 +146,10 @@ class TestController extends Controller
         return call_user_func([$this, $method], $request);
     }
 
-    public function bindOrder()
-    {
-        ini_set('max_execution_time',2500);
-        ini_set('memory_limit','1526M');
-        $models = Waybill::query()->whereNotNull("wms_bill_number")->whereNotIn("status",['已完结','无模型'])->get();
-        foreach ($models as $model){
-            $order = Order::query()->where("code",$model->wms_bill_number)->first();
-            if ($order)$model->update(["order_id"=>$order->id]);
-        }
-    }
-
     public function tt1()
     {
-        $a = "";
-        $b = "1";
 
-        //dump($a??$b);
-        dump([]?'c':[]);
-        dump('0'?'c':[]);
-        dump(0?'c':[]);
-        dump(''?'c':[]);
-        dump(false?'c':[]);
-        dump(null?'c':[]);
+
     }
     public function zzd(){
         ini_set('max_execution_time',2500);

+ 1 - 1
app/Imports/UpdatePickZone.php

@@ -181,7 +181,7 @@ class UpdatePickZone implements ToCollection,WithHeadingRow
                 ];
             }
         }
-        Cache::put("commodityAssign",["success"=>true,"data"=>$models,"errors"=>$errors]);
+        Cache::put("commodityAssign",["success"=>true,"data"=>$models,"errors"=>array_unique($errors)]);
     }
 
     private function matchingMax($lots, $amount)

+ 43 - 0
app/Jobs/RejectedBillCreateInstantBill.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Jobs;
+
+use App\RejectedBill;
+use App\Services\LogService;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class RejectedBillCreateInstantBill implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+    protected $rejected;
+    /**
+     * Create a new job instance.
+     *
+     * @return void
+     *
+     * @param RejectedBill $rejectedBill
+     */
+    public function __construct(RejectedBill $rejectedBill)
+    {
+        $this->rejected = $rejectedBill;
+    }
+
+    /**
+     * Execute the job.
+     *
+     * @return void
+     */
+    public function handle()
+    {
+        try{
+            app("RejectedBillService")->buildInstantBill($this->rejected);
+        }catch(\Exception $exception){
+            LogService::log(__CLASS__,"退货单建立即时账单",$exception->getMessage()." | ".json_encode($this->rejected));
+        }
+    }
+}

+ 6 - 0
app/OwnerPriceExpress.php

@@ -17,6 +17,12 @@ class OwnerPriceExpress extends Model
         "additional_weight",//续重
         "operation",        //操作
         "target_id",        //目标ID
+        "amount_interval",  //数量区间
+        "weight_interval",  //重量区间
+    ];
+    protected $casts = [
+        "amount_interval" => "array",
+        "weight_interval" => "array"
     ];
 
     public function owners()

+ 4 - 0
app/OwnerPriceExpressProvince.php

@@ -16,6 +16,10 @@ class OwnerPriceExpressProvince extends Model
         "initial_weight_price",     //初始单价
         "additional_weight_price",  //续重单价
     ];
+    protected $casts = [
+        "initial_weight_price" => "array",
+        "additional_weight_price" => "array"
+    ];
 
     public function ownerPriceExpress()
     {   //快递计费

+ 4 - 0
app/OwnerPriceOperation.php

@@ -22,10 +22,14 @@ class OwnerPriceOperation extends Model
         "total_discount_price",//按单计价减免
         "operation",        //操作
         "target_id",        //目标ID
+        "type_mark",        //类型标记
     ];
     public static $features = null;
     public static $columnMapping = null;
 
+    const MARK=[
+        0 => "退货单",
+    ];
     public function items()
     {   //出库规则
         return $this->hasMany(OwnerPriceOperationItem::class,"owner_price_operation_id","id");

+ 5 - 0
app/OwnerStoragePriceModel.php

@@ -22,6 +22,11 @@ class OwnerStoragePriceModel extends Model
         "time_unit_id",     //计时单位ID
         "operation",        //操作
         "target_id",        //目标ID
+        "amount_interval",  //数量区间
+    ];
+    protected $casts = [
+        "amount_interval" => "array",
+        "price" => "array"
     ];
 
     public function unit()

+ 17 - 4
app/Services/CommodityService.php

@@ -138,6 +138,8 @@ class CommodityService
             "width" => $wmsCommodity->skuwidth,
             "height" => $wmsCommodity->skuhigh,
             "volumn" => $wmsCommodity->cube,
+            "pack_spec"  => $wmsCommodity->packid == 'STANDARD' ? 0 : explode("/",$wmsCommodity->packid)[1],
+            "remark" => $wmsCommodity->notes,
         ]);
         if ($wmsCommodity->alternate_sku1) app('CommodityBarcodeService')->first([
             'commodity_id' => $commodity->id,
@@ -233,7 +235,9 @@ class CommodityService
                 'length' => $bas_sku->skulength,
                 'width' => $bas_sku->skuwidth,
                 'height' => $bas_sku->skuhigh,
-                'volumn' => $bas_sku->cube
+                'volumn' => $bas_sku->cube,
+                "pack_spec"  => $bas_sku->packid == 'STANDARD' ? 0 : explode("/",$bas_sku->packid)[1],
+                "remark" => $bas_sku->notes,
             ];
         }
         if (count($insert_params) > 0) {
@@ -324,7 +328,9 @@ class CommodityService
                 'length' => $bas_sku->skulength,
                 'width' => $bas_sku->skuwidth,
                 'height' => $bas_sku->skuhigh,
-                'volumn' => $bas_sku->cube
+                'volumn' => $bas_sku->cube,
+                "pack_spec"  => $bas_sku->packid == 'STANDARD' ? 0 : explode("/",$bas_sku->packid)[1],
+                "remark" => $bas_sku->notes,
             ];
         });
         if (count($inner_params) > 0) {
@@ -388,7 +394,9 @@ class CommodityService
             'length' => $basSku['skulength'],
             'width' => $basSku['skuwidth'],
             'height' => $basSku['skuhigh'],
-            'volumn' => $basSku['cube']
+            'volumn' => $basSku['cube'],
+            "pack_spec"  => $basSku['packid'] == 'STANDARD' ? 0 : explode("/",$basSku['packid'])[1],
+            "remark" => $basSku['notes'],
         ];
     }
 
@@ -544,6 +552,7 @@ class CommodityService
                     'created_at' => $basSku->addtime,
                     'updated_at' => $basSku->edittime,
                     'pack_spec' => $basSku->packid == 'STANDARD' ? 0 : explode("/", $basSku->packid)[1],
+                    'remark' => $basSku->notes,
                 ];
             });
             return $map;
@@ -591,7 +600,7 @@ class CommodityService
             ->get();
         $commodities_map = $dataHandlerService->dataHeader(['owner_id', 'sku'], $commodities);
         $updateParams = [[
-            'id', 'name', 'sku', 'owner_id', 'length', 'width', 'height', 'volumn', 'pack_spec', 'updated_at', 'created_at'
+            'id', 'name', 'sku', 'owner_id', 'length', 'width', 'height', 'volumn', 'pack_spec', 'remark', 'updated_at', 'created_at'
         ]];
         $insert_params = [];
         $updateBasSkus=collect();
@@ -608,6 +617,7 @@ class CommodityService
                         'width' => $basSku->skuwidth,
                         'height' => $basSku->skuhigh,
                         'volumn' => $basSku->cube,
+                        'remark' => $basSku->notes,
                         'created_at' => $basSku->addtime,
                         'updated_at' => $basSku->edittime,
                         'pack_spec' => $basSku->packid == 'STANDARD' ? 0 : explode("/", $basSku->packid)[1],
@@ -620,6 +630,7 @@ class CommodityService
                   $commodity->width != $basSku->skuwidth ||
                   $commodity->height != $basSku->skuhigh ||
                   $commodity->volumn != $basSku->cube ||
+                  $commodity->remark != $basSku->notes ||
                   $commodity->created_at != $basSku->addtime ||
                   $commodity->pack_spec != $basSku->pickid ||
                   $commodity->updated_at != $basSku->edittime
@@ -634,6 +645,7 @@ class CommodityService
                     'width' => $basSku->skuwidth,
                     'height' => $basSku->skuhigh,
                     'volumn' => $basSku->cube,
+                    'remark' => $basSku->notes,
                     'created_at' => $basSku->addtime,
                     'updated_at' => $basSku->edittime,
                     'pack_spec' => $basSku->packid == 'STANDARD' ? 0 : explode("/", $basSku->packid)[1],
@@ -871,6 +883,7 @@ class CommodityService
                 'width' => $basSku->skuwidth,
                 'height' => $basSku->skuhigh,
                 'volumn' => $basSku->cube,
+                'remark' => $basSku->notes,
                 'created_at' => $basSku->addtime,
                 'updated_at' => $basSku->edittime,
                 'pack_spec' => $basSku->packid == 'STANDARD' ? 0 : explode("/", $basSku->packid)[1],

+ 70 - 78
app/Services/FeatureService.php

@@ -73,7 +73,7 @@ class FeatureService
             foreach ($m as $string){
                 if (is_numeric($string)){//填入特征信息
                     if (isset($featureMap[$string])){
-                        $arr["type"] = Feature::type[$features[$featureMap[$string]]->type];
+                        $arr["type"] = Feature::TYPE[$features[$featureMap[$string]]->type];
                         $arr["id"] = $features[$featureMap[$string]]->id;
                         $arr["logic"] = $features[$featureMap[$string]]->logic;
                         $arr["describe"] = $features[$featureMap[$string]]->describe;
@@ -128,7 +128,7 @@ class FeatureService
         $map = [];
         foreach ($features as &$feature){
             if (!$feature["type"] || !$feature["logic"] || !$feature["describe"])continue;
-            $typeMap = array_flip(Feature::type);
+            $typeMap = array_flip(Feature::TYPE);
             $f = Feature::query()->firstOrCreate([
                 "type"=>$typeMap[$feature["type"]],  //特征类型
                 "logic"=>$feature["logic"],  //特征逻辑
@@ -163,7 +163,7 @@ class FeatureService
         preg_match_all('/\d+|[\&\|\(\)]/',$value,$result);
         foreach ($result[0] as &$str){
             if (is_numeric($str) && isset($features[$str])){
-                $column = Feature::type[$features[$str]["type"]];
+                $column = Feature::TYPE[$features[$str]["type"]];
                 $logic = $features[$str]["logic"];
                 $describe = $features[$str]["describe"];
                 if ($columnMapping){
@@ -209,106 +209,96 @@ class FeatureService
     }
 
     /**
-     *  匹配特征
-     *      $vale : 特征简述 例: "1&2|(3|4)"
-     *      $columnMapping : 列映射 例:["商品名称"=>"commodity_name"]
-     *      $matchObject : 被匹配对象,必须存在列映射所指定字段 例:["commodity_name"=>"衣服"]
-     *      $isMultiMatching 是否开启多重匹配 开启将匹配对象视为二维数组深层寻找商品(入库需要)
-     *      bool true匹配成功 false匹配失败
+     *  匹配特征 true匹配成功 false匹配失败
      *
      * @param string $value
      * @param array $columnMapping
      * @param array $matchObject
-     * @param bool $isMultiMatching
+     *
      * @return bool
      */
-    public function matchFeature($value, $columnMapping, $matchObject, $isMultiMatching = false) :bool
+    public function matchFeature($value, $columnMapping, $matchObject) :bool
     {
         if (!$value)return true;
 
         preg_match_all('/\d+|[\&\|\(\)]/',$value,$result);
         if (implode("",$result[0]) != $value)return false;
 
-        $features = app(CacheService::class)->getOrExecute($value,function ()use($value){
+        foreach ($result[0] as &$str) {
+            switch ($str){
+                case "&":
+                    $str = "&&";
+                    break;
+                case "|":
+                    $str = "||";
+                    break;
+                default:
+                    $str = $this->match($str, $value, $columnMapping, $matchObject);
+            }
+        }
+        $is = implode("",$result[0]);
+        return eval("return $is;");
+    }
+
+    /**
+     * 匹配实例
+     *
+     * @param string|integer $id
+     * @param string $value
+     * @param array $columnMapping
+     * @param array $matchObject
+     *
+     * @return string
+     */
+    private function match($id, $value, $columnMapping, $matchObject):string
+    {
+        if (!is_numeric($id))return $id; //非特征返回本身
+
+        $features = app(CacheService::class)->getOrExecute("feature:".$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;
-            }
+            foreach ($fs as $f)$features[$f->id] = $f;
             return $features;
         });
 
-        foreach ($result[0] as &$str) {
-            if (is_numeric($str) && isset($features[$str])) {
-                $column = Feature::type[$features[$str]["type"]];
-                $logic = $features[$str]["logic"];
-                $describe = $features[$str]["describe"];
-                if (($column == '商品名称' || $column == '商品备注' || $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 "包含":
-                        $str = mb_strpos($value,$describe) === false ? 'false' : 'true';
-                        break;
-                    case "不包含":
-                        $str = mb_strpos($value,$describe) === false ? 'true' : 'false';
-                        break;
-                    case "等于":
-                        $str = $value == $describe ? 'true' : 'false';
-                        break;
-                    case "小于":
-                        $str = $value < $describe ? 'true' : 'false';
-                        break;
-                    case "大于":
-                        $str = $value > $describe ? 'true' : 'false';
-                        break;
-                    case "小于等于":
-                        $str = $value <= $describe ? 'true' : 'false';
-                        break;
-                    case "大于等于":
-                        $str = $value >= $describe ? 'true' : 'false';
-                        break;
-                    default:
-                        $str = 'false';
-                }
-                continue;
-            }
-            if ($str == "&") {
-                $str = '&&';
-                continue;
-            }
-            if ($str == "|") {
-                $str = '||';
-            }
-        }
-        $is = implode("",$result[0]);
-        return eval("return $is;");
+        if (!isset($features[$id]))return 'false'; //特征不存在返回 false
+        if (!($columnMapping[$features[$id]["type"]] ?? false))return 'false';
+        return $this->getMatchBool($features[$id],$matchObject,explode(".",$columnMapping[$features[$id]["type"]]));
     }
 
     /**
-     * 多重子项匹配
+     * 获取匹配结果
      *
-     * @param array $packages
-     * @param string $logic
-     * @param string $describe
-     * @param string $column
-     * @return string           //"true" || "false"
+     * @param array $feature
+     * @param array|\stdClass $matchObject
+     * @param array $column
+     *
+     * @return string
      */
-    private function multiMatching($packages, $logic, $describe, $column):string
+    private function getMatchBool($feature, $matchObject, $column)
     {
-        if(!$column)return 'false';
-
-        foreach ($packages as $package){
-            $value = $package[$column] ?? '';
+        /*递归: 1.列数组为空 对象不存在列 返回false
+                2.为数组时,递归数组内对象,任意一个符合返回true,全部不符合返回false
+                3.为正常值时,进入核心匹配,必然返回一个值
+                4.为对象时,向下递归,splice列数组
+        */
+        if (!$column)return 'false';
+        if (!isset($matchObject[$column[0]]))return 'false';
+        if (is_array($matchObject)){
+            foreach ($matchObject as $object){
+                if ($this->getMatchBool($feature,$object,$column) === 'true')return 'true';
+            }
+            return 'false';
+        }
+        $value = $matchObject[$column[0]];
+        if (count($column)==1 && (is_string($value) || is_numeric($value) || is_null($value))){
+            $logic = $feature["logic"];
+            $describe = $feature["describe"];
             switch ($logic) {
                 case "包含":
-                    if (mb_strpos($value,$describe)!==false)return 'true';
+                    if (mb_strpos($value,$describe) !== false)return 'true';
                     break;
                 case "不包含":
                     if (mb_strpos($value,$describe) === false)return 'true';
@@ -329,8 +319,10 @@ class FeatureService
                     if ($value >= $describe)return 'true';
                     break;
             }
-        }
-        return "false";
+            return 'false';
+        };
+        array_splice($column,0,1);
+        $this->getMatchBool($feature, $value, $column);
     }
 
 }

+ 3 - 19
app/Services/OrderService.php

@@ -2,6 +2,7 @@
 
 namespace App\Services;
 
+use App\Feature;
 use App\Jobs\OrderCreateInstantBill;
 use App\Jobs\OrderFreeze;
 use App\Log;
@@ -1087,7 +1088,6 @@ sql
         /** @var OwnerPriceExpressService $service */
         $service = app("OwnerPriceExpressService");
         $logistic_fee = 0;
-        $commodities = [];
         $amount = 0;
         $volume = 0;
         $weight = 0;
@@ -1095,23 +1095,17 @@ sql
 
         if (!$order->logistic || $order->logistic->type == "物流")$logistic_fee = null;
 
-
-
         $items = [];
         foreach ($order->packages as &$package){
             $logistic_bill .= $package->logistic_number.",";
             $volume += $package->bulk;
             $weight += $package->weight;
 
-            // 四维转二维
             $partAmount = 0;
-            foreach($package->commodities as &$commodity){
-                $commodity["commodity_name"] = $commodity->commodity ? $commodity->commodity->name : '';
-                $commodity["sku"] = $commodity->commodity ? $commodity->commodity->sku : '';
+            foreach($package->commodities as $commodity){
                 $partAmount += $commodity->amount;
             }
             $amount += $partAmount;
-            $commodities = array_merge($commodities,$package->commodities->toArray());
 
             $provinceName = mb_substr($order->province,0,2);
             $province = app(CacheService::class)->getOrExecute("province_".$provinceName,function ()use($provinceName){
@@ -1138,19 +1132,9 @@ sql
         }
         if ($logistic_fee!==null && $logistic_fee<0)$logistic_fee = null;
 
-        $object = ["commodities"=>$commodities,
-            "logistic_name"=>($order->logistic ? $order->logistic->name : ''),
-            "shop_name"=>($order->shop ? $order->shop->name : ''),
-            "order_type"=>$order->order_type,
-            "batch_type" => $order->batch ? $order->batch->wms_type : '',
-            "owner_id"=>$order->owner_id];
-        $mapping = ["packages"=>"commodities","商品名称"=>"commodity_name",
-            "承运商"=>"logistic_name","店铺类型"=>"shop_name","订单类型"=>"order_type",
-            "波次类型"=>"batch_type"];
-
         /** @var OwnerPriceOperationService $service */
         $service = app("OwnerPriceOperationService");
-        $result = $service->matching($object,$mapping,$order->owner_id,"出库");
+        $result = $service->matching($order,Feature::MAPPING["order"],$order->owner_id,"出库");
 
         $detail = app("OwnerFeeDetailService")->create([
             "owner_id"          => $order->owner_id,

+ 19 - 2
app/Services/OwnerPriceExpressService.php

@@ -254,8 +254,25 @@ sql
             $query->whereNull("operation")->orWhere("operation","");
         })->first();
         if (!$model || count($model->details)<1)return -1;
-        if ($weight <= $model->initial_weight)return $model->details[0]->initial_weight_price;
+
+        if ($model->amount_interval){
+            $total = app("OrderService")->getOrderQuantity($owner_id);//获取该货主本月C端单量
+            for ($i=count($model->amount_interval);$i<0;$i--){
+                if ($total>=$model->amount_interval[$i])$to1 = $i;
+            }
+        }
+        if ($model->weight_interval){
+            for ($i=count($model->weight_interval);$i<0;$i--){
+                if ($weight>=$model->weight_interval[$i])$to2 = $i;
+            }
+        }
+        if (!isset($to1))$to1 = 0;
+        if (!isset($to2))$to2 = 0;
+
+        $initPrice = $model->details[0]->initial_weight_price[$to1][$to2];
+        $additionalPrice = $model->details[0]->additional_weight_price[$to1][$to2];
+        if ($weight <= $model->initial_weight)return $initPrice;
         $weight -= $model->initial_weight;
-        return (ceil($weight/$model->additional_weight)*$model->details[0]->additional_weight_price)+$model->details[0]->initial_weight_price;
+        return (ceil($weight/$model->additional_weight)*$additionalPrice)+$initPrice;
     }
 }

+ 28 - 28
app/Services/OwnerPriceOperationService.php

@@ -2,6 +2,7 @@
 
 namespace App\Services;
 
+use App\Feature;
 use App\OwnerFeeDetail;
 use App\OwnerPriceOperation;
 use App\OwnerPriceOperationItem;
@@ -99,9 +100,16 @@ class OwnerPriceOperationService
             }
         }else{
             foreach ($items as $item){
-                $item["owner_price_operation_id"] = $copyModel->id;
-                $item["discount_price"] = implode(",",($item["discount_price"] ? $item["discount_price"] : [])) ?? null;
-                $insert[] = $item;
+                $arr = [];
+                $arr["owner_price_operation_id"] = $copyModel->id;
+                $arr["strategy"] = $item["strategy"];
+                $arr["amount"] = $item["amount"] ?? null;
+                $arr["unit_id"] = $item["unit_id"];
+                $arr["unit_price"] = $item["unit_price"];
+                $arr["feature"] = $item["feature"] ?? null;
+                $arr["priority"] = $item["priority"] ?? 0;
+                $arr["discount_price"] = isset($item["discount_price"]) ? (is_array($item["discount_price"]) ? implode(",",$item["discount_price"]) : $item["discount_price"]) : null;
+                $insert[] = $arr;
             }
         }
         if ($insert)OwnerPriceOperationItem::query()->insert($insert);
@@ -190,6 +198,8 @@ class OwnerPriceOperationService
      * @param array $columnMapping       key-val
      * @param string $owner_id
      * @param string $type
+     * @param int|null $typeMark
+     *
      * @return double|array
      * 错误代码: -1:无匹配对象 -2:无计费模型 -3:未知单位 -4:sku为空 -5:货主未找到 -6:无箱规 -7:未匹配到计费模型
      *
@@ -200,14 +210,18 @@ class OwnerPriceOperationService
      *      增加按订单计价策略:主匹配模型增加字段量价,该字段存在时视为按单计价,价格为该值
      * 四. 2021-02-18 zzd
      *      满减多阶段匹配 满减字段由单值改为字符串多值 匹配时转数组寻找最相近
+     * 五. 2021-03-18 zzd
+     *      区分单据类型,增加字段
      */
-    public function matching($matchObject, $columnMapping, $owner_id, $type = '出库')
+    public function matching($matchObject, $columnMapping, $owner_id, $type = '出库', $typeMark = null)
     {
-        $unitModels = Unit::query()->whereIn("name",["件","箱"])->get();
-        $units = [];
-        foreach ($unitModels as $unitModel)$units[$unitModel->id] = $unitModel->name;
+        $units = Cache::remember("billing:unit_件_箱",config("cache.expirations.rarelyChange"),function (){
+            $units = [];
+            foreach (Unit::query()->whereIn("name",["件","箱"])->get() as $unit)$units[$unit->id] = $unit->name;
+            return $units;
+        });
 
-        $rules = OwnerPriceOperation::query()->with(["items"=>function($query){
+        $query = OwnerPriceOperation::query()->with(["items"=>function($query){
             /** @var Builder $query */
             $query->orderByRaw("CASE strategy  WHEN '起步' THEN 1 WHEN '默认' THEN 2 WHEN '特征' THEN 3 END DESC,priority");
         }])->where("operation_type",$type)->whereHas("owners",function ($query)use($owner_id){
@@ -215,7 +229,11 @@ class OwnerPriceOperationService
                 $query->where("id",$owner_id);
         })->where(function(Builder $query){
             $query->whereNull("operation")->orWhere("operation","");
-        })->orderByRaw("strategy desc,priority desc")->get(); //货主下的全部规则
+        })->orderByRaw("strategy desc,priority desc");
+
+        if ($typeMark!==null)$query->where("type_mark",$typeMark);
+
+        $rules = $query->get(); //货主下的全部规则
 
         if (!$rules)return -2;  //规则不存在跳出
 
@@ -456,27 +474,9 @@ class OwnerPriceOperationService
                 $order = $detail->order;
 
                 $logistic_fee = 0;
-                $commodities = [];
-                foreach ($order->packages as &$package){
-                    // 四维转二维
-                    foreach($package->commodities as &$commodity){
-                        $commodity["commodity_name"] = $commodity->commodity ? $commodity->commodity->name : '';
-                        $commodity["sku"] = $commodity->commodity ? $commodity->commodity->sku : '';
-                    }
-                    $commodities = array_merge($commodities,$package->commodities->toArray());
-                }
                 if ($logistic_fee!==null && $logistic_fee<0)$logistic_fee = null;
 
-                $object = ["commodities"=>$commodities,
-                    "logistic_name"=>($order->logistic ? $order->logistic->name : ''),
-                    "shop_name"=>($order->shop ? $order->shop->name : ''),
-                    "order_type"=>$order->order_type,
-                    "batch_type" => $order->batch ? $order->batch->wms_type : '',
-                    "owner_id"=>$order->owner_id];
-                $mapping = ["packages"=>"commodities","商品名称"=>"commodity_name",
-                    "承运商"=>"logistic_name", "店铺类型"=>"shop_name",
-                    "订单类型"=>"order_type","波次类型"=>"batch_type"];
-                $money = $this->matchItem($rule->items,$mapping,$object,$units,$owner_id,false,true,$discountIndex);
+                $money = $this->matchItem($rule->items,Feature::MAPPING["order"],$order,$units,$owner_id,false,true,$discountIndex);
                 if ($money>0)$detail->update(["work_fee"=>$money]);
                 else LogService::log(__CLASS__,"处理历史即时账单时发生匹配错误","账单主键:".$detail->id."; 错误代码".$money);
             };

+ 8 - 1
app/Services/OwnerStoragePriceModelService.php

@@ -147,6 +147,13 @@ class OwnerStoragePriceModelService
                 }
                 break;
         }
-        return $area*$model->price;
+        $index = 0;
+        if ($model->amount_interval){
+            $total = app("OrderService")->getOrderQuantity($owner_id);
+            for ($i=count($model->amount_interval);$i<0;$i--){
+                if ($total>=$model->amount_interval[$i])$model->price = $index;
+            }
+        }
+        return $area*$model->price[$index];
     }
 }

+ 37 - 0
app/Services/RejectedBillService.php

@@ -2,6 +2,7 @@
 
 namespace App\Services;
 
+use App\Feature;
 use App\OracleActAllocationDetails;
 use App\OracleDOCASNHeader;
 use App\OracleDOCOrderHeader;
@@ -9,9 +10,11 @@ use App\Order;
 use App\OrderIssue;
 use App\OrderIssueRejectedBill;
 use App\OrderPackage;
+use App\OwnerFeeDetail;
 use App\RejectedBill;
 use App\Services\common\BatchUpdateService;
 use App\Services\common\DataHandlerService;
+use App\Store;
 use App\StoreRejected;
 use Carbon\Carbon;
 use App\Traits\ServiceAppAop;
@@ -285,4 +288,38 @@ class RejectedBillService
         }
         return null;
     }
+
+    /**
+     * 建立即时账单,已存在覆盖,不存在补录
+     *
+     * @param RejectedBill $rejectedBill
+     *
+     */
+    public function buildInstantBill(RejectedBill $rejectedBill)
+    {
+        /** @var \stdClass $rejectedBill */
+        $number = array_column(StoreRejected::query()->where("logistic_number_return",$rejectedBill->logistic_number_return)->get()->toArray(),"store_id");
+
+        foreach (Store::query()->with("storeItems")->whereIn("id",$number)->get() as $store){
+            /** @var OwnerPriceOperationService $service */
+            $service = app("OwnerPriceOperationService");
+            $result = $service->matching($store, Feature::MAPPING["store"], $store->owner_id, "入库",0);
+            $bill = OwnerFeeDetail::query()->where("outer_id",$store->id)->where("outer_table_name","stores")->first();
+            if ($bill) $bill->update([
+                    "work_fee" => is_array($result) ? ($result["money"]>0 ? $result["money"] : null) : null,
+                    "owner_price_operation_id" => is_array($result) ? $result["id"] : null,
+            ]); else app("OwnerFeeDetailService")->create([
+                "owner_id" => $store->owner_id,
+                "worked_at" => $store->created_at,
+                "type" => "收货",
+                "operation_bill" => $store->asn_code,
+                "commodity_amount" => array_sum(array_column($store->storeItems->toArray(), "amount")),
+                "work_fee" => is_array($result) ? ($result["money"]>0 ? $result["money"] : null) : null,
+                "owner_price_operation_id" => is_array($result) ? $result["id"] : null,
+                "created_at" => date('Y-m-d H:i:s'),
+                "outer_id" => $store->id,
+                "outer_table_name" => "stores",
+            ]);
+        }
+    }
 }

+ 2 - 3
app/Services/StoreService.php

@@ -2,6 +2,7 @@
 
 namespace App\Services;
 
+use App\Feature;
 use App\Jobs\StoreCreateInstantBill;
 use App\Order;
 use App\OwnerFeeDetail;
@@ -331,9 +332,7 @@ class StoreService
         /** @var OwnerPriceOperationService $service */
         $service = app("OwnerPriceOperationService");
 
-        $mapping = ["packages" => "storeItems", "商品名称" => "name", "订单类型" => "stored_method", "订单数"=>"amount"];
-
-        $result = $service->matching($store, $mapping, $store->owner_id, "入库");
+        $result = $service->matching($store, Feature::MAPPING["store"], $store->owner_id, "入库");
 
         if (app("OwnerFeeDetailService")->create([
             "owner_id" => $store->owner_id,

+ 0 - 22
app/Services/WaybillService.php

@@ -136,28 +136,6 @@ class WaybillService
             $request->offsetSet('dispatch_remark', str_replace(["\n","\r"], ' ', $request->dispatch_remark));
         }
         if (!$request->destination) $request->offsetSet('destination', $waybill->destination);
-        /*if ($request->destination_city_id && $waybill->destination_city_id != $request->destination_city_id) {
-            $city = app(CityService::class)->find($request->destination_city_id);
-            if ($city && $city->province_name && (mb_strpos($request->destination, $city->name) === false || mb_strpos($request->destination, $city->province_name) === false)) {
-                if (mb_strpos($request->destination, $city->name) === false && mb_strpos($request->destination, $city->province_name) === false) {
-                    $request->offsetSet('destination', $city->province_name . $city->name . $request->destination);
-                    goto sign;
-                }
-                if (mb_strpos($request->destination, $city->province_name) === false) {
-                    $request->offsetSet('destination', $city->province_name . $request->destination);
-                }
-                if (mb_strpos($request->destination, $city->name) === false) {
-                    $province_name = $city->province_name;
-                    $start_index = mb_strpos($request->destination, $city->province_name . '省');
-                    if ($start_index === false) $start_index = mb_strpos($request->destination, $city->province_name);
-                    else $province_name = $province_name . '省';
-                    $strBefore = mb_substr($request->destination, $start_index, mb_strlen($province_name));
-                    $strAfter = mb_substr($request->destination, $start_index + mb_strlen($province_name));
-                    $request->offsetSet('destination', $strBefore . $city->name . $strAfter);
-                }
-            }
-        }
-        sign:*/
         $waybill->fill($request->input());
         $waybill->update();
         return $waybill;

+ 0 - 4
app/Store.php

@@ -19,10 +19,6 @@ class Store extends Model
         'asn_code','warehouse_id','owner_id','stored_method','status','remark','deleted_at','is_fast_stored'
     ];
 
-//    protected $appends=[
-//        'owner_name','warehouse_name'
-//    ];
-
     public function owner(){
         return $this->belongsTo('App\Owner','owner_id','id');
     }

+ 16 - 1
resources/sass/text.scss

@@ -138,7 +138,7 @@
 .scrollbar::-webkit-scrollbar {
     /*滚动条整体样式*/
     width : 10px;  /*高宽分别对应横竖滚动条的尺寸*/
-    height: 1px;
+    height: 10px;
 }
 .scrollbar::-webkit-scrollbar-thumb {
     /*滚动条里面小方块*/
@@ -206,3 +206,18 @@
     z-index:100;
     position:relative;
 }
+
+//超高滚动 200px
+.overflow-scrollbar-200{
+    max-height: 200px;
+    max-width: 100%;
+    overflow: auto;
+    border: RGB(204,204,204) solid 1px;
+    border-radius: 5px
+}
+.overflow-y-scrollbar-200{
+    max-height: 200px;
+    overflow-y: auto;
+    border: RGB(204,204,204) solid 1px;
+    border-radius: 5px
+}

+ 61 - 6
resources/views/customer/project/create.blade.php

@@ -138,7 +138,8 @@
                         counting_type : "",
                         using_type : "",
                         minimum_area : "",
-                        price : "",
+                        price : [""],
+                        amount_interval : [""],
                         discount_type : "无减免",
                         discount_value : "",
                         unit_id : "",
@@ -149,6 +150,8 @@
                         name:"",
                         initial_weight:"",
                         additional_weight:"",
+                        amount_interval:[""],
+                        weight_interval:[[]],
                         items:[],
                         logistics:[],
                     },
@@ -172,7 +175,7 @@
                     discount_type:[
                         "无减免","按单减免","固定减免"
                     ],
-                    feature_type:{!! json_encode(\App\Feature::type,JSON_UNESCAPED_UNICODE) !!},
+                    feature_type:{!! json_encode(\App\Feature::TYPE,JSON_UNESCAPED_UNICODE) !!},
                     logic : ['包含','不包含','等于',"大于","大于等于","小于","小于等于"],
                 },
                 poolMapping:{},//基础数据选择池的映射对象 供展示使用
@@ -223,6 +226,7 @@
                             strategy:"默认",
                             discount_count:[''],
                             name:"",
+                            isRejected:false,
                             feature:"",
                             total_discount_price:[''],
                             items : [
@@ -438,6 +442,7 @@
                         if (item.discount_price) operation.items[j].discount_price = item.discount_price.split(",");
                     });
                     if (operation.total_price)operation.isSingle = true;
+                    if (operation.type_mark===0 || operation.type_mark==='0')operation.isRejected = true;
                     return operation;
                 },
                 //重载快递费
@@ -610,14 +615,35 @@
                     if (!this.model.storage.counting_type)error["counting_type"] = ["未选择计费类型"];
                     if (!this.model.storage.name)error["name"] = ["未填写名称"];
                     if (!this.model.storage.using_type)error["using_type"] = ["未选择用仓类型"];
-                    if (!this.model.storage.price)error["price"] = ["未输入单价"];
+                    if (!this.model.storage.price[0])error["price.0"] = ["未输入单价"];
                     if (!this.model.storage.discount_type)error["discount_type"] = ["未选择减免类型"];
                     if (!this.model.storage.unit_id)error["unit_id"] = ["未选择单位"];
                     if (!this.model.storage.time_unit_id)error["time_unit_id"] = ["未选择计时单位"];
+                    if (this.model.storage.isInterval){
+                        if (this.model.storage.amount_interval.length<1 || this.model.storage.price.length<1){
+                            error["amount_interval.0"] = ["未设定数量区间"];
+                            error["price.0"] = ["未输入单价"];
+                        }else{
+                            this.model.storage.amount_interval.forEach((amount,i)=>{
+                                if (!amount)error["amount_interval."+i] = ["未设定数量区间"];
+                                else if (i!==0 && amount<=this.model.storage.amount_interval[i-1])
+                                    error["amount_interval."+i] = ["阶梯区间不应大于上一区间值"];
+                                this.model.storage.amount_interval[i] = Number(this.model.storage.amount_interval[i]);
+                            });
+                            this.model.storage.price.forEach((price,i)=>{
+                                if (!price)error["price."+i] = ["未输入单价"];
+                                this.model.storage.price[i] = Number(this.model.storage.price[i]);
+                            });
+                        }
+                    }
                     if (JSON.stringify(error) !== "{}"){
                         this.errors = error;
                         return;
                     }
+                    if (!this.model.storage.isInterval){
+                        this.model.storage.amount_interval = null;
+                        this.model.storage.price = [Number(this.model.storage.price[0])];
+                    }
                     let url = "{{url('maintenance/priceModel/apiStoreStorage')}}";
                     let params = this.model.storage;
                     params.owner_id = this.ownerTemp.id;
@@ -638,7 +664,8 @@
                             counting_type : "",
                             using_type : "",
                             minimum_area : "",
-                            price : "",
+                            price : [""],
+                            amount_interval : [""],
                             discount_type : "无减免",
                             discount_value : "",
                             unit_id : "",
@@ -704,6 +731,7 @@
                         this.model.operation.discount_count = [""];
                         this.model.operation.total_discount_price = [""];
                     }
+                    if (this.model.operation.isRejected)this.model.operation.type_mark = 0;
                     let url = "{{url('maintenance/priceModel/apiStoreOperation')}}";
                     let params = this.model.operation;
                     params.owner_id = this.ownerTemp.id;
@@ -732,6 +760,7 @@
 
                         res.discount_count = res.discount_count ? res.discount_count.split(",") : [""];
                         res.total_discount_price = res.total_discount_price ? res.total_discount_price.split(",") : [""];
+                        res.isRejected = this.model.operation.type_mark==='0'||this.model.operation.type_mark===0;
 
                         if (params.id) this.selectedModel.operation[params.index] = res;
                         else this.selectedModel.operation.push(res);
@@ -1025,7 +1054,9 @@
                 },
                 //删除快递子项
                 delExpressItem(index){
-                    this.$delete(this.model.express.items,index);
+                    window.tempTip.confirm("确定要删除该子项吗?",res=>{
+                        this.$delete(this.model.express.items,index);
+                    })
                 },
                 //选择文件
                 selectFile(id){
@@ -1255,6 +1286,8 @@
                                 feature : model.feature,
                                 featureFormat : model.featureFormat,
                                 remark : model.remark,
+                                type_mark : model.type_mark,
+                                isRejected : model.type_mark==='0'||model.type_mark===0,
                                 items:model.items,
                             };
                         });
@@ -1503,7 +1536,7 @@
                     this.model.operation = JSON.parse(JSON.stringify(this.selectedModel.operation[index]));
                     if (this.model.operation.operation_type==='入库') this.model.operation.items.unshift({});
                     this.model.operation.index = index;
-                    if (this.model.operation.items.length == 0){
+                    if (this.model.operation.items.length === 0){
                         this.model.operation.items = [
                             {strategy:"起步",type:"0"},
                             {strategy:"默认"},
@@ -1631,6 +1664,28 @@
                         })
                     })
                 },
+                //增加数量区间
+                addStoreAmount(){
+                    this.model.storage.amount_interval.push("");
+                    this.model.storage.price.push("");
+                },
+                //删除数量区间
+                delStoreAmount(index){
+                    if (this.model.storage.amount_interval.length<2)return;
+                    this.$delete(this.model.storage.amount_interval,index);
+                    this.$delete(this.model.storage.price,index);
+                },
+                //增加快递数量区间
+                addExpressAmount(){
+                    this.model.express.amount_interval.push("");
+                    this.model.express.weight_interval.push([]);
+                },
+                //增加快递重量区间
+                addExpressWeight(index){
+                    this.model.express.weight_interval[index].push("");
+                    if (!this.model.express.maxDom || this.model.express.weight_interval[index].length > this.model.express.maxDom)
+                        this.$set(this.model.express,'maxDom',this.model.express.weight_interval[index].length);
+                }
             },
         });
     </script>

+ 36 - 4
resources/views/customer/project/part/_express.blade.php

@@ -20,6 +20,38 @@
     <label class="col-7"><input type="number" min="0" step="0.01" class="form-control"
            v-model="model.express.additional_weight" :class="errors.additional_weight ? 'is-invalid' : ''"></label>
 </div>
+<div class="row mt-3">
+    <label class="col-3">区间值</label>
+    <div class="col-8">
+        <div class="scrollbar overflow-scrollbar-200">
+            <div class="w-100 text-nowrap">
+                <div class="w-25 d-inline-block border border-1 border-secondary rounded rounded-5 font-weight-bold">
+                    <span class="pull-right">重量</span><br><span class="pull-left">数量</span>
+                </div>
+                <label class="w-25 d-inline-block m-0 text-center" v-for="index of model.express.maxDom">
+                    第@{{ index }}阶梯
+                </label>
+            </div>
+            <div class="w-100 text-nowrap" v-for="(amount,i) in model.express.amount_interval">
+                <label class="w-25 d-inline-block m-0">
+                    <input type="number" step="1" min="0" v-model="model.express.amount_interval[i]" class="form-control border-dark"
+                        :min="(model.express.amount_interval[i-1]) ? (Number(model.express.amount_interval[i-1])+1) : '0'"
+                        :placeholder="'数量:最小'+((model.express.amount_interval[i-1]) ? (Number(model.express.amount_interval[i-1])+1) : '0')">
+                </label>
+                <label class="w-25 d-inline-block m-0" v-for="(weight,j) in model.express.weight_interval[i]">
+                    <input type="number" v-model="model.express.weight_interval[i][j]" step="0.01" min="0" class="form-control"
+                    :placeholder="'重量:最小'+((model.express.weight_interval[i][j-1]) ? (Number(model.express.weight_interval[i][j-1])+1) : '0')">
+                </label>
+                <span class="fa fa-plus cursor-pointer mr-3" @click="addExpressWeight(i)"></span>
+            </div>
+            <div class="w-100 text-nowrap mt-0 mb-3">
+                <label class="w-25 d-inline-block mb-0 p-0 text-center border border-1 cursor-pointer border-info rounded rounded-5" @click="addExpressAmount()">
+                    <span class="fa fa-plus" style="font-size: 1rem"></span>
+                </label>
+            </div>
+        </div>
+    </div>
+</div>
 <div class="row mt-3">
     <label class="col-3 cursor-pointer"><span @click="show('express-item')">详情&nbsp;
         <span class="fa" :class="upList['express-item'] ? 'fa-angle-double-right' : 'fa-angle-double-down'"></span></span></label>
@@ -32,7 +64,7 @@
         </div>
         <div class="w-100 mt-1 ml-1" v-if="model.express.items.length>searchBase">
             <label>
-                <input placeholder="  定位" class="form-control form-control-sm rounded-pill" @input="searchExpress($event)"/>
+                <input placeholder="定位" class="form-control form-control-sm rounded-pill" @input="searchExpress($event)"/>
             </label>
         </div>
         <div class="w-100 text-center mb-1 mt-1" v-if="importError.length > 0">
@@ -52,7 +84,7 @@
             <label class="col-3"></label>
         </div>
         <div class="row" id="express-item">
-            <div class="row" v-for="(item,i) in model.express.items" v-if="!searchItem.express || (searchItem.express && searchItem.express.includes(i))">
+            <div class="row col-12" v-for="(item,i) in model.express.items" v-if="!searchItem.express || (searchItem.express && searchItem.express.includes(i))">
                 <label class="col-3">
                     <select class="form-control form-control-sm" v-model="item.province_id" :class="errors['items.'+i+'.province_id'] ? 'is-invalid' : ''">
                         <option v-for="province in pool.provinces" :value="province.id">@{{ province.name }}</option>
@@ -64,8 +96,8 @@
                 <label class="col-3">
                     <input type="number" step="0.01" min="0" class="form-control form-control-sm" v-model="item.additional_weight_price" :class="errors['items.'+i+'.additional_weight_price'] ? 'is-invalid' : ''">
                 </label>
-                <label class="col-3 cursor-pointer h3 font-weight-bold text-danger" @click="delExpressItem(i)">
-                    &times;
+                <label class="col-3 cursor-pointer h3 font-weight-bold text-danger">
+                    <span @click="delExpressItem(i)">&times;</span>
                 </label>
             </div>
         </div>

+ 4 - 0
resources/views/customer/project/part/_operation.blade.php

@@ -25,6 +25,10 @@
         <strong>@{{ errors.name[0] }}</strong>
     </span>
 </div>
+<div class="row mt-3" v-if="model.operation.operation_type == '入库'">
+    <label class="col-2" for="isRejected">是退货</label>
+    <input content="col-3" id="isRejected" type="checkbox" class="switch" v-model="model.operation.isRejected">
+</div>
 <div class="row mt-3" v-if="model.operation.strategy == '特征'">
     <label class="col-2">特征</label>
     <label class="col-8">

+ 46 - 10
resources/views/customer/project/part/_storage.blade.php

@@ -33,18 +33,14 @@
         <strong>@{{ errors.minimum_area[0] }}</strong>
     </span>
 </div>
+<div class="row mt-3">
+    <label for="isInterval" class="col-2 text-info">使用满减区间</label>
+    <input id="isInterval" type="checkbox" class="switch"  v-model="model.storage.isInterval">
+</div>
 <div class="row mt-3">
     <div class="col-4 row">
-        <label for="price" class="col-4 text-info">单价</label>
-        <input id="price" type="number" min="0" step="0.001" class="offset-3 col-5 form-control"
-               :class="errors.price ? 'is-invalid' : ''" v-model="model.storage.price">
-        <span class="invalid-feedback mt-0 offset-6" role="alert" v-if="errors.price">
-            <strong>@{{ errors.price[0] }}</strong>
-        </span>
-    </div>
-    <div class="col-3 row m-0">
-        <label for="unit_id" class="col-5 offset-1 text-info">单位</label>
-        <select id="unit_id" class="col-6 form-control"
+        <label for="unit_id" class="col-4 text-info">单位</label>
+        <select id="unit_id" class="offset-3 col-5 form-control"
                 :class="errors.unit_id ? 'is-invalid' : ''" v-model="model.storage.unit_id">
             <option v-for="unit in pool.units" :value="unit.id" v-if="unit.name == 'm²' || unit.name=='㎡' || unit.name == 'm³' || unit.name == '件'">
                 @{{ unit.name }}</option>
@@ -63,6 +59,46 @@
             <strong>@{{ errors.time_unit_id[0] }}</strong>
         </span>
     </div>
+    <div class="col-3 row m-0" v-if="!model.storage.isInterval">
+        <label for="price" class="col-5 offset-1 text-info">单价</label>
+        <input id="price" type="number" min="0" step="0.001" class="col-6 form-control"
+               :class="errors['price.0'] ? 'is-invalid' : ''" v-model="model.storage.price[0]">
+        <span class="invalid-feedback mt-0 offset-6" role="alert" v-if="errors['price.0']">
+            <strong>@{{ errors['price.0'][0] }}</strong>
+        </span>
+    </div>
+</div>
+<div class="row mt-3" v-if="model.storage.isInterval">
+    <label for="amount_interval" class="col-2 text-info">数量区间</label>
+    <div class="col-8 scrollbar overflow-y-scrollbar-200">
+        <div class="row mt-0 text-muted">
+            <label class="col-4 offset-2 text-center">区间值</label>
+            <label class="col-5 text-center">单价</label>
+        </div>
+        <div class="row mt-1" v-for="(amount,i) in model.storage.amount_interval">
+            <label class="col-2">
+                <span class="fa fa-plus cursor-pointer" @click="addStoreAmount()">&nbsp;增加</span>
+            </label>
+            <label class="col-4">
+                <input type="number" class="form-control form-control-sm" :class="errors['amount_interval.'+i] ? 'is-invalid' : ''"
+                       step="1" :min="Number(model.storage.amount_interval[i-1] ? model.storage.amount_interval[i-1] : 0)+1" v-model="model.storage.amount_interval[i]">
+            </label>
+            <label class="col-5 text-center">
+                <input type="number" class="form-control form-control-sm"  step="0.01" v-model="model.storage.price[i]" :class="errors['price.'+i] ? 'is-invalid' : ''"
+                       :placeholder="model.storage.amount_interval[i] ?
+                       ('区间范围:'+model.storage.amount_interval[i]+(model.storage.amount_interval[i+1] ? '-'+(model.storage.amount_interval[i+1]-1) : ' +')) : ''">
+            </label>
+            <label class="col-1">
+                <span class="cursor-pointer text-danger font-weight-bold h4" @click="delStoreAmount(i)" v-if="i!=0">&times;</span>
+            </label>
+            <label class="small text-danger offset-2 col-4" role="alert" v-if="errors['amount_interval.'+i]">
+                <strong>@{{ errors['amount_interval.'+i][0] }}</strong>
+            </label>
+            <label class="small text-danger col-5" :class="!errors['amount_interval.'+i] ? 'offset-6' : ''" role="alert" v-if="errors['price.'+i]">
+                <strong>@{{ errors['price.'+i][0] }}</strong>
+            </label>
+        </div>
+    </div>
 </div>
 <div class="row mt-3">
     <label for="discount_type" class="col-2 text-info">减免类型</label>

+ 1 - 1
resources/views/customer/project/part/_three.blade.php

@@ -65,7 +65,7 @@
                                         <span class="fa" :class="upList['operation-item-'+i] ? 'fa-caret-right' : 'fa-caret-down'"></span>
                                         &nbsp;@{{ operation.strategy }}:
                                     </label>
-                                    <label>@{{ operation.name }}</label>
+                                    <label>@{{ operation.name }}</label><span class="badge badge-pill badge-danger" v-if="operation.isRejected">退</span>
                                     <label v-if="operation.remark" class="text-secondary">&nbsp;&nbsp;(@{{ operation.remark }})</label>
                                 </div>
                                 <div class="col-1">