cqp 1 nedēļu atpakaļ
vecāks
revīzija
bf9ff2819a

+ 24 - 0
app/Http/Controllers/Api/StatisticsController.php

@@ -90,4 +90,28 @@ class StatisticsController extends BaseController
             return $this->json_return(201,$data);
         }
     }
+
+    public function statisticsFreightFee(Request $request){
+        $service = new StatisticsService();
+        $userData = $request->userData->toArray();
+        list($status,$data) = $service->statisticsFreightFee($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function statisticsFreightFeeDetail(Request $request){
+        $service = new StatisticsService();
+        $userData = $request->userData->toArray();
+        list($status,$data) = $service->statisticsFreightFeeDetail($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
 }

+ 16 - 0
app/Http/Controllers/Api/TPlusController.php

@@ -54,4 +54,20 @@ class TPlusController extends BaseController
             return $this->json_return(201,$data);
         }
     }
+
+    public function synFreightFee(Request $request)
+    {
+        $service = new TPlusServerService();
+        $error = $service->getError();
+        if(! empty($error)) return $this->json_return(201, $error);
+
+        $userData = $request->userData->toArray();
+        list($status,$data) = $service->synFreightFee($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
 }

+ 4 - 2
app/Jobs/ProcessDataJob.php

@@ -43,8 +43,10 @@ class ProcessDataJob implements ShouldQueue
             if($type == 1){
                 //收付款单
                 list($status, $msg) = $service->synRevenueCostFromTPlus($data, $user);
-            }else{
+            }elseif($type == 2){
                 list($status, $msg) = $service->synSalaryEmployeeFromMine($data, $user);
+            }else{
+                list($status, $msg) = $service->synFreightFeeFromMine($data, $user);
             }
 
             $this->finalDo($msg, $service);
@@ -57,7 +59,7 @@ class ProcessDataJob implements ShouldQueue
     private function finalDo($msg, $service){
         $type = $this->type;
         $service->delTableKey($type);
-        if($type == 1) $service->clearTmpTable();
+        $service->clearTmpTable($type);
 
         $user = $this->user;
         $data = $this->data;

+ 20 - 0
app/Model/FreightFee.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Model;
+
+class FreightFee extends UseScopeBaseModel
+{
+    protected $table = "freight_fee"; //指定表
+    const CREATED_AT = 'crt_time';
+    const UPDATED_AT = 'upd_time';
+    protected $dateFormat = 'U';
+
+    const businessTypeNormal = 65;
+    const businessTypeReturn = 66;
+    const deliveryModeNormal = 70519;
+    const deliveryModeRightNow = 70536;
+
+    const employee_column = 'employee_id_1';
+
+    public static $field = ['order_time','id'];
+}

+ 1 - 0
app/Model/RevenueCost.php

@@ -23,6 +23,7 @@ class RevenueCost extends UseScopeBaseModel
 
     const job = 'yf_revenue_cost';
     const job2 = 'salary_employee';
+    const job3 = 'freight_fee';
 
     public static $field = ['id','order_time','order_type','price_1','price_1_total','price_2','price_2_total','price_3','price_3_total','price_4','price_4_total','payment_amount','profit','profit_rate','employee_id_1','employee_id_1_title'];
     public static $field_xhd = ['id','order_type','order_number','order_time','employee_id_1','employee_id_1_title','employee_id_2','employee_id_2_title','customer_code','customer_title','channel_finance','channel_details','product_code','product_title','product_size','unit','price_1','price_1_total','price_2','price_2_total','quantity','price_3','price_3_total','price_4','price_4_total','profit','profit_rate'];

+ 10 - 0
app/Service/ExportFileService.php

@@ -420,6 +420,11 @@ class ExportFileService extends Service
                 $this->fillData($list['data'], $column, $return);
             });
 
+        //合计
+        $total = $this->countTotal($return, $header_default);
+        //填充合计
+        $this->fillTotalData($total, $header_default, $return);
+
         return $this->saveExportData($return,$header);
     }
 
@@ -461,6 +466,11 @@ class ExportFileService extends Service
                 $this->fillData($list['data'], $column, $return);
             });
 
+        //合计
+        $total = $this->countTotal($return, $header_default);
+        //填充合计
+        $this->fillTotalData($total, $header_default, $return);
+
         return $this->saveExportData($return,$header);
     }
 

+ 271 - 0
app/Service/StatisticsService.php

@@ -3,6 +3,7 @@
 namespace App\Service;
 
 use App\Model\EmployeeIndex;
+use App\Model\FreightFee;
 use App\Model\GiveOut;
 use App\Model\RevenueCost;
 use App\Model\RevenueCostTotal;
@@ -251,6 +252,8 @@ class StatisticsService extends Service
         $list = $this->limit($model,'',$data);
         $list = $this->statisticsProfitFillData($list);
 
