Browse Source

Merge branch 'master' into Haozi

haozi 5 years ago
parent
commit
cfb700b6f4
100 changed files with 4200 additions and 389 deletions
  1. 25 0
      .gitlab-ci.yml
  2. 1 1
      app/Commodity.php
  3. 65 0
      app/Console/Commands/CreateOwnerAreaReport.php
  4. 82 0
      app/Console/Commands/CreateOwnerBillReport.php
  5. 14 9
      app/Console/Commands/CreateOwnerReport.php
  6. 3 0
      app/Console/Kernel.php
  7. 5 0
      app/Http/Controllers/CarTypesController.php
  8. 4 0
      app/Http/Controllers/CitiesController.php
  9. 7 3
      app/Http/Controllers/CommodityController.php
  10. 50 22
      app/Http/Controllers/CustomerBaseController.php
  11. 323 11
      app/Http/Controllers/CustomerController.php
  12. 0 84
      app/Http/Controllers/JobTypeController.php
  13. 57 33
      app/Http/Controllers/OrderIssueController.php
  14. 9 2
      app/Http/Controllers/OrderTrackingController.php
  15. 866 17
      app/Http/Controllers/PriceModelController.php
  16. 57 23
      app/Http/Controllers/ProcessMethodController.php
  17. 4 0
      app/Http/Controllers/ProvincesController.php
  18. 20 50
      app/Http/Controllers/TestController.php
  19. 5 0
      app/Http/Controllers/UnitsController.php
  20. 44 22
      app/Http/Controllers/UserOwnerGroupController.php
  21. 4 2
      app/Http/Controllers/api/thirdPart/goodscan/PackageController.php
  22. 18 13
      app/Http/Controllers/api/thirdPart/haiq/StorageController.php
  23. 2 1
      app/Http/Controllers/api/thirdPart/weight/PackageController.php
  24. 108 0
      app/Imports/ExpressImport.php
  25. 1 1
      app/Imports/OrderIssueImport.php
  26. 2 21
      app/Imports/OrderTrackingImport.php
  27. 135 0
      app/Imports/OwnerPriceDirectLogisticDetailImport.php
  28. 187 0
      app/Imports/OwnerPriceLogisticDetailImport.php
  29. 5 0
      app/Logistic.php
  30. 1 0
      app/OracleBasSKU.php
  31. 11 4
      app/OrderIssue.php
  32. 20 0
      app/OrderTracking.php
  33. 41 0
      app/Owner.php
  34. 17 7
      app/OwnerAreaReport.php
  35. 2 1
      app/OwnerBillReport.php
  36. 0 1
      app/OwnerFeeDetail.php
  37. 1 0
      app/OwnerInStorageRule.php
  38. 13 1
      app/OwnerOutStorageRule.php
  39. 11 1
      app/OwnerPriceDirectLogistic.php
  40. 20 5
      app/OwnerPriceExpress.php
  41. 2 2
      app/OwnerPriceExpressProvince.php
  42. 24 0
      app/OwnerPriceLogistic.php
  43. 14 0
      app/OwnerPriceOperation.php
  44. 1 0
      app/OwnerReport.php
  45. 10 0
      app/OwnerStoragePriceModelOwner.php
  46. 23 0
      app/Providers/AppServiceProvider.php
  47. 21 0
      app/Services/CommodityService.php
  48. 28 0
      app/Services/CustomerService.php
  49. 189 0
      app/Services/FeatureService.php
  50. 37 22
      app/Services/OrderIssueService.php
  51. 0 1
      app/Services/OrderPackageService.php
  52. 1 1
      app/Services/OrderService.php
  53. 37 0
      app/Services/OrderTrackingService.php
  54. 85 0
      app/Services/OwnerAreaReportService.php
  55. 58 0
      app/Services/OwnerBillReportService.php
  56. 58 0
      app/Services/OwnerFeeDetailService.php
  57. 57 0
      app/Services/OwnerOutStorageRuleService.php
  58. 111 0
      app/Services/OwnerPriceDirectLogisticService.php
  59. 130 0
      app/Services/OwnerPriceExpressService.php
  60. 139 0
      app/Services/OwnerPriceLogisticService.php
  61. 253 0
      app/Services/OwnerPriceOperationService.php
  62. 0 5
      app/Services/OwnerReportService.php
  63. 31 1
      app/Services/OwnerService.php
  64. 66 0
      app/Services/OwnerStoragePriceModelService.php
  65. 30 0
      app/Services/ProcessMethodService.php
  66. 4 0
      app/Services/ShopService.php
  67. 29 0
      app/Services/UserOwnerGroupService.php
  68. 0 5
      app/User.php
  69. 13 0
      database/factories/LogisticFactory.php
  70. 27 0
      database/factories/OrderTrackingFactory.php
  71. 3 3
      database/factories/OwnerBillReportFactory.php
  72. 39 0
      database/factories/OwnerFeeDetailFactory.php
  73. 17 0
      database/factories/OwnerInStorageRuleFactory.php
  74. 20 0
      database/factories/OwnerOutStorageRuleFactory.php
  75. 16 0
      database/factories/OwnerPriceExpressFactory.php
  76. 17 0
      database/factories/OwnerPriceOperationFactory.php
  77. 22 0
      database/factories/OwnerStoragePriceModelFactory.php
  78. 16 0
      database/factories/ProcessMethodFactory.php
  79. 15 0
      database/factories/ShopFactory.php
  80. 12 0
      database/factories/UnitFactory.php
  81. 1 0
      database/migrations/2020_10_20_143953_create_owner_reports_table.php
  82. 2 0
      database/migrations/2020_10_26_142753_create_owner_area_reports_table.php
  83. 0 1
      database/migrations/2020_10_26_165012_create_owner_fee_details_table.php
  84. 1 0
      database/migrations/2020_10_27_103741_create_owner_bill_reports_table.php
  85. 2 2
      database/migrations/2020_10_27_142647_create_owner_storage_price_model_table.php
  86. 1 0
      database/migrations/2020_10_27_175452_create_owner_price_operations_table.php
  87. 3 2
      database/migrations/2020_10_28_105613_create_owner_out_storage_rules_table.php
  88. 2 1
      database/migrations/2020_10_28_105639_create_owner_in_storage_rules_table.php
  89. 2 2
      database/migrations/2020_10_28_162458_create_owner_price_expresses_table.php
  90. 20 0
      database/migrations/2020_10_28_170858_save_customer_authority_data.php
  91. 31 0
      database/migrations/2020_11_02_095633_create_owner_storage_price_model_owner_table.php
  92. 31 0
      database/migrations/2020_11_03_095611_create_owner_price_operation_owner_table.php
  93. 31 0
      database/migrations/2020_11_03_101827_create_owner_price_direct_logistic_owner_table.php
  94. 32 0
      database/migrations/2020_11_17_170541_add_column_pack_commodities_table.php
  95. 32 0
      database/migrations/2020_11_18_111612_add_signed_at_index_to_order_trackings.php
  96. 36 0
      database/migrations/2020_11_18_142512_add_finance_confirm_to_order_issue_and_add_auth.php
  97. 32 0
      database/migrations/2020_11_19_100831_add_hidden_tag_to_order_issues.php
  98. 38 0
      database/migrations/2020_11_19_113953_change_order_issue_auth.php
  99. 4 5
      database/migrations/2020_11_19_113955_change_order_issue_type_id_index.php
  100. 4 1
      database/seeds/DatabaseSeeder.php

+ 25 - 0
.gitlab-ci.yml

@@ -0,0 +1,25 @@
+stages:
+  - build
+  - test
+  - deploy
+
+build_maven:
+  stage: build
+  script:
+    - echo "build maven....."
+    - echo "mvn clean"
+    - echo "done"
+
+test_springboot:
+  stage: test
+  script:
+    - echo "run java test....."
+    - echo "java -test"
+    - echo "done"
+
+deploy_springboot:
+  stage: deploy
+  script:
+    - echo "deploy springboot...."
+    - echo "run mvn install"
+    - echo "done"

+ 1 - 1
app/Commodity.php

@@ -9,7 +9,7 @@ use App\Traits\ModelTimeFormat;
 class Commodity extends Model
 {
     use ModelTimeFormat;
-    protected $fillable=['name','sku','owner_id','created_at','length','width','height','volumn',"type"];
+    protected $fillable=['name','sku','owner_id','created_at','length','width','height','volumn',"type","pack"];
     protected $appends=['barcode'];
 //    protected $appends=['barcode','owner_name','owner_code'];
 

+ 65 - 0
app/Console/Commands/CreateOwnerAreaReport.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\OwnerAreaReport;
+use App\Services\OwnerService;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\DB;
+
+class CreateOwnerAreaReport extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'createOwnerAreaReport';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'create owner area report';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * TODO 25号生成盘点面积记录,记录留空由人工填写
+     *
+     * @return void
+     */
+    public function handle()
+    {
+        /** @var OwnerService $ownerService */
+        $ownerService = app('OwnerService');
+        $chunks = ($ownerService->get([],["ownerStoragePriceModels"],false,true))->chunk(50);
+        $month = date('Y-m-d');
+        foreach ($chunks as $owners){
+            $date = date('Y-m-d H:i:s');
+            $createOwnerAreaReport = [];
+            foreach ($owners as $owner){
+                if (!$owner->ownerStoragePriceModels)continue;
+                foreach ($owner->ownerStoragePriceModels as $model){
+                    $createOwnerAreaReport[] = [
+                        "owner_id"              => $owner->id,
+                        "counting_month"        => $month,
+                        "user_owner_group_id"   => $owner->user_owner_group_id,
+                        "created_at"            => $date,
+                        "owner_storage_price_model_id"  => $model->id,
+                    ];
+                }
+            }
+            DB::table("owner_area_reports")->insert($createOwnerAreaReport);
+        }
+    }
+}

+ 82 - 0
app/Console/Commands/CreateOwnerBillReport.php

@@ -0,0 +1,82 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\OwnerAreaReport;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\DB;
+
+class CreateOwnerBillReport extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'createOwnerBillReport';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'create owner bill report';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * 1号生成账单确认,确认金额由人工填写 原始金额默认为:即时账单月记录金额+仓储计费与面积计算金额
+     *
+     * @return void
+     */
+    public function handle()
+    {
+        $year = (int)date('Y');
+        $month = (int)date('m');
+        if ($month == 1){
+            $year--;
+            $lastMonth = '12';
+        }else $lastMonth = ($month-1) < 10 ? "0".($month-1) : ($month-1);
+        $bills = DB::select(DB::raw("select owner_id,SUM(work_fee)+SUM(logistic_fee) as total from owner_fee_details where worked_at like ? GROUP BY owner_id"),[$year."-".$lastMonth."%"]);
+
+        $areas = OwnerAreaReport::query()->with("ownerStoragePriceModel")->where("counting_month","like",$year."-".$lastMonth."%")->get();
+        $map = [];
+        foreach($areas as $area){
+            if (isset($map[$area->owner_id."_".$area->counting_month])){
+                if (!$area->ownerStoragePriceModel)continue;
+                $map[$area->owner_id."_".$area->counting_month] += app('OwnerStoragePriceModelService')
+                    ->calculationAmount($area->ownerStoragePriceModel,$area->accounting_area,$area->owner_id,$area->counting_month);
+            }else{
+                if (!$area->ownerStoragePriceModel)continue;
+                $map[$area->owner_id."_".$area->counting_month] = app('OwnerStoragePriceModelService')
+                    ->calculationAmount($area->ownerStoragePriceModel,$area->accounting_area,$area->owner_id,$area->counting_month);
+            }
+        }
+
+        $chunks = array_chunk($bills,50);
+        foreach ($chunks as $bills){
+            $date = date('Y-m-d H:i:s');
+            $createOwnerBillReport = [];
+            foreach ($bills as $bill){
+                $key = $bill->owner_id."_".$year."-".$lastMonth;
+                $total = $bill->total;
+                if (isset($map[$key]))$total += $map[$key];
+                $createOwnerBillReport[] = [
+                    "owner_id"          => $bill->owner_id,       //项目ID
+                    "counting_month"    => $year."-".$lastMonth."-01", //结算月
+                    "initial_fee"       => $total,    //原始账单金额
+                    "created_at"        => $date,
+                ];
+            }
+            DB::table("owner_bill_reports")->insert($createOwnerBillReport);
+        }
+    }
+}

+ 14 - 9
app/Console/Commands/CreateOwnerReport.php

@@ -58,18 +58,20 @@ class CreateOwnerReport extends Command
         $lastDay = date("d",strtotime("$year-$lastMonth +1 month -1 day"));
 
         //获取上月面积与报表
-        $areas = OwnerAreaReport::query()->with(['owner'=>function($query){
-            $query->select('id',"code");
-        }])->where("counting_month","like",$year."-".$lastMonth."%")->get();
+        $areas = OwnerAreaReport::query()->select("id","owner_id","counting_month",DB::raw("SUM(accounting_area) total,YEAR(counting_month) y,MONTH(counting_month) m"))
+            ->with(['owner'=>function($query){
+                $query->select('id',"code");
+            }])->where("counting_month","like",$year."-".$lastMonth."%")
+            ->groupBy("y","m","owner_id")->get();
         $reports = OwnerReport::query()->where("counting_month","like",$year."-".$lastMonth."%")->orWhere("counting_month","like",$historyYear."-".$historyMonth."%")->get();
         $bills = OwnerBillReport::query()->where("counting_month","like",$year."-".$lastMonth."%")->get();
 
         //日均单量统计
-        $query = DB::raw("select  count(*) c,CUSTOMERID from DOC_ORDER_HEADER where EDITTIME >= to_date('$year-$lastMonth-01 00:00:00','yyyy-mm-dd hh24:mi:ss') and EDITTIME <= to_date('$year-$lastMonth-$lastDay 23:59:59','yyyy-mm-dd hh24:mi:ss') group by CUSTOMERID");
+        $query = DB::raw("select  count(*) c,CUSTOMERID from DOC_ORDER_HEADER where EDITTIME >= to_date('".$year."-".$lastMonth."-01 00:00:00','yyyy-mm-dd hh24:mi:ss') and EDITTIME <= to_date('".$year."-".$lastMonth."-".$lastDay." 23:59:59','yyyy-mm-dd hh24:mi:ss') group by CUSTOMERID");
         $orderStatistic = DB::connection("oracle")->select($query);
         $map = [];
         foreach ($orderStatistic as $item){
-            $map[$item->customerid] = round($item->c / $lastDay,2);
+            $map[$item->customerid] = $item->c;
         }
 
         //已存在的报表记录
@@ -95,18 +97,21 @@ class CreateOwnerReport extends Command
         ]];
         $createReports = [];
         foreach ($areas as $area){
+            $total = $area->owner ? ($map[$area->owner->code] ?? 0) : 0;
             if ($reportMap[$area->owner_id."_".$area->counting_month] ?? false){
                 $updateReports[] = [
                     "id"=>$reportMap[$area->owner_id."_".$area->counting_month],
-                    "daily_average_order_amount"=>$area->owner ? ($map[$area->owner->code] ?? 0) : 0,
-                    "current_month_counting_area"=>$area->accounting_area ?? 0,
+                    "total" =>$total,
+                    "daily_average_order_amount"=>round($total / $lastDay,2),
+                    "current_month_counting_area"=>$area->total ?? 0,
                     "owner_bill_report_id" => $billMap[$area->owner_id."_".$area->counting_month] ?? 0,
                 ];
             }else $createReports[] = [
                 "owner_id"=>$area->owner_id,
                 "counting_month"=>$area->counting_month."-01",
-                "daily_average_order_amount"=>$area->owner ? ($map[$area->owner->code] ?? 0) : 0,
-                "current_month_counting_area"=>$area->accounting_area ?? 0,
+                "total" =>$total,
+                "daily_average_order_amount"=>round($total / $lastDay,2),
+                "current_month_counting_area"=>$area->total ?? 0,
                 "owner_bill_report_id" => $billMap[$area->owner_id."_".$area->counting_month] ?? 0,
                 "last_month_counting_area" => $historyReportMap[$area->owner_id."_".($historyYear."-".$historyMonth)] ?? 0,
             ];

+ 3 - 0
app/Console/Kernel.php

@@ -36,6 +36,9 @@ class Kernel extends ConsoleKernel
 //        $schedule->command('FluxOrderFix')->cron('* * * * *');
         $schedule->command('WASSyncWMSOrderInformation')->everyMinute();
         $schedule->command('syncLogCacheTask')->everyMinute();
+        $schedule->command('createOwnerReport')->monthlyOn(1);
+        $schedule->command('createOwnerBillReport')->monthlyOn(1);
+        $schedule->command('createOwnerAreaReport')->monthlyOn(25);
     }
 
     /**

+ 5 - 0
app/Http/Controllers/CarTypesController.php

@@ -66,6 +66,11 @@ class CarTypesController extends Controller
         return ['success'=>$result];
     }
 
+    public function get()
+    {
+        return CarType::query()->select("id","name","model")->get();
+    }
+
     protected  function validatorCarType(Request $request,$id){
         if ($id){$name=$id;}
         $validator=Validator::make($request->input(),[

+ 4 - 0
app/Http/Controllers/CitiesController.php

@@ -80,4 +80,8 @@ class CitiesController extends Controller
         ]);
         return $validator;
     }
+
+    public function get(){
+        return City::query()->select("id","name","province_id")->get();
+    }
 }

+ 7 - 3
app/Http/Controllers/CommodityController.php

@@ -217,7 +217,7 @@ class CommodityController extends Controller
         $commodities = $commodityService->getOwnerCommodities(['owner_id' => $owner_id, 'sku'=>$skus]);
         $updateCommodities = [];
         $updateCommodities[] = [
-            'id', 'sku', 'name', 'length', 'width', 'height', 'volumn',
+            'id', 'sku', 'name', 'length', 'width', 'height', 'volumn',"pack"
         ];
         $barcodeMap = [];
         $commoditiesId = [];
@@ -228,7 +228,8 @@ class CommodityController extends Controller
             $trimSku = rtrim($wms->sku,"*");
             if (($commodity->sku != $trimSku) || ($commodity->length != $wms->skulength)
                 || ($commodity->width != $wms->skuwidth) || ($commodity->name != $wms->descr_c)
-                || ($commodity->height != $wms->skuhigh) || ($commodity->volumn != $wms->cube)){
+                || ($commodity->height != $wms->skuhigh) || ($commodity->volumn != $wms->cube)
+                || ($commodity->pack === null)){
                 $updateCommodities[] = [
                     'id'=>$commodity->id,
                     'sku'=>$trimSku,
@@ -236,7 +237,8 @@ class CommodityController extends Controller
                     'length' => $wms->skulength,
                     'width' => $wms->skuwidth,
                     'height' => $wms->skuhigh,
-                    'volumn' => $wms->cube
+                    'volumn' => $wms->cube,
+                    "pack"  => $wms->packid == 'STANDARD' ? 0 : explode("/",$wms->packid)[1],
                 ];
             }
             if ($wms->alternate_sku1){
@@ -298,6 +300,7 @@ class CommodityController extends Controller
                 'width' => $wms->skuwidth,
                 'height' => $wms->skuhigh,
                 'volumn' => $wms->cube,
+                "pack"  => $wms->packid == 'STANDARD' ? 0 : explode("/",$wms->packid)[1],
                 "created_at" => $today,
             ];
             $barcodeMap[$wms->sku] = [];
@@ -337,6 +340,7 @@ class CommodityController extends Controller
                             'width' => $goods['width'],
                             'height' => $goods['height'],
                             'volumn' => $goods['volumn'],
+                            "pack" => $goods["pack"],
                         ];
                         unset($createCommodities[$barcodeIndex[$code->code]]);
                         break;

+ 50 - 22
app/Http/Controllers/CustomerBaseController.php

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
 use Illuminate\Http\Request;
 use Illuminate\Http\Response;
 use Illuminate\Support\Facades\Gate;
+use Illuminate\Support\Facades\Validator;
 
 class CustomerBaseController extends Controller
 {
@@ -16,7 +17,8 @@ class CustomerBaseController extends Controller
     public function index()
     {
         if(!Gate::allows('客户-查询')){ return redirect('denied');  }
-        return response()->view('maintenance.customer.index');
+        $customers = app('CustomerService')->paginate();
+        return response()->view('maintenance.customer.index',compact("customers"));
     }
 
     /**
@@ -33,56 +35,82 @@ class CustomerBaseController extends Controller
     /**
      * Store a newly created resource in storage.
      *
-     * @param  \Illuminate\Http\Request  $request
-     * @return \Illuminate\Http\Response
+     * @param  Request  $request
+     * @return Response
      */
     public function store(Request $request)
     {
-        //
-    }
-
-    /**
-     * Display the specified resource.
-     *
-     * @param  int  $id
-     * @return \Illuminate\Http\Response
-     */
-    public function show($id)
-    {
-        //
+        if(!Gate::allows('客户-录入')){ return redirect('denied');  }
+        $this->validator($request->input())->validate();
+        app('CustomerService')->create([
+            "code"=>$request->input("code"),
+            "name"=>$request->input("name"),
+            "company_name"=>$request->input("company_name"),
+        ]);
+        return response()->redirectTo("maintenance/customer")->with("successTip","成功创建客户“".$request->input("name")."”");
     }
 
     /**
      * Show the form for editing the specified resource.
      *
      * @param  int  $id
-     * @return \Illuminate\Http\Response
+     * @return Response
      */
     public function edit($id)
     {
-        //
+        if(!Gate::allows('客户-编辑')){ return redirect('denied');  }
+        $customer = app('CustomerService')->find($id);
+        return response()->view('maintenance.customer.create',compact("customer"));
     }
 
     /**
      * Update the specified resource in storage.
      *
-     * @param  \Illuminate\Http\Request  $request
+     * @param  Request  $request
      * @param  int  $id
-     * @return \Illuminate\Http\Response
+     * @return Response
      */
     public function update(Request $request, $id)
     {
-        //
+        if(!Gate::allows('客户-编辑')){ return redirect('denied');  }
+        $this->validator($request->input(),$id)->validate();
+        $result = app('CustomerService')->update(["id"=>$id],[
+            "code"=>$request->input("code"),
+            "name"=>$request->input("name"),
+            "company_name"=>$request->input("company_name"),
+        ]);
+        if ($result == 1){
+            return response()->redirectTo("maintenance/customer")->with("successTip","成功修改客户“".$request->input("name")."”的信息");
+        }
+        return response()->view("exception.default",["code"=>"509"]);
     }
 
     /**
      * Remove the specified resource from storage.
      *
      * @param  int  $id
-     * @return \Illuminate\Http\Response
+     * @return array
      */
     public function destroy($id)
     {
-        //
+        if(!Gate::allows('客户-删除')){ return ["success"=>false,"data"=>"无权操作!"];  }
+        $result = app('CustomerService')->destroy($id);
+        if ($result == 1)return ["success"=>true];
+        return ["success"=>false,"data"=>"删除了“".$result."”行"];
+    }
+
+    private function validator(array $params, $id = null)
+    {
+        return Validator::make($params,[
+            'code'=>['required',$id?"unique:customers,code,$id":'unique:customers,code','max:20'],
+            'name'=>['required','max:20'],
+        ],[
+            'required'=>':attribute 为必填项',
+            'max'=>':attribute 字符过多或输入值过大',
+            'unique'=>':attribute 已存在',
+        ],[
+            'code'=>'客户代码',
+            'name'=>'客户名称',
+        ]);
     }
 }

+ 323 - 11
app/Http/Controllers/CustomerController.php

@@ -2,14 +2,19 @@
 
 namespace App\Http\Controllers;
 
+use App\Owner;
+use App\Services\OwnerAreaReportService;
+use App\Services\OwnerBillReportService;
 use App\Services\OwnerReportService;
 use App\Services\OwnerService;
 use Exception;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Http\Request;
 use Illuminate\Http\Response;