+        $list['count'] = $this->countTotal($list['data'], $user['header_default']);
+
         return [true, $list];
     }
 
@@ -421,6 +424,8 @@ class StatisticsService extends Service
         $list = $this->limit($model,'',$data);
         $list = $this->statisticsEmployeeSalaryFillData($list);
 
+        $list['count'] = $this->countTotal($list['data'], $user['header_default']);
+
         return [true, $list];
     }
 
@@ -434,4 +439,270 @@ class StatisticsService extends Service
 
         return $data;
     }
+
+    public function statisticsFreightFeeCommon($data,$user, $field = []){
+        if(empty($field)) {
+            $field = FreightFee::$field;
+            $field[] = DB::raw('GROUP_CONCAT(id) as result');
+        }
+        $model = FreightFee::Clear($user,$data);
+
+        $model = $model->where('del_time',0)
+            ->select($field)
+            ->groupby('order_time')
+            ->orderby('order_time', 'desc');
+        if(! empty($data['order_time'][0]) && ! empty($data['order_time'][1])){
+            list($start_time, $end_time) = $this->changeDateToTimeStampAboutRange($data['order_time'],false);
+            if ($start_time === null || $end_time === null || $start_time > $end_time) return [false, "单据日期的区间无效"];
+            $model->where('order_time', '>=', $start_time)
+                ->where('order_time', '<=', $end_time);
+        }
+        if(! empty($data['employee_id_1_title'])) $model->where('employee_id_1_title', 'LIKE', '%'.$data['employee_id_1_title'].'%');
+
+        return [true, $model];
+    }
+
+    public function statisticsFreightFee($data,$user){
+        list($status, $model) = $this->statisticsFreightFeeCommon($data, $user);
+        if(! $status) return [false, $model];
+        $list = $this->limit($model,'',$data);
+        $list = $this->statisticsFreightFeeFillData($list);
+
+        $list['count'] = $this->countTotal($list['data'], $user['header_default']);
+
+        return [true, $list];
+    }
+
+    public function statisticsFreightFeeFillData($data){
+        if(empty($data['data'])) return $data;
+
+        $id = implode(',', array_column($data['data'], 'result'));
+        $idArr = explode(',', $id);
+        $allFees = FreightFee::where('del_time', 0)
+            ->whereIn('id', $idArr)
+            ->get()
+            ->toArray();
+        $feesByDay = [];
+        foreach ($allFees as $f) {
+            $feesByDay[$f['order_time']][] = $f;
+        }
+
+        foreach ($data['data'] as $key => $value) {
+            $fees = $feesByDay[$value['order_time']] ?? [];
+            if (empty($fees)) {
+                $data['data'][$key]['total_amount'] = 0;
+                continue;
+            }
+
+            // 准备 time_amount(和详情逻辑一致)
+            $time_amount = [];
+            foreach ($fees as $f) {
+                if ($f['business_type_id'] == FreightFee::businessTypeNormal) {
+                    $k = $f['order_time'] . $f['area_hs'];
+                    $time_amount[$k]['amount'] = isset($time_amount[$k]['amount'])
+                        ? bcadd($f['freight_amount'], $time_amount[$k]['amount'], 2)
+                        : $f['freight_amount'];
+                    $time_amount[$k]['is_use'] = $time_amount[$k]['is_use'] ?? 0;
+                }
+            }
+
+            // 逐条算金额
+            $valueTotal = 0;
+            foreach ($fees as $f) {
+                $f = $this->calculateFreightFeeRow($f, $time_amount);
+                $valueTotal = bcadd($valueTotal, $f['total_amount'], 2);
+            }
+
+            $data['data'][$key]['total_amount'] = $valueTotal;
+
+            $order_time = $value['order_time'] ? date('Y-m-d',$value['order_time']) : '';
+            $data['data'][$key]['order_time_show'] = $order_time;
+            unset($data['data'][$key]['result']);
+        }
+
+        return $data;
+    }
+
+//    public function statisticsFreightFeeDetail($data, $user){
+//        if(empty($data['order_time'])) return [false, '单据日期不能为空'];
+//
+//        $fee = FreightFee::where('del_time',0)
+//            ->where('order_time', $data['order_time'])
+//            ->get()->toArray();
+//        if(empty($fee)) return [false, '单据日期下暂无数据'];
+//
+//        //同一天 同一个地区 非退货的配送费总金额
+//        $time_amount = [];
+//        foreach ($fee as $value){
+//            if($value['business_type_id'] == FreightFee::businessTypeNormal){
+//                $key = $value['order_time'] . $value['area_hs'];
+//                if(isset($time_amount[$key])){
+//                    $freight_amount = bcadd($value['freight_amount'], $time_amount[$key]['amount'],2);
+//                    $time_amount[$key]['amount'] = $freight_amount;
+//                }else{
+//                    $time_amount[$key] = [
+//                        'is_use' => 0,
+//                        'amount' => $value['freight_amount'],
+//                    ];
+//                }
+//            }
+//        }
+//
+//        $return = [];
+//        foreach ($fee as $value){
+//            //结算金额
+//            $js_amount = 0;
+//            $key = $value['order_time'] . $value['area_hs'];
+//            if($value['business_type_id'] == FreightFee::businessTypeNormal){
+//                $tmp_total_arr = $time_amount[$key];
+//                if($tmp_total_arr['amount'] < $value['min_freight_amount']){
+//                    if(! $time_amount[$key]['is_use']){
+//                        $js_amount = $value['min_freight_amount'];
+//                        $time_amount[$key]['is_use'] = 1;
+//                    }
+//                }else{
+//                    $js_amount = $value['js_single_amount'];
+//                }
+//                $value['js_amount'] = $js_amount;
+//                //加急费
+//                $jj_fee = 0;
+//                if($value['delivery_mode'] == FreightFee::deliveryModeRightNow) $jj_fee = bcmul($js_amount, 0.5,2);
+//                $value['jj_fee'] = $jj_fee;
+//                //总金额
+//                $total_amount = bcadd($js_amount,$value['customer_store_zx_fee'],2);
+//                $total_amount = bcadd($total_amount,$value['sl_fee'],2);
+//                $total_amount = bcadd($total_amount,$jj_fee,2);
+//                $total_amount = bcadd($total_amount,$value['dh_fee'],2);
+//                $value['total_amount'] = $total_amount;
+//                $return[FreightFee::businessTypeNormal][$key][] = $value;
+//            }else{
+//                $js_amount = $value['js_single_amount'];
+//                $value['js_amount'] = $js_amount;
+//                $jj_fee = 0;
+//                if($value['delivery_mode'] == FreightFee::deliveryModeRightNow) $jj_fee = bcmul($js_amount, 0.5,2);
+//                //加急费
+//                $value['jj_fee'] = $jj_fee;
+//                //总金额
+//                $total_amount = bcadd($js_amount,$value['customer_store_zx_fee'],2);
+//                $total_amount = bcadd($total_amount,$value['sl_fee'],2);
+//                $total_amount = bcadd($total_amount,$jj_fee,2);
+//                $total_amount = bcadd($total_amount,$value['dh_fee'],2);
+//                $value['total_amount'] = $total_amount;
+//                $return[FreightFee::businessTypeReturn][$key][] = $value;
+//            }
+//        }
+//
+//        $result = [];
+//        foreach ($return as $value){
+//            foreach (array_values($value) as $val){
+//                $result[] = $val;
+//            }
+//        }
+//        dd($result);
+//    }
+
+    public function statisticsFreightFeeDetail($data, $user)
+    {
+        if (empty($data['order_time'])) {
+            return [false, '单据日期不能为空'];
+        }
+
+        $model = FreightFee::Clear($user,$data);
+        $fee = $model->where('del_time', 0)
+            ->where('order_time', $data['order_time'])
+            ->get()
+            ->toArray();
+
+        if (empty($fee)) {
+            return [false, '单据日期下暂无数据'];
+        }
+
+        // 按时间+地区聚合同一天、同地区的非退货配送费
+        $time_amount = [];
+        foreach ($fee as $value) {
+            if ($value['business_type_id'] == FreightFee::businessTypeNormal) {
+                $key = $value['order_time'] . $value['area_hs'];
+                $time_amount[$key]['amount'] = isset($time_amount[$key]['amount'])
+                    ? bcadd($value['freight_amount'], $time_amount[$key]['amount'], 2)
+                    : $value['freight_amount'];
+                $time_amount[$key]['is_use'] = $time_amount[$key]['is_use'] ?? 0;
+            }
+        }
+
+        $return = [];
+        foreach ($fee as $value) {
+            $value = $this->calculateFreightFeeRow($value, $time_amount);
+            $key = $value['order_time'] . $value['area_hs'];
+            $return[$value['business_type_id']][$key][] = $value;
+        }
+
+        $result = [];
+        // 需要合计的字段
+        $sumFields = ['xs', 'weight', 'freight_amount', 'js_amount', 'customer_store_zx_fee', 'jj_fee', 'dh_fee', 'total_amount'];
+
+        foreach ($return as $group) {
+            foreach ($group as $val) {
+                // 计算合计
+                $sumRow = [];
+                foreach ($val as $row) {
+                    foreach ($sumFields as $field) {
+                        $sumRow[$field] = isset($sumRow[$field])
+                            ? bcadd($sumRow[$field], $row[$field], 2)
+                            : $row[$field];
+                    }
+                }
+
+                // 末行合计行(非合计字段设为空字符串)
+                $footer = [];
+                foreach ($val[0] as $field => $v) {
+                    $footer[$field] = in_array($field, $sumFields) ? $sumRow[$field] : '';
+                }
+
+                $val[] = $footer;
+                $result[] = $val;
+            }
+        }
+
+        return [true, $result];
+    }
+
+    protected function calculateFreightFeeRow(array $value, array &$time_amount)
+    {
+        $key = $value['order_time'] . $value['area_hs'];
+        $js_amount = 0;
+
+        if ($value['business_type_id'] == FreightFee::businessTypeNormal) {
+            $tmp_total_arr = $time_amount[$key];
+
+            // 判断是否使用最低运费
+            if ($tmp_total_arr['amount'] < $value['min_freight_amount']) {
+                if (!$time_amount[$key]['is_use']) {
+                    $js_amount = $value['min_freight_amount'];
+                    $time_amount[$key]['is_use'] = 1;
+                }
+            } else {
+                $js_amount = $value['js_single_amount'];
+            }
+        } else {
+            $js_amount = $value['js_single_amount'];
+        }
+
+        $value['js_amount'] = $js_amount;
+
+        // 加急费
+        $jj_fee = 0;
+        if ($value['delivery_mode'] == FreightFee::deliveryModeRightNow) {
+            $jj_fee = bcmul($js_amount, 0.5, 2);
+        }
+        $value['jj_fee'] = $jj_fee;
+
+        // 总金额
+        $total_amount = bcadd($js_amount, $value['customer_store_zx_fee'], 2);
+        $total_amount = bcadd($total_amount, $value['sl_fee'], 2);
+        $total_amount = bcadd($total_amount, $jj_fee, 2);
+        $total_amount = bcadd($total_amount, $value['dh_fee'], 2);
+        $value['total_amount'] = $total_amount;
+
+        return $value;
+    }
 }