+use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Gate;
 use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Validator;
 
 class CustomerController extends Controller
 {
@@ -30,12 +35,13 @@ class CustomerController extends Controller
         $customers = app('CustomerService')->getSelection();
         $owners = app('OwnerService')->getSelection();
         $reports = app("OwnerReportService")->paginate($request->input(),$withs);
-        return response()->view('customer.project.report',compact("reports","ownerGroups","customers","owners"));
+        $params = $request->input();
+        return response()->view('customer.project.report',compact("reports","ownerGroups","customers","owners","params"));
     }
 
     public function projectReportExport(Request $request)
     {
-        if(!Gate::allows('客户管理-项目-报表')){ return '没有权限';  }
+        if(!Gate::allows('客户管理-项目-报表')){ return redirect('denied');  }
         /** @var OwnerReportService $service */
         $service = app('OwnerReportService');
         $withs = ["ownerBillReport","owner"=>function($query){
@@ -82,31 +88,337 @@ class CustomerController extends Controller
         if(!Gate::allows('客户管理-项目-查询')){ return redirect('denied');  }
         /** @var OwnerService $service */
         $service = app('OwnerService');
-        $customers = $service->get(['customer_id'=>true],['customer']);
-        return response()->view('customer.project.index');
+        $owners = $service->paginate(['customer_id'=>true],['customer',"userOwnerGroup","ownerStoragePriceModels","ownerAreaReport"=>function($query){
+            $month = date('Y-m');
+            /** @var Builder $query */
+            $query->where("counting_month","like",$month."%");
+        }]);
+        return response()->view('customer.project.index',compact("owners"));
+    }
+
+    public function projectIndexExport(Request $request)
+    {
+        if(!Gate::allows('客户管理-项目-查询')){ return redirect('denied');  }
+        /** @var OwnerService $service */
+        $service = app('OwnerService');
+        $withs = ['customer',"userOwnerGroup","ownerStoragePriceModels","ownerAreaReport"=>function($query){
+            $month = date('Y-m');
+            /** @var Builder $query */
+            $query->where("counting_month","like",$month."%");
+        }];
+        $params = $request->input();
+        $params['customer_id']=true;
+        if ($request->checkAllSign ?? false) unset($params['checkAllSign']);
+        else $params = ["id"=>$request->data ?? ''];
+        $owners = $service->get($params,$withs);
+        $column = ["客户","税率","项目","货主代码","合同号","创建日期","销售名称","公司全称","联系人","联系电话","项目小组","用仓类型","当月结算面积","月单量预警","是否激活","项目描述"];
+        $list = [];
+        foreach ($owners as $owner){
+            $list[] = [
+                $owner->customer ? $owner->customer->name : '',
+                $owner->tax_rate,
+                $owner->name,
+                $owner->code,
+                $owner->contract_number,
+                $owner->created_at,
+                $owner->salesman,
+                $owner->customer ? $owner->customer->company_name : '',
+                $owner->linkman,
+                $owner->phone_number,
+                $owner->userOwnerGroup ? $owner->userOwnerGroup->name : '',
+                implode(",",array_unique(array_column(($owner->ownerStoragePriceModels)->toArray(),"using_type"))),
+                $owner->ownerAreaReport ? $owner->ownerAreaReport->accounting_area : '',
+                $owner->waring_line_on,
+                $owner->deleted_at ? '否' : '是',
+                $owner->description
+            ];
+        }
+        $post = Http::post(config('go.export.url'),['type'=>'base','data'=>json_encode(["row"=>$column,"list"=>$list],JSON_UNESCAPED_UNICODE)]);
+        if ($post->status() == 500){
+            throw new Exception($post->header("Msg"));
+        }
+        return response($post,200, [
+            "Content-type"=>"application/octet-stream",
+            "Content-Disposition"=>"attachment; filename=客户报表-".date('ymdHis').'.xlsx',
+        ]);
     }
 
     public function projectCreate()
     {
         if(!Gate::allows('客户管理-项目-录入')){ return redirect('denied');  }
-        return response()->view('customer.project.create');
+        $customers = app('CustomerService')->getSelection();
+        $ownerGroups = app('UserOwnerGroupService')->getSelection();
+        $storagePriceModels = app('OwnerStoragePriceModelService')->getSelection(["id","counting_type","using_type","minimum_area","price","unit_id"],["unit"=>function($query){$query->select("id","name");}]);
+        $owner = null;
+        return response()->view('customer.project.create',compact("customers","ownerGroups","storagePriceModels","owner"));
+    }
+
+    public function seekOwner(Request $request)
+    {
+        $params = $request->input();
+        $params["customer_id"] = true;
+        $owner = app('OwnerService')->first($params,["customer_id"=>"null"]);
+        if ($owner)return ["success"=>true,"data"=>$owner];
+        else return ["success"=>false];
+    }
+
+    public function projectStore(Request $request)
+    {
+        if(!Gate::allows('客户管理-项目-录入')){ return redirect('denied');  }
+        $this->validator($request->input())->validate();
+        $params = $request->input();
+        if ($params["id"]){
+            /** @var Owner $owner */
+            $owner = app('OwnerService')->find($params["id"]);
+            app('OwnerService')->update($owner,[
+                "customer_id"           => $params["customer_id"],
+                "tax_rate"              => $params["tax_rate"],
+                "contract_number"       => $params["contract_number"],
+                "salesman"              => $params["salesman"],
+                "linkman"               => $params["linkman"],
+                "phone_number"          => $params["phone_number"],
+                "user_owner_group_id"   => $params["owner_group_id"],
+                "waring_line_on"        => $params["waring_line_on"],
+                "description"           => $params["description"],
+            ],[
+                "ownerStoragePriceModels" => explode(',',$params["owner_storage_price_model_id"])
+            ]);
+            $msg = "成功更新“".$owner->name."”的信息!";
+        }else{
+            $owner = app('OwnerService')->create([
+                "name"                  => $params["name"],
+                "code"                  => $params["code"],
+                "customer_id"           => $params["customer_id"],
+                "tax_rate"              => $params["tax_rate"],
+                "contract_number"       => $params["contract_number"],
+                "salesman"              => $params["salesman"],
+                "linkman"               => $params["linkman"],
+                "phone_number"          => $params["phone_number"],
+                "user_owner_group_id"   => $params["owner_group_id"],
+                "waring_line_on"        => $params["waring_line_on"],
+                "description"           => $params["description"],
+            ],[
+                "ownerStoragePriceModels" => explode(',',$params["owner_storage_price_model_id"])
+            ]);
+            $msg = "成功创建“".$owner->name."”项目!";
+        }
+        return response()->redirectTo('customer/project/index')->with('successTip',$msg);
+    }
+
+    //获取货主下所有相关计费模型
+    public function getOwnerPriceModel(Request $request)
+    {
+        $owner = new Owner();
+        $owner->id = $request->id;
+        $owner->load(["ownerPriceOperations","ownerPriceExpresses","ownerPriceLogistics","ownerPriceDirectLogistics"]);
+        return ["success"=>true,"data"=>["ownerPriceOperations"=>$owner->ownerPriceOperations,
+            "ownerPriceExpresses"=>$owner->ownerPriceExpresses,
+            "ownerPriceLogistics"=>$owner->ownerPriceLogistics,
+            "ownerPriceDirectLogistics"=>$owner->ownerPriceDirectLogistics]];
+    }
+
+    public function projectEdit($id)
+    {
+        if(!Gate::allows('客户管理-项目-编辑')){ return redirect('denied');  }
+        /** @var Owner $owner */
+        $owner = app('OwnerService')->find($id);
+        $owner->owner_storage_price_model_id = $owner->getOwnerStoragePriceModelIds();
+        $customers = app('CustomerService')->getSelection();
+        $ownerGroups = app('UserOwnerGroupService')->getSelection();
+        $storagePriceModels = app('OwnerStoragePriceModelService')->getSelection(["id","counting_type","using_type","minimum_area","price","unit_id"],["unit"=>function($query){$query->select("id","name");}]);
+        return response()->view('customer.project.create',compact("customers","ownerGroups","storagePriceModels",'owner'));
     }
 
-    public function projectArea()
+    public function projectArea(Request $request)
     {
         if(!Gate::allows('客户管理-项目-面积')){ return redirect('denied');  }
-        return response()->view('customer.project.area');
+        $areas = app('OwnerAreaReportService')->paginate($request->input(),["owner"=>function($query){$query->with(["customer","ownerStoragePriceModels"]);}]);
+        $ownerGroups = app('UserOwnerGroupService')->getSelection();
+        $customers = app('CustomerService')->getSelection();
+        $owners = app('OwnerService')->getSelection();
+        $params = $request->input();
+        return response()->view('customer.project.area',compact("areas","ownerGroups","customers","owners","params"));
     }
 
-    public function financeInstantBill()
+    public function updateArea(Request $request)
+    {
+        if(!Gate::allows('客户管理-项目-面积-编辑')){ return ["success"=>false,'data'=>"无权操作!"];  }
+        if (!($request->id ?? false) || !($request->area ?? false)) return ["success"=>false,'data'=>"传递错误!"];
+        $values = $request->area ?? null;
+        if (!$values)return ["success"=>true,"data"=>$values];
+        foreach ($values as $column=>$value){
+            if ($value && (!is_numeric($value) || $value<0))return ["success"=>false,'data'=>$column."非数字或小于0!"];
+        }
+        $accounting_area = ((int)$values["area_on_tray"]*205) + ((int)$values["area_on_half_tray"]*1.8) + ((int)$values["area_on_flat"]*1.3);
+        $values["accounting_area"] = $accounting_area;
+        if (app('OwnerAreaReportService')->update(["id"=>$request->id],$values))
+            return ["success"=>true,"data"=>$values];
+        return ["success"=>false,"data"=>"未知错误!"];
+    }
+
+    public function projectAreaExport(Request $request)
+    {
+        if(!Gate::allows('客户管理-项目-面积')){ return redirect('denied');  }
+        $params = $request->input();
+        if ($request->checkAllSign)unset($params['checkAllSign']);
+        else $params = ["id"=>$request->data];
+        /** @var OwnerAreaReportService $serves */
+        $serves = app('OwnerAreaReportService');
+        $areas = $serves->get($params,["owner"=>function($query){$query->with(["customer","ownerStoragePriceModels","userOwnerGroup"]);}]);
+
+        $column = ["状态","项目组","客户","子项目","结算月","录入时间","用仓类型","货物整托","货物半托","平面区面积","结算面积"];
+        $list = [];
+        foreach ($areas as $area){
+            $list[] = [
+                $area->status,
+                $area->owner ? ($area->owner->userOwnerGroup ? $area->owner->userOwnerGroup->name : '') : '',
+                $area->owner ? ($area->owner->customer ? $area->owner->customer->name : '') : '',
+                $area->owner ? $area->owner->name : '',
+                $area->counting_month,
+                $area->updated_at,
+                $area->owner ? implode(",",array_unique(array_column(($area->owner->ownerStoragePriceModels)->toArray(),"using_type"))) : '',
+                $area->area_on_tray,
+                $area->area_on_half_tray,
+                $area->area_on_flat,
+                $area->accounting_area,
+            ];
+        }
+
+        $post = Http::post(config('go.export.url'),['type'=>'base','data'=>json_encode(["row"=>$column,"list"=>$list],JSON_UNESCAPED_UNICODE)]);
+        if ($post->status() == 500){
+            throw new Exception($post->header("Msg"));
+        }
+        return response($post,200, [
+            "Content-type"=>"application/octet-stream",
+            "Content-Disposition"=>"attachment; filename=项目面积报表-".date('ymdHis').'.xlsx',
+        ]);
+    }
+
+    public function financeInstantBill(Request $request)
     {
         if(!Gate::allows('客户管理-财务-即时账单')){ return redirect('denied');  }
-        return response()->view('customer.finance.instantBill');
+        $params = $request->input();
+        $shops = app('ShopService')->getSelection();
+        $customers = app('CustomerService')->getSelection();
+        $owners = app('OwnerService')->getSelection();
+        $details = app('OwnerFeeDetailService')->paginate($params,["owner"=>function($query){$query->with("customer");},"shop","processMethod","logistic"]);
+        return response()->view('customer.finance.instantBill',compact("details","params","shops","customers","owners"));
     }
 
-    public function financeBillConfirmation()
+    public function financeInstantBillExport(Request $request)
+    {
+        if(!Gate::allows('客户管理-财务-即时账单')){ return redirect('denied');  }
+        $params = $request->input();
+        if ($request->checkAllSign)unset($params['checkAllSign']);
+        else $params = ["id"=>$request->data];
+        $sql = app('OwnerFeeDetailService')->getSql($params);
+
+        $row = ["客户", "项目", "作业时间", "类型","店铺", "单号(发/收/退/提)", "收件人", "收件人电话", "商品数量",
+            "物流/快递单号", "体积", "重量", "承运商", "操作费", "物流费", "合计"];
+        $column = ["customer_name", "owner_name", "worked_at", "type","shop_name", "operation_bill", "consignee_name", "consignee_phone", "commodity_amount",
+            "logistic_bill", "volume", "weight", "logistic_name", "work_fee", "logistic_fee", "total"];
+        $rule = ["work_fee"=>"mysqlDate"];
+
+        $post = Http::post(config('go.export.url'),['type'=>'unify','sql'=>$sql, 'connection'=>'mysql',
+            'row'=>json_encode($row,JSON_UNESCAPED_UNICODE), 'column'=>json_encode($column), 'rule'=>json_encode($rule)]);
+        if ($post->status() == 500){
+            throw new Exception($post->header("Msg"));
+        }
+        return response($post,200, [
+            "Content-type"=>"application/octet-stream",
+            "Content-Disposition"=>"attachment; filename=即时账单记录-".date('ymdHis').'.xlsx',
+        ]);
+    }
+
+    public function financeBillConfirmation(Request $request)
     {
         if(!Gate::allows('客户管理-财务-账单确认')){ return redirect('denied');  }
-        return response()->view('customer.finance.billConfirmation');
+        $params = $request->input();
+        $ownerGroups = app('UserOwnerGroupService')->getSelection();
+        $customers = app('CustomerService')->getSelection();
+        $owners = app('OwnerService')->getSelection();
+        $bills = app('OwnerBillReportService')->paginate($params,["owner"=>function($query){
+            /** @var Builder $query */
+            $query->with(["customer","userOwnerGroup"]);
+        }]);
+        return response()->view('customer.finance.billConfirmation',compact("params","owners","ownerGroups","customers","bills"));
+    }
+
+    public function financeBillConfirmationExport(Request $request)
+    {
+        if(!Gate::allows('客户管理-财务-账单确认')){ return redirect('denied');  }
+        $params = $request->input();
+        if ($request->checkAllSign)unset($params['checkAllSign']);
+        else $params = ["id"=>$request->data];
+        /** @var OwnerBillReportService $serves */
+        $serves = app('OwnerBillReportService');
+        $bills = $serves->get($params,["owner"=>function($query){
+            /** @var Builder $query */
+            $query->with(["customer","userOwnerGroup"]);
+        }]);
+
+        $column = ["项目小组","客户","子项目","结算月","录入日期","原始账单金额","确认账单金额","差额","状态"];
+        $list = [];
+        foreach ($bills as $bill){
+            $list[] = [
+                $bill->owner ? ($bill->owner->userOwnerGroup ? $bill->owner->userOwnerGroup->name : '') : '',
+                $bill->owner ? ($bill->owner->customer ? $bill->owner->customer->name : '') : '',
+                $bill->owner ? $bill->owner->name : '',
+                $bill->counting_month,
+                $bill->updated_at,
+                $bill->initial_fee,
+                $bill->confirm_fee,
+                $bill->difference,
+                $bill->confirmed == '是' ? '已确认' : '未确认',
+            ];
+        }
+
+        $post = Http::post(config('go.export.url'),['type'=>'base','data'=>json_encode(["row"=>$column,"list"=>$list],JSON_UNESCAPED_UNICODE)]);
+        if ($post->status() == 500){
+            throw new Exception($post->header("Msg"));
+        }
+        return response($post,200, [
+            "Content-type"=>"application/octet-stream",
+            "Content-Disposition"=>"attachment; filename=客户账单报表-".date('ymdHis').'.xlsx',
+        ]);
+    }
+
+    public function updateBillReport(Request $request)
+    {
+        if(!Gate::allows('客户管理-财务-账单确认-编辑')){ return ["success"=>false,'data'=>"无权操作!"];  }
+        if (!$request->confirm_fee || !is_numeric($request->confirm_fee) || $request->confirm_fee<0)return ["success"=>false,"data"=>"非法金额参数"];
+        $date = date('Y-m-d H:i:s');
+        app('OwnerBillReportService')->update(["id"=>$request->id],["confirm_fee"=>$request->confirm_fee,"difference"=>DB::raw($request->confirm_fee.'- initial_fee'),"updated_at"=>$date]);
+        return ["success"=>true,"data"=>$date];
+    }
+
+    public function billConfirm(Request $request)
+    {
+        if(!Gate::allows('客户管理-财务-账单确认-完结')){ return ["success"=>false,'data'=>"无权操作!"];  }
+        if (!($request->id ?? false))return["success"=>false,"data"=>"非法参数"];
+        app('OwnerBillReportService')->update(["id"=>$request->id],["confirmed"=>"是"]);
+        return ["success"=>true];
+    }
+
+    private function validator(array $params){
+        $id = $params['id'] ?? null;
+        $validator=Validator::make($params,[
+            'id' => ['required_without_all:code,name'],
+            'code'=>['required','max:50',$id ? "unique:owners,code,$id":'unique:owners,code'],
+            'name'=>['required','max:50'],
+            'customer_id'=>['required'],
+            'owner_group_id'=>['required'],
+            'tax_rate' => ['required','numeric'],
+        ],[
+            'required'=>':attribute 为必填项',
+            'unique'=>':attribute 已存在',
+        ],[
+            'code'=>'项目代码',
+            'name'=>'项目名称',
+            'customer_id'=>'客户',
+            'owner_group_id'=>'工作组',
+            'tax_rate' => '税率'
+        ]);
+        return $validator;
     }
 }

+ 0 - 84
app/Http/Controllers/JobTypeController.php

@@ -1,84 +0,0 @@
-<?php
-
-namespace App\Http\Controllers;
-
-use Illuminate\Http\Request;
-
-class JobTypeController extends Controller
-{
-    /**
-     * Display a listing of the resource.
-     *
-     * @return \Illuminate\Http\Response
-     */
-    public function index()
-    {
-        return view('maintenance.jobType.index');
-    }
-
-    /**
-     * Show the form for creating a new resource.
-     *
-     * @return \Illuminate\Http\Response
-     */
-    public function create()
-    {
-        return view('maintenance.jobType.create');
-    }
-
-    /**
-     * Store a newly created resource in storage.
-     *
-     * @param  \Illuminate\Http\Request  $request
-     * @return \Illuminate\Http\Response
-     */
-    public function store(Request $request)
-    {
-        //
-    }
-
-    /**
-     * Display the specified resource.
-     *
-     * @param  int  $id
-     * @return \Illuminate\Http\Response
-     */
-    public function show($id)
-    {
-        //
-    }
-
-    /**
-     * Show the form for editing the specified resource.
-     *
-     * @param  int  $id
-     * @return \Illuminate\Http\Response
-     */
-    public function edit($id)
-    {
-        //
-    }
-
-    /**
-     * Update the specified resource in storage.
-     *
-     * @param  \Illuminate\Http\Request  $request
-     * @param  int  $id
-     * @return \Illuminate\Http\Response
-     */
-    public function update(Request $request, $id)
-    {
-        //
-    }
-
-    /**
-     * Remove the specified resource from storage.
-     *
-     * @param  int  $id
-     * @return \Illuminate\Http\Response
-     */
-    public function destroy($id)
-    {
-        //
-    }
-}

+ 57 - 33
app/Http/Controllers/OrderIssueController.php

@@ -101,7 +101,7 @@ class OrderIssueController extends Controller
 
     public function batchImport(Request $request)
     {
-        if (!Gate::allows('订单管理-订单问题件生成')) {
+        if (!Gate::allows('订单管理-问题件-导入-Excel导入')) {
             return redirect(url('/'));
         }
         $file = $request->file('file');
@@ -155,7 +155,7 @@ class OrderIssueController extends Controller
 
     public function excelImport()
     {
-        if (!Gate::allows('订单管理-订单问题件生成')) {
+        if (!Gate::allows('订单管理-问题件-导入')) {
             return redirect(url('/'));
         }
         return view('order.issue.import');
@@ -172,6 +172,10 @@ class OrderIssueController extends Controller
         /** @var OrderIssueService $orderIssueService */
         $orderIssueService = app(OrderIssueService::class);
         $exits_orderNos = $orderIssueService->校验问题件是否存在_WMS订单号_返回存在的订单号($request->input('orderNos'));
+        $count = OracleDOCOrderHeader::query()->with('oracleBASCode')->whereIn('OrderNo',$request['orderNos'])->whereHas('oracleBASCode',function($query){
+            $query->whereNotIn('codename_c',['完全装箱','订单完成','完全发运','分配完成']);
+        })->count();
+        if($count>0)return ['success'=>false,'fail_info'=>'勾选的订单中有没有完成的订单,请取消勾选'];
         if(count($exits_orderNos)>0){
             return ['success'=>false,'fail_info'=>'标记问题件存在已有订单号','exitsOrderNos' =>$exits_orderNos];
         }
@@ -497,7 +501,7 @@ class OrderIssueController extends Controller
 
     public function importPasteDataApi(Request $request)
     {
-        if (!Gate::allows('订单管理-订单问题件生成'))
+        if (!Gate::allows('订单管理-问题件-导入-文本导入'))
             return ['success'=>false,'fail_info'=>'没有对应权限'];
         $rows = $request->input('rows');
         $logistic_numbers = [];
@@ -516,7 +520,11 @@ class OrderIssueController extends Controller
 //            $string= preg_replace('/[\s,\,\,]+/','*++*',$str);
 //            $items = explode('*++*',$string);
             $items=[];
+
             preg_match('/^(\w*?)[\s,,;;]([\x{4e00}-\x{9fa5}]*?)[\s,,;;](.*?)[\s,,;;](\w*?)$/u', $str, $items);
+            if(count($items) == 0){
+                preg_match('/^(\w*?)[\s,,;;]([\x{4e00}-\x{9fa5}]*?)[\s,,;;](.*?)$/u', $str, $items);
+            }
             array_shift($items);
             $head = '第'.($i+1).'行';
             if(count($items)<count($rows)-1){
@@ -583,7 +591,7 @@ class OrderIssueController extends Controller
                 $result_explain = $map['result_explain'];
                 $type = $map['type'];
                 $custom_code = $map['custom_code'] ?? null;
-                $service->createOrderIssue($logistic_number, $type, $result_explain,'导入未处理',$custom_code);
+                $service->createOrderIssue($logistic_number, $type, $result_explain,'导入未处理',$custom_code,$request['hiddenTag'] ?? null);
             }
             return ['success'=>true];
         } catch (Exception $e) {
@@ -626,39 +634,39 @@ class OrderIssueController extends Controller
             $orderPacakges = $order_issue->order->packages ?? collect();
             $logistic_numbers = '';$order_sku  = '';$order_sku_name  = '';$order_sku_amount  = '';
             $orderPacakges->each(function($package,$index)use(&$logistic_numbers,&$order_sku,&$order_sku_name,&$order_sku_amount){
-                $logistic_numbers.=$package->logistic_number."\r\n";
+                if(!str_starts_with('null',$package->logistic_number))$logistic_numbers.=$package->logistic_number.",\r\n";
                 $package->commodities->each(function($commodities)use(&$order_sku,&$order_sku_name,&$order_sku_amount){
                     $commodity = $commodities->commodity ?? '';
-                    $order_sku.= ($commodity->sku ?? '')."\r\n";
-                    $order_sku_name.= ($commodity->name ?? '')."\r\n";
-                    $order_sku_amount.= ($commodities->amount ?? '')."\r\n";
+                    $order_sku.= ($commodity->sku ?? '').",\r\n";
+                    $order_sku_name.= ($commodity->name ?? '').",\r\n";
+                    $order_sku_amount.= ($commodities->amount ?? '').",\r\n";
                 });
             });
             $rejected_Bill_remark = $order_issue->rejectedBill->remark ?? '';
             $rejected_name = ''; $rejected_barcode = '';$rejected_amount = '';
             if($order_issue->rejectedBill){
                 $order_issue->rejectedBill->items(function($item)use(&$rejected_name,&$rejected_barcode, &$rejected_amount){
-                    $rejected_name.= $item->name_goods."\r\n";
-                    $rejected_barcode.= $item->barcode_goods."\r\n";
-                    $rejected_amount.= $item->amount."\r\n";
+                    $rejected_name.= $item->name_goods.",\r\n";
+                    $rejected_barcode.= $item->barcode_goods.",\r\n";
+                    $rejected_amount.= $item->amount.",\r\n";
                 });
             }
 
             $log_type = ''; $log_content = '';$log_user = '';
             $order_issue->logs->each(function($log)use(&$log_type, &$log_content,&$log_user){
-                $log_type.=$log->type."\r\n";
-                $log_content.=$log->content."\r\n";
-                $log_user.=$log->user->name."\r\n";
+                $log_type.=$log->type.",\r\n";
+                $log_content.=$log->content.",\r\n";
+                $log_user.=$log->user->name.",\r\n";
             });
             $send_order = $order_issue->secondOrder ??  new Order();
             $send_order_numbers = '';$send_order_sku ='';$send_order_name ='';$send_order_amount = '';
             $send_order->packages->each(function($package)use(&$send_order_numbers ,&$send_order_sku ,&$send_order_name ,&$send_order_amount ){
-                $send_order_numbers.=($package->logistic_number)."\r\n";
+                $send_order_numbers.=($package->logistic_number).",\r\n";
                 $package->commodities->each(function ($commodities)use( &$send_order_sku ,&$send_order_name ,&$send_order_amount ){
                     $commodity = $commodities->commodity;
-                    $send_order_sku.=$commodity->sku."\r\n";
-                    $send_order_name.=$commodity->name."\r\n";
-                    $send_order_amount.=$commodities->amount."\r\n";
+                    $send_order_sku.=$commodity->sku.",\r\n";
+                    $send_order_name.=$commodity->name.",\r\n";
+                    $send_order_amount.=$commodities->amount.",\r\n";
                 });
             });
 
@@ -675,22 +683,22 @@ class OrderIssueController extends Controller
                 $order->district,               // 区
                 $order->address,                // 收货人地址
 
-                $logistic_numbers,              //原始运单号
-                $order_sku,                     //原始商品
-                $order_sku_name,                //原始商品名称
-                $order_sku_amount,              //原始商品数量
+                rtrim($logistic_numbers,",\r\n"),              //原始运单号
+                rtrim($order_sku,",\r\n"),                     //原始商品
+                rtrim($order_sku_name,",\r\n"),                //原始商品名称
+                rtrim($order_sku_amount,",\r\n"),              //原始商品数量
 
                 //'退单备注','退单商品名','退单商品条码','退单商品数量','退单状态',
-                $rejected_Bill_remark,                                          // 退单备注
-                $rejected_name,        // 退单商品名
-                $rejected_barcode ,    // 退单商品条码
-                $rejected_amount,      // 退单商品数量
+                rtrim($rejected_Bill_remark,",\r\n"),                                          // 退单备注
+                rtrim($rejected_name,",\r\n"),        // 退单商品名
+                rtrim($rejected_barcode,",\r\n") ,    // 退单商品条码
+                rtrim($rejected_amount,",\r\n"),      // 退单商品数量
                 $order_issue->rejecting_status ,                                // 退单状态
 
                 // '操作类型','情况说明','问题类别',
-                $log_type,                        //操作类型
-                $log_content,                     //情况说明
-                $log_user,                        //操作者
+                rtrim($log_type,",\r\n"),                        //操作类型
+                rtrim($log_content,",\r\n"),                     //情况说明
+                rtrim($log_user,",\r\n"),                        //操作者
 
                 // '情况说明','问题类别',
                 $order_issue->result_explain,                               // 情况说明
@@ -699,10 +707,10 @@ class OrderIssueController extends Controller
                 // '二次订单号','二次承运商','二次运单号','二次商品条码','二次商品名','二次商品数量',
                 $order_issue->secondOrder->client_code ?? '',                //二次订单号
                 $order_issue->secondOrder->logistic->name ?? '',             //二次承运商
-                $send_order_numbers ,                                        //二次运单号
-                $send_order_sku,                                             // 二次商品条码
-                $send_order_name,                                            // 二次商品名
-                $send_order_amount,                                          // 二次商品数量
+                rtrim($send_order_numbers,",\r\n") ,                                        //二次运单号
+                rtrim($send_order_sku,",\r\n"),                                             // 二次商品条码
+                rtrim($send_order_name,",\r\n"),                                            // 二次商品名
+                rtrim($send_order_amount,",\r\n"),                                          // 二次商品数量
 
                 //'最终状态', '承运商赔偿金额', '承运商快递减免', '宝时赔偿金额', '宝时快递减免','事故责任方'
                 $order_issue->final_status??'',
@@ -742,4 +750,20 @@ class OrderIssueController extends Controller
         $service = app('OrderIssueService');
         return  $service->recoverOrderIssue($request['ids']);
     }
+
+    public function financeConfirmApi(Request $request)
+    {
+        if (!Gate::allows('订单管理-问题件-财务确认')) {
+            return ['success'=>false,'error'=>'没有对应权限'];
+        }
+        try {
+            $bool = OrderIssue::query()->whereIn('id', $request['ids'])->update(['finance_confirm' => '是']);
+            if($bool==false)return ['success'=>false,'error'=>'财务确认失败'];
+            app('LogService')->log(__METHOD__, __FUNCTION__,'财务确认'. json_encode($request->getContent()), Auth::user()['id']);
+            return ['success'=>true];
+        } catch (Exception $e) {
+            app('LogService')->log(__METHOD__,'Error'. __FUNCTION__,'财务确认 Error'. json_encode($request->getContent()).' || '.json_encode($e->getMessage()).' || '.json_encode($e->getTraceAsString()), Auth::user()['id']);
+            return ['success'=>false,'error'=>$e->getMessage()];
+        }
+    }
 }

+ 9 - 2
app/Http/Controllers/OrderTrackingController.php

@@ -11,6 +11,7 @@ use App\Services\OwnerService;
 use App\UploadFile;
 use Exception;
 use Illuminate\Http\Request;
+use Illuminate\Support\Carbon;
 use Illuminate\Support\Facades\Gate;
 use Illuminate\Support\Facades\Http;
 use Intervention\Image\Facades\Image;
@@ -21,11 +22,14 @@ class OrderTrackingController extends Controller
 
     public function index(Request $request)
     {
+        /**
+         * @var OrderTrackingService $service
+         */
         if (!Gate::allows('订单管理-跟踪'))
             return redirect(url('/'));
         $owners =  app(OwnerService::class)->getAuthorizedOwners();
-        /** @var OrderTrackingService $service */
         $service = app('OrderTrackingService');
+        $service->fillInOrderTracking();
         $trackOrders = $service->paginate($request->input());
         $trackOrders->map(function($trackOrder){
             if($trackOrder->uploadFile){
@@ -157,7 +161,7 @@ class OrderTrackingController extends Controller
         $order_client_code_temp = '';
         $row_count = 0;
         foreach ($orderTrackings as $index=> $orderTracking) {
-            $logistic =  $orderTracking->commodities->package->order->logistic->name;
+            $logistic =  $orderTracking->commodities->package->order->logistic->name ?? '';
             if($order_client_code_temp==''){
                 $order_client_code_temp=$orderTracking->order_client_code;
                 $row_count=1;
@@ -190,6 +194,9 @@ class OrderTrackingController extends Controller
             if($logistic=='新杰物流'||$logistic=='新杰物流到付'){
                 $logistic_number = $orderTracking->order_client_code;
             }
+            if(str_starts_with('null',$logistic_number)){
+                $logistic_number = '';
+            }
             $list[]=[
                 $orderTracking->owner->name ?? '',
                 $order_client_code,

+ 866 - 17
app/Http/Controllers/PriceModelController.php

@@ -2,61 +2,910 @@
 
 namespace App\Http\Controllers;
 
+use App\Imports\ExpressImport;
+use App\Imports\OwnerPriceDirectLogisticDetailImport;
+use App\Imports\OwnerPriceLogisticDetailImport;
+use App\Owner;
+use App\OwnerOutStorageRule;
+use App\OwnerPriceDirectLogistic;
+use App\OwnerPriceExpress;
+use App\OwnerPriceExpressProvince;
+use App\OwnerPriceLogistic;
+use App\OwnerPriceOperation;
+use App\Services\common\ExportService;
+use App\Services\OwnerOutStorageRuleService;
+use App\Services\OwnerPriceOperationService;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\Gate;
+use Illuminate\Support\Facades\Validator;
+use Maatwebsite\Excel\Facades\Excel;
 
 class PriceModelController extends Controller
 {
-    public function storeIndex()
+    public function storageIndex(Request $request)
     {
         if(!Gate::allows('计费模型-仓储')){ return redirect('denied');  }
-        return response()->view('maintenance.priceModel.storage.index');
+        $models = app('OwnerStoragePriceModelService')->paginate($request->input("id"),["unit"]);
+        return response()->view('maintenance.priceModel.storage.index',compact("models"));
     }
 
-    public function storeCreate()
+    public function storageCreate()
     {
         if(!Gate::allows('计费模型-仓储-录入')){ return redirect('denied');  }
-        return response()->view('maintenance.priceModel.storage.create');
+        $units = app('UnitService')->getSelection();
+        return response()->view('maintenance.priceModel.storage.create',compact("units"));
     }
 
-    public function operationIndex(){
+    public function storageStore(Request $request)
+    {
+        if(!Gate::allows('计费模型-仓储-录入')){ return redirect('denied');  }
+        $this->storageValidator($request->input())->validate();
+        app('OwnerStoragePriceModelService')->create($request->input());
+        return response()->redirectTo('maintenance/priceModel/storage')->with('successTip',"创建成功!");
+    }
+
+    public function storageEdit($id)
+    {
+        if(!Gate::allows('计费模型-仓储-编辑')){ return redirect('denied');  }
+        $model = app('OwnerStoragePriceModelService')->find($id);
+        $units = app('UnitService')->getSelection();
+        return response()->view('maintenance.priceModel.storage.create',compact("units","model"));
+    }
+
+    public function storageUpdate(Request $request)
+    {
+        if(!Gate::allows('计费模型-仓储-编辑')){ return redirect('denied');  }
+        app('OwnerStoragePriceModelService')->update(["id"=>$request->input("id")],[
+            "counting_type" => $request->input("counting_type"),
+            "using_type"    => $request->input("using_type"),
+            "minimum_area"  => $request->input("minimum_area"),
+            "price"         => $request->input("price"),
+            "discount_type" => $request->input("discount_type"),
+            "discount_value"=> $request->input("discount_value"),
+            "unit_id"       => $request->input("unit_id"),
+        ]);
+        return response()->redirectTo('maintenance/priceModel/storage')->with('successTip',"更新成功!");
+    }
+
+    public function storageDestroy($id)
+    {
+        app("OwnerStoragePriceModelService")->destroy($id);
+        return ["success"=>true];
+    }
+
+    private function storageValidator(array $params)
+    {
+        return Validator::make($params,[
+            'counting_type'=>['required'],
+            'using_type'=>['required'],
+            'minimum_area'=>['nullable','numeric','min:0'],
+            'discount_value'=>['nullable','numeric','min:0'],
+            'price'=>['required','numeric','min:0'],
+            'discount_type'=>['required'],
+            'unit_id'=>['required','integer'],
+        ],[
+            'required'=>':attribute 为必填项',
+            'min'=>':attribute 不得小于0',
+            'integer'=>':attribute 未选择',
+        ],[
+            'counting_type' =>"计费类型",
+            'using_type'    =>"用仓类型",
+            'minimum_area'  =>"最低起租面积",
+            'price'         =>"单价",
+            'discount_type' =>"减免类型",
+            'discount_value'=>"减免值",
+            'unit_id'       =>"单位",
+        ]);
+    }
+
+    public function operationIndex(Request $request){
         if(!Gate::allows('计费模型-作业-查询')){ return redirect('denied');  }
-        return response()->view('maintenance.priceModel.operation.index');
+        $features = app("FeatureService")->getMapArray();
+        OwnerPriceOperation::$features = $features;
+        $models = app('OwnerPriceOperationService')->paginate($request->input(),["ownerPriceOperationOwners","ownerInStorageRule"=>function($query){$query->with("unit");}])->append("featureFormat");
+        $owners = app("OwnerService")->getSelection();
+        return response()->view('maintenance.priceModel.operation.index',compact("models","owners"));
+    }
+
+    /* 获取出库模型规则 */
+    public function operationGetOutStorageRule(Request $request)
+    {
+        if(!Gate::allows('计费模型-作业-查询')){ return ["success"=>false,"data"=>"无权操作"];  }
+        /** @var OwnerOutStorageRuleService $service */
+        $service = app('OwnerOutStorageRuleService');
+        $ownerOutStorageRules = $service->get(["owner_price_operation_id"=>$request->input("id")],["unit"],true)->append("featureFormat");
+        return ["success"=>true,"data"=>$ownerOutStorageRules];
+    }
+    /* 修改出库模型规则 */
+    public function updateOutStorageRule(Request $request)
+    {
+        if(!Gate::allows('计费模型-作业-编辑')){ return ["success"=>false,"data"=>"无权操作"];  }
+        /** @var OwnerOutStorageRuleService $service */
+        $service = app('OwnerOutStorageRuleService');
+        $row = $service->update(["id"=>$request->input("id")],[
+            "amount"=>$request->input("amount"),
+            "unit_id"=>$request->input("unit_id"),
+            "priority"=>$request->input("priority"),
+            "unit_price"=>$request->input("unit_price")]);
+        if ($row == 1) return ["success"=>true];
+        return ["success"=>false,"data"=>"受影响数据数为:".$row];
+    }
+
+    public function createOutStorageRule(Request $request)
+    {
+        if(!Gate::allows('计费模型-作业-编辑')){ return ["success"=>false,"data"=>"无权操作"];  }
+        /** @var OwnerOutStorageRuleService $service */
+        $service = app('OwnerOutStorageRuleService');
+        switch ($request->input("strategy")){
+            case "起步":
+                $c = $service->isExist(["owner_price_operation_id"=>$request->input("owner_price_operation_id"),"strategy"=>"起步"]);
+                if ($c > 0)return ["success"=>false,"data"=>"已存在起步策略"];
+                break;
+            case "默认":
+                $c = $service->isExist(["owner_price_operation_id"=>$request->input("owner_price_operation_id"),"strategy"=>"默认"]);
+                if ($c > 0)return ["success"=>false,"data"=>"已存在默认策略"];
+                break;
+        }
+        $data = $service->create($request->input());
+        $data->load("unit");
+        return ["success"=>true,"data"=>$data];
+    }
+    public function getFeatures(Request $request)
+    {
+        return ["success"=>true,"data"=>app("FeatureService")->translationFeature($request->input("feature"))];
+    }
+
+    public function addFeature(Request $request)
+    {
+        if(!Gate::allows('计费模型-作业-编辑')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $id = $request->input("id");
+        $features = $request->input("features");
+        if (!$id || !$features)return ["success"=>false,"data"=>"非法参数"];
+        $result = app("FeatureService")->analysisFeature($features);
+        $feature = $result["feature"];
+        $stack = [];
+        if ($feature && ($feature[0]=='|' || $feature[0]=='&'))$feature=substr($feature,1);
+        for ($i=0;$i<strlen($feature);$i++){
+            if ($feature[$i] == '(')array_unshift($stack,'(');
+            if ($feature[$i] == ')'){
+                if (count($stack) == 0)return ["success"=>false,"data"=>"组标记错误,起始与结束标记必须对应"];
+                array_shift($stack);
+            }
+        }
+        if (count($stack) > 0)return ["success"=>false,"data"=>"组标记错误,起始与结束标记必须对应"];
+        $row = app('OwnerOutStorageRuleService')->update(["id"=>$id],["feature"=>$feature]);
+        if ($row != 1)return ["success"=>false,"data"=>"影响了“".$row."”行"];
+        OwnerOutStorageRule::$features = $result["map"];
+        $rule = app('OwnerOutStorageRuleService')->find($id)->append("featureFormat");
+        return ["success"=>true,"data"=>["featureFormat"=>$rule->featureFormat,"feature"=>$feature]];
+    }
+
+    public function getFeature(Request $request)
+    {
+        $features = $request->input("features");
+        if (!$features)return ["success"=>false,"data"=>"非法参数"];
+        $result = app("FeatureService")->analysisFeature($features);
+        $feature = $result["feature"];
+        $stack = [];
+        if ($feature && ($feature[0]=='|' || $feature[0]=='&'))$feature=substr($feature,1);
+        for ($i=0;$i<strlen($feature);$i++){
+            if ($feature[$i] == '(')array_unshift($stack,'(');
+            if ($feature[$i] == ')'){
+                if (count($stack) == 0)return ["success"=>false,"data"=>"组标记错误,起始与结束标记必须对应"];
+                array_shift($stack);
+            }
+        }
+        if (count($stack) > 0)return ["success"=>false,"data"=>"组标记错误,起始与结束标记必须对应"];
+        return ["success"=>true,"data"=>$feature];
+    }
+
+    public function operationDestroy($id)
+    {
+        if(!Gate::allows('计费模型-作业-删除')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $row = app("OwnerPriceOperationService")->destroy($id);
+        if ($row == 1)return ["success"=>true];
+        return ["success"=>false,"data"=>"影响了“".$row."”行"];
     }
 
     public function operationCreate(){
         if(!Gate::allows('计费模型-作业-录入')){ return redirect('denied');  }
-        return response()->view('maintenance.priceModel.operation.create');
+        $owners = app("OwnerService")->getSelection();
+        $units = app('UnitService')->getSelection();
+        return response()->view('maintenance.priceModel.operation.create',compact("owners","units"));
     }
 
-    public function expressIndex(){
+    public function operationStore(Request $request)
+    {
+        if(!Gate::allows('计费模型-作业-录入')){ return redirect('denied');  }
+        $request->offsetSet("rules",json_decode($request->input("rules"),true));
+        $request->offsetSet("owner_id",explode(',',$request->input("owner_id")));
+        $this->operationValidator($request->input())->validate();
+
+        //录入主表
+        /** @var OwnerPriceOperationService $service */
+        $service = app("OwnerPriceOperationService");
+        $ownerPriceOperation = $service->create([
+            "operation_type" => $request->input("operation_type"),
+            "strategy" => $request->input("strategy"),
+            "name" => $request->input("name"),
+            "priority" => $request->input("priority"),
+            "remark" => $request->input("remark"),
+            "feature" => $request->input("feature"),
+        ]);
+        //录入子表
+        if ($request->input("operation_type") == '入库') $service->insertRule([
+            "owner_price_operation_id" => $ownerPriceOperation->id,
+            "amount" => $request->input("rules")[0]["amount"],
+            "unit_id" => $request->input("rules")[0]["unit_id"],
+            "unit_price" => $request->input("rules")[0]["unit_price"],
+        ],"入库");
+        else{
+            $insert = [];
+            foreach ($request->input("rules") as $rule){
+                $insert[] = [
+                    "owner_price_operation_id" => $ownerPriceOperation->id,
+                    "amount" => $rule["amount"],
+                    "unit_id" => $rule["unit_id"],
+                    "unit_price" => $rule["unit_price"],
+                    "strategy" => $rule["strategy"],
+                    "feature" => $rule["feature"],
+                    "priority" => $rule["priority"],
+                ];
+            }
+            $service->insertRule($insert);
+        }
+        //录入中间表
+        /** @var OwnerPriceOperation $model */
+        if ($request->input("owner_id"))$model->ownerPriceOperationOwners()->sync($request->input("owner_id"));
+        return response()->redirectTo("maintenance/priceModel/operation")->with("successTip","创建“".$request->input("name")."”成功");
+    }
+
+    public function operationEdit($id)
+    {
+        if(!Gate::allows('计费模型-作业-编辑')){ return redirect('denied');  }
+        $model = app('OwnerPriceOperationService')->find($id,true,["ownerPriceOperationOwners"]);
+        $owners = app("OwnerService")->getSelection();
+        $units = app('UnitService')->getSelection();
+        return response()->view('maintenance.priceModel.operation.create',compact("owners","units","model"));
+    }
+
+    public function operationUpdate($id,Request $request)
+    {
+        if(!Gate::allows('计费模型-作业-编辑')){ return redirect('denied');  }
+        $request->offsetSet("rules",json_decode($request->input("rules"),true));
+        $request->offsetSet("owner_id",explode(',',$request->input("owner_id")));
+        $this->operationValidator($request->input(),$id)->validate();
+
+        /** @var OwnerPriceOperationService $service */
+        $service = app("OwnerPriceOperationService");
+
+        $model = $service->find($id);
+        $service->findUpdate($model,[
+            "name" => $request->input("name"),
+            "priority" => $request->input("priority"),
+            "remark" => $request->input("remark"),
+            "feature" => $request->input("feature"),
+        ]);
+        $service->destroyRule($id, $model->operation_type);
+        //录入子表
+        if ($request->input("operation_type") == '入库') $service->insertRule([
+            "owner_price_operation_id" => $model->id,
+            "amount" => $request->input("rules")[0]["amount"],
+            "unit_id" => $request->input("rules")[0]["unit_id"],
+            "unit_price" => $request->input("rules")[0]["unit_price"],
+        ],"入库");
+        else{
+            $insert = [];
+            foreach ($request->input("rules") as $rule){
+                $insert[] = [
+                    "owner_price_operation_id" => $model->id,
+                    "amount" => $rule["amount"],
+                    "unit_id" => $rule["unit_id"],
+                    "unit_price" => $rule["unit_price"],
+                    "strategy" => $rule["strategy"],
+                    "feature" => $rule["feature"],
+                    "priority" => $rule["priority"],
+                ];
+            }
+            $service->insertRule($insert);
+        }
+        //录入中间表
+        /** @var OwnerPriceOperation $model */
+        if ($request->input("owner_id"))$model->ownerPriceOperationOwners()->sync($request->input("owner_id"));
+        return response()->redirectTo("maintenance/priceModel/operation")->with("successTip","修改“".$request->input("name")."”成功");
+    }
+
+    private function operationValidator(array $params, $id= null)
+    {
+        return Validator::make($params,[
+            //required_with:id
+            'operation_type'=>['required'],
+            'owner_id'=>[function ($attribute, $value, $fail)use($params,$id) {
+                if ($params["strategy"] == '默认'){
+                    $owners = Owner::query()->whereIn("id",$value)->withCount(["ownerPriceOperations"=>function($query)use($params,$id){
+                        if ($id)$query->where('id',"!=",$id);
+                        $query->where("strategy","默认")->where("operation_type",$params["operation_type"]);
+                    }])->get();
+                    $err = [];
+                    foreach ($owners as $owner){
+                        if ($owner->owner_price_operations_count > 0)$err[] = $owner->name;
+                    }
+                    if (count($err)>0)$fail("(".implode(',',$err).') 已经绑定'.$params["operation_type"].'的默认策略');
+                }
+            }],
+            'strategy'=>['required'],
+            'name'=>['required',$id?"unique:owner_price_operations,name,$id":'unique:owner_price_operations,name'],
+            'priority'=>['required','integer','min:0','max:100'],
+            'rules.*.strategy'=>['required_if:operation_type,出库'],
+            'rules.*.amount'=>['required',"integer"],
+            'rules.*.unit_id'=>['required','integer'],
+            'rules.*.unit_price'=>['required','numeric',"min:0"],
+            'rules.*.priority'=>['required_if:operation_type,出库','integer','min:0','max:100'],
+        ],[
+            'required'=>':attribute 为必填项',
+            'min'=>':attribute 不得小于0',
+            'integer'=>':attribute 必须为整数',
+            'numeric'=>':attribute 必须为数字',
+            'max'=>':attribute 超出最大值',
+            'required_if'=>':attribute 操作类型为出库时不得为空',
+        ],[
+            'operation_type' =>"操作类型",
+            'strategy'    =>"计费策略",
+            'name'  =>"名称",
+            'priority' =>"优先级",
+        ]);
+    }
+
+    public function expressIndex(Request $request){
         if(!Gate::allows('计费模型-快递-查询')){ return redirect('denied');  }
-        return response()->view('maintenance.priceModel.express.index');
+        $models = app('OwnerPriceExpressService')->paginate($request->input("id"));
+        return response()->view('maintenance.priceModel.express.index',compact("models"));
+    }
+
+    public function expressGetDetail(Request $request)
+    {
+        if(!Gate::allows('计费模型-快递-查询')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $model = new OwnerPriceExpress();
+        $model->id = $request->input("id");
+        $model->load(["details"=>function($query){$query->with("province");}]);
+        return ["success"=>true,"data"=>$model->details];
+    }
+
+    public function expressUpdateDetail(Request $request)
+    {
+        if(!Gate::allows('计费模型-快递-编辑')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $detail = $request->input("detail");
+        if ($detail["id"]){
+            app('OwnerPriceExpressService')->updateDetail(["id"=>$detail["id"]],[
+                "additional_weight_price" => $detail["additional_weight_price"],
+                "initial_weight_price" => $detail["initial_weight_price"],
+            ]);
+        }else{
+            $row = app('OwnerPriceExpressService')->isExistDetail(["owner_price_express_id"=>$request->input("id"),"province_id"=>$detail["province_id"]]);
+            if ($row>0)return ["success"=>false,"data"=>"已存在该省份计费模型"];
+            /** @var OwnerPriceExpressProvince $detail */
+            $detail = app('OwnerPriceExpressService')->createDetail([
+                "owner_price_express_id" =>  $request->input("id"),
+                "province_id" => $detail["province_id"],
+                "additional_weight_price" => $detail["additional_weight_price"],
+                "initial_weight_price" => $detail["initial_weight_price"],
+            ]);
+            $detail->load("province");
+        }
+        return ["success"=>true,"data"=>$detail];
+    }
+
+    public function expressDestroyDetail(Request $request)
+    {
+        if(!Gate::allows('计费模型-快递-删除')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $id = $request->input("id");
+        if (!$id)return ["success"=>false,"data"=>"非法参数"];
+        app("OwnerPriceExpressService")->destroyDetail($id);
+        return ["success"=>true];
+    }
+
+    public function expressImport(Request $request){
+        if(!Gate::allows('计费模型-快递-录入')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $fileSuffix=$request->file('file')->getClientOriginalExtension();
+        if ($fileSuffix != 'xlsx' && $fileSuffix != 'xls' && $fileSuffix != 'csv')
+            return ['success'=>false,'data'=>'不支持该文件类型'];
+        ini_set('max_execution_time',2500);
+        ini_set('memory_limit','1526M');
+        $fileSuffix = ucwords($fileSuffix);
+        /** @var OwnerPriceExpress $model */
+        $model = app('OwnerPriceExpressService')->find($request->input("id"),["details"]);
+        Excel::import(new ExpressImport($model),$request->file('file')->path(),null,$fileSuffix);
+        if (Cache::has('express'))return Cache::pull('express');
+
+        return ["success"=>false,"data"=>"导入发生错误,数据无响应"];
     }
 
     public function expressCreate(){
         if(!Gate::allows('计费模型-快递-录入')){ return redirect('denied');  }
-        return response()->view('maintenance.priceModel.express.create');
+        $logistics = app("LogisticService")->getSelection();
+        $owners = app("OwnerService")->getSelection();
+        return response()->view('maintenance.priceModel.express.create',compact("logistics","owners"));
+    }
+
+    public function expressStore(Request $request)
+    {
+        if(!Gate::allows('计费模型-快递-录入')){ return redirect('denied');  }
+        $request->offsetSet("owner_id",explode(",",$request->input("owner_id")));
+        $request->offsetSet("logistic_id",explode(",",$request->input("logistic_id")));
+        $this->expressValidator($request->input())->validate();
+        /** @var OwnerPriceExpress $model */
+        $model = app("OwnerPriceExpressService")->create([
+            "name" => $request->input("name"),
+            "initial_weight" => $request->input("initial_weight"),
+            "additional_weight" => $request->input("additional_weight"),
+        ]);
+        $model->owners()->sync($request->input("owner_id"));
+        $model->logistics()->sync($request->input("logistic_id"));
+        return response()->redirectTo("maintenance/priceModel/express")->with("successTip","录入“".$request->input("name")."”成功");
+    }
+
+    public function expressEdit($id)
+    {
+        if(!Gate::allows('计费模型-快递-编辑')){ return redirect('denied');  }
+        /** @var OwnerPriceExpress $model */
+        $model = app('OwnerPriceExpressService')->find($id)->append(["owner_id","logistic_id"]);
+        $owners = app("OwnerService")->getSelection();
+        $logistics = app('LogisticService')->getSelection();
+        return response()->view('maintenance.priceModel.express.create',compact("owners","logistics","model"));
+    }
+
+    public function expressUpdate($id,Request $request)
+    {
+        if(!Gate::allows('计费模型-快递-编辑')){ return redirect('denied');  }
+        $request->offsetSet("owner_id",explode(",",$request->input("owner_id")));
+        $request->offsetSet("logistic_id",explode(",",$request->input("logistic_id")));
+        $this->expressValidator($request->input(),$id)->validate();
+        /** @var OwnerPriceExpress $model */
+        app("OwnerPriceExpressService")->update(["id"=>$id],[
+            "name" => $request->input("name"),
+            "initial_weight" => $request->input("initial_weight"),
+            "additional_weight" => $request->input("additional_weight"),
+        ]);
+        $model = new OwnerPriceExpress();
+        $model->id = $id;
+        $model->owners()->sync($request->input("owner_id"));
+        $model->logistics()->sync($request->input("logistic_id"));
+        return response()->redirectTo("maintenance/priceModel/express")->with("successTip","修改“".$request->input("name")."”成功");
+    }
+
+    private function expressValidator(array $params, $id=null)
+    {
+        return Validator::make($params,[
+            'name'=>['required',$id?"unique:owner_price_expresses,name,$id":'unique:owner_price_expresses,name'],
+            'initial_weight'=>['required','numeric','min:0'],
+            'additional_weight'=>['required','numeric','min:0'],
+            'owner_id'=>[function ($attribute, $value, $fail)use($id) {
+                $owners = app("OwnerPriceExpressService")->getExistOwnerName($value,$id);
+                if ($owners)$fail("(".implode(',',$owners).') 已经绑定计费模型');
+            }],
+            'logistic_id'=>[function ($attribute, $value, $fail)use($id) {
+                $logistics = app("OwnerPriceExpressService")->getExistLogisticName($value,$id);
+                if ($logistics)$fail("(".implode(',',$logistics).') 已经绑定计费模型');
+            }],
+        ],[
+            'required'=>':attribute 为必填项',
+            'unique' => ':attribute 已存在',
+        ],[
+            'name' =>"名称",
+            'initial_weight'  =>"首重",
+            'additional_weight'  =>"续重",
+        ]);
     }
 
-    public function logisticIndex(){
+    public function expressDestroy($id)
+    {
+        if(!Gate::allows('计费模型-快递-删除')){ return ["success"=>false,"data"=>"无权操作"]; };
+        app("OwnerPriceExpressService")->destroy($id);
+        return ["success"=>true];
+    }
+
+    public function logisticIndex(Request $request)
+    {
         if(!Gate::allows('计费模型-物流-查询')){ return redirect('denied');  }
-        return response()->view('maintenance.priceModel.logistic.index');
+        $models = app("OwnerPriceLogisticService")->paginate($request->input("id"))->append(["unit_range_json","other_unit_range_json"]);
+        return response()->view('maintenance.priceModel.logistic.index',compact("models"));
     }
 
-    public function logisticCreate(){
+    public function logisticCreate()
+    {
+        if(!Gate::allows('计费模型-物流-录入')){ return redirect('denied');  }
+        $owners = app("OwnerService")->getSelection();
+        $logistics = app('LogisticService')->getSelection();
+        $units = app('UnitService')->getSelection();
+        return response()->view('maintenance.priceModel.logistic.create',compact("owners","logistics","units"));
+    }
+
+    public function logisticStore(Request $request)
+    {
         if(!Gate::allows('计费模型-物流-录入')){ return redirect('denied');  }
-        return response()->view('maintenance.priceModel.logistic.create');
+        $request->offsetSet("owner_id",explode(",",$request->input("owner_id")));
+        $request->offsetSet("logistic_id",explode(",",$request->input("logistic_id")));
+        $this->logisticValidator($request->input())->validate();
+        /** @var OwnerPriceLogistic $model */
+        $model = app("OwnerPriceLogisticService")->create([
+            "name" => $request->input("name"),
+            "pick_up_price" => $request->input("pick_up_price"),
+            "fuel_price" => $request->input("fuel_price"),
+            "service_price" => $request->input("service_price"),
+            "unit_id" => $request->input("unit_id"),
+            "unit_range" => $request->input("unit_range"),
+            "other_unit_id" => $request->input("other_unit_id"),
+            "other_unit_range" => $request->input("other_unit_range"),
+        ]);
+        $model->owners()->sync($request->input("owner_id"));
+        $model->logistics()->sync($request->input("logistic_id"));
+        return response()->redirectTo("maintenance/priceModel/logistic")->with("successTip","创建“".$request->input("name")."”成功");
+    }
+
+    public function logisticEdit($id)
+    {
+        if(!Gate::allows('计费模型-物流-编辑')){ return redirect('denied');  }
+        $owners = app("OwnerService")->getSelection();
+        $logistics = app('LogisticService')->getSelection();
+        $units = app('UnitService')->getSelection();
+        $model = app("OwnerPriceLogisticService")->find($id)->append(["owner_id","logistic_id"]);
+        return response()->view('maintenance.priceModel.logistic.create',compact("owners","logistics","units","model"));
+    }
+
+    public function logisticUpdate($id, Request $request)
+    {
+        if(!Gate::allows('计费模型-物流-编辑')){ return redirect('denied');  }
+        $request->offsetSet("owner_id",explode(",",$request->input("owner_id")));
+        $request->offsetSet("logistic_id",explode(",",$request->input("logistic_id")));
+        $this->logisticValidator($request->input(),$id)->validate();
+        app("OwnerPriceLogisticService")->update(["id"=>$id],[
+            "name" => $request->input("name"),
+            "pick_up_price" => $request->input("pick_up_price"),
+            "fuel_price" => $request->input("fuel_price"),
+            "service_price" => $request->input("service_price"),
+            "unit_id" => $request->input("unit_id"),
+            "unit_range" => $request->input("unit_range"),
+            "other_unit_id" => $request->input("other_unit_id"),
+            "other_unit_range" => $request->input("other_unit_range"),
+        ]);
+        $model = new OwnerPriceLogistic();
+        $model->id = $id;
+        $model->owners()->sync($request->input("owner_id"));
+        $model->logistics()->sync($request->input("logistic_id"));
+        return response()->redirectTo("maintenance/priceModel/logistic")->with("successTip","修改“".$request->input("name")."”成功");
+    }
+
+    public function logisticGetDetail(Request $request)
+    {
+        if(!Gate::allows('计费模型-物流-查询')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $model = new OwnerPriceLogistic();
+        $model->id = $request->input("id");
+        $model->load(["details"=>function($query){
+            /** @var Builder $query */
+            $query->with(["unit","province","city"]);
+        }]);
+        return ["success"=>true,"data"=>$model->details];
+    }
+
+    public function expressExport($id)
+    {
+        if(!Gate::allows('计费模型-快递-查询')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $model = app("OwnerPriceExpressService")->find($id,[
+            "owners","logistics","details"=>function($query){
+                /** @var Builder $query */
+                $query->with("province");
+            }]);
+        $row = ["客户","首重","续重","承运商"];
+        $list = [[
+            implode(",",array_column($model->owners->toArray(),"name")),
+            $model->initial_weight,
+            $model->additional_weight,
+            implode(",",array_column($model->logistics->toArray(),"name")),
+        ],[
+            "价格名称","省","首重价格","续重价格",
+        ]];
+        foreach ($model->details as $detail){
+            $list[] = [
+                $model->name,
+                $detail->province ? $detail->province->name : '',
+                $detail->initial_weight_price,
+                $detail->additional_weight_price,
+            ];
+        }
+        return app(ExportService::class)->json($row,$list,"快递计费模型");
+    }
+
+    public function logisticImport(Request $request)
+    {
+        if(!Gate::allows('计费模型-物流-录入')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $fileSuffix=$request->file('file')->getClientOriginalExtension();
+        if ($fileSuffix != 'xlsx' && $fileSuffix != 'xls' && $fileSuffix != 'csv')
+            return ['success'=>false,'data'=>'不支持该文件类型'];
+        ini_set('max_execution_time',2500);
+        ini_set('memory_limit','1526M');
+        $fileSuffix = ucwords($fileSuffix);
+        /** @var OwnerPriceLogistic $model */
+        $model = app('OwnerPriceLogisticService')->find($request->input("id"),["unit","otherUnit","details"]);
+        Excel::import(new OwnerPriceLogisticDetailImport($model),$request->file('file')->path(),null,$fileSuffix);
+        if (Cache::has('logistic'))return Cache::pull('logistic');
+
+        return ["success"=>false,"data"=>"导入发生错误,数据无响应"];
+    }
+
+    public function logisticExport($id)
+    {
+        if(!Gate::allows('计费模型-物流-查询')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $model = app("OwnerPriceLogisticService")->find($id,[
+            "owners","logistics","unit","otherUnit","details"=>function($query){
+                /** @var Builder $query */
+                $query->with(["province","unit","city"]);
+            }]);
+        $row = ["客户","价格名称",
+            "单位一区间/".($model->unit ? $model->unit->name : ''),
+            "单位二区间/".($model->otherUnit ? $model->otherUnit->name : ''),
+            "提货费","燃油附加费","信息服务费","创建时间","承运商"];
+        $range = "";
+        foreach (explode(",",$model->unit_range) as $str){
+            $range .= $str."\r\n";
+        }
+        $otherRange = "";
+        foreach (explode(",",$model->other_unit_range) as $str){
+            $otherRange .= $str."\r\n";
+        }
+        $list = [[
+            implode(",",array_column($model->owners->toArray(),"name")),
+            $model->name,
+            $range,
+            $otherRange,
+            $model->pick_up_price,
+            $model->fuel_price,
+            $model->service_price,
+            $model->created_at,
+            implode(",",array_column($model->logistics->toArray(),"name")),
+        ],[
+            "单位","区间","省份","市","单价","送货费","起始计费","起始计数","费率"
+        ]];
+        foreach ($model->details as $detail){
+            $list[] = [
+                $detail->unit ? $detail->unit->name : '',
+                $detail->range,
+                $detail->province ? $detail->province->name : '',
+                $detail->city ? $detail->city->name : '',
+                $detail->unit_price,
+                $detail->delivery_fee,
+                $detail->initial_fee,
+                $detail->initial_amount,
+                $detail->rate ? $detail->rate."%" : '',
+            ];
+        }
+        return app(ExportService::class)->json($row,$list,"物流计费模型");
+    }
+
+    public function logisticUpdateDetail(Request $request)
+    {
+        if(!Gate::allows('计费模型-物流-编辑')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $detail = $request->input("detail");
+        if ($detail["id"]){
+            app('OwnerPriceLogisticService')->updateDetail(["id"=>$detail["id"]],[
+                "unit_price" => $detail["unit_price"],
+                "delivery_fee" => $detail["delivery_fee"],
+                "initial_fee" => $detail["initial_fee"],
+                "initial_amount" => $detail["initial_amount"],
+                "rate" => $detail["rate"],
+            ]);
+        }else{
+            $row = app('OwnerPriceLogisticService')->isExistDetail([
+                "owner_price_logistic_id"=>$request->input("id"),
+                "unit_id"=>$detail["unit_id"],
+                "range"=>$detail["range"],
+                "province_id"=>$detail["province_id"],
+                "city_id"=>$detail["city_id"],
+            ]);
+            if ($row>0)return ["success"=>false,"data"=>"已存在该计费模型"];
+            /** @var OwnerPriceExpressProvince $detail */
+            $detail = app('OwnerPriceLogisticService')->createDetail([
+                "owner_price_logistic_id"=>$request->input("id"),
+                "unit_id"=>$detail["unit_id"],
+                "range"=>$detail["range"],
+                "province_id"=>$detail["province_id"],
+                "city_id"=>$detail["city_id"],
+                "unit_price" => $detail["unit_price"],
+                "delivery_fee" => $detail["delivery_fee"],
+                "initial_fee" => $detail["initial_fee"],
+                "initial_amount" => $detail["initial_amount"],
+                "rate" => $detail["rate"],
+            ]);
+            $detail->load("province","unit","city");
+        }
+        return ["success"=>true,"data"=>$detail];
     }
 
-    public function directLogisticIndex(){
+    public function logisticDestroyDetail(Request $request)
+    {
+        if(!Gate::allows('计费模型-物流-删除')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $id = $request->input("id");
+        if (!$id)return ["success"=>false,"data"=>"非法参数"];
+        app("OwnerPriceLogisticService")->destroyDetail($id);
+        return ["success"=>true];
+    }
+
+    private function logisticValidator(array $params,$id = null)
+    {
+        return Validator::make($params,[
+            'name'=>['required',$id?"unique:owner_price_logistics,name,$id":'unique:owner_price_logistics,name'],
+            'pick_up_price'=>['nullable','numeric','min:0'],
+            'fuel_price'=>['nullable','numeric','min:0'],
+            'service_price'=>['nullable','numeric','min:0'],
+            'unit_id'=>['required'],
+            'unit_range'=>['required',function ($attribute, $value, $fail) {
+                $bool = app("OwnerPriceLogisticService")->checkRange($value);
+                if (!$bool)$fail("格式错误,值必须为连续的且最后一个值不允许封闭");
+            }],
+            'other_unit_id'=>['required'],
+            'other_unit_range'=>['required',function ($attribute, $value, $fail) {
+                $bool = app("OwnerPriceLogisticService")->checkRange($value);
+                if (!$bool)$fail("格式错误,值必须为连续的且最后一个值不允许封闭");
+            }],
+        ],[
+            'required'=>':attribute 为必填项',
+            'unique' => ':attribute 已存在',
+            'numeric' => ':attribute 必须为数字',
+            'min' => ':attribute 不得为负',
+        ],[
+            'name' =>"名称",
+            'pick_up_price'  =>"提货费",
+            'fuel_price'  =>"燃油附加费",
+            'service_price'  =>"信息服务费",
+            'unit_id'  =>"单位一",
+            'unit_range'  =>"区间值",
+            'other_unit_id'  =>"单位二",
+            'other_unit_range'  =>"区间值",
+        ]);
+    }
+
+    public function directLogisticIndex(Request $request){
         if(!Gate::allows('计费模型-直发-查询')){ return redirect('denied');  }
-        return response()->view('maintenance.priceModel.directLogistic.index');
+        $models = app("OwnerPriceDirectLogisticService")->paginate($request->input("id"));
+        return response()->view('maintenance.priceModel.directLogistic.index',compact("models"));
     }
 
     public function directLogisticCreate(){
         if(!Gate::allows('计费模型-直发-录入')){ return redirect('denied');  }
-        return response()->view('maintenance.priceModel.directLogistic.create');
+        $owners = app("OwnerService")->getSelection();
+        return response()->view('maintenance.priceModel.directLogistic.create',compact("owners"));
+    }
+
+    public function directLogisticStore(Request $request)
+    {
+        if(!Gate::allows('计费模型-直发-录入')){ return redirect('denied');  }
+        $request->offsetSet("owner_id",explode(",",$request->input("owner_id")));
+        $this->directLogisticValidator($request->input())->validate();
+        /** @var OwnerPriceDirectLogistic $model */
+        $model = app("OwnerPriceDirectLogisticService")->create([
+            "name" => $request->input("name"),
+            "base_km" => $request->input("base_km"),
+        ]);
+        $model->owners()->sync($request->input("owner_id"));
+        return response()->redirectTo("maintenance/priceModel/directLogistic")->with("successTip","创建“".$request->input("name")."”成功");
+    }
+
+    public function directLogisticDestroy($id)
+    {
+        if(!Gate::allows('计费模型-直发-删除')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $row = app("OwnerPriceDirectLogisticService")->destroy($id);
+        if ($row == 1)return ["success"=>true];
+        return ["success"=>false,"data"=>"影响了“".$row."”行"];
+    }
+
+    public function directLogisticEdit($id)
+    {
+        if(!Gate::allows('计费模型-直发-编辑')){ return redirect('denied');  }
+        $owners = app("OwnerService")->getSelection();
+        $model = app("OwnerPriceDirectLogisticService")->find($id)->append("owner_id");
+        return response()->view('maintenance.priceModel.directLogistic.create',compact("model","owners"));
+    }
+
+    public function directLogisticUpdate($id, Request $request)
+    {
+        if(!Gate::allows('计费模型-直发-编辑')){ return redirect('denied');  }
+        $request->offsetSet("owner_id",explode(",",$request->input("owner_id")));
+        $this->directLogisticValidator($request->input(),$id)->validate();
+        app("OwnerPriceDirectLogisticService")->update(["id"=>$id],[
+            "name" => $request->input("name"),
+            "base_km" => $request->input("base_km"),
+        ]);
+        $model = new OwnerPriceDirectLogistic();
+        $model->id = $id;
+        $model->owners()->sync($request->input("owner_id"));
+        return response()->redirectTo("maintenance/priceModel/directLogistic")->with("successTip","修改“".$request->input("name")."”成功");
+    }
+
+    public function directLogisticGetDetail(Request $request)
+    {
+        if(!Gate::allows('计费模型-直发-查询')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $model = new OwnerPriceDirectLogistic();
+        $model->id = $request->input("id");
+        $model->load(["details"=>function($query){
+            /** @var Builder $query */
+            $query->with("carType");
+        }]);
+        return ["success"=>true,"data"=>$model->details];
+    }
+
+    public function directLogisticImport(Request $request)
+    {
+        if(!Gate::allows('计费模型-直发-录入')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $fileSuffix=$request->file('file')->getClientOriginalExtension();
+        if ($fileSuffix != 'xlsx' && $fileSuffix != 'xls' && $fileSuffix != 'csv')
+            return ['success'=>false,'data'=>'不支持该文件类型'];
+        ini_set('max_execution_time',2500);
+        ini_set('memory_limit','1526M');
+        $fileSuffix = ucwords($fileSuffix);
+        $model = new OwnerPriceDirectLogistic();
+        $model->id = $request->input("id");
+        $model->load("details");
+        Excel::import(new OwnerPriceDirectLogisticDetailImport($model),$request->file('file')->path(),null,$fileSuffix);
+        if (Cache::has('directLogistic'))return Cache::pull('directLogistic');
+
+        return ["success"=>false,"data"=>"导入发生错误,数据无响应"];
+    }
+
+    public function directLogisticUpdateDetail(Request $request)
+    {
+        if(!Gate::allows('计费模型-直发-编辑')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $detail = $request->input("detail");
+        if ($detail["id"]){
+            app('OwnerPriceDirectLogisticService')->updateDetail(["id"=>$detail["id"]],[
+                "base_fee" => $detail["base_fee"],
+                "additional_fee" => $detail["additional_fee"],
+            ]);
+        }else{
+            $row = app('OwnerPriceDirectLogisticService')->isExistDetail([
+                "owner_price_direct_logistic_id"=>$request->input("id"),
+                "car_type_id"=>$detail["car_type_id"],
+            ]);
+            if ($row>0)return ["success"=>false,"data"=>"已存在该计费模型"];
+            /** @var OwnerPriceExpressProvince $detail */
+            $detail = app('OwnerPriceDirectLogisticService')->createDetail([
+                "owner_price_direct_logistic_id"=>$request->input("id"),
+                "car_type_id"=>$detail["car_type_id"],
+                "base_fee" => $detail["base_fee"],
+                "additional_fee" => $detail["additional_fee"],
+            ]);
+            $detail->load("carType");
+        }
+        return ["success"=>true,"data"=>$detail];
+    }
+
+    public function directLogisticDestroyDetail(Request $request)
+    {
+        if(!Gate::allows('计费模型-直发-删除')){ return ["success"=>false,"data"=>"无权操作"];  }
+        $id = $request->input("id");
+        if (!$id)return ["success"=>false,"data"=>"非法参数"];
+        app("OwnerPriceDirectLogisticService")->destroyDetail($id);
+        return ["success"=>true];
+    }
+
+    private function directLogisticValidator(array $params, $id= null)
+    {
+        return Validator::make($params,[
+            'name'=>['required',$id?"unique:owner_price_direct_logistics,name,$id":'unique:owner_price_direct_logistics,name'],
+            'base_km'=>['required','numeric','min:0'],
+            'owner_id'=>[function ($attribute, $value, $fail)use($id) {
+                $owners = app("OwnerPriceDirectLogisticService")->getExistOwnerName($value,$id);
+                if ($owners)$fail("(".implode(',',$owners).') 已经绑定直发计费模型');
+            }],
+        ],[
+            'required'=>':attribute 为必填项',
+            'unique' => ':attribute 已存在',
+            'numeric' => ':attribute 必须为数字',
+            'min' => ':attribute 不得为负',
+        ],[
+            'name' =>"名称",
+            'base_km'  =>"起步公里数",
+        ]);
     }
 
 }

+ 57 - 23
app/Http/Controllers/ProcessMethodController.php

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
 use Illuminate\Http\Request;
 use Illuminate\Http\Response;
 use Illuminate\Support\Facades\Gate;
+use Illuminate\Support\Facades\Validator;
 
 class ProcessMethodController extends Controller
 {
@@ -16,7 +17,8 @@ class ProcessMethodController extends Controller
     public function index()
     {
         if(!Gate::allows('作业类型-查询')){ return redirect('denied');  }
-        return response()->view("maintenance.processMethod.index");
+        $methods = app('ProcessMethodService')->paginate();
+        return response()->view("maintenance.processMethod.index",compact("methods"));
     }
 
     /**
@@ -27,62 +29,94 @@ class ProcessMethodController extends Controller
     public function create()
     {
         if(!Gate::allows('作业类型-录入')){ return redirect('denied');  }
-        return response()->view("maintenance.processMethod.create");
+        $units = app('UnitService')->getSelection();
+        return response()->view("maintenance.processMethod.create",compact("units"));
     }
 
     /**
      * Store a newly created resource in storage.
      *
-     * @param  \Illuminate\Http\Request  $request
-     * @return \Illuminate\Http\Response
+     * @param  Request  $request
+     * @return Response
      */
     public function store(Request $request)
     {
-        //
-    }
-
-    /**
-     * Display the specified resource.
-     *
-     * @param  int  $id
-     * @return \Illuminate\Http\Response
-     */
-    public function show($id)
-    {
-        //
+        if(!Gate::allows('作业类型-录入')){ return redirect('denied');  }
+        $this->validator($request->input())->validate();
+        app('ProcessMethodService')->create([
+            "name"=>$request->input("name"),
+            "unit_id"=>$request->input("unit_id"),
+            "unit_price"=>$request->input("unit_price"),
+        ]);
+        return response()->redirectTo("maintenance/processMethod")->with("successTip","成功创建项目组“".$request->input("name")."”");
     }
 
     /**
      * Show the form for editing the specified resource.
      *
      * @param  int  $id
-     * @return \Illuminate\Http\Response
+     * @return Response
      */
     public function edit($id)
     {
-        //
+        if(!Gate::allows('作业类型-编辑')){ return redirect('denied');  }
+        $method = app('ProcessMethodService')->find($id);
+        $units = app('UnitService')->getSelection();
+        return response()->view('maintenance.processMethod.create',compact("method","units"));
     }
 
     /**
      * Update the specified resource in storage.
      *
-     * @param  \Illuminate\Http\Request  $request
+     * @param  Request  $request
      * @param  int  $id
-     * @return \Illuminate\Http\Response
+     * @return Response
      */
     public function update(Request $request, $id)
     {
-        //
+        if(!Gate::allows('作业类型-编辑')){ return redirect('denied');  }
+        $this->validator($request->input(),$id)->validate();
+        $result = app('ProcessMethodService')->update(["id"=>$id],[
+            "name"=>$request->input("name"),
+            "unit_id"=>$request->input("unit_id"),
+            "unit_price"=>$request->input("unit_price"),
+        ]);
+        if ($result == 1){
+            return response()->redirectTo("maintenance/processMethod")->with("successTip","成功修改项目组“".$request->input("name")."”的信息");
+        }
+        return response()->view("exception.default",["code"=>"509"]);
     }
 
     /**
      * Remove the specified resource from storage.
      *
      * @param  int  $id
-     * @return \Illuminate\Http\Response
+     * @return array
      */
     public function destroy($id)
     {
-        //
+        if(!Gate::allows('作业类型-删除')){ return ["success"=>false,"data"=>"无权操作!"];  }
+        $result = app('ProcessMethodService')->destroy($id);
+        if ($result == 1)return ["success"=>true];
+        return ["success"=>false,"data"=>"删除了“".$result."”行"];
+    }
+
+    private function validator(array $params, $id = null)
+    {
+        return Validator::make($params,[
+            'name'=>['required',$id?"unique:process_methods,name,$id":'unique:process_methods,name','max:20'],
+            "unit_id" => ["nullable",'numeric'],
+            "unit_price" => ["nullable",'numeric','min:0'],
+        ],[
+            'required'=>':attribute 为必填项',
+            'max'=>':attribute 字符过多或输入值过大',
+            'unique'=>':attribute 已存在',
+            'numeric'=>':attribute 必须为数字',
+            'min'=>':attribute 数值过小',
+        ],[
+            'name'=>'作业类型名称',
+            'unit_id'=>'作业类型单位',
+            'unit_price'=>'作业类型单价',
+        ]);
     }
 }

+ 4 - 0
app/Http/Controllers/ProvincesController.php

@@ -77,4 +77,8 @@ class ProvincesController extends Controller
         ]);
         return $validator;
     }
+
+    public function get(){
+        return Province::query()->select("id","name")->get();
+    }
 }

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

@@ -4,27 +4,15 @@ namespace App\Http\Controllers;
 
 
 use App\Authority;
-use App\Batch;
-use App\City;
 use App\Commodity;
 use App\CommodityBarcode;
 use App\Events\CancelOrder;
-use App\Imports\OrderIssueImport;
 use App\Imports\OrderTrackingImport;
 use App\InventoryAccount;
-use App\Events\ResetProcessStatisticStartDateEvent;
-use App\InventoryAccountMission;
-use App\InventoryCompare;
-use App\InventoryDailyLog;
 use App\LaborReport;
 use App\Log;
 use App\Logistic;
-use App\LogisticTiming;
 use App\OracleActAllocationDetails;
-use App\OracleBasCode;
-use App\OracleBasSKU;
-use App\OracleDOCASNDetail;
-use App\OracleDOCASNHeader;
 use App\OracleDOCOrderHeader;
 use App\OracleDocOrderPackingSummary;
 use App\OracleDOCWaveDetails;
@@ -33,33 +21,19 @@ use App\OrderBin;
 use App\OrderCommodity;
 use App\OrderIssue;
 use App\OrderPackage;
-use App\OrderPackageCommodities;
-use App\OrderTracking;
-use App\OrderTrackingOwner;
 use App\Owner;
 use App\Package;
 use App\Process;
 use App\ProcessDaily;
-use App\ProcessesContent;
 use App\ProcessStatistic;
-use App\Province;
 use App\RejectedBill;
 use App\RejectedBillItem;
 use App\Services\CacheService;
-use App\Services\CityService;
-use App\Services\CommodityService;
 use App\Services\common\BatchUpdateService;
 use App\Services\common\DataHandlerService;
-use App\Services\common\ExportService;
 use App\Services\InventoryCompareService;
-use App\Services\LogService;
-use App\Services\OracleActAllocationDetailService;
-use App\Services\OracleBasCustomerService;
 use App\Services\OracleDocAsnHerderService;
 use App\Services\OracleDOCOrderHeaderService;
-use App\Services\OrderIssuePerformanceService;
-use App\Services\OrderIssueService;
-use App\Services\OrderPackageCommoditiesService;
 use App\Services\OrderPackageService;
 use App\Services\OrderService;
 use App\Services\OrderTrackingOwnerService;
@@ -67,23 +41,15 @@ use App\Services\OrderTrackingService;
 use App\Services\OwnerService;
 use App\Services\StoreService;
 use App\Services\WarehouseService;
-use App\Store;
-use App\StoreCheckingReceive;
-use App\StoreCheckingReceiveItem;
 use App\Unit;
 use App\User;
 use App\Warehouse;
-use App\Waybill;
 use Carbon\Carbon;
-use Exception;
-use Facade\Ignition\QueryRecorder\Query;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Cache;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Http;
-use Illuminate\Support\Facades\Redis;
 use Illuminate\Support\Str;
 use Maatwebsite\Excel\Facades\Excel;
 use Ramsey\Collection\Collection;
@@ -124,24 +90,17 @@ class TestController extends Controller
         }
     }
     public function test4(){
-        $row = [];
-        for ($i=0;$i<50;$i++){
-            $row[] = "表头-".Str::random(5);
+        DB::beginTransaction();
+        Unit::query()->lockForUpdate()->where("id",14)->first();
+        for($i=0;$i<=100;$i++){
+            sleep(1);
+            var_dump($i);
         }
-        $list = [];
-        for ($i=0;$i<3000;$i++){
-            $line = [];
-            for($j=0;$j<50;$j++){
-                $line[] = Str::random(3)."\r\n".Str::random(3);
-            }
-            $list[] = $line;
-        }
-        return app(ExportService::class)->json($row,$list,"测试记录");
     }
 
     public function updateLaborRemark(){
-       $laborReports=LaborReport::query()->with(['remarks'=>function($query){
-           return $query->whereNotNull('mark');
+        $laborReports=LaborReport::query()->with(['remarks'=>function($query){
+            return $query->whereNotNull('mark');
         }])->get();
         $updateParams = [[
             'id','remark','updated_at'
@@ -160,6 +119,19 @@ class TestController extends Controller
             app(BatchUpdateService::class)->batchUpdate('labor_reports',$updateParams);
         }
     }
+    public function test2(){
+        $b = Logistic::query()->first();
+        $a = OrderPackage::query()->with("order")->first();
+        $a->bulk = 521;
+        $a->save();
+        if (!$a->order) $a->order = new Order();
+        dd($a);
+        if (!$a->order->logistic)$a->order->logistic = $b;
+        dd($a->order->logistic);
+        dd($a);
+        $a->save();
+        dd($a);
+    }
 
     function packageFromLog(Request $request)
     { //x        $packagesBatch=Package::where('batch_number',$batch_number)->first();
@@ -186,8 +158,6 @@ class TestController extends Controller
                 $uploaded += 1;
         });
         dd($uploaded . '/' . $count);
-
-
     }
 
     function wmsSql()

+ 5 - 0
app/Http/Controllers/UnitsController.php

@@ -79,4 +79,9 @@ class UnitsController extends Controller
         ]);
         return $validator;
     }
+
+    public function getUnits()
+    {
+        return ["success"=>true,"data"=>app("UnitService")->getSelection()];
+    }
 }

+ 44 - 22
app/Http/Controllers/UserOwnerGroupController.php

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
 use Illuminate\Http\Request;
 use Illuminate\Http\Response;
 use Illuminate\Support\Facades\Gate;
+use Illuminate\Support\Facades\Validator;
 
 class UserOwnerGroupController extends Controller
 {
@@ -16,7 +17,8 @@ class UserOwnerGroupController extends Controller
     public function index()
     {
         if(!Gate::allows('项目组-查询')){ return redirect('denied');  }
-        return response()->view("maintenance.userOwnerGroup.index");
+        $groups = app('UserOwnerGroupService')->paginate();
+        return response()->view("maintenance.userOwnerGroup.index",compact("groups"));
     }
 
     /**
@@ -33,56 +35,76 @@ class UserOwnerGroupController extends Controller
     /**
      * Store a newly created resource in storage.
      *
-     * @param  \Illuminate\Http\Request  $request
-     * @return \Illuminate\Http\Response
+     * @param  Request  $request
+     * @return Response
      */
     public function store(Request $request)
     {
-        //
-    }
-
-    /**
-     * Display the specified resource.
-     *
-     * @param  int  $id
-     * @return \Illuminate\Http\Response
-     */
-    public function show($id)
-    {
-        //
+        if(!Gate::allows('项目组-录入')){ return redirect('denied');  }
+        $this->validator($request->input())->validate();
+        app('UserOwnerGroupService')->create([
+            "name"=>$request->input("name"),
+        ]);
+        return response()->redirectTo("maintenance/userOwnerGroup")->with("successTip","成功创建项目组“".$request->input("name")."”");
     }
 
     /**
      * Show the form for editing the specified resource.
      *
      * @param  int  $id
-     * @return \Illuminate\Http\Response
+     * @return Response
      */
     public function edit($id)
     {
-        //
+        if(!Gate::allows('项目组-编辑')){ return redirect('denied');  }
+        $group = app('UserOwnerGroupService')->find($id);
+        return response()->view('maintenance.userOwnerGroup.create',compact("group"));
     }
 
     /**
      * Update the specified resource in storage.
      *
-     * @param  \Illuminate\Http\Request  $request
+     * @param  Request  $request
      * @param  int  $id
-     * @return \Illuminate\Http\Response
+     * @return Response
      */
     public function update(Request $request, $id)
     {
-        //
+        if(!Gate::allows('项目组-编辑')){ return redirect('denied');  }
+        $this->validator($request->input(),$id)->validate();
+        $result = app('UserOwnerGroupService')->update(["id"=>$id],[
+            "name"=>$request->input("name"),
+        ]);
+        if ($result == 1){
+            return response()->redirectTo("maintenance/userOwnerGroup")->with("successTip","成功修改项目组“".$request->input("name")."”的信息");
+        }
+        return response()->view("exception.default",["code"=>"509"]);
     }
 
     /**
      * Remove the specified resource from storage.
      *
      * @param  int  $id
-     * @return \Illuminate\Http\Response
+     * @return array
      */
     public function destroy($id)
     {
-        //
+        if(!Gate::allows('项目组-删除')){ return ["success"=>false,"data"=>"无权操作!"];  }
+        $result = app('UserOwnerGroupService')->destroy($id);
+        if ($result == 1)return ["success"=>true];
+        return ["success"=>false,"data"=>"删除了“".$result."”行"];
+    }
+
+    private function validator(array $params, $id = null)
+    {
+        return Validator::make($params,[
+            'name'=>['required',$id?"unique:user_owner_groups,name,$id":'unique:user_owner_groups,name','max:20'],
+        ],[
+            'required'=>':attribute 为必填项',
+            'max'=>':attribute 字符过多或输入值过大',
+            'unique'=>':attribute 已存在',
+        ],[
+            'name'=>'项目组名称',
+        ]);
     }
 }

+ 4 - 2
app/Http/Controllers/api/thirdPart/goodscan/PackageController.php

@@ -113,7 +113,8 @@ class PackageController
     public function updateOrderPackage(&$orderPackage,$params,$measuringMachine) //更新包裹信息 前往处理活动波次
     {
         $edges=$this->getEdges($params);
-        $req_date=$params['time']??Carbon::now();
+//        $req_date=$params['time']??Carbon::now();
+        $req_date=Carbon::now();
         $orderPackage->weight=$params['weight'];
         $orderPackage->measuring_machine_id=$measuringMachine->id;
         $orderPackage->length=$edges[0];
@@ -244,7 +245,8 @@ class PackageController
      */
     public function getOrderPackage($requestInput,$measuringMachine,$order)
     {
-        $weighed_at =$requestInput['time']??Carbon::now();
+//        $weighed_at =$requestInput['time']??Carbon::now();
+        $weighed_at =Carbon::now();
         $edges=$this->getEdges($requestInput);
         OrderPackage::query()->create([
             'order_id'=>$order->id,

+ 18 - 13
app/Http/Controllers/api/thirdPart/haiq/StorageController.php

@@ -21,33 +21,38 @@ class StorageController
         $bin = [
             "taskCode" => "TEST-BS2010100001",//任务编号 全局唯一
             "binCode" => "TEST-BIN01",//料箱编码
-            //"toWorkStation" => "TEST-HQ01",//出库工作站
-            //"fromWorkStation" => "TEST-HQ01",//回库工作站
             "fromLocCode" => "HAIB1-02-01",//源库位编码
             "toLocCode" => "HAIB1-02-01",//目标库位编码 出库填多个,表示这些库位都可以支持
             "sequence" => -1,//出库顺序 -1表示没有顺序,只有移库出库时需要指定顺序,其他可为-1
             "stockInfo" => [$stockInfo],//商品信息
         ];
-        $this->request = [[
+        /*$this->request = [[
             "groupCode" => 1,//组号/波次号 一组任务需要一起完成,再开始下一组任务;没有组任务的限制默认传-1或空
             "taskMode" => 3,//任务模式 值 1 (输送线入库)值 2 (输送线出库)值 3(货架到缓存货架)值4(货架到流利货架)
             "priority" => 99,//优先级 1-2147483647 1最低
             "sequenceFlag" => -1,//是否需要有序 1:需要有序 0:不需要有序
             "bins" => [$bin],//可执行货箱任务
+        ]];*/
+        $this->request = [[
+            "taskMode"      => 8,
+            "bins"=>[[
+                "taskCode"  =>"TEST-BS2011160004",
+                "binCode"   => "TESTBINCODE-0",
+                "fromLocCode" => "BIN-IN1",
+                //"toLocCode" => "BIN-OUT1",
+            ]],
+            "groupCode"     => 4,
+            "priority"      => 20,
+            "sequenceFlag"  => -1,
         ]];
     }
 
     public function relocate(Request $request){
-        $req = [[
-            "groupCode"=> "test_code2",
-            "priority"=> 1,
-            "taskMode"=> 1,
-            "bins"=> [[
-                "binCode"=> "test_bin_1",
-                "fromLocCode"=> "HAIB1-02-01"
-            ]],
-        ]];
-        $response = Http::post(config('api.haiq.storage.relocate'),$req);
+        $response = Http::post(config('api.haiq.storage.relocate'),$this->request);return $response;
+        if (!$response->ok()){
+            app('LogService')->log(__METHOD__,"haiq-请求失败,路径异常","REQUEST:".json_encode($this->request)." | RESPONSE:".$response);
+            return ['success'=>false,"data"=>"接口异常"];
+        }
         if (($response["code"] ?? false) && $response["code"] != 200){
             app('LogService')->log(__METHOD__,"haiq-料箱出库失败","REQUEST:".json_encode($this->request)." | RESPONSE:".$response);
             return ['success'=>false,"data"=>$response["errMsg"]];

+ 2 - 1
app/Http/Controllers/api/thirdPart/weight/PackageController.php

@@ -168,7 +168,8 @@ class PackageController extends Controller
         foreach ($requestInitial->all() as $k=>$v){
             $request[strtolower($k)]=$v;
         }
-        $reqDate=isset($request['time'])?$request['time']:Carbon::now();
+//        $reqDate=isset($request['time'])?$request['time']:Carbon::now();
+        $reqDate=Carbon::now();
         $errors=$this->validatorWeight($request)->errors();
 
         if (count($errors)>0){

+ 108 - 0
app/Imports/ExpressImport.php

@@ -0,0 +1,108 @@
+<?php
+
+namespace App\Imports;
+
+use App\OwnerPriceExpress;
+use App\OwnerPriceExpressProvince;
+use App\Province;
+use App\Services\common\BatchUpdateService;
+use App\Services\LogService;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\Cache;
+use Maatwebsite\Excel\Concerns\ToCollection;
+use Maatwebsite\Excel\Concerns\WithHeadingRow;
+use Maatwebsite\Excel\Imports\HeadingRowFormatter;
+
+HeadingRowFormatter::default('none');
+class ExpressImport implements ToCollection,WithHeadingRow
+{
+    protected $express;
+    public function __construct(OwnerPriceExpress $express = null)
+    {
+        $this->express = $express;
+    }
+
+    /**
+    * @param Collection $collection
+    * @return bool
+    */
+    public function collection(Collection $collection)
+    {
+        if (!$this->express){
+            Cache::put("express",["success"=>false, "data"=>"不存在父级"],86400);
+            return false;
+        }
+        $row = $collection->first();
+        $header = [
+            "省","首重价格","续重价格"
+        ];
+        foreach ($header as $str){
+            if (!isset($row[$str])){
+                Cache::put("express",["success"=>false, "data"=>"表头不存在“".$str."”"],86400);
+                return false;
+            }
+        }
+
+        //省份map
+        $map = [];
+        $provinces = Province::query()->get();
+        foreach ($provinces as $province){
+            $map[$province->name] = $province->id;
+        }
+
+        //已存在的计费
+        $existDetails = [];
+        foreach ($this->express->details as $detail){
+            $existDetails[$detail->province_id] = $detail->id;
+        }
+
+        //导入的数据整理,存在更新
+        $id = $this->express->id;
+        $errors = [];
+        $insert = [];
+        $update = [["id","initial_weight_price","additional_weight_price","updated_at"]];
+        $date = date('Y-m-d H:i:s');
+        foreach ($collection as $index => $item){
+            if (!isset($map[$item["省"]])){
+                $errors[] = "第“".($index+2)."”行未知省份";
+                continue;
+            }
+            if (!is_numeric($item["首重价格"]) || $item["首重价格"] <= 0){
+                $errors[] = "第“".($index+2)."”行非法首重价格";
+                continue;
+            }
+            if (!is_numeric($item["续重价格"]) || $item["续重价格"] <= 0){
+                $errors[] = "第“".($index+2)."”行非法续重价格";
+                continue;
+            }
+            if (isset($existDetails[$map[$item["省"]]])){
+                $update[] = [
+                    "id" => $existDetails[$map[$item["省"]]],
+                    "initial_weight_price" => $item["首重价格"],
+                    "additional_weight_price" => $item["续重价格"],
+                    "updated_at" => $date,
+                ];
+                continue;
+            }
+            $insert[] = [
+                "owner_price_express_id" => $id,
+                "province_id" => $map[$item["省"]],
+                "initial_weight_price" => $item["首重价格"],
+                "additional_weight_price" => $item["续重价格"],
+                "created_at" => $date,
+            ];
+        }
+        if (count($update) > 1){
+            app(BatchUpdateService::class)->batchUpdate("owner_price_express_provinces",$update);
+            LogService::log(__METHOD__,"快递计费导入修改",json_encode($update));
+        }
+        if (count($insert) > 0){
+            OwnerPriceExpressProvince::query()->insert($insert);
+            LogService::log(__METHOD__,"快递计费导入录入",json_encode($insert));
+        }
+
+        $this->express->load(["details"=>function($query){$query->with("province");}]);
+        Cache::put("express",["success"=>true,"data"=>$this->express->details,"errors"=>$errors],86400);
+        return true;
+    }
+}

+ 1 - 1
app/Imports/OrderIssueImport.php

@@ -113,7 +113,7 @@ class OrderIssueImport implements ToCollection, WithHeadingRow, WithMultipleShee
 
     /**
      * 该方法是实现上传文件只选中 第一个表
-     * ExcelImprot 默认是有多少个分表就执行多少次的分表
+     * ExcelImport 默认是有多少个分表就执行多少次的分表
      * @return OrderIssueImport[]|array
      */
     public function sheets(): array

+ 2 - 21
app/Imports/OrderTrackingImport.php

@@ -110,26 +110,6 @@ class OrderTrackingImport implements ToCollection
                     }
                 }
             }
-//            $packages->each(function ($package) use ($items, &$orderPackageCommodities, &$bool) {
-//                if (!$bool) {
-//                    if ($package->commodities ?? false) {
-//                        $_commodities = $package->commodities;
-//                        $package->commodities = $package->commodities->filter(function ($commodities) use ($items, &$orderPackageCommodities, &$bool, &$_commodities) {
-//                            try {
-//                                if (isset($commodities->commodity) && $bool == false) {
-//                                    if ($commodities->commodity->sku == $items[6] && $commodities->amount == $items[8]) {
-//                                        $orderPackageCommodities = $_commodities->pull($commodities);
-//                                        $bool = true;
-//                                    }
-//                                }
-//                            } catch (\Exception $e) {
-//                                dd($_commodities);
-//                            }
-//                        });
-//                    }
-//                }
-//            });
-
         }elseif(count($packages)==1){
             $bool = false;
             foreach ($packages as $package) {
@@ -139,6 +119,7 @@ class OrderTrackingImport implements ToCollection
                             $package->commodities = $package->commodities->filter(function($item)use($commodities){
                                 return $item->id != $commodities->id;
                             });
+                            $this->orderPackages[$items[1]] = $packages;
                             return $commodities;
                         }
                     }
@@ -257,7 +238,7 @@ class OrderTrackingImport implements ToCollection
             return $this->orderPackages[$client_code];
         }else{
             $order = $this->getOrder($client_code,$items);
-            if($order->packages->count() > 0 ){
+            if($order && $order->packages->count() > 0 ){
                 $this->orderPackages[$client_code] = $order->packages;
                 return $order->packages;
             }else{

+ 135 - 0
app/Imports/OwnerPriceDirectLogisticDetailImport.php

@@ -0,0 +1,135 @@
+<?php
+
+namespace App\Imports;
+
+use App\CarType;
+use App\OwnerPriceDirectLogistic;
+use App\OwnerPriceDirectLogisticCar;
+use App\Services\common\BatchUpdateService;
+use App\Services\LogService;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\Cache;
+use Maatwebsite\Excel\Concerns\ToCollection;
+use Maatwebsite\Excel\Concerns\WithHeadingRow;
+use Maatwebsite\Excel\Imports\HeadingRowFormatter;
+
+HeadingRowFormatter::default('none');
+class OwnerPriceDirectLogisticDetailImport implements ToCollection,WithHeadingRow
+{
+    protected $model;
+
+    public function __construct(OwnerPriceDirectLogistic $model)
+    {
+        $this->model = $model;
+    }
+
+    /**
+    * @param Collection $collection
+    * @return bool
+    */
+    public function collection(Collection $collection)
+    {
+        if (!$this->model){
+            Cache::put("directLogistic",["success"=>false, "data"=>"不存在父级"],86400);
+            return false;
+        }
+        $row = $collection->first();
+        $additional = "续费";
+        foreach ($row as $key => $str){
+            if (mb_strpos($key,$additional) !== false){
+                $row["续费"] = $str;
+                $additional = $key;
+                break;
+            }
+        }
+        $header = [
+            "车型","起步费","续费"
+        ];
+        foreach ($header as $str){
+            if (!isset($row[$str])){
+                Cache::put("directLogistic",["success"=>false, "data"=>"表头不存在“".$str."”"],86400);
+                return false;
+            }
+        }
+        if ($row)
+
+        //车型map
+        $map = [];
+        $carTypes = CarType::query()->get();
+        foreach ($carTypes as $carType){
+            $map[$carType->name] = $carType->id;
+        }
+
+        //已存在的计费
+        $existDetails = [];
+        foreach ($this->model->details as $detail){
+            $existDetails[$detail->car_type_id] = $detail->id;
+        }
+
+        //生成列表内的重复条目
+        $existInsert = [];
+
+        //导入的数据整理,存在更新
+        $id = $this->model->id;
+        $errors = [];
+        $insert = [];
+        $update = [["id","base_fee","additional_fee"]];
+        $date = date('Y-m-d H:i:s');
+        foreach ($collection as $index => $item){
+            /* 数据校验 */
+            if (!$item["车型"]){
+                $errors[] = "第“".($index+2)."”行车型为空";
+                continue;
+            }else{
+                if (!isset($map[$item["车型"]])){
+                    $errors[] = "第“".($index+2)."”行未知车型";
+                    continue;
+                }
+                $item["车型"] = $map[$item["车型"]];
+            }
+            if (!$item["起步费"] || !is_numeric($item["起步费"]) || $item["起步费"] <= 0){
+                $errors[] = "第“".($index+2)."”行非法起步费";
+                continue;
+            }
+            if (!$item[$additional] || !is_numeric($item[$additional]) || $item[$additional] <= 0){
+                $errors[] = "第“".($index+2)."”行非法续费";
+                continue;
+            }
+
+            if (isset($existInsert[$item["车型"]])){
+                $errors[] = "第“".($index+2)."”行与第“".$existInsert[$item["车型"]]."”行重复";
+                continue;
+            }
+
+            if (isset($existDetails[$item["车型"]])){
+                $update[] = [
+                    "id" => $existDetails[$item["车型"]],
+                    "base_fee" => $item["起步费"],
+                    "additional_fee" => $item[$additional],
+                    "updated_at" => $date,
+                ];
+                continue;
+            }
+            $insert[] = [
+                "owner_price_direct_logistic_id" => $id,
+                "car_type_id" => $item["车型"],
+                "base_fee" => $item["起步费"],
+                "additional_fee" => $item[$additional],
+                "created_at" => $date,
+            ];
+            $existInsert[$item["车型"]] = $index+2;
+        }
+        if (count($update) > 1){
+            app(BatchUpdateService::class)->batchUpdate("owner_price_direct_logistic_cars",$update);
+            LogService::log(__METHOD__,"直发车计费导入修改",json_encode($update));
+        }
+        if (count($insert) > 0){
+            OwnerPriceDirectLogisticCar::query()->insert($insert);
+            LogService::log(__METHOD__,"直发车计费导入录入",json_encode($insert));
+        }
+
+        $this->model->load(["details"=>function($query){$query->with("carType");}]);
+        Cache::put("directLogistic",["success"=>true,"data"=>$this->model->details,"errors"=>$errors],86400);
+        return true;
+    }
+}

+ 187 - 0
app/Imports/OwnerPriceLogisticDetailImport.php

@@ -0,0 +1,187 @@
+<?php
+
+namespace App\Imports;
+
+use App\City;
+use App\OwnerPriceLogistic;
+use App\OwnerPriceLogisticDetail;
+use App\Province;
+use App\Services\common\BatchUpdateService;
+use App\Services\LogService;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\Cache;
+use Maatwebsite\Excel\Concerns\ToCollection;
+use Maatwebsite\Excel\Concerns\WithHeadingRow;
+use Maatwebsite\Excel\Imports\HeadingRowFormatter;
+
+
+HeadingRowFormatter::default('none');
+class OwnerPriceLogisticDetailImport implements ToCollection,WithHeadingRow
+{
+    protected $logistic;
+    public function __construct(OwnerPriceLogistic $logistic = null)
+    {
+        $this->logistic = $logistic;
+    }
+
+    /**
+    * @param Collection $collection
+    * @return bool
+    */
+    public function collection(Collection $collection)
+    {
+
+        if (!$this->logistic){
+            Cache::put("logistic",["success"=>false, "data"=>"不存在父级"],86400);
+            return false;
+        }
+        $row = $collection->first();
+        $header = [
+            "计数单位","计数区间","省份","市","单价","送货费","起始计费","起始计数","费率"
+        ];
+        foreach ($header as $str){
+            if (!isset($row[$str])){
+                Cache::put("logistic",["success"=>false, "data"=>"表头不存在“".$str."”"],86400);
+                return false;
+            }
+        }
+
+        //省份map
+        $map = [];
+        $provinces = Province::query()->get();
+        foreach ($provinces as $province){
+            $map[$province->name] = $province->id;
+        }
+
+        //市map
+        $cityMap = [];
+        $cityMappingProvince = [];
+        $cities = City::query()->get();
+        foreach ($cities as $city){
+            $cityMap[$city->name] = $city->id;
+            $cityMappingProvince[$city->id] = $city->province_id;
+        }
+
+        //对比单位
+        $unit = $this->logistic->unit ? strtoupper($this->logistic->unit->name) : '';
+        $otherUnit = $this->logistic->otherUnit ? strtoupper($this->logistic->otherUnit->name) : '';
+
+        //对比区间
+        $range = [
+            $unit => explode(",",$this->logistic->unit_range),
+            $otherUnit => explode(",",$this->logistic->other_unit_range),
+        ];
+
+        //已存在的计费
+        $existDetails = [];
+        foreach ($this->logistic->details as $detail){
+            $existDetails[$detail->unit_id.'_'.$detail->range."_".$detail->province_id."_".$detail->city_id] = $detail->id;
+        }
+
+        //生成列表内的重复条目
+        $existInsert = [];
+
+        //导入的数据整理,存在更新
+        $id = $this->logistic->id;
+        $errors = [];
+        $insert = [];
+        $update = [["id","unit_price","delivery_fee","initial_fee","initial_amount","rate","updated_at"]];
+        $date = date('Y-m-d H:i:s');
+        foreach ($collection as $index => $item){
+            /* 数据校验 */
+            if (!$item["省份"]){
+                $errors[] = "第“".($index+2)."”行省份为空";
+                continue;
+            }else{
+                if ((!isset($map[$item["省份"]]) && !isset($map[mb_substr($item["省份"], 0,-1)]))){
+                    $errors[] = "第“".($index+2)."”行未知省份";
+                    continue;
+                }
+                if (isset($map[mb_substr($item["省份"], 0,-1)]))$item["省份"] = mb_substr($item["省份"], 0,-1);
+            }
+            if (!$item["计数单位"] || (strtoupper($item["计数单位"]) != $unit && strtoupper($item["计数单位"]) != $otherUnit)){
+                //$errors[] = "第“".($index+2)."”行单位不符合";
+                //continue;
+                Cache::put("logistic",["success"=>false, "data"=>"第“".($index+2)."”行单位不符合"],86400);
+                return false;
+            }
+            if (!$item["计数区间"] || array_search($item["计数区间"],$range[strtoupper($item["计数单位"])]) === false){
+                //$errors[] = "第“".($index+2)."”行非法首重价格";
+                //continue;
+                Cache::put("logistic",["success"=>false, "data"=>"第“".($index+2)."”行区间不符合"],86400);
+                return false;
+            }
+            if (!isset($cityMap[$item["市"]])){
+                $errors[] = "第“".($index+2)."”行未知城市";
+                continue;
+            }
+            if (!$item["单价"] || !is_numeric($item["单价"]) || $item["单价"] <= 0){
+                $errors[] = "第“".($index+2)."”行非法单价";
+                continue;
+            }
+            $numeric = ["送货费","起始计费","起始计数","费率"];
+            $sign = false;
+            foreach ($numeric as $column){
+                if ($item[$column] && (!is_numeric($item[$column]) || $item[$column] <= 0)){
+                    $errors[] = "第“".($index+2)."”行非法".$column;
+                    $sign = true;
+                    break;
+                }
+            }
+            if ($sign)continue;
+
+            /* 数据转换及存在校验 */
+            if ($cityMappingProvince[$cityMap[$item["市"]]] != $map[$item["省份"]]){
+                $errors[] = "第“".($index+2)."”行城市不属于该省份";
+                continue;
+            }
+            $item["省份"] = $map[$item["省份"]];
+            $item["计数单位"] = strtoupper($item["计数单位"]) == $unit ? $this->logistic->unit_id : $this->logistic->other_unit_id;
+            $item["市"] = $cityMap[$item["市"]];
+            $key = $item["计数单位"]."_".$item["计数区间"]."_".$item["省份"]."_".$item["市"];
+            if (isset($existInsert[$key])){
+                $errors[] = "第“".($index+2)."”行与第“".$existInsert[$key]."”行重复";
+                continue;
+            }
+
+            if (isset($existDetails[$key])){
+                $update[] = [
+                    "id" => $existDetails[$key],
+                    "unit_price" => $item["单价"],
+                    "delivery_fee" => $item["送货费"],
+                    "initial_fee" => $item["起始计费"],
+                    "initial_amount" => $item["起始计数"],
+                    "rate" => $item["费率"],
+                    "updated_at" => $date,
+                ];
+                continue;
+            }
+            $insert[] = [
+                "owner_price_logistic_id" => $id,
+                "unit_id" => $item["计数单位"],
+                "range" => $item["计数区间"],
+                "province_id" => $item["省份"],
+                "city_id" => $item["市"],
+                "unit_price" => $item["单价"],
+                "delivery_fee" => $item["送货费"],
+                "initial_fee" => $item["起始计费"],
+                "initial_amount" => $item["起始计数"],
+                "rate" => $item["费率"],
+                "created_at" => $date,
+            ];
+            $existInsert[$key] = $index+2;
+        }
+        if (count($update) > 1){
+            app(BatchUpdateService::class)->batchUpdate("owner_price_logistic_details",$update);
+            LogService::log(__METHOD__,"物流计费导入修改",json_encode($update));
+        }
+        if (count($insert) > 0){
+            OwnerPriceLogisticDetail::query()->insert($insert);
+            LogService::log(__METHOD__,"物流计费导入录入",json_encode($insert));
+        }
+
+        $this->logistic->load(["details"=>function($query){$query->with(["province","unit","city"]);}]);
+        Cache::put("logistic",["success"=>true,"data"=>$this->logistic->details,"errors"=>$errors],86400);
+        return true;
+    }
+}

+ 5 - 0
app/Logistic.php

@@ -19,4 +19,9 @@ class Logistic extends Model
         $logistic=Logistic::where('id',$id)->first();
         return $logistic?$logistic['name']:'';
     }
+
+    public function ownerPriceExpresses()
+    {
+        return $this->belongsToMany(OwnerPriceExpress::class,"owner_price_express_logistic","logistic_id","owner_price_express_id");
+    }
 }

+ 1 - 0
app/OracleBasSKU.php

@@ -20,5 +20,6 @@ class OracleBasSKU extends Model
      * column: SKU 产品编码
      *         ALTERNATE_SKU1 产品条码
      *         Descr_C 商品名称
+     *
      * */
 }

+ 11 - 4
app/OrderIssue.php

@@ -13,10 +13,15 @@ class OrderIssue extends Model
     use SoftDeletes;
 
     protected $fillable = [
-        'order_id', 'created_at', 'rejected_bill_id', 'rejecting_status', 'result_explain','logistic_number_return',
-        'situation_explain', 'order_issue_type_id', 'second_order_id', 'is_new_rejecting','second_client_no','second_logistic_number',
-        'final_status', 'logistic_indemnity_money', 'logistic_express_remission', 'baoshi_indemnity_money', 'baoshi_express_remission', 'user_workgroup_id',
-        'custom_code','imported_status'];
+        'order_id', 'created_at', 'rejected_bill_id',
+        'rejecting_status', 'result_explain','logistic_number_return',
+        'situation_explain', 'order_issue_type_id', 'second_order_id',
+        'is_new_rejecting','second_client_no','second_logistic_number',
+        'final_status',
+        'logistic_indemnity_money', 'logistic_express_remission',
+        'baoshi_indemnity_money', 'baoshi_express_remission', 'user_workgroup_id',
+        'custom_code','imported_status','finance_confirm',
+        'hidden_tag'];
     /*
      * second_client_no 二次客户订单号
      * second_logistic_number 二次运单号 【二次运单号可以单独存在,当二次客户订单号有对应的订单信息时,显示的是二次客户订单号对应的运单号,没有的话显示二次原单号】
@@ -27,6 +32,8 @@ class OrderIssue extends Model
      * custom_code  自定义订单号 客户客服自定义
      * imported_status 导入处理
      * 退回单号
+     * finance_confirm 财务确认
+     * hidden_tag 隐藏标识
      */
     protected $appends = [
 //        'secondLogisticNumber',

+ 20 - 0
app/OrderTracking.php

@@ -16,6 +16,26 @@ class OrderTracking extends Model
         'is_on_duty_shift','is_arrival','signed_at',
         'receive_bill_status','remark','gross_weight','bulk'];
 
+    /*
+     * order_package_commodity_id 订单商品id
+     * owner_id 货主
+     * web_order_number WEB+订单号
+     * pick_up_at 提货时间
+     * sale 销售
+     * client 客户
+     * order_client_code 订单号
+     * order_remark 订单备注
+     * pallet_total 托盘合计
+     * planning_sent_at 应送达时间
+     * is_on_duty_shift 是否赶上卡班
+     * is_arrival 到货情况
+     * signed_at 签收时间
+     * receive_bill_status
+     * remark 签收单情况
+     * gross_weight 重量
+     * bulk 体积
+     */
+
     protected $appends =[
         'ownerName','sku','packageWeight','packageBulk','orderCity','packageLogisticNumber','packageLogistic','orderClientNumber'
     ];

+ 41 - 0
app/Owner.php

@@ -71,4 +71,45 @@ class Owner extends Model
     {   //项目组
         return $this->hasOne(UserOwnerGroup::class,"id","user_owner_group_id");
     }
+    public function ownerStoragePriceModels()
+    {   //仓储计费
+        return $this->belongsToMany(OwnerStoragePriceModel::class,"owner_storage_price_model_owner","owner_id","owner_storage_price_model_id");
+    }
+    public function ownerAreaReport()
+    {   //面积报表
+        return $this->hasOne(OwnerAreaReport::class,"owner_id","id");
+    }
+    public function ownerStoragePriceModelOwners()
+    {   //仓储计费-货主 中间表
+        return $this->hasMany(OwnerStoragePriceModelOwner::class,"owner_id","id");
+    }
+    public function ownerPriceOperations()
+    {   //作业计费
+        return $this->belongsToMany(OwnerPriceOperation::class,"owner_price_operation_owner","owner_id","owner_price_operation_id");
+    }
+    public function ownerPriceExpresses()
+    {   //快递计费
+        return $this->belongsToMany(OwnerPriceExpress::class,"owner_price_express_owner","owner_id","owner_price_express_id");
+    }
+    public function ownerPriceLogistics()
+    {   //物流计费
+        return $this->belongsToMany(OwnerPriceLogistic::class,"owner_price_logistic_owner","owner_id","owner_price_logistic_id");
+    }
+    public function ownerPriceDirectLogistics()
+    {   //直发车计费
+        return $this->belongsToMany(OwnerPriceDirectLogistic::class,"owner_price_direct_logistic_owner","owner_id","owner_price_direct_logistic_id");
+    }
+
+    public function getOwnerStoragePriceModelIds($type = 'string')
+    {   //获取仓储计费的关联ID字符串或数组
+        $this->load('ownerStoragePriceModelOwners');
+        if ($type == 'string'){
+            $ids = '';
+            foreach ($this->ownerStoragePriceModelOwners as $os){
+                $ids .= $os->owner_storage_price_model_id.",";
+            }
+            return $ids;
+        }
+        return array_column(($this->ownerStoragePriceModelOwners)->toArray(),"owner_storage_price_model_id");
+    }
 }

+ 17 - 7
app/OwnerAreaReport.php

@@ -7,19 +7,29 @@ use Illuminate\Database\Eloquent\Model;
 class OwnerAreaReport extends Model
 {
     protected $fillable = [
-        "owner_id",         //货主ID
-        "counting_month",   //结算月
-        "area_on_tray",     //货物整托
-        "area_on_half_tray",//货物半托
-        "area_on_flat",     //平面区面积
-        "accounting_area",  //结算面积
-        "status"            //状态
+        "owner_id",             //货主ID
+        "counting_month",       //结算月
+        "owner_storage_price_model_id", //仓储计费ID
+        "user_owner_group_id",  //项目组ID
+        "area_on_tray",         //货物整托
+        "area_on_half_tray",    //货物半托
+        "area_on_flat",         //平面区面积
+        "accounting_area",      //结算面积
+        "status"                //状态
     ];
 
     public function owner()
     {   //货主
         return $this->hasOne(Owner::class,"id","owner_id");
     }
+    public function userOwnerGroup()
+    {   //项目组
+        return $this->hasOne(UserOwnerGroup::class,"id","user_owner_group_id");
+    }
+    public function ownerStoragePriceModel()
+    {   //仓储计费
+        return $this->hasOne(OwnerStoragePriceModel::class,"id","owner_storage_price_model_id");
+    }
 
     /* 结算月格式转换,仅截取至月
      * 引用:CreateOwnerReport

+ 2 - 1
app/OwnerBillReport.php

@@ -14,10 +14,11 @@ class OwnerBillReport extends Model
        "difference",     //差额
        "confirmed",      //确认状态
    ];
+   public $timestamps=false;
 
    public function owner()
    {   //货主
-       $this->hasOne(Owner::class,"id","owner_id");
+       return $this->hasOne(Owner::class,"id","owner_id");
    }
 
     /* 结算月格式转换,仅截取至月

+ 0 - 1
app/OwnerFeeDetail.php

@@ -9,7 +9,6 @@ class OwnerFeeDetail extends Model
 {
     protected $fillable = [
         "owner_id",         //货主ID
-        "counting_month",   //结算月
         "worked_at",        //作业时间
         "type",             //类型
         "shop_id",          //店铺ID

+ 1 - 0
app/OwnerInStorageRule.php

@@ -12,6 +12,7 @@ class OwnerInStorageRule extends Model
         "unit_id",                  //单位ID
         "unit_price",               //单价
     ];
+    public $timestamps=false;
 
     public function unit()
     {   //单位

+ 13 - 1
app/OwnerOutStorageRule.php

@@ -8,16 +8,28 @@ class OwnerOutStorageRule extends Model
 {
     protected $fillable = [
         "owner_price_operation_id",         //作业计费ID
-        "owner_price_operation_strategy",   //作业计费策略
         "strategy",                         //出库策略
         "amount",                           //起步数
         "unit_id",                          //单位ID
         "unit_price",                       //单价
         "feature",                          //特征
+        "priority",                         //优先级 值越大越高
     ];
+    public $timestamps=false;
+
+    public static $features = null;
+    public static $columnMapping = null;
 
     public function unit()
     {   //单位
         return $this->hasOne(Unit::class,"id","unit_id");
     }
+
+
+    /* 格式化依据静态参数,在调用前设置  */
+    public function getFeatureFormatAttribute()
+    {
+        if ($this->strategy == '默认')return "/";
+        return app("FeatureService")->formatFeature(self::$features,$this->feature,self::$columnMapping);
+    }
 }

+ 11 - 1
app/OwnerPriceDirectLogistic.php

@@ -3,6 +3,7 @@
 namespace App;
 
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
 
 class OwnerPriceDirectLogistic extends Model
 {
@@ -11,8 +12,17 @@ class OwnerPriceDirectLogistic extends Model
         "base_km"   //起步公里数
     ];
 
-    public function ownerPriceDirectLogisticCars()
+    public function details()
     {   //直发车计费对应车型费
         return $this->hasMany(OwnerPriceDirectLogisticCar::class,"owner_price_direct_logistic_id","id");
     }
+    public function owners()
+    {   //货主中间表
+        return $this->belongsToMany(Owner::class,"owner_price_direct_logistic_owner","owner_price_direct_logistic_id","owner_id");
+    }
+
+    public function getOwnerIdAttribute()
+    {   //获取货主ID数组
+        return array_column(DB::select(DB::raw("SELECT * FROM owner_price_direct_logistic_owner WHERE owner_price_direct_logistic_id = ?"),[$this->id]),"owner_id");
+    }
 }

+ 20 - 5
app/OwnerPriceExpress.php

@@ -3,21 +3,36 @@
 namespace App;
 
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
 
 class OwnerPriceExpress extends Model
 {
     protected $fillable = [
-        "name",                     //名称
-        "initial_weight_unit_id",   //首重单位
-        "additional_weight_unit_id",//续重单位
+        "name",             //名称
+        "initial_weight",   //首重
+        "additional_weight",//续重
     ];
 
     public function owners()
     {   //货主
-        $this->belongsToMany(Owner::class,"owner_price_express_owner","owner_price_express_id","owner_id");
+        return $this->belongsToMany(Owner::class,"owner_price_express_owner","owner_price_express_id","owner_id");
     }
     public function logistics()
     {   //物流
-        $this->belongsToMany(Logistic::class,"owner_price_express_logistic","owner_price_express_id","logistic_id");
+        return $this->belongsToMany(Logistic::class,"owner_price_express_logistic","owner_price_express_id","logistic_id");
+    }
+    public function details()
+    {   //计费详情
+        return $this->hasMany(OwnerPriceExpressProvince::class,"owner_price_express_id","id");
+    }
+
+    public function getOwnerIdAttribute()
+    {   //获取货主ID数组
+        return array_column(DB::select(DB::raw("SELECT * FROM owner_price_express_owner WHERE owner_price_express_id = ?"),[$this->id]),"owner_id");
+    }
+
+    public function getLogisticIdAttribute()
+    {   //获取快递ID数组
+        return array_column(DB::select(DB::raw("SELECT * FROM owner_price_express_logistic WHERE owner_price_express_id = ?"),[$this->id]),"logistic_id");
     }
 }

+ 2 - 2
app/OwnerPriceExpressProvince.php

@@ -15,10 +15,10 @@ class OwnerPriceExpressProvince extends Model
 
     public function ownerPriceExpress()
     {   //快递计费
-        $this->belongsTo(OwnerPriceExpress::class,"owner_price_express_id","id");
+        return $this->belongsTo(OwnerPriceExpress::class,"owner_price_express_id","id");
     }
     public function province()
     {   //省份
-        $this->hasOne(Province::class,"id","province_id");
+        return $this->hasOne(Province::class,"id","province_id");
     }
 }

+ 24 - 0
app/OwnerPriceLogistic.php

@@ -3,6 +3,7 @@
 namespace App;
 
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
 
 class OwnerPriceLogistic extends Model
 {
@@ -17,6 +18,19 @@ class OwnerPriceLogistic extends Model
         "service_price",    //信息服务费
     ];
 
+    public function getUnitRangeJsonAttribute()
+    {
+        return json_encode(explode(",",$this->unit_range));
+    }
+    public function getOtherUnitRangeJsonAttribute()
+    {
+        return json_encode(explode(",",$this->other_unit_range));
+    }
+
+    public function details()
+    {
+        return $this->hasMany(OwnerPriceLogisticDetail::class,"owner_price_logistic_id","id");
+    }
     public function unit()
     {   //单位一
         return $this->hasOne(Unit::class,"id","unit_id");
@@ -33,4 +47,14 @@ class OwnerPriceLogistic extends Model
     {   //物流
         return $this->belongsToMany(Logistic::class,"owner_price_logistic_logistic","owner_price_logistic_id","logistic_id");
     }
+
+    public function getOwnerIdAttribute()
+    {   //获取货主ID数组
+        return array_column(DB::select(DB::raw("SELECT * FROM owner_price_logistic_owner WHERE owner_price_logistic_id = ?"),[$this->id]),"owner_id");
+    }
+
+    public function getLogisticIdAttribute()
+    {   //获取快递ID数组
+        return array_column(DB::select(DB::raw("SELECT * FROM owner_price_logistic_logistic WHERE owner_price_logistic_id = ?"),[$this->id]),"logistic_id");
+    }
 }

+ 14 - 0
app/OwnerPriceOperation.php

@@ -12,7 +12,11 @@ class OwnerPriceOperation extends Model
         "strategy",         //策略
         "feature",          //特征
         "remark",           //备注
+        "priority",         //优先级 值越大越高
     ];
+    public static $features = null;
+    public static $columnMapping = null;
+
 
     public function ownerInStorageRule()
     {   //入库规则
@@ -22,4 +26,14 @@ class OwnerPriceOperation extends Model
     {   //出库规则
         return $this->hasMany(OwnerOutStorageRule::class,"owner_price_operation_id","id");
     }
+    public function ownerPriceOperationOwners()
+    {   //货主中间表
+        return $this->belongsToMany(Owner::class,"owner_price_operation_owner","owner_price_operation_id","owner_id");
+    }
+
+    public function getFeatureFormatAttribute()
+    {
+        if ($this->strategy == '默认')return "/";
+        return app("FeatureService")->formatFeature(self::$features,$this->feature,self::$columnMapping);
+    }
 }

+ 1 - 0
app/OwnerReport.php

@@ -13,6 +13,7 @@ class OwnerReport extends Model
         "owner_id",                     //货主ID
         "counting_month",               //结算月
         "daily_average_order_amount",   //日均单量
+        "total",                        //总单量
         "current_month_counting_area",  //结算月盘点面积
         "last_month_counting_area",     //结算月上月盘点面积
         "owner_bill_report_id"          //账单ID

+ 10 - 0
app/OwnerStoragePriceModelOwner.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace App;
+
+use Illuminate\Database\Eloquent\Model;
+
+class OwnerStoragePriceModelOwner extends Model
+{
+    protected $table = "owner_storage_price_model_owner";
+}

+ 23 - 0
app/Providers/AppServiceProvider.php

@@ -12,6 +12,7 @@ use App\Services\CommodityBarcodeService;
 use App\Services\common\DataHandlerService;
 use App\Services\CustomerService;
 use App\Services\DepositoryService;
+use App\Services\FeatureService;
 use App\Services\InventoryAccountMissionService;
 use App\Services\InventoryCompareService;
 use App\Services\LogService;
@@ -32,8 +33,17 @@ use App\Services\OrderService;
 use App\Services\OrderIssueWorkLoadService;
 use App\Services\OrderPackageCommoditiesService;
 use App\Services\OrderTrackingService;
+use App\Services\OwnerAreaReportService;
+use App\Services\OwnerBillReportService;
+use App\Services\OwnerFeeDetailService;
+use App\Services\OwnerOutStorageRuleService;
+use App\Services\OwnerPriceDirectLogisticService;
+use App\Services\OwnerPriceExpressService;
+use App\Services\OwnerPriceLogisticService;
+use App\Services\OwnerPriceOperationService;
 use App\Services\OwnerReportService;
 use App\Services\OwnerService;
+use App\Services\OwnerStoragePriceModelService;
 use App\Services\PackageService;
 use App\Services\PackageStatisticsService;
 use App\Services\ProcessesContentService;
@@ -48,6 +58,7 @@ use App\Services\StoreCheckingReceiveItemService;
 use App\Services\StoreCheckingReceiveService;
 use App\Services\StoreItemService;
 use App\Services\StoreService;
+use App\Services\UnitService;
 use App\Services\UserOwnerGroupService;
 use App\Services\UserService;
 use App\Services\WarehouseService;
@@ -142,6 +153,13 @@ class AppServiceProvider extends ServiceProvider
         app()->singleton('StoreItemService',StoreItemService::class);
         app()->singleton('PackageService',PackageService::class);
         app()->singleton('ProcessMethodService',ProcessMethodService::class);
+        app()->singleton('OwnerReportService',OwnerReportService::class);
+        app()->singleton('OwnerAreaReportService',OwnerAreaReportService::class);
+        app()->singleton('OwnerFeeDetailService',OwnerFeeDetailService::class);
+        app()->singleton('OwnerBillReportService',OwnerBillReportService::class);
+        app()->singleton('OwnerPriceExpressService',OwnerPriceExpressService::class);
+        app()->singleton('OwnerPriceLogisticService',OwnerPriceLogisticService::class);
+        app()->singleton('OwnerPriceDirectLogisticService',OwnerPriceDirectLogisticService::class);
 
         $this->loadingOrderModuleService();
         $this->loadingBasedModuleService();
@@ -169,6 +187,11 @@ class AppServiceProvider extends ServiceProvider
         app()->singleton('DepositoryService',DepositoryService::class);
         app()->singleton('UserOwnerGroupService',UserOwnerGroupService::class);
         app()->singleton('CustomerService',CustomerService::class);
+        app()->singleton('OwnerStoragePriceModelService',OwnerStoragePriceModelService::class);
+        app()->singleton('UnitService',UnitService::class);
+        app()->singleton('OwnerPriceOperationService',OwnerPriceOperationService::class);
+        app()->singleton('FeatureService',FeatureService::class);
+        app()->singleton('OwnerOutStorageRuleService',OwnerOutStorageRuleService::class);
     }
 
     private function loadingRejectedModuleService(){

+ 21 - 0
app/Services/CommodityService.php

@@ -3,6 +3,7 @@
 namespace App\Services;
 
 use App\Commodity;
+use App\Http\Controllers\CommodityController;
 use App\CommodityBarcode;
 use App\OracleBasSKU;
 use App\Owner;
@@ -292,4 +293,24 @@ Class CommodityService
             }
         }
     }
+    //获取箱规
+    public function getPack($owner_id, $sku)
+    {
+        $that = $this;
+        return app("CacheService")->getOrExecute("pack_{$owner_id}_{$sku}",function ()use($owner_id,$sku,$that){
+            $commodity = $that->first([
+                "owner_id" => $owner_id,
+                "sku" => $sku
+            ]);
+            if (!$commodity || $commodity->pack === null){
+                $owner = app("OwnerService")->find($owner_id);
+                $action = new CommodityController();
+                $action->syncOwnerCommodities($owner->id,$owner->code,$sku);
+            }
+            return $that->first([
+                "owner_id" => $owner_id,
+                "sku" => $sku
+            ])->pack;
+        });
+    }
 }

+ 28 - 0
app/Services/CustomerService.php

@@ -11,4 +11,32 @@ Class CustomerService
         return Customer::query()->select($column)->get();
     }
 
+    public function paginate()
+    {
+        return Customer::query()->orderByDesc('id')->paginate(50);
+    }
+
+    public function create(array $params)
+    {
+        return Customer::query()->create($params);
+    }
+
+    public function find($id)
+    {
+        return Customer::query()->find($id);
+    }
+
+    public function update(array $params, array $values)
+    {
+        $query = Customer::query();
+        foreach ($params as $column => $value){
+            $query->where($column,$value);
+        }
+        return $query->update($values);
+    }
+
+    public function destroy($id)
+    {
+        return Customer::destroy($id);
+    }
 }

+ 189 - 0
app/Services/FeatureService.php

@@ -0,0 +1,189 @@
+<?php 
+
+namespace App\Services; 
+
+use App\Feature;
+
+Class FeatureService
+{
+    public function getMapArray()
+    {
+        $features = Feature::query()->get();
+        $map = [];
+        foreach ($features as $feature){
+            $map[$feature->id] = ["type"=>$feature->type,"logic"=>$feature->logic,"describe"=>$feature->describe];
+        }
+        return $map;
+    }
+
+    public function translationFeature($str)
+    {
+        if (!$str)return null;
+        $result = [];
+        preg_match_all('/\d+|[\&\|\(\)]/',$str,$result); //初次匹配以数字&|()为分隔符生成数组
+        $sign = 0;  //为第二次切割做起点标记
+        $model = [];//第二次切割数组
+        $ids = [];//记录出现的特征ID,统一查询
+        foreach ($result[0] as $index => &$str){
+            if (is_numeric($str)){
+                $model[] = array_slice($result[0],$sign,($index-$sign)+1);
+                $sign = $index+1;
+                $ids[] = $str;
+                continue;
+            }
+            if ($index == count($result[0])-1 && $str == ')'){
+                $model[] = [")"];
+            }
+        }//以数字为标准切割策略组
+        $features = Feature::query()->find($ids);//查询出现的特征
+        $featureMap = [];
+        foreach ($features as $index => $feature){
+            $featureMap[$feature->id] = $index;
+        }//为查询的特征重组为key-val形式数组留做引用
+        foreach ($model as $index => &$m){
+            $arr = [
+                "strategyGroupStartSign" => false,//是否为策略组起点,这将在解析时解析为 (
+                "calculation" => "",//运算规则,目前仅有 &,| 翻译后填入
+                "type"=>"",  //特征类型
+                "id"=>"",  //特征ID
+                "logic"=>"",  //特征逻辑
+                "describe"=>"",  //特征信息
+                "strategyGroupEndSign" => false,//是否为策略组终点,这将在解析时解析为 )
+            ];//最终对象组模型,策略组将几组特征组合引用
+            foreach ($m as $str){
+                if (is_numeric($str)){//填入特征信息
+                    if (isset($featureMap[$str])){
+                        $arr["type"] = $features[$featureMap[$str]]->type;
+                        $arr["id"] = $features[$featureMap[$str]]->id;
+                        $arr["logic"] = $features[$featureMap[$str]]->logic;
+                        $arr["describe"] = $features[$featureMap[$str]]->describe;
+                    }
+                    continue;
+                }
+                switch ($str){//特殊字符的翻译
+                    case "(":
+                        $arr["strategyGroupStartSign"] = true;
+                        break;
+                    case ")":
+                        $model[$index-1]["strategyGroupEndSign"] = true;
+                        break;
+                    case "&":
+                        $arr["calculation"] = "并且";
+                        break;
+                    case "|":
+                        $arr["calculation"] = "或";
+                        break;
+                }
+            }
+            if (!$arr["id"]){
+                unset($model[$index]);
+                continue;
+            }
+            $m = $arr;//变更当前指针为翻译结果
+        }
+        return $model;
+    }
+
+    public function analysisFeature($features)
+    {
+        $str = "";
+        $map = [];
+        foreach ($features as &$feature){
+            if (!$feature["type"] || !$feature["logic"] || !$feature["describe"])continue;
+            $f = Feature::query()->firstOrCreate([
+                "type"=>$feature["type"],  //特征类型
+                "logic"=>$feature["logic"],  //特征逻辑
+                "describe"=>$feature["describe"],  //特征信息
+            ]);
+            $feature["id"] = $f->id;
+            $map[$feature["id"]] = $f;
+            if ($feature["calculation"] == '并且')$str .= '&';
+            else $str .= '|';
+            if ($feature["strategyGroupStartSign"])$str .= "(";
+            $str .= $feature["id"];
+            if ($feature["strategyGroupEndSign"])$str .= ")";
+        }
+        return ['feature'=>$str,"map"=>$map];
+    }
+
+    public function formatFeature(array $features, $value, $columnMapping = null)
+    {
+        if (!$features)return $value;
+        preg_match_all('/\d+|[\&\|\(\)]/',$value,$result);
+        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 ($columnMapping){
+                    $column = $columnMapping[$column] ?? $column;
+                    switch ($logic){
+                        case "包含":
+                            $logic = " like ";
+                            $describe = "%".$describe."%";
+                            break;
+                        case "不包含":
+                            $logic = " not like ";
+                            $describe = "%".$describe."%";
+                            break;
+                        case "等于":
+                            $logic = " = ";
+                            break;
+                    }
+                    $str = $column.$logic.$describe;
+                }else $str = $features[$str]["type"].' '.$features[$str]["logic"].' '.$features[$str]["describe"];
+            }
+            if ($str == "&"){
+                if ($columnMapping) $str = " and ";
+                else $str = " 并且 ";
+            }
+            if ($str == "|"){
+                if ($columnMapping) $str = " or ";
+                else $str = " 或 ";
+            }
+        }
+        return implode("",$result[0]);
+    }
+
+    public function matchFeature($value, $columnMapping, $matchObject) :bool
+    {
+        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;
+        }
+        preg_match_all('/\d+|[\&\|\(\)]/',$value,$result);
+        foreach ($result[0] as &$str) {
+            if (is_numeric($str) && isset($features[$str])) {
+                $column = $features[$str]["type"];
+                $logic = $features[$str]["logic"];
+                $describe = $features[$str]["describe"];
+                $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;
+                }
+                continue;
+            }
+            if ($str == "&") {
+                $str = '&&';
+                continue;
+            }
+            if ($str == "|") {
+                $str = '||';
+            }
+        }
+        $is = implode("",$result[0]);
+        return eval("return $is;");
+    }
+
+}

+ 37 - 22
app/Services/OrderIssueService.php

@@ -82,7 +82,11 @@ class OrderIssueService
         if (isset($arr['custom_code'])) {
             $query->where('custom_code', $arr['custom_code']);
         }
-
+        if(isset($arr['hiddenTag'])){
+            $query->where('hidden_tag', $arr['hiddenTag']);
+        }else{
+            $query->whereNull('hidden_tag');
+        }
         $query->selectRaw('order_issues.* ,order_issue_on_tops.id top_id ,order_issue_on_tops.remark,order_issue_on_tops.updated_at top_update')
             ->leftJoin('order_issue_on_tops', 'order_issue_on_tops.order_issue_id', '=', 'order_issues.id')
             ->whereNull('order_issue_on_tops.deleted_at')
@@ -171,7 +175,8 @@ class OrderIssueService
             }
         }
         if (isset($condition['order_issue_type_id'])) {
-            $query->where('order_issue_type_id', $condition['order_issue_type_id']);
+            $type_ids = explode(',',$condition['order_issue_type_id']);
+            $query->whereIn('order_issue_type_id', $type_ids);
         }
         if (!($condition['is_handle'] ?? false) && !($condition['final_status'] ?? false)) {
             if (!(isset($condition['settlement_at_start']) || isset($condition['settlement_at_end']))) {
@@ -181,10 +186,21 @@ class OrderIssueService
             }
         }
         if (isset($condition['logistic_indemnity_money'])) {
-            $query->where('logistic_indemnity_money', $condition['logistic_indemnity_money']);
+            if($condition['logistic_indemnity_money']== '是'){
+                $query->whereNotNull('logistic_indemnity_money');
+            }elseif($condition['logistic_indemnity_money']== '否'){
+                $query->whereNull('logistic_indemnity_money');
+            }
         }
         if (isset($condition['baoshi_indemnity_money'])) {
-            $query->where('baoshi_indemnity_money', $condition['baoshi_indemnity_money']);
+            if($condition['baoshi_indemnity_money']== '是'){
+                $query->whereNotNull('baoshi_indemnity_money');
+            }elseif($condition['baoshi_indemnity_money']== '否'){
+                $query->whereNull('baoshi_indemnity_money');
+            }
+        }
+        if (isset($condition['rejectingStatus'])) {
+            $query->where('rejecting_status',$condition['rejectingStatus']);
         }
         if (isset($condition['order_issue_ids'])) {
             $orderIssuesId = $condition['order_issue_ids'];
@@ -290,11 +306,11 @@ class OrderIssueService
         if ($bool) {
             return ['success' => $bool];
         } else {
-            return ['success' => $bool, 'fail_info' => '问题件创建失败'];
+            return ['success' => $bool, 'fail_info' => '问题件创建失败,请检查勾选订单的状态'];
         }
     }
 
-    public function createOrderIssueByWmsOrder($orderHeaders, $order_issue_type_id, $result_explain, $imported_status = '正常', $custom_code = null)
+    public function createOrderIssueByWmsOrder($orderHeaders, $order_issue_type_id, $result_explain, $imported_status = '正常', $custom_code = null,$hiddenTag = null)
     {
         /** @var OrderService $orderService */
         $orderService = app('OrderService');
@@ -302,22 +318,21 @@ class OrderIssueService
 //        $orders = $orderService->getByWmsOrders($orderHeaders);
         $orderService->createByWmsOrder($orderHeaders);
         $orders = Order::query()->whereIn('code',data_get($orderHeaders,'*.orderno'))->whereHas('packages')->get();
-
+        if($orders->count()==0)return false;
         $innerParams = [];
-        if($orders->count()>0){
-            foreach ($orderHeaders as $orderHeader) {
-                $order = $orders->where('code',$orderHeader->orderno)->first();
-                if($order==null){
-                    $order = Order::query()->where('code',$orderHeader->orderno)->first();
-                }
-                $innerParams[] = [
-                    'order_id' => $order->id,
-                    'order_issue_type_id' => $order_issue_type_id,
-                    'result_explain' => $result_explain,
-                    'imported_status' => $imported_status,
-                    'custom_code' => $custom_code
-                ];
+        foreach ($orderHeaders as $orderHeader) {
+            $order = $orders->where('code',$orderHeader->orderno)->first();
+            if($order==null){
+                $order = Order::query()->where('code',$orderHeader->orderno)->first();
             }
+            $innerParams[] = [
+                'order_id' => $order->id,
+                'order_issue_type_id' => $order_issue_type_id,
+                'result_explain' => $result_explain,
+                'imported_status' => $imported_status,
+                'custom_code' => $custom_code,
+                'hidden_tag' => $hiddenTag
+            ];
         }
         try {
             $this->insert($innerParams);
@@ -498,14 +513,14 @@ class OrderIssueService
     }
 
 
-    public function createOrderIssue($logisticNumber, $type, $result_explain, $importedStatus = '正常', $custom_code = null)
+    public function createOrderIssue($logisticNumber, $type, $result_explain, $importedStatus = '正常', $custom_code = null,$hiddenTag = null)
     {
         $orderHeaders = OracleDOCOrderHeader::query()->with(['oracleDOCOrderDetails', 'actAllocationDetails', 'oracleBASCode'])
             ->whereHas('actAllocationDetails', function ($query) use ($logisticNumber) {
                 $query->where('picktotraceid', $logisticNumber);
             })->get();
         $orderIssueType = OrderIssueType::query()->where('name', $type)->first();
-        return $this->createOrderIssueByWmsOrder($orderHeaders, $orderIssueType->id, $result_explain, $importedStatus, $custom_code);
+        return $this->createOrderIssueByWmsOrder($orderHeaders, $orderIssueType->id, $result_explain, $importedStatus, $custom_code,$hiddenTag);
     }
 
     /**

+ 0 - 1
app/Services/OrderPackageService.php

@@ -437,7 +437,6 @@ class OrderPackageService
             $params = $this->getInnerParams($orderHeader,$order,$packages_maps);
             $inner_params = array_merge($inner_params,$params);
         }
-
         if(count($inner_params)>0){
             try {
                 $bool = $this->insert($inner_params);

+ 1 - 1
app/Services/OrderService.php

@@ -203,7 +203,7 @@ class OrderService
             $ordernos = app('OracleActAllocationDetailService')
                 ->getOrderno(['checktime_start'=>$checktime_start,'checktime_end'=>$checktime_end,
                     'paginate'=>$paginate,'page'=>$page]);
-            $params['ordernos'] = $ordernos;
+            if ($ordernos)$params['ordernos'] = $ordernos;
         }
         $sql="select ACT_ALLOCATION_DETAILS.CHECKTIME,DOC_ORDER_HEADER.addtime,DOC_ORDER_HEADER.C_PROVINCE,DOC_ORDER_HEADER.C_CITY,DOC_ORDER_HEADER.C_DISTRICT,DOC_ORDER_HEADER.C_CONTACT,DOC_ORDER_HEADER.OrderNo,DOC_ORDER_HEADER.SOStatus,DOC_ORDER_HEADER.WAREHOUSEID,DOC_ORDER_HEADER.CustomerID
         ,DOC_ORDER_HEADER.C_Tel2,DOC_ORDER_HEADER.C_Tel1,DOC_ORDER_HEADER.CarrierName,DOC_ORDER_HEADER.IssuePartyName,DOC_ORDER_HEADER.EDIREMARKS2,

+ 37 - 0
app/Services/OrderTrackingService.php

@@ -496,4 +496,41 @@ class OrderTrackingService
         ];
     }
 
+    public function fillInOrderTracking($orderTracking = null)
+    {
+        $orderTrackingIds = [];
+        try {
+            $date = new Carbon();
+            if($orderTracking==null){
+                $orderTracking = OrderTracking::query()
+                    ->where('created_at', '!=', '0000-00-00 00:00:00')
+                    ->where('planning_sent_at', '!=', '0000-00-00 00:00:00')
+                    ->whereNull('signed_at')
+                    ->where('planning_sent_at','<',$date)
+                    ->get();
+            }
+            if(count($orderTracking)==0)return;
+            $update_params = [['id','signed_at']];
+            $orderTracking = $orderTracking->where('created_at', '!=', '0000-00-00 00:00:00')
+                ->where('planning_sent_at', '!=', '0000-00-00 00:00:00')
+                ->whereNull('signed_at')
+                ->where('planning_sent_at','<',$date);
+            $orderTracking->each(function($item)use(&$update_params){
+                $update_params[] = [
+                    'id' => $item->id,
+                    'signed_at' => $item->planning_sent_at
+                ];
+            });
+            if(count($update_params) > 0) $this->batchUpdate($update_params);
+            $orderTrackingIds = data_get($orderTracking, '*.id');
+            OrderTracking::query()->whereIn('id', $orderTrackingIds)
+                ->whereNull('is_on_duty_shift')
+                ->whereNull('is_arrival')
+                ->update(['is_on_duty_shift' => '是', 'is_arrival' => '是']);
+            app('LogService')->log(__METHOD__,__FUNCTION__,'修改签收日期 是否赶上卡班 到货情况'.json_encode($orderTrackingIds));
+        } catch (\Exception $e) {
+            app('LogService')->log(__METHOD__,'ERROR '.__FUNCTION__,'修改签收日期 是否赶上卡班 到货情况 ERROR'.json_encode($orderTrackingIds).' || '.json_encode($e->getMessage()).' || '.json_encode($e->getTraceAsString()));
+        }
+    }
+
 }

+ 85 - 0
app/Services/OwnerAreaReportService.php

@@ -0,0 +1,85 @@
+<?php 
+
+namespace App\Services; 
+
+use App\OwnerAreaReport;
+use App\OwnerBillReport;
+use App\Services\common\QueryService;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Support\Facades\DB;
+
+Class OwnerAreaReportService
+{
+    /**
+     * @param Builder $builder
+     * @param array $params
+     * @return Builder
+     */
+    private function query(Builder $builder, array $params)
+    {
+        $columnQueryRules = [
+            'counting_month_start' => ['alias' => 'counting_month', 'startDate' => '-01'],
+            'counting_month_end' => ['alias' => 'counting_month', 'endDate' => '-31'],
+            'owner_id' => ['multi' => ','],
+        ];
+        if ($params["customer_id"] ?? false){
+            $builder->whereHas('owner',function ($query)use(&$params){
+                /** @var Builder $query*/
+                $query->where("customer_id",$params["customer_id"]);
+                unset($params["customer_id"]);
+            });
+        }
+        return app(QueryService::class)->query($params, $builder, $columnQueryRules);
+    }
+
+    public function paginate(array $params, array $withs = null)
+    {
+        $areas = OwnerAreaReport::query()->orderByDesc('id');
+        if ($withs)$areas->with($withs);
+        return $this->query($areas,$params)->paginate($params["paginate"] ?? 50);
+    }
+
+
+    /**
+     * 面积变更会去对比账单更新账单 考虑到后续账单变更有多种渠道此处加排他锁
+     *
+     * @param array $params
+     * @param array $values
+     * @return int
+     */
+    public function update(array $params, array $values):bool
+    {
+        DB::beginTransaction();
+        $area = $this->query(OwnerAreaReport::query(),$params)->with("ownerStoragePriceModel")->lockForUpdate()->first();
+        try{
+            if ($values["accounting_area"] ?? null && $area->accounting_area != $values["accounting_area"]){
+                $report = OwnerBillReport::query()->lockForUpdate()->where("owner_id",$area->owner_id)
+                    ->where("counting_month",'like',$area->counting_month."%")->first();
+                if ($report){
+                    if (!$area->ownerStoragePriceModel)return false;
+                    $diff = $area->accounting_area - $values["accounting_area"];
+                    $diffAmount = app("OwnerStoragePriceModelService")->calculationAmount($area->ownerStoragePriceModel, $diff, $area->owner_id, $area->counting_month);
+                    if ($diffAmount != 0){
+                        $up = ["initial_fee"=>$report->initial_fee - $diffAmount];
+                        if ($report->confirm_fee !== null)$up["difference"] = $up["initial_fee"] - $report->confirm_fee;
+                        $report->update($up);
+                    }
+                }
+            }
+            $area->update($values);
+            DB::commit();
+            return true;
+        }catch (\Exception $e){
+            DB::rollBack();
+            return false;
+        }
+    }
+
+    public function get(array $params, array $withs = null)
+    {
+        $query = OwnerAreaReport::query()->orderByDesc('id');
+        if ($withs)$query->with($withs);
+        return $this->query($query,$params)->get();
+    }
+
+}

+ 58 - 0
app/Services/OwnerBillReportService.php

@@ -0,0 +1,58 @@
+<?php 
+
+namespace App\Services; 
+
+use App\OwnerBillReport;
+use App\Services\common\QueryService;
+use Illuminate\Database\Eloquent\Builder;
+
+Class OwnerBillReportService
+{
+
+    /**
+     * @param Builder $builder
+     * @param array $params
+     * @return Builder
+     */
+    private function query(Builder $builder, array $params)
+    {
+        $columnQueryRules = [
+            'counting_month_start' => ['alias' => 'counting_month', 'startDate' => '-01'],
+            'counting_month_end' => ['alias' => 'counting_month', 'endDate' => '-31'],
+            'owner_id' => ['multi' => ','],
+        ];
+        if (($params["customer_id"] ?? false) || ($params["owner_group_id"] ?? false)){
+            $builder->whereHas('owner',function ($query)use(&$params){
+                /** @var Builder $query*/
+                if ($params["customer_id"] ?? false){
+                    $query->where("customer_id",$params["customer_id"]);
+                    unset($params["customer_id"]);
+                }
+                if ($params["owner_group_id"] ?? false){
+                    $query->where("user_owner_group_id",$params["owner_group_id"]);
+                    unset($params["owner_group_id"]);
+                }
+            });
+        }
+        return app(QueryService::class)->query($params, $builder, $columnQueryRules);
+    }
+
+    public function paginate(array $params, array $withs = null)
+    {
+        $bills = OwnerBillReport::query()->orderByDesc('id');
+        if ($withs)$bills->with($withs);
+        return $this->query($bills,$params)->paginate($params["paginate"] ?? 50);
+    }
+
+    public function update(array $params, array $values)
+    {
+        return $this->query(OwnerBillReport::query(),$params)->update($values);
+    }
+
+    public function get(array $params, array $withs = null)
+    {
+        $bills = OwnerBillReport::query()->orderByDesc('id');
+        if ($withs)$bills->with($withs);
+        return $this->query($bills,$params)->get();
+    }
+}

+ 58 - 0
app/Services/OwnerFeeDetailService.php

@@ -0,0 +1,58 @@
+<?php 
+
+namespace App\Services; 
+
+use App\OwnerFeeDetail;
+use App\Services\common\QueryService;
+use Illuminate\Database\Eloquent\Builder;
+
+Class OwnerFeeDetailService
+{
+    /**
+     * @param Builder $builder
+     * @param array $params
+     * @return Builder
+     */
+    private function query(Builder $builder, array $params)
+    {
+        $columnQueryRules = [
+            'worked_at_start' => ['alias' => 'worked_at', 'startDate' => ''],
+            'worked_at_end' => ['alias' => 'worked_at', 'endDate' => ''],
+            'owner_id' => ['multi' => ','],
+            'id' => ['multi' => ','],
+            'operation_bill' => ['like' => ''],
+            'logistic_bill' => ['like' => ''],
+        ];
+        if ($params["customer_id"] ?? false){
+            $builder->whereHas('owner',function ($query)use(&$params){
+                /** @var Builder $query*/
+                $query->where("customer_id",$params["customer_id"]);
+                unset($params["customer_id"]);
+            });
+        }
+        return app(QueryService::class)->query($params, $builder, $columnQueryRules, 'owner_fee_details');
+    }
+
+    public function paginate(array $params, array $withs = null)
+    {
+        $areas = OwnerFeeDetail::query()->orderByDesc('id');
+        if ($withs)$areas->with($withs);
+        return $this->query($areas,$params)->paginate($params["paginate"] ?? 50);
+    }
+
+    public function getSql($params)
+    {
+        $query = $this->query(OwnerFeeDetail::query()->orderByDesc('id'),$params);
+        $query->selectRaw("owner_fee_details.*,(work_fee+logistic_fee) total");
+        $query->leftJoin("owners","owner_fee_details.owner_id","owners.id")
+            ->selectRaw("owners.name owner_name")
+        ->leftJoin("customers","owners.customer_id","customers.id")
+            ->selectRaw("customers.name customer_name")
+        ->leftJoin("shops","owner_fee_details.shop_id","shops.id")
+            ->selectRaw("shops.name shop_name")
+        ->leftJoin("logistics","owner_fee_details.logistic_id","logistics.id")
+            ->selectRaw("logistics.name logistic_name");
+        return $query->sql();
+    }
+
+}

+ 57 - 0
app/Services/OwnerOutStorageRuleService.php

@@ -0,0 +1,57 @@
+<?php 
+
+namespace App\Services; 
+
+use App\OwnerOutStorageRule;
+
+Class OwnerOutStorageRuleService
+{ 
+    public function get(array $params, array $withs = [], $isTranslateFeature = false, array $translateColumn = [])
+    {
+        if ($isTranslateFeature){
+            $features = app("FeatureService")->getMapArray();
+            OwnerOutStorageRule::$features = $features;
+            OwnerOutStorageRule::$columnMapping = $translateColumn;
+        }
+        $rule = OwnerOutStorageRule::query();
+        if ($withs)$rule->with($withs);
+        foreach ($params as $column=>$param){
+            $rule->where($column,$param);
+        }
+        return $rule->get();
+    }
+
+    public function update(array $params, array $values)
+    {
+        $query = OwnerOutStorageRule::query();
+        foreach ($params as $column=>$param){
+            $query->where($column,$param);
+        }
+        return $query->update($values);
+    }
+
+    public function create(array $params)
+    {
+        return OwnerOutStorageRule::query()->create($params);
+    }
+
+    public function findUpdate(OwnerOutStorageRule $rule, array $values)
+    {
+        return $rule->update($values);
+    }
+
+    public function find($id)
+    {
+        return OwnerOutStorageRule::query()->find($id);
+    }
+
+
+    public function isExist(array $params)
+    {
+        $query = OwnerOutStorageRule::query();
+        foreach ($params as $column=>$param){
+            $query->where($column,$param);
+        }
+        return $query->count();
+    }
+}

+ 111 - 0
app/Services/OwnerPriceDirectLogisticService.php

@@ -0,0 +1,111 @@
+<?php 
+
+namespace App\Services; 
+
+use App\Owner;
+use App\OwnerPriceDirectLogistic;
+use App\OwnerPriceDirectLogisticCar;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Support\Facades\DB;
+
+Class OwnerPriceDirectLogisticService
+{ 
+    public function paginate($id = null)
+    {
+        $query = OwnerPriceDirectLogistic::query()->with("owners");
+        if($id)$query->where("id",$id);
+        return $query->paginate(50);
+    }
+
+    public function create(array $params)
+    {
+        return OwnerPriceDirectLogistic::query()->create($params);
+    }
+
+    public function destroy($id)
+    {
+        OwnerPriceDirectLogisticCar::query()->where("owner_price_direct_logistic_id",$id)->delete();
+        DB::table("owner_price_direct_logistic_owner")->where("owner_price_direct_logistic_id",$id)->delete();
+        return OwnerPriceDirectLogistic::destroy($id);
+    }
+
+    public function find($id)
+    {
+        return OwnerPriceDirectLogistic::query()->find($id);
+    }
+
+    public function update(array $params, array $values)
+    {
+        $query = OwnerPriceDirectLogistic::query();
+        foreach ($params as $column=>$param){
+            $query->where($column,$param);
+        }
+        return $query->update($values);
+    }
+
+    public function updateDetail(array $params, array $values)
+    {
+        $query = OwnerPriceDirectLogisticCar::query();
+        foreach ($params as $column => $param){
+            $query->where($column,$param);
+        }
+        return $query->update($values);
+    }
+
+    public function isExistDetail(array $params)
+    {
+        $query = OwnerPriceDirectLogisticCar::query();
+        foreach ($params as $column => $param){
+            $query->where($column,$param);
+        }
+        return $query->count();
+    }
+
+    public function createDetail(array $params)
+    {
+        return OwnerPriceDirectLogisticCar::query()->create($params);
+    }
+
+    public function destroyDetail($id)
+    {
+        return OwnerPriceDirectLogisticCar::destroy($id);
+    }
+
+    public function getExistOwnerName($owner_id, $id) :array
+    {
+        if (!is_array($owner_id))$owner_id = [$owner_id];
+        $owners = Owner::query()->withCount(["ownerPriceDirectLogistics"=>function($query)use($id){
+            if ($id)$query->where("id","!=",$id);
+        }])->whereIn("id",$owner_id)->get();
+        $arr = [];
+        foreach ($owners as $owner){
+            if ($owner->owner_price_direct_logistics_count > 0)$arr[] = $owner->name;
+        }
+        return $arr;
+    }
+
+
+    /**
+     * CODE: -1:未找到计费模型
+     *
+     * @param double $amount
+     * @param integer $owner_id
+     * @param integer $car_id
+     * @return double
+     */
+    public function matching($amount, $owner_id, $car_id)
+    {
+        $model = OwnerPriceDirectLogistic::query()->with(["details"=>function($query)use($car_id){
+            /** @var Builder $query */
+            $query->where("car_type_id",$car_id);
+        }])->whereHas("owners",function ($query)use($owner_id){
+            /** @var Builder $query */
+            $query->where("id",$owner_id);
+        })->first();
+        if (!$model || !$model->details)return -1;
+        if ($amount < $model->base_km)$amount = $model->base_km;
+        $initialMoney = $model->base_km*$model->details[0]->base_fee;
+        $amount -= $model->base_km;
+        return ($amount*$model->details[0]->additional_fee)+$initialMoney;
+    }
+}

+ 130 - 0
app/Services/OwnerPriceExpressService.php

@@ -0,0 +1,130 @@
+<?php 
+
+namespace App\Services; 
+
+use App\Logistic;
+use App\Owner;
+use App\OwnerPriceExpress;
+use App\OwnerPriceExpressProvince;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Support\Facades\DB;
+
+Class OwnerPriceExpressService
+{ 
+
+    public function paginate($id = null)
+    {
+        $query = OwnerPriceExpress::query()->with(["owners","logistics"])
+            ->orderByDesc("id");
+        if ($id)$query->where("id",$id);
+        return $query->paginate(50);
+    }
+
+    public function find($id, $withs = [])
+    {
+        return OwnerPriceExpress::query()->with($withs)->find($id);
+    }
+
+    public function updateDetail(array $params, array $values)
+    {
+        $query = OwnerPriceExpressProvince::query();
+        foreach ($params as $column => $param){
+            $query->where($column,$param);
+        }
+        return $query->update($values);
+    }
+
+    public function create(array $params)
+    {
+        return OwnerPriceExpress::query()->create($params);
+    }
+
+    public function createDetail(array $params)
+    {
+        return OwnerPriceExpressProvince::query()->create($params);
+    }
+
+    public function isExistDetail(array $params)
+    {
+        $query = OwnerPriceExpressProvince::query();
+        foreach ($params as $column => $param){
+            $query->where($column,$param);
+        }
+        return $query->count();
+    }
+
+    public function destroyDetail($id)
+    {
+        return OwnerPriceExpressProvince::destroy($id);
+    }
+
+    public function getExistOwnerName($owner_id, $id=null) :array
+    {
+        if (!is_array($owner_id))$owner_id = [$owner_id];
+        $owners = Owner::query()->withCount(["ownerPriceExpresses"=>function($query)use($id){
+            if ($id)$query->where("id","!=",$id);
+        }])->whereIn("id",$owner_id)->get();
+        $arr = [];
+        foreach ($owners as $owner){
+            if ($owner->owner_price_expresses_count > 0)$arr[] = $owner->name;
+        }
+        return $arr;
+    }
+
+    public function getExistLogisticName($logistic_id, $id=null):array
+    {
+        $logistics = Logistic::query()->withCount(["ownerPriceExpresses"=>function($query)use($id){
+            if ($id)$query->where("id","!=",$id);
+        }])->whereIn("id",$logistic_id)->get();
+        $arr = [];
+        foreach ($logistics as $logistic){
+            if ($logistic->owner_price_expresses_count > 0)$arr[] = $logistic->name;
+        }
+        return $arr;
+    }
+
+    public function destroy($id)
+    {
+        OwnerPriceExpressProvince::query()->where("owner_price_express_id",$id)->delete();
+        DB::table("owner_price_express_owner")->where("owner_price_express_id",$id)->delete();
+        DB::table("owner_price_express_logistic")->where("owner_price_express_id",$id)->delete();
+        return OwnerPriceExpress::destroy($id);
+    }
+
+    public function update(array $params, array $values)
+    {
+        $query = OwnerPriceExpress::query();
+        foreach ($params as $column=>$param){
+            $query->where($column,$params);
+        }
+        return $query->update($values);
+    }
+
+    /**
+     * CODE: -1:未找到计费模型
+     *
+     * @param double $weight
+     * @param integer $owner_id
+     * @param integer $logistic_id
+     * @param integer $province_id
+     * @return double
+     */
+    public function matching($weight, $owner_id, $logistic_id, $province_id)
+    {
+        $model = OwnerPriceExpress::query()->with(["details"=>function($query)use($province_id){
+            /** @var Builder $query */
+            $query->where("province_id",$province_id);
+        }])->whereHas("owners",function ($query)use($owner_id){
+            /** @var Builder $query */
+           $query->where("id",$owner_id);
+        })->whereHas("logistics",function ($query)use($logistic_id){
+            /** @var Builder $query */
+            $query->where("id",$logistic_id);
+        })->first();
+        if (!$model || !$model->details)return -1;
+        if ($weight < $model->initial_weight)$weight = $model->initial_weight;
+        $initialMoney = $model->initial_weight*$model->details[0]->initial_weight_price;
+        $weight -= $model->initial_weight;
+        return ($weight*$model->details[0]->additional_weight_price)+$initialMoney;
+    }
+}

+ 139 - 0
app/Services/OwnerPriceLogisticService.php

@@ -0,0 +1,139 @@
+<?php 
+
+namespace App\Services; 
+
+use App\OwnerPriceLogistic;
+use App\OwnerPriceLogisticDetail;
+use Illuminate\Database\Eloquent\Builder;
+
+Class OwnerPriceLogisticService
+{ 
+    public function paginate($id = null)
+    {
+        $query = OwnerPriceLogistic::query()->with(["owners","logistics","unit","otherUnit"]);
+        if ($id)$query->where("id",$id);
+        return $query->paginate(50);
+    }
+
+    public function create(array $params)
+    {
+        return OwnerPriceLogistic::query()->create($params);
+    }
+
+    public function find($id, $withs=[])
+    {
+        return OwnerPriceLogistic::query()->with($withs)->find($id);
+    }
+
+    public function update(array $params, array $values)
+    {
+        $query = OwnerPriceLogistic::query();
+        foreach ($params as $column=>$param){
+            $query->where($column,$params);
+        }
+        return $query->update($values);
+    }
+
+    public function updateDetail(array $params, array $values)
+    {
+        $query = OwnerPriceLogisticDetail::query();
+        foreach ($params as $column => $param){
+            $query->where($column,$param);
+        }
+        return $query->update($values);
+    }
+
+    public function isExistDetail(array $params)
+    {
+        $query = OwnerPriceLogisticDetail::query();
+        foreach ($params as $column => $param){
+            $query->where($column,$param);
+        }
+        return $query->count();
+    }
+
+    public function createDetail(array $params)
+    {
+        return OwnerPriceLogisticDetail::query()->create($params);
+    }
+
+    public function destroyDetail($id)
+    {
+        return OwnerPriceLogisticDetail::destroy($id);
+    }
+
+    public function checkRange($range):bool
+    {
+        $arrRanges = explode(",",$range);
+        $len = count($arrRanges);
+        if ($len==0)return false;   //范围为空 false
+        $previous = []; //慢指针数组 不记录第一个值
+        foreach ($arrRanges as $index => $value){
+            if ($index == $len-1)$preg = "/\d*\-/"; //最后一个范围不允许封闭
+            else $preg = "/\d*\-\d*/";
+            preg_match($preg, $value, $match);
+            if (!$match || $match[0]!=$value)return false;//匹配结果不等于值 false
+            $arr = explode("-",$value); //二次切割判断是否连续
+            if ($index != 0){
+                if ($index == $len-1){
+                    if ((int)$arr[0] != (int)$previous[$index-1][1])return false; //最后一个范围只需要判断起始值
+                }else{
+                    if ((int)$arr[0] != (int)$previous[$index-1][1] || (int)$arr[1] <= (int)$arr[0])return false; //普通范围起始值必须为上一个结束值 当前结束值必须大于起始值
+                }
+            }else{
+                if ((int)$arr[1] <= (int)$arr[0])return false; //第一个范围只需判断当前结束值大于起始值
+            }
+            $previous[] = $arr;
+        }
+        return true;
+    }
+
+    /**
+     * CODE: -1:未找到计费模型
+     *
+     * @param double $amount
+     * @param integer $owner_id
+     * @param integer $logistic_id
+     * @param integer $unit_id
+     * @param integer $province_id
+     * @param integer $city_id
+     * @return double
+     */
+    public function matching($amount, $owner_id, $logistic_id, $unit_id, $province_id, $city_id)
+    {
+        $model = OwnerPriceLogistic::query()->with(["details"=>function($query)use($province_id,$city_id){
+            /** @var Builder $query */
+            $query->where("province_id",$province_id)->where("city_id",$city_id);
+        }])->where(function ($query)use($unit_id){
+            /** @var Builder $query */
+            $query->where("unit_id",$unit_id)->orWhere("other_unit_id",$unit_id);
+        })->whereHas("owners",function ($query)use($owner_id){
+            /** @var Builder $query */
+            $query->where("id",$owner_id);
+        })->whereHas("logistics",function ($query)use($logistic_id){
+            /** @var Builder $query */
+            $query->where("id",$logistic_id);
+        })->first();
+        if (!$model || !$model->details)return -1;
+        $fee = $model->pick_up_price + $model->fuel_price + $model->service_price; //服务费
+        foreach ($model->details as $detail){
+            if ($unit_id != $detail->unit_id)continue;
+            $arr = explode("-",$detail->range);
+            if (count($arr) < 2){
+                if ($amount >= $arr[0])return $this->calculation($amount,$detail,$fee);
+            }else{
+                if ($amount >= $arr[0] && $amount < $arr[1])return $this->calculation($amount,$detail,$fee);
+            }
+        }
+        return -1;
+    }
+
+    private function calculation($amount, $detail, $fee)
+    {
+        if ($amount < $detail->initial_amount)$amount = $detail->initial_amount; //小于起始数以起始数为准
+        $initialMoney = $detail->initial_amount*$detail->unit_price; //起始数计费
+        $amount -= $detail->initial_amount; //减起始数为续数
+        if ($initialMoney < $detail->initial_fee)$initialMoney = $detail->initial_fee; //小于起始计费以起始计费为准
+        return ($amount*$detail->unit_price)+$initialMoney+$detail->delivery_fee+$fee;
+    }
+}

+ 253 - 0
app/Services/OwnerPriceOperationService.php

@@ -0,0 +1,253 @@
+<?php 
+
+namespace App\Services; 
+
+use App\OwnerInStorageRule;
+use App\OwnerOutStorageRule;
+use App\OwnerPriceOperation;
+use App\Services\common\QueryService;
+use App\Unit;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
+
+Class OwnerPriceOperationService
+{
+    /**
+     * @param Builder $builder
+     * @param array $params
+     * @return Builder
+     */
+    private function query(Builder $builder, array $params)
+    {
+        if ($params["owner_id"] ?? false){
+            $ids = $this->ownerGetIds($params["owner_id"]);
+            if ($ids)$builder->whereIn("id",$ids);
+            unset($params["owner_id"]);
+        }
+        $columnQueryRules = [
+            "name" => ["like"=>""]
+        ];
+        return app(QueryService::class)->query($params, $builder, $columnQueryRules);
+    }
+
+    public function paginate(array $params, array $withs = [])
+    {
+        return $this->query(OwnerPriceOperation::query()->orderByDesc('id')->with($withs),$params)
+            ->paginate($params["paginate"] ?? 50);
+    }
+
+
+    private function ownerGetIds(string $owner_id)
+    {
+        if (!$owner_id)return [];
+        $arr = DB::select(DB::raw("SELECT owner_price_operation_id AS id FROM owner_price_operation_owner WHERE owner_id in (".$owner_id.")"));
+        return array_column($arr,"id");
+    }
+
+    public function destroy($id)
+    {
+        OwnerOutStorageRule::query()->where("owner_price_operation_id",$id)->delete();
+        OwnerInStorageRule::query()->where("owner_price_operation_id",$id)->delete();
+        DB::table("owner_price_operation_owner")->where("owner_price_operation_id",$id)->delete();
+        return OwnerPriceOperation::destroy($id);
+    }
+
+    /**
+     * @param array $params
+     * @return Model
+     */
+    public function create(array $params)
+    {
+        return OwnerPriceOperation::query()->create($params);
+    }
+
+    public function insertRule(array $params, $type = '出库')
+    {
+        if ($type == '出库')OwnerOutStorageRule::query()->insert($params);
+        else OwnerInStorageRule::query()->insert($params);
+    }
+
+    public function find($id, $isGetRule = false, $withs = [])
+    {
+        $query = OwnerPriceOperation::query()->with($withs)->find($id);
+        if ($isGetRule){
+            if ($query->operation_type == '入库'){
+                $query->load("ownerInStorageRule");
+                $query->rules = $query->ownerInStorageRule ? json_encode([$query->ownerInStorageRule]) : null;
+            }else{
+                $query->load("ownerOutStorageRules");
+                $query->rules = json_encode($query->ownerOutStorageRules);
+            }
+        }
+        return $query;
+    }
+
+    public function destroyRule($id, $type)
+    {
+        if ($type=="入库")OwnerInStorageRule::query()->where("owner_price_operation_id",$id)->delete();
+        else OwnerOutStorageRule::query()->where("owner_price_operation_id",$id)->delete();
+    }
+
+    public function findUpdate(OwnerPriceOperation $model, array $params)
+    {
+        return $model->update($params);
+    }
+
+    /** 参数顺序: 数量 匹配对象 列映射 货主ID 单位ID 类型 SKU .
+     *  匹配顺序: 类型 货主 策略 单位 特征                    ..多对多匹配规则废弃,1对1,设单位必定为件,对应规则必然只有一项存在
+     *  单位匹配: 件,箱,单 由小到大,依次换算匹配           .
+     * @param int $amount
+     * @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:未匹配到计费模型
+     */
+    public function matchRule($amount, $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");
+        }] : ['ownerInStorageRule'] ;
+        $rules = OwnerPriceOperation::query()->with($withs)
+            ->where("operation_type","出库")
+            ->whereHas("ownerPriceOperationOwners",function ($query)use($owner_id){
+                /** @var Builder $query */
+                $query->where("id",$owner_id);
+            })
+            ->orderByRaw("strategy desc,priority desc")->get(); //货主下的全部规则
+        if (!$rules)return -2;
+
+        if ($type == '入库'){
+            foreach ($rules as $rule){
+                if (!$rule->ownerInStorageRule)continue;
+                if ($rule->strategy == '特征'){
+                    $bool = app("FeatureService")->matchFeature($rule->feature,$columnMapping,$matchObject);
+                    if ($bool === true){
+                        if (!isset($units[$rule->ownerInStorageRule->unit_id])) return -3;
+                        if ($units[$rule->ownerInStorageRule->unit_id] == '箱'){ //为箱时同步商品寻找箱规
+                            $amount = $this->changeUnit($amount,$owner_id,$sku);
+                            if ($amount<0) return $amount;
+                        }
+                        if ($units[$rule->ownerInStorageRule->unit_id] == '单')$amount = 1; //为单时数量设为1;
+                        return ceil($amount/$rule->ownerInStorageRule->amount)*$rule->ownerInStorageRule->unit_price;
+                    };
+                }else{
+                    if (!isset($units[$rule->ownerInStorageRule->unit_id])) return -3;
+                    if ($units[$rule->ownerInStorageRule->unit_id] == '箱'){ //为箱时同步商品寻找箱规
+                        $amount = $this->changeUnit($amount,$owner_id,$sku);
+                        if ($amount<0) return $amount;
+                    }
+                    if ($units[$rule->ownerInStorageRule->unit_id] == '单')$amount = 1; //为单时数量设为1;
+                    return ceil($amount/$rule->ownerInStorageRule->amount)*$rule->ownerInStorageRule->unit_price;
+                };
+            }
+            return -7;
+        }
+        //出库
+        foreach ($rules as $rule){
+            if (!$rule->ownerOutStorageRules)continue;
+            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);
+                    if ($money>0)return $money;
+                };
+            }else{
+                $money = $this->matchOutStorage($amount,$rule->ownerOutStorageRules,$columnMapping,$matchObject,$units,$owner_id,$sku);
+                if ($money>0)return $money;
+            };
+        }
+        return -7;
+    }
+    private function changeUnit($amount,$owner_id,$sku)
+    {
+        if (!$sku)return -4;
+        $pack = app("CommodityService")->getPack($owner_id,$sku);
+        if (!$pack)return -6;
+        return ceil($amount/$pack);
+    }
+    private function matchOutStorage($amount, $rules, $columnMapping, $matchObject, $units, $owner_id, $sku)
+    {
+        $money = 0;
+        foreach ($rules as $rule){
+            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;
+                    }
+
+                    if ($amount < $rule->amount)$amount = $rule->amount;
+                    else $amount -= $rule->amount;
+                    break;
+                case "特征":
+                    if (app("FeatureService")->matchFeature($rule->feature,$columnMapping,$matchObject)){
+                        if (!isset($units[$rule->unit_id]) || $units[$rule->unit_id] == '单') return -3;
+                        if ($units[$rule->unit_id] == '箱'){ //为箱时同步商品寻找箱规
+                            $amount = $this->changeUnit($amount,$owner_id,$sku);
+                        }
+                        return (ceil($amount/$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] == '箱'){ //为箱时同步商品寻找箱规
+                        $amount = $this->changeUnit($amount,$owner_id,$sku);
+                    }
+                    return (ceil($amount/$rule->amount)*$rule->unit_price)+$money;
+                    break;
+            }
+        }
+        return -7;
+    }
+
+    private function matchInStorage($amount, $matchObject, $columnMapping, $owner_id, $unit_id, $rules, $sku, $units = null, $isMatch = false)
+    {
+        /*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 (!$units){
+            $unitModels = Unit::query()->whereIn("name",["件","箱","单"])->get();
+            if (!$unitModels) return null;
+            foreach ($unitModels as $unitModel)$units[$unitModel->name] = $unitModel->id;
+        }
+        $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;
+        }*/
+    }
+}

+ 0 - 5
app/Services/OwnerReportService.php

@@ -59,9 +59,4 @@ Class OwnerReportService
         return $this->query($query,$params)->paginate($params["paginate"] ?? 50);
     }
 
-    public function getSql(array $params)
-    {
-
-    }
-
 }

+ 31 - 1
app/Services/OwnerService.php

@@ -85,8 +85,21 @@ Class OwnerService
         },config('cache.expirations.rarelyChange'));
     }
 
-    public function create(array $params){
+    public function find($id)
+    {
+        return Owner::query()->find($id);
+    }
+
+    public function update(Owner $owner, array $values, array $related = [])
+    {
+        if ($related["ownerStoragePriceModels"] ?? false)$owner->ownerStoragePriceModels()->sync($related["ownerStoragePriceModels"]);
+        return $owner->update($values);
+    }
+
+    public function create(array $params, array $related = []){
+        /** @var Owner $owner */
         $owner = Owner::query()->create($params);
+        if ($related["ownerStoragePriceModels"] ?? false)$owner->ownerStoragePriceModels()->syncWithoutDetaching($related["ownerStoragePriceModels"]);
         return $owner;
     }
 
@@ -158,6 +171,7 @@ Class OwnerService
         /** @var User $user */
         $user = Auth::user();
         $query = Owner::query();
+        if ($withs)$query->with($withs);
         if ($authority){
             $ids = $user->getPermittingOwnerIdsAttribute();
             if ($ids) $query->whereIn("id",$ids);
@@ -168,6 +182,22 @@ Class OwnerService
         return $query->get();
     }
 
+    public function paginate(array $params, array $withs = null, bool $authority = true, bool $notShowSoftDelete = false)
+    {
+        /** @var User $user */
+        $user = Auth::user();
+        $query = Owner::query();
+        if ($withs)$query->with($withs);
+        if ($authority){
+            $ids = $user->getPermittingOwnerIdsAttribute();
+            if ($ids) $query->whereIn("id",$ids);
+            else return null;
+        }
+        if ($notShowSoftDelete) $query->whereNull('deleted_at');
+        $query = $this->query($query,$params);
+        return $query->paginate($params["paginate"] ?? 50);
+    }
+
     private function query(Builder $builder, array $params)
     {
         foreach ($params as $column => $param){

+ 66 - 0
app/Services/OwnerStoragePriceModelService.php

@@ -0,0 +1,66 @@
+<?php 
+
+namespace App\Services; 
+
+use App\OwnerReport;
+use App\OwnerStoragePriceModel;
+
+Class OwnerStoragePriceModelService
+{ 
+    public function getSelection(array $columns = ["counting_type","using_type"], array $withs = [])
+    {
+        return OwnerStoragePriceModel::query()->select($columns)->with($withs)->get();
+    }
+
+    public function paginate($id = null,array $withs = [])
+    {
+        $query = OwnerStoragePriceModel::query()->orderByDesc('id')->with($withs);
+        if ($id)$query->where("id",$id);
+        return $query->paginate($params["paginate"] ?? 50);
+    }
+
+    public function create(array $params)
+    {
+        return OwnerStoragePriceModel::query()->create($params);
+    }
+
+    public function update(array $params, array $values)
+    {
+        $query = OwnerStoragePriceModel::query();
+        foreach ($params as $column => $value){
+            $query->where($column,$value);
+        }
+        return $query->update($values);
+    }
+
+    public function find($id)
+    {
+        return OwnerStoragePriceModel::query()->find($id);
+    }
+    public function destroy($id)
+    {
+        return OwnerStoragePriceModel::destroy($id);
+    }
+
+    //暂时不考虑单位换算问题:后期可能存在多单位换算,此处仅视为单位为 m²
+    public function calculationAmount(OwnerStoragePriceModel $model, $area, $owner_id = null, $month = null) :int
+    {
+        if (!$model || !$area) return 0;
+        if ((int)$area < $model->minimum_area) $area = (int)$model->minimum_area;
+        $money = $area*$model->price;
+        switch ($model->discount_type){
+            case "按单减免":
+                if ($owner_id && $month){
+                    $report = OwnerReport::query()->select("id","total")
+                        ->where("owner_id",$owner_id)
+                        ->where("counting_month","like",$month."%")->first();
+                    $money -= $report ? ($report->total)*($model->discount_value) : 0;
+                }
+                break;
+            case "固定减免":
+                $money -= (int)$model->discount_value;
+                break;
+        }
+        return $money;
+    }
+}

+ 30 - 0
app/Services/ProcessMethodService.php

@@ -11,4 +11,34 @@ Class ProcessMethodService
         return ProcessMethod::query()->select($column)->get();
     }
 
+    public function paginate()
+    {
+        return ProcessMethod::query()->orderByDesc('id')->paginate(50);
+    }
+
+    public function create(array $params)
+    {
+        return ProcessMethod::query()->create($params);
+    }
+
+
+    public function find($id)
+    {
+        return ProcessMethod::query()->find($id);
+    }
+
+    public function update(array $params, array $values)
+    {
+        $query = ProcessMethod::query();
+        foreach ($params as $column => $value){
+            $query->where($column,$value);
+        }
+        return $query->update($values);
+    }
+
+    public function destroy($id)
+    {
+        return ProcessMethod::destroy($id);
+    }
+
 }

+ 4 - 0
app/Services/ShopService.php

@@ -9,6 +9,10 @@ use Carbon\Carbon;
 
 class ShopService
 {
+    public function getSelection(array $column = ['id', 'name'])
+    {
+        return Shop::query()->select($column)->get();
+    }
 
     function firstOrCreate(array $param, array $values = null){
         $shop = Shop::query();

+ 29 - 0
app/Services/UserOwnerGroupService.php

@@ -12,4 +12,33 @@ Class UserOwnerGroupService
         return UserOwnerGroup::query()->select($column)->get();
     }
 
+    public function paginate()
+    {
+        return UserOwnerGroup::query()->orderByDesc('id')->paginate(50);
+    }
+
+    public function create(array $params)
+    {
+        return UserOwnerGroup::query()->create($params);
+    }
+
+
+    public function find($id)
+    {
+        return UserOwnerGroup::query()->find($id);
+    }
+
+    public function update(array $params, array $values)
+    {
+        $query = UserOwnerGroup::query();
+        foreach ($params as $column => $value){
+            $query->where($column,$value);
+        }
+        return $query->update($values);
+    }
+
+    public function destroy($id)
+    {
+        return UserOwnerGroup::destroy($id);
+    }
 }

+ 0 - 5
app/User.php

@@ -2,16 +2,11 @@
 
 namespace App;
 
-use App\Services\UserService;
-use Carbon\Carbon;
 use Illuminate\Notifications\Notifiable;
-use Illuminate\Contracts\Auth\MustVerifyEmail;
 use Illuminate\Foundation\Auth\User as Authenticatable;
 use Illuminate\Support\Collection;
-use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\Gate;
-use Illuminate\Database\Eloquent\SoftDeletes;
 use App\Traits\ModelTimeFormat;
 
 class User extends Authenticatable

+ 13 - 0
database/factories/LogisticFactory.php

@@ -0,0 +1,13 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\Logistic;
+use Faker\Generator as Faker;
+
+$factory->define(Logistic::class, function (Faker $faker) {
+    return [
+        'name' => $faker->name,
+        'code' => \Illuminate\Support\Str::random(8),
+    ];
+});

+ 27 - 0
database/factories/OrderTrackingFactory.php

@@ -0,0 +1,27 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use Faker\Generator as Faker;
+
+$factory->define(\App\OrderTracking::class, function (Faker $faker) {
+    return [
+        'order_package_commodity_id' => rand(10,100),
+        'owner_id' => rand(0,10),
+        'web_order_number'=>$faker->uuid,
+        'pick_up_at' =>$faker->dateTime(),
+        'sale' => $faker->name,
+        'client' => $faker->name,
+        'order_client_code' => $faker->uuid,
+        'order_remark' => $faker->text(10),
+        'pallet_total' => $faker->numberBetween(0,10),
+        'planning_sent_at'=>$faker->dateTimeBetween('-100 hour','now'),
+        'is_on_duty_shift'=>['是','否',null][rand(0,1)],
+        'is_arrival'=>['是','否',null][rand(0,1)],
+        'signed_at' => null,
+        'receive_bill_status'=>null,
+        'remark' => $faker->text(10),
+        'gross_weight'=>$faker->numberBetween(0,10),
+        'bulk' => $faker->numberBetween(0,10)
+    ];
+});

+ 3 - 3
database/factories/OwnerBillReportFactory.php

@@ -4,9 +4,9 @@
 
 use App\OwnerBillReport;
 use Faker\Generator as Faker;
-
-$factory->define(OwnerBillReport::class, function (Faker $faker) {
-    $owner = \App\Owner::query()->whereNotNull("user_owner_group_id")->first();
+$owner = \App\Owner::query()->whereNotNull("user_owner_group_id")->first();
+$factory->define(OwnerBillReport::class, function (Faker $faker)use(&$owner) {
+    if (!$owner)$owner = \App\Owner::query()->whereNotNull("user_owner_group_id")->first();
     $initial_fee = mt_rand(0,50000) / 10;
     $confirm_fee = mt_rand(0,50000) / 10;
     return [

+ 39 - 0
database/factories/OwnerFeeDetailFactory.php

@@ -0,0 +1,39 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\OwnerFeeDetail;
+use Faker\Generator as Faker;
+
+$owner = \App\Owner::query()->whereNotNull('customer_id')->first();
+if ($owner)$shop = \App\Shop::query()->where("owner_id",$owner->id)->first();
+else $shop = null;
+$logistic = \App\Logistic::query()->first();
+$method = \App\ProcessMethod::query()->first();
+$factory->define(OwnerFeeDetail::class, function (Faker $faker)use(&$owner,&$shop,&$logistic,&$method) {
+    if (!$owner)$owner = \App\Owner::query()->whereNotNull('customer_id')->first();
+    if (!$shop){
+        if ($owner)$shop = \App\Shop::query()->where("owner_id",$owner->id)->first();
+        else $shop = null;
+    }
+    if (!$logistic) $logistic = \App\Logistic::query()->first();
+    if (!$method)$method = \App\ProcessMethod::query()->first();
+    $type = ["发货","收货","增值服务"];
+    return [
+        "owner_id"          => $owner ? $owner->id : factory(\App\Owner::class),         //货主ID
+        "worked_at"         => $faker->date(),//作业时间
+        "type"              =>$type[array_rand($type)],//类型
+        "shop_id"           =>$shop ? $shop->id : factory(\App\Shop::class),//店铺ID
+        "operation_bill"    => \Illuminate\Support\Str::random(10),//发/收/退/提货单号
+        "consignee_name"    => $faker->name,   //收件人
+        "consignee_phone"   =>$faker->phoneNumber,  //收件人电话
+        "commodity_amount"  =>mt_rand(0,100), //商品数量
+        "logistic_bill"     =>\Illuminate\Support\Str::random(12),    //快递单号
+        "volume"            =>mt_rand(10,2600) / 88,//体积
+        "weight"            =>mt_rand(10,2600) / 88,           //重量
+        "logistic_id"       =>$logistic ? $logistic->id : factory(\App\Logistic::class),      //物流ID
+        "process_method_id" =>$method ? $method->id : factory(\App\ProcessMethod::class),//加工类型ID
+        "work_fee"          =>mt_rand(100,10000) / 10,         //作业费
+        "logistic_fee"      =>mt_rand(100,10000) / 10,     //物流费
+    ];
+});

+ 17 - 0
database/factories/OwnerInStorageRuleFactory.php

@@ -0,0 +1,17 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\OwnerInStorageRule;
+use Faker\Generator as Faker;
+
+$unit = \App\Unit::query()->first();
+$factory->define(OwnerInStorageRule::class, function (Faker $faker)use(&$unit){
+    if (!$unit)$unit = \App\Unit::query()->first();
+    return [
+        "owner_price_operation_id"  => factory(\App\OwnerPriceOperation::class), //作业计费ID
+        "amount"                    => mt_rand(0,100),                   //计量
+        "unit_id"                   => $unit ? $unit->id : factory(\App\Unit::class),//单位ID
+        "unit_price"                =>mt_rand(10,100) / 16,               //单价
+    ];
+});

+ 20 - 0
database/factories/OwnerOutStorageRuleFactory.php

@@ -0,0 +1,20 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\OwnerOutStorageRule;
+use Faker\Generator as Faker;
+
+$unit = \App\Unit::query()->first();
+$factory->define(OwnerOutStorageRule::class, function (Faker $faker)use(&$unit) {
+    if (!$unit)$unit = \App\Unit::query()->first();
+    $strategy = ['默认','特征'];
+    return [
+        "owner_price_operation_id"          => factory(\App\OwnerPriceOperation::class),         //作业计费ID
+        "strategy"                          =>$strategy[array_rand($strategy)],         //策略
+        "amount"                            =>mt_rand(0,100),                           //起步数
+        "unit_id"                           => $unit ? $unit->id : factory(\App\Unit::class),//单位ID
+        "unit_price"                        =>mt_rand(10,100) / 12,                       //单价
+        "feature"                           =>\Illuminate\Support\Str::random(6),                          //特征
+    ];
+});

+ 16 - 0
database/factories/OwnerPriceExpressFactory.php

@@ -0,0 +1,16 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\OwnerPriceExpress;
+use Faker\Generator as Faker;
+
+$unit = \App\Unit::query()->first();
+$factory->define(OwnerPriceExpress::class, function (Faker $faker)use(&$unit) {
+    if (!$unit)$unit = \App\Unit::query()->first();
+    return [
+        "name" => $faker->name,                     //名称
+        "initial_weight_unit_id" => $unit ? $unit->id : factory(\App\Unit::class),   //首重单位
+        "additional_weight_unit_id" => $unit ? $unit->id : factory(\App\Unit::class),//续重单位
+    ];
+});

+ 17 - 0
database/factories/OwnerPriceOperationFactory.php

@@ -0,0 +1,17 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\OwnerPriceOperation;
+use Faker\Generator as Faker;
+$factory->define(OwnerPriceOperation::class, function (Faker $faker) {
+    $operation_type = ['入库','出库'];
+    $strategy = ['默认','特征'];
+    return [
+        "operation_type"=>$operation_type[array_rand($operation_type)],   //操作类型
+        "name"          =>$faker->name,             //名称
+        "strategy"      =>$strategy[array_rand($strategy)],         //策略
+        "feature"       =>\Illuminate\Support\Str::random(10),          //特征
+        "remark"        =>$faker->text,           //备注
+    ];
+});

+ 22 - 0
database/factories/OwnerStoragePriceModelFactory.php

@@ -0,0 +1,22 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\OwnerStoragePriceModel;
+use Faker\Generator as Faker;
+$unit = \App\Unit::query()->first();
+$factory->define(OwnerStoragePriceModel::class, function (Faker $faker) use(&$unit){
+    if (!$unit) $unit = \App\Unit::query()->first();
+    $counting_type = ['包仓','灵活用仓','统单价'];
+    $using_type = ['常温','恒温'];
+    $discount_type = ['无减免','按单减免','固定减免'];
+    return [
+        "counting_type" => $counting_type[array_rand($counting_type)],    //计费类型
+        "using_type" => $using_type[array_rand($using_type)],       //用仓类型
+        "minimum_area" => mt_rand(100,1000) / 50,     //最低起租面积
+        "price" => mt_rand(1,20) / 10,            //单价
+        "discount_type" => $discount_type[array_rand($discount_type)],    //减免类型
+        "discount_value" => mt_rand(0,10) / 12,   //减免值
+        "unit_id" => $unit ? $unit->id : factory(\App\Unit::class),          //单位ID
+    ];
+});

+ 16 - 0
database/factories/ProcessMethodFactory.php

@@ -0,0 +1,16 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\ProcessMethod;
+use Faker\Generator as Faker;
+
+$unit = \App\Unit::query()->first();
+$factory->define(ProcessMethod::class, function (Faker $faker)use(&$unit) {
+    if (!$unit)$unit = \App\Unit::query()->first();
+    return [
+        'name' => $faker->name,
+        "unit_id" => $unit ? $unit->id : factory(\App\Unit::class),
+        "unit_price" => mt_rand(10,50) / 9,
+    ];
+});

+ 15 - 0
database/factories/ShopFactory.php

@@ -0,0 +1,15 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\Shop;
+use Faker\Generator as Faker;
+
+$owner = \App\Owner::query()->whereNotNull('customer_id')->first();
+$factory->define(Shop::class, function (Faker $faker)use(&$owner) {
+    if (!$owner) $owner = \App\Owner::query()->whereNotNull('customer_id')->first();
+    return [
+        'name' => $faker->name,
+        'owner_id' => $owner ? $owner->id : factory(\App\Owner::class),
+    ];
+});

+ 12 - 0
database/factories/UnitFactory.php

@@ -0,0 +1,12 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\Unit;
+use Faker\Generator as Faker;
+
+$factory->define(Unit::class, function (Faker $faker) {
+    return [
+        'name' => $faker->name
+    ];
+});

+ 1 - 0
database/migrations/2020_10_20_143953_create_owner_reports_table.php

@@ -18,6 +18,7 @@ class CreateOwnerReportsTable extends Migration
             $table->bigInteger('owner_id')->index()->comment('外键货主');
             $table->date('counting_month')->nullable()->comment('结算月');
             $table->decimal('daily_average_order_amount',11,2)->nullable()->comment('日均单量');
+            $table->integer('total')->nullable()->comment("结算月总单量");
             $table->decimal('current_month_counting_area',11,2)->nullable()->comment('结算月盘点面积');
             $table->decimal('last_month_counting_area',11,2)->nullable()->comment('结算月上月盘点面积');
             $table->bigInteger('owner_bill_report_id')->nullable()->index()->comment('账单');

+ 2 - 0
database/migrations/2020_10_26_142753_create_owner_area_reports_table.php

@@ -17,11 +17,13 @@ class CreateOwnerAreaReportsTable extends Migration
             $table->id();
             $table->bigInteger('owner_id')->index()->comment('外键货主');
             $table->date('counting_month')->index()->comment('结算月');
+            $table->bigInteger('user_owner_group_id')->index()->nullable()->comment('项目组');
             $table->decimal('area_on_tray',8,2)->nullable()->comment('货物整托');
             $table->decimal('area_on_half_tray',8,2)->nullable()->comment('货物半托');
             $table->decimal('area_on_flat',8,2)->nullable()->comment('平面区面积');
             $table->decimal('accounting_area',8,2)->nullable()->comment('结算面积');
             $table->enum('status',['编辑中','已完成'])->default('编辑中')->comment('状态');
+            $table->bigInteger("owner_storage_price_model_id")->index()->comment("关联仓储计费标准");
             $table->timestamps();
         });
     }

+ 0 - 1
database/migrations/2020_10_26_165012_create_owner_fee_details_table.php

@@ -16,7 +16,6 @@ class CreateOwnerFeeDetailsTable extends Migration
         Schema::create('owner_fee_details', function (Blueprint $table) {
             $table->id();
             $table->bigInteger('owner_id')->index()->comment('外键货主');
-            $table->date('counting_month')->index()->comment('结算月');
             $table->date('worked_at')->index()->comment('作业时间');
             $table->enum('type',["发货","收货","增值服务"])->index()->comment('类型');
             $table->bigInteger('shop_id')->nullable()->index()->comment('外键店铺');

+ 1 - 0
database/migrations/2020_10_27_103741_create_owner_bill_reports_table.php

@@ -14,6 +14,7 @@ class CreateOwnerBillReportsTable extends Migration
     public function up()
     {
         Schema::create('owner_bill_reports', function (Blueprint $table) {
+            $table->engine = 'InnoDB';
             $table->id();
             $table->bigInteger('owner_id')->index()->comment('外键项目');
             $table->date('counting_month')->index()->comment('结算月');

+ 2 - 2
database/migrations/2020_10_27_142647_create_owner_storage_price_model_table.php

@@ -13,7 +13,7 @@ class CreateOwnerStoragePriceModelTable extends Migration
      */
     public function up()
     {
-        Schema::create('owner_storage_price_model', function (Blueprint $table) {
+        Schema::create('owner_storage_price_models', function (Blueprint $table) {
             $table->id();
             $table->enum("counting_type",["包仓","灵活用仓","统单价"])->default("灵活用仓")->comment('计费类型');
             $table->enum("using_type",["常温","恒温"])->default("常温")->comment('用仓类型');
@@ -33,6 +33,6 @@ class CreateOwnerStoragePriceModelTable extends Migration
      */
     public function down()
     {
-        Schema::dropIfExists('owner_storage_price_model');
+        Schema::dropIfExists('owner_storage_price_models');
     }
 }

+ 1 - 0
database/migrations/2020_10_27_175452_create_owner_price_operations_table.php

@@ -18,6 +18,7 @@ class CreateOwnerPriceOperationsTable extends Migration
             $table->enum("operation_type",["入库","出库"])->default("入库")->comment("操作类型");
             $table->string("name")->nullable()->comment("名称");
             $table->enum("strategy",["默认","特征"])->default("默认")->comment("策略");
+            $table->integer("priority")->default(0)->index()->comment("匹配优先级(越大越优先)");
             $table->string("feature")->nullable()->comment("特征");
             $table->string("remark")->nullable()->comment("备注");
             $table->timestamps();

+ 3 - 2
database/migrations/2020_10_28_105613_create_owner_out_storage_rules_table.php

@@ -14,13 +14,14 @@ class CreateOwnerOutStorageRulesTable extends Migration
     public function up()
     {
         Schema::create('owner_out_storage_rules', function (Blueprint $table) {
-            $table->bigInteger("owner_price_operation_id")->comment("外键作业计费模型");
-            $table->enum("owner_price_operation_strategy",["默认","特征"])->comment("作业计费模型策略");
+            $table->id();
+            $table->bigInteger("owner_price_operation_id")->index()->comment("外键作业计费模型");
             $table->enum("strategy",["起步","默认","特征"])->comment("出库策略");
             $table->integer("amount")->nullable()->comment("起步数");
             $table->bigInteger("unit_id")->index()->comment("外键单位");
             $table->decimal("unit_price",8,4)->comment("单价");
             $table->string("feature")->nullable()->comment("特征");
+            $table->integer("priority")->default(0)->index()->comment("匹配优先级(越大越优先)");
         });
     }
 

+ 2 - 1
database/migrations/2020_10_28_105639_create_owner_in_storage_rules_table.php

@@ -14,7 +14,8 @@ class CreateOwnerInStorageRulesTable extends Migration
     public function up()
     {
         Schema::create('owner_in_storage_rules', function (Blueprint $table) {
-            $table->bigInteger("owner_price_operation_id")->primary()->comment("外键作业计费模型");
+            $table->id();
+            $table->bigInteger("owner_price_operation_id")->index()->comment("外键作业计费模型");
             $table->integer("amount")->default(1)->comment("计量");
             $table->bigInteger("unit_id")->index()->comment("外键单位");
             $table->decimal("unit_price",8,4)->comment("单价");

+ 2 - 2
database/migrations/2020_10_28_162458_create_owner_price_expresses_table.php

@@ -16,8 +16,8 @@ class CreateOwnerPriceExpressesTable extends Migration
         Schema::create('owner_price_expresses', function (Blueprint $table) {
             $table->id();
             $table->string("name")->comment("价格名称");
-            $table->bigInteger("initial_weight_unit_id")->index()->comment("首重单位");
-            $table->bigInteger("additional_weight_unit_id")->index()->comment("续重单位");
+            $table->decimal("initial_weight")->comment("首重");
+            $table->decimal("additional_weight")->comment("续重");
             $table->timestamps();
         });
     }

+ 20 - 0
database/migrations/2020_10_28_170858_save_customer_authority_data.php

@@ -12,34 +12,54 @@ class SaveCustomerAuthorityData extends Migration
         '客户管理-项目-查询',
         '客户管理-项目-录入',
         '客户管理-项目-面积',
+        '客户管理-项目-面积-编辑',
+        '客户管理-项目-编辑',
         '客户管理-财务-即时账单',
         '客户管理-财务-账单确认',
+        '客户管理-财务-账单确认-编辑',
+        '客户管理-财务-账单确认-完结',
         '计费模型-仓储',
         '计费模型-仓储-录入',
+        '计费模型-仓储-编辑',
+        '计费模型-仓储-删除',
         '客户',
         '客户-查询',
         '客户-录入',
+        '客户-编辑',
+        '客户-删除',
         '项目组',
         '项目组-查询',
         '项目组-录入',
+        '项目组-编辑',
+        '项目组-删除',
         '作业类型',
         '作业类型-查询',
         '作业类型-录入',
+        '作业类型-编辑',
+        '作业类型-删除',
         '特征',
         '特征-录入',
         '特征-查询',
         '计费模型-作业',
         '计费模型-作业-查询',
         '计费模型-作业-录入',
+        '计费模型-作业-编辑',
+        '计费模型-作业-删除',
         '计费模型-快递',
         '计费模型-快递-查询',
         '计费模型-快递-录入',
+        '计费模型-快递-编辑',
+        '计费模型-快递-删除',
         '计费模型-物流',
         '计费模型-物流-查询',
         '计费模型-物流-录入',
+        '计费模型-物流-编辑',
+        '计费模型-物流-删除',
         '计费模型-直发',
         '计费模型-直发-查询',
         '计费模型-直发-录入',
+        '计费模型-直发-编辑',
+        '计费模型-直发-删除',
     ];
     /**
      * Run the migrations.

+ 31 - 0
database/migrations/2020_11_02_095633_create_owner_storage_price_model_owner_table.php

@@ -0,0 +1,31 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOwnerStoragePriceModelOwnerTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('owner_storage_price_model_owner', function (Blueprint $table) {
+            $table->bigInteger("owner_storage_price_model_id")->comment("外键仓储计费");
+            $table->bigInteger("owner_id")->comment("外键货主");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('owner_storage_price_model_owner');
+    }
+}

+ 31 - 0
database/migrations/2020_11_03_095611_create_owner_price_operation_owner_table.php

@@ -0,0 +1,31 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOwnerPriceOperationOwnerTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('owner_price_operation_owner', function (Blueprint $table) {
+            $table->bigInteger("owner_price_operation_id")->comment("外键作业价格");
+            $table->bigInteger("owner_id")->comment("外键货主");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('owner_price_operation_owner');
+    }
+}

+ 31 - 0
database/migrations/2020_11_03_101827_create_owner_price_direct_logistic_owner_table.php

@@ -0,0 +1,31 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOwnerPriceDirectLogisticOwnerTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('owner_price_direct_logistic_owner', function (Blueprint $table) {
+            $table->bigInteger("owner_price_direct_logistic_id")->comment("外键直发车价格");
+            $table->bigInteger("owner_id")->comment("外键货主");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('owner_price_direct_logistic_owner');
+    }
+}

+ 32 - 0
database/migrations/2020_11_17_170541_add_column_pack_commodities_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddColumnPackCommoditiesTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('commodities', function (Blueprint $table) {
+            $table->integer("pack")->nullable()->comment("包装规格");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('commodities', function (Blueprint $table) {
+            $table->dropColumn("pack");
+        });
+    }
+}

+ 32 - 0
database/migrations/2020_11_18_111612_add_signed_at_index_to_order_trackings.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddSignedAtIndexToOrderTrackings extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('order_trackings', function (Blueprint $table) {
+            $table->index('signed_at','order_trackings_signed_at_index');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('order_trackings', function (Blueprint $table) {
+            $table->dropIndex('order_trackings_signed_at_index');
+        });
+    }
+}

+ 36 - 0
database/migrations/2020_11_18_142512_add_finance_confirm_to_order_issue_and_add_auth.php

@@ -0,0 +1,36 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddFinanceConfirmToOrderIssueAndAddAuth extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('order_issues', function (Blueprint $table) {
+            //
+            $table->enum('finance_confirm',['是','否'])->default('否')->after('rejecting_status')->comment('财务确认');
+        });
+        \App\Authority::query()->create(['name'=>'订单管理-问题件-财务确认','alias_name'=>'订单管理-问题件-财务确认']);
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('order_issues', function (Blueprint $table) {
+            //
+            $table->dropColumn('finance_confirm');
+        });
+        \App\Authority::query()->where('name','订单管理-问题件-财务确认')->delete();
+    }
+}

+ 32 - 0
database/migrations/2020_11_19_100831_add_hidden_tag_to_order_issues.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddHiddenTagToOrderIssues extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('order_issues', function (Blueprint $table) {
+            $table->string('hidden_tag')->nullable()->index()->comment('隐藏标识');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('order_issues', function (Blueprint $table) {
+            $table->dropColumn('hidden_tag');
+        });
+    }
+}

+ 38 - 0
database/migrations/2020_11_19_113953_change_order_issue_auth.php

@@ -0,0 +1,38 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class ChangeOrderIssueAuth extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        \App\Authority::query()->create(['name'=>'订单管理-问题件-导入','alias_name'=>'订单管理-问题件-导入']);
+
+        \App\Authority::query()->create(['name'=>'订单管理-订单-生成问题件','alias_name'=>'订单管理-订单-生成问题件']);
+
+        \App\Authority::query()->where('name','订单管理-订单问题件生成-文本导入')
+            ->update(['name'=>'订单管理-问题件-导入-Excel导入','alias_name'=>'订单管理-问题件-导入-Excel导入']);
+
+        \App\Authority::query()->create(['name'=>'订单管理-问题件-导入-文本导入','alias_name'=>'订单管理-问题件-导入-文本导入']);
+
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        \App\Authority::query()->whereIn('name',['订单管理-订单-生成问题件','订单管理-问题件-导入-文本导入','订单管理-问题件-导入'])->delete();
+        \App\Authority::query()->where('name','订单管理-问题件-导入-Excel导入')
+            ->update(['name'=>'订单管理-订单问题件生成-文本导入','alias_name'=>'订单管理-订单问题件生成-文本导入']);
+    }
+}

+ 4 - 5
database/migrations/2020_06_18_111452_create_job_types_table.php → database/migrations/2020_11_19_113955_change_order_issue_type_id_index.php

@@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration;
 use Illuminate\Database\Schema\Blueprint;
 use Illuminate\Support\Facades\Schema;
 
-class CreateJobTypesTable extends Migration
+class ChangeOrderIssueTypeIdIndex extends Migration
 {
     /**
      * Run the migrations.
@@ -13,9 +13,8 @@ class CreateJobTypesTable extends Migration
      */
     public function up()
     {
-        Schema::create('job_types', function (Blueprint $table) {
-            $table->id();
-            $table->timestamps();
+        Schema::table('order_issues', function (Blueprint $table) {
+            $table->string('order_issue_type_id')->index()->change();
         });
     }
 
@@ -26,6 +25,6 @@ class CreateJobTypesTable extends Migration
      */
     public function down()
     {
-        Schema::dropIfExists('job_types');
+        Schema::dropIfExists('order_issues');
     }
 }

+ 4 - 1
database/seeds/DatabaseSeeder.php

@@ -11,9 +11,12 @@ class DatabaseSeeder extends Seeder
      */
     public function run()
     {
-        // $this->call(UsersTableSeeder::class);
         $this->call([
             OwnerReportSeeder::class,
+            OwnerStoragePriceModelSeeder::class,
+            OwnerFeeDetailSeeder::class,
+            OwnerPriceOperationSeeder::class,
+            OwnerPriceExpressSeeder::class
         ]);
     }
 }

Some files were not shown because too many files changed in this diff