+ 362 - 10
app/Service/TPlusServerService.php

@@ -7,6 +7,8 @@ use App\Model\Depart;
 use App\Model\Employee;
 use App\Model\EmployeeDepartPermission;
 use App\Model\EmployeeIndex;
+use App\Model\Freight;
+use App\Model\FreightFee;
 use App\Model\Product;
 use App\Model\RevenueCost;
 use App\Model\RevenueCostTotal;
@@ -49,6 +51,7 @@ class TPlusServerService extends Service
 
     private $table = "tmp_revenue_cost_data";
     private $table_2 = "tmp_salary_employee";
+    private $table_3 = "tmp_freight_fee";
 
     /**
      * 同步人员部门
@@ -187,8 +190,6 @@ class TPlusServerService extends Service
 //            //同步
 //            list($status, $msg) = $this->synRevenueCostFromTPlus($data, $user);
 //            if(! $status) {
-//                $this->clearTmpTable();
-//                $this->dellimitingSendRequest($this->table);
 //                return [false, $msg];
 //            }
 
@@ -785,13 +786,20 @@ class TPlusServerService extends Service
         }
     }
 
-    public function clearTmpTable(){
-        if (Schema::hasTable($this->table)) DB::table($this->table)->truncate();
+    public function clearTmpTable($type = 1){
+        if($type == 1){
+            if (Schema::hasTable($this->table)) DB::table($this->table)->truncate();
+        }elseif ($type == 2){
+            if (Schema::hasTable($this->table_2)) DB::table($this->table_2)->truncate();
+        }elseif ($type == 3){
+            if (Schema::hasTable($this->table_3)) DB::table($this->table_3)->truncate();
+        }
     }
 
     public function delTableKey($type = 1){
         $key = $this->table;
         if($type == 2) $key = $this->table_2;
+        if($type == 3) $key = $this->table_3;
         $this->dellimitingSendRequest($key);
     }
 
@@ -827,7 +835,7 @@ class TPlusServerService extends Service
         //创建临时表 如果不存在
         $this->createTmpTable2();
         //清理临时表 如果内容不为空
-        $this->clearTmpTable2();
+        $this->clearTmpTable(2);
 
         //写入临时表
         DB::table('revenue_cost')
@@ -884,7 +892,7 @@ class TPlusServerService extends Service
         if(! $status) return [false, $msg];
 
         //清理临时表 如果内容不为空
-        $this->clearTmpTable2();
+        $this->clearTmpTable(2);
         //释放redis
         $this->delTableKey(2);
 
@@ -958,10 +966,6 @@ class TPlusServerService extends Service
         }
     }
 
-    public function clearTmpTable2(){
-        if (Schema::hasTable($this->table_2)) DB::table($this->table_2)->truncate();
-    }
-
     private function updateSalaryEmployee($data){
         try {
             $start_timeStamp = $data['start_time'];
@@ -1026,4 +1030,352 @@ class TPlusServerService extends Service
 
         return [true, ''];
     }
+
+    public function synFreightFee($data, $user){
+        if(empty($data['crt_time'][0]) || empty($data['crt_time'][1])) return [false, '同步时间不能为空'];
+        list($start_time, $end_time) = $this->changeDateToTimeStampAboutRange($data['crt_time'],false);
+        if ($start_time === null || $end_time === null || $start_time > $end_time) return [false, "同步时间:时间区间无效"];
+        list($bool, $bool_msg) = $this->isOverThreeMonths($start_time, $end_time);
+        if(! $bool) return [false, $bool_msg];
+        $data['start_timeStamp'] = $start_time;
+        $data['end_timeStamp'] = $end_time;
+        $start = date('Y-m-d H:i:s.000', $start_time);
+        $end = date('Y-m-d H:i:s.000', $end_time);
+        $data['start_time'] = $start;
+        $data['end_time'] = $end;
+        $data['operation_time'] = time();
+
+//        list($status, $msg) = $this->synFreightFeeFromMine($data, $user);dd(333);
+        list($status,$msg) = $this->limitingSendRequest($this->table_3);
+        if(! $status) return [false, '运费统计同步正在后台运行,请稍后'];
+
+        //同步
+//        list($status, $msg) = $this->synFreightFeeFromMine($data, $user);
+//        if(! $status) {
+//            $this->dellimitingSendRequest($this->table_3);
+//            return [false, $msg];
+//        }
+
+        //队列
+        ProcessDataJob::dispatch($data, $user, 3)->onQueue(RevenueCost::job3);
+
+        return [true, '运费统计同步已进入后台任务'];
+    }
+
+    public function synFreightFeeFromMine($data, $user){
+        //创建临时表 如果不存在
+        $this->createTmpTable3();
+        //清理临时表 如果内容不为空
+        $this->clearTmpTable(3);
+
+        //生成临时数据
+        list($status, $msg) = $this->getFreightData($data);
+        if(! $status) return [false, $msg];
+
+        //写入
+        list($status, $msg) = $this->updateFreightFeeFromMine($data);
+        if(! $status) return [false, $msg];
+
+        //清理临时表 如果内容不为空
+        $this->clearTmpTable(3);
+        //释放redis
+        $this->delTableKey(3);
+
+        return [true, '同步成功'];
+    }
+
+    private function createTmpTable3(){
+        $table = $this->table_3;
+        if (! Schema::hasTable($table)) {
+            // 可以通过 migration 创建,或程序启动时检查
+            Schema::create($table, function (Blueprint $table) {
+                // 主键
+                $table->bigIncrements('id');
+                // 原始字段
+                $table->bigInteger('order_id')->default(0)->comment('订单ID');
+                $table->string('order_number')->default('')->comment('订单编号');
+                $table->dateTime('order_time')->nullable()->comment('订单时间');
+                $table->integer('order_state')->default(0)->comment('订单状态');
+                $table->string('employee_id_1_title')->default('')->comment('业务员1名称');
+                $table->bigInteger('employee_id_1')->default(0)->comment('业务员1 ID');
+                $table->string('employee_id_2_title')->default('')->comment('上级管理人员名称');
+                $table->bigInteger('employee_id_2')->default(0)->comment('上级管理人员ID');
+                $table->string('customer_code')->default('')->comment('客户编码');
+                $table->string('customer_title')->default('')->comment('客户名称');
+                $table->decimal('customer_store_price', 10, 2)->default(0)->comment('客户卸货费单价');
+                $table->string('product_code')->default('')->comment('产品编码');
+                $table->string('product_title')->default('')->comment('产品名称');
+                $table->string('product_size')->default('')->comment('产品规格');
+                $table->decimal('product_box_size', 10, 2)->default(0)->comment('装箱数');
+                $table->decimal('product_weight', 10, 3)->default(0)->comment('单件重量(kg)');
+                $table->decimal('product_store_price', 10, 2)->default(0)->comment('门店卸货费单价');
+                $table->decimal('product_store_price2', 10, 2)->default(0)->comment('到货装卸费单价');
+                $table->string('product_category')->default('')->comment('货类');
+                $table->string('unit')->default('')->comment('单位');
+                $table->decimal('quantity', 12, 3)->default(0)->comment('数量');
+                $table->decimal('price_3', 12, 2)->default(0)->comment('含税单价');
+                $table->decimal('price_3_total', 14, 2)->default(0)->comment('含税金额');
+                $table->bigInteger('id_detail')->default(0)->comment('明细ID');
+                $table->boolean('is_present')->default(false)->comment('是否赠品');
+                $table->string('mark')->default('')->comment('订单备注');
+                $table->string('item_mark')->default('')->comment('明细备注');
+                $table->bigInteger('warehouse_id')->default(0)->comment('仓库ID');
+                $table->string('warehouse_name')->default('')->comment('仓库名称');
+                $table->bigInteger('business_type_id')->default(0)->comment('业务类型ID');
+                $table->string('business_type_title')->default('')->comment('业务类型名称');
+                $table->string('address')->default('')->comment('送货地址');
+                $table->string('area_hs')->default('')->comment('区域');
+                $table->string('delivery_mode')->default('')->comment('配送方式');
+                $table->decimal('sl_fee', 10, 2)->default(0)->comment('其它费用');
+                // 新增的计算字段
+                $table->integer('xs')->default(0)->comment('箱数');
+                $table->decimal('weight', 12, 3)->default(0)->comment('总重量(kg)');
+                $table->tinyInteger('area_range')->default(1)->comment('运价区间 (1: <5kg, 2: >=5kg)');
+                $table->decimal('freight_unit_price', 10, 2)->default(0)->comment('配送费单价');
+                $table->decimal('freight_amount', 12, 2)->default(0)->comment('配送费金额');
+                $table->decimal('js_single_amount', 12, 2)->default(0)->comment('结算金额');
+                $table->decimal('min_freight_amount', 12, 2)->default(0)->comment('地区最低运价');
+                $table->decimal('customer_store_zx_fee', 12, 2)->default(0)->comment('门店卸货费');
+                $table->decimal('dh_fee', 12, 2)->default(0)->comment('到货装卸费');
+            });
+        }
+    }
+
+    private function getFreightData($data){
+        //写入临时表
+        try {
+            $table = $this->table_3;
+            $limit = 500;
+            $lastId = 0;
+
+            do {
+                $rows = $this->databaseService->table('SA_SaleDelivery_b as sd_b')
+                    ->join('SA_SaleDelivery as sd', 'sd_b.idSaleDeliveryDTO', '=', 'sd.ID')
+                    ->leftJoin('AA_Partner as pn', 'sd.idsettlecustomer', '=', 'pn.ID') // 结算客户
+                    ->leftJoin('AA_Person as ps', 'sd.idclerk', '=', 'ps.ID') // 业务员
+                    ->leftJoin('AA_Person as ps2', 'pn.idsaleman', '=', 'ps2.ID')
+                    ->leftJoin('AA_Inventory as it', 'sd_b.idinventory', '=', 'it.ID')
+                    ->leftJoin('AA_Unit as ui', 'sd_b.idbaseunit', '=', 'ui.ID')
+                    ->leftJoin('AA_Warehouse as wa', 'sd_b.idwarehouse', '=', 'wa.id')
+                    ->leftJoin('AA_Busitype as bs', 'sd.idbusinesstype', '=', 'bs.id')
+                    ->where('sd.voucherdate', '>=', $data['start_time'])
+                    ->where('sd.voucherdate', '<=', $data['end_time'])
+                    ->where('sd.voucherState', '=', 189) //181  未审核   189  已审核
+                    ->where('sd_b.ID', '>', $lastId) // 用真实字段
+                    ->orderBy('sd_b.ID')
+                    ->limit($limit)
+                    ->selectRaw("
+                        COALESCE(sd.ID, 0) as order_id,
+                        COALESCE(sd.code, '') as order_number,
+                        sd.voucherdate as order_time,
+                        sd.voucherState as order_state,
+                        COALESCE(ps.name, '') as employee_id_1_title,
+                        COALESCE(sd.idclerk, 0) as employee_id_1,
+                        COALESCE(ps2.name, '') as employee_id_2_title,
+                        COALESCE(pn.idsaleman, 0) as employee_id_2,
+                        COALESCE(pn.code, '') as customer_code,
+                        COALESCE(pn.name, '') as customer_title,
+                        COALESCE(pn.priuserdefdecm3, 0) as customer_store_price,
+                        COALESCE(it.code, '') as product_code,
+                        COALESCE(it.name, '') as product_title,
+                        COALESCE(it.specification, '') as product_size,
+                        COALESCE(it.priuserdefdecm1, 0) as product_box_size,
+                        COALESCE(it.priuserdefdecm3, 0) as product_weight,
+                        COALESCE(it.priuserdefdecm10, 0) as product_store_price,
+                        COALESCE(it.priuserdefdecm9, 0) as product_store_price2,
+                        COALESCE(it.priuserdefnvc5, '') as product_category,
+                        COALESCE(ui.name, '') as unit,
+                        COALESCE(sd_b.quantity, 0) as quantity,
+                        COALESCE(sd_b.taxPrice, 0) as price_3,
+                        COALESCE(sd_b.taxAmount, 0) as price_3_total,
+                        COALESCE(sd_b.ID, 0) as id_detail,
+                        COALESCE(sd_b.isPresent, 0) as is_present,
+                        COALESCE(sd_b.DetailMemo, '') as item_mark,
+                        COALESCE(sd.memo, '') as mark,
+                        sd_b.idwarehouse as warehouse_id,
+                        COALESCE(wa.name, '') as warehouse_name,
+                        sd.idbusinesstype as business_type_id,
+                        COALESCE(bs.name , '') as business_type_title,
+                        COALESCE(sd.address , '') as address,
+                        COALESCE(sd.priuserdefnvc2 , '') as area_hs,
+                        COALESCE(sd.deliveryMode , 0) as delivery_mode,
+                        COALESCE(sd.priuserdefdecm5 , 0) as sl_fee
+                    ")
+                    ->get();
+
+                if ($rows->isEmpty()) break;
+
+                $dataArray = Collect($rows)->map(function ($object) {
+                    return (array)$object;
+                })->toArray();
+
+                $freight = Freight::where('del_time',0)
+                    ->whereIn('region',array_column($dataArray,'area_hs'))
+                    ->select('region','one_and_five','greater_than_five','min_freight_fee')
+                    ->get()->toArray();
+                $freight_map = array_column($freight,null,'region');
+
+                //组织数据
+                foreach ($dataArray as $key => $value) {
+                    $quantity = abs($value['quantity']);
+                    //箱数
+                    $xs = 0;
+                    if(! empty($value['product_box_size']) && is_numeric($value['product_box_size']) && $value['product_box_size'] > 0) $xs = ceil($quantity / $value['product_box_size']);
+                    $dataArray[$key]['xs'] = $xs;
+                    //总重量
+                    $weight = 0;
+                    if(! empty($value['product_weight']) && is_numeric($value['product_weight']) && $value['product_weight'] > 0) $weight = bcdiv(bcmul($xs, $value['product_weight']),1000,3);
+                    $dataArray[$key]['weight'] = $weight;
+                    //运价区间
+                    $area_range = 1;
+                    if($weight >= 5) $area_range = 2;
+                    $dataArray[$key]['area_range'] = $area_range;
+                    //配送费单价
+                    $freight = $min_freight = 0;
+                    if(isset($freight_map[$value['area_hs']])) {
+                        $tmp = $freight_map[$value['area_hs']];
+                        if($area_range == 1){
+                            $freight = $tmp['one_and_five'];
+                        }else{
+                            $freight = $tmp['greater_than_five'];
+                        }
+                        $min_freight = $tmp['min_freight_fee'];
+                    }
+                    $dataArray[$key]['freight_unit_price'] = $freight;
+                    //配送费金额
+                    $freight_amount = bcmul($weight, $freight,2);
+                    $dataArray[$key]['freight_amount'] = $freight_amount;
+                    //结算金额 记录的是每一条的
+                    $dataArray[$key]['js_single_amount'] = $freight_amount;
+                    //地区最低运价
+                    $dataArray[$key]['min_freight_amount'] = $min_freight;
+                    //门店卸货费
+                    $customer_store_price = 0;
+                    if(! empty($value['customer_store_price']) && is_numeric($value['customer_store_price']) && $value['customer_store_price'] > 0){
+                        $customer_store_price = bcmul($value['customer_store_price'], $xs,2);
+                    }else{
+                        if(! empty($value['product_store_price']) && is_numeric($value['product_store_price']) && $value['product_store_price'] > 0){
+                            $customer_store_price = bcmul($value['product_store_price'], $xs,2);
+                        }
+                    }
+                    $dataArray[$key]['customer_store_zx_fee'] = $customer_store_price;
+                    //到货装卸费
+                    $product_store_price2 = 0;
+                    if(! empty($value['product_store_price2']) && is_numeric($value['product_store_price2']))  $product_store_price2 = $value['product_store_price2'];
+                    if(! empty($value['product_category']) && $value['product_category'] == "礼盒"){
+                        $dh_fee = bcmul($xs, $product_store_price2,2);
+                    }else{
+                        $dh_fee = bcmul($weight, $product_store_price2,2);
+                    }
+                    if($value['business_type_id'] == FreightFee::businessTypeReturn) $dh_fee = bcmul($dh_fee,2,2);
+                    $dataArray[$key]['dh_fee'] = $dh_fee;
+                }
+
+                DB::table($table)->insert($dataArray);
+
+                // 更新 lastId 继续下一批
+                $lastId = end($dataArray)['id_detail'] ?? $lastId;
+
+            } while (count($rows) === $limit);
+        }catch  (\Throwable $exception){
+            return [false, "运费获取销货单数据异常" . $exception->getMessage() . "|" . $exception->getLine() . "|" . $exception->getFile()];
+        }
+
+        return [true, ''];
+    }
+
+    private function updateFreightFeeFromMine($data){
+        try {
+            $start_timeStamp = $data['start_time'];
+            $end_timeStamp = $data['end_time'];
+            $tmpTable = $this->table_3;
+            $time = time();
+            $ergs = $data;
+
+            DB::transaction(function () use ($start_timeStamp, $end_timeStamp, $tmpTable,$time, $ergs) {
+                // 1. 先软删除旧数据(你已有)
+                FreightFee::where('del_time', 0)
+                    ->where('order_time', '>=', $start_timeStamp)
+                    ->where('order_time', '<=', $end_timeStamp)
+                    ->update(['del_time' => $time]);
+
+                // 2. 分批从临时表插入新数据
+                $batchSize = 500;
+                $lastId = 0;
+                do {
+                    $chunk = DB::table($tmpTable)
+                        ->where('id', '>', $lastId)
+                        ->orderBy('id')
+                        ->limit($batchSize)
+                        ->get();
+
+                    if ($chunk->isEmpty()) {
+                        break;
+                    }
+
+                    $data = $chunk->map(function ($item) use($time){
+                        return [
+                            // 基础字段(按你给的顺序)
+                            'order_id' => $item->order_id ?? 0,
+                            'order_number' => $item->order_number ?? '',
+                            'order_time' => $item->order_time ? strtotime($item->order_time) : 0,
+                            'order_state' => $item->order_state ?? 0,
+                            'employee_id_1_title' => $item->employee_id_1_title ?? '',
+                            'employee_id_1' => $item->employee_id_1 ?? 0,
+                            'employee_id_2_title' => $item->employee_id_2_title ?? '',
+                            'employee_id_2' => $item->employee_id_2 ?? 0,
+                            'customer_code' => $item->customer_code ?? '',
+                            'customer_title' => $item->customer_title ?? '',
+                            'customer_store_price' => $item->customer_store_price ?? 0,
+                            'product_code' => $item->product_code ?? '',
+                            'product_title' => $item->product_title ?? '',
+                            'product_size' => $item->product_size ?? '',
+                            'product_box_size' => $item->product_box_size ?? 0,
+                            'product_weight' => $item->product_weight ?? 0,
+                            'product_store_price' => $item->product_store_price ?? 0,
+                            'product_store_price2' => $item->product_store_price2 ?? 0,
+                            'product_category' => $item->product_category ?? '',
+                            'unit' => $item->unit ?? '',
+                            'quantity' => $item->quantity ?? 0,
+                            'price_3' => $item->price_3 ?? 0,
+                            'price_3_total' => $item->price_3_total ?? 0,
+                            'id_detail' => $item->id_detail ?? 0,
+                            'is_present' => $item->is_present ?? '',
+                            'mark' => $item->mark ?? '',
+                            'item_mark' => $item->item_mark ?? '',
+                            'warehouse_id' => $item->warehouse_id ?? 0,
+                            'warehouse_name' => $item->warehouse_name ?? '',
+                            'business_type_id' => $item->business_type_id ?? 0,
+                            'business_type_title' => $item->business_type_title ?? '',
+                            'address' => $item->address ?? '',
+                            'area_hs' => $item->area_hs ?? '',
+                            'delivery_mode' => $item->delivery_mode ?? 0,
+                            'sl_fee' => $item->sl_fee ?? 0,
+                            'xs' => $item->xs,
+                            'weight' => $item->weight ?? 0,
+                            'area_range' => $item->area_range ?? 0,
+                            'freight_unit_price' => $item->freight_unit_price ?? 0,
+                            'freight_amount' => $item->freight_amount ?? 0,
+                            'js_single_amount' => $item->js_single_amount ?? 0,
+                            'min_freight_amount' => $item->min_freight_amount ?? 0,
+                            'customer_store_zx_fee' => $item->customer_store_zx_fee ?? 0,
+                            'dh_fee' => $item->dh_fee ?? 0,
+                            'crt_time' => $time,
+                        ];
+                    })->toArray();
+
+                    // 每批单独插入(可选:加小事务)
+                    FreightFee::insert($data);
+
+                    // 更新 lastId
+                    $lastId = $chunk->last()->id;
+
+                } while ($chunk->count() == $batchSize);
+            });
+        }catch  (\Throwable $exception){
+            return [false, "单据明细同步异常" . $exception->getMessage() . "|" . $exception->getLine() . "|" . $exception->getFile()];
+        }
+
+        return [true, ''];
+    }
 }

+ 2 - 0
routes/api.php

@@ -135,6 +135,7 @@ Route::group(['middleware'=> ['checkLogin']],function ($route){
     $route->any('synPersonDepart', 'Api\TPlusController@synPersonDepart');
     $route->any('synRevenueCost', 'Api\TPlusController@synRevenueCost');
     $route->any('synSalaryEmployee', 'Api\TPlusController@synSalaryEmployee');
+    $route->any('synFreightFee', 'Api\TPlusController@synFreightFee');
 
     //收入成本
     $route->any('statisticsRevenueCost', 'Api\StatisticsController@statisticsRevenueCost');
@@ -148,4 +149,5 @@ Route::group(['middleware'=> ['checkLogin']],function ($route){
     $route->any('statisticsEmployeeSalary', 'Api\StatisticsController@statisticsEmployeeSalary');
     //运费
     $route->any('statisticsFreightFee', 'Api\StatisticsController@statisticsFreightFee');
+    $route->any('statisticsFreightFeeDetail', 'Api\StatisticsController@statisticsFreightFeeDetail');
 });