Selaa lähdekoodia

结算帐单开发部分

Zhouzhendong 4 vuotta sitten
vanhempi
commit
98f97af60f

+ 3 - 2
app/Console/Commands/CreateOwnerBillReport.php

@@ -64,7 +64,8 @@ class CreateOwnerBillReport extends Command
                 "counting_type"     =>$area->ownerStoragePriceModel->counting_type,
                 "using_type"        =>$area->ownerStoragePriceModel->using_type,
                 "fee_description"   =>"",
-                "total"             =>0,
+                "total_fee"         =>0,
+                "tax_rate"          =>0,
             ];
             $key = $area->owner_id."_".$area->counting_month;
             if (!isset($map[$key]))$map[$key] = $mapTax[$key] = 0;
@@ -73,7 +74,7 @@ class CreateOwnerBillReport extends Command
             $map[$key] += $money;
             $mapTax[$key] += $taxFee;
 
-            $GLOBALS["FEE_INFO"]["total"] = $money;
+            $GLOBALS["FEE_INFO"]["total_fee"] = $money;
             OwnerFeeStorage::query()->create($GLOBALS["FEE_INFO"]);
         }
         foreach (OwnerPriceSystem::query()->with(["timeUnit","taxRate"])->select("owner_id","usage_fee")->whereNull("operation")->orWhere("operation","")->get() as $system){

+ 31 - 12
app/Http/Controllers/TestController.php

@@ -15,17 +15,23 @@ use App\MaterialBox;
 use App\MaterialBoxModel;
 use App\Order;
 use App\Owner;
+use App\OwnerAreaReport;
 use App\OwnerFeeDetail;
+use App\OwnerFeeOperation;
+use App\OwnerFeeOperationDetail;
+use App\OwnerFeeStorage;
 use App\OwnerPriceOperation;
 use App\OrderPackageCountingRecord;
 use App\RejectedBill;
 use App\Services\ForeignHaiRoboticsService;
+use App\Services\OwnerPriceOperationService;
 use App\Services\StationService;
 use App\Services\StorageService;
 use App\Services\TestService;
 use App\Station;
 use App\StationTask;
 use App\StationTaskMaterialBox;
+use App\Store;
 use App\TaskTransaction;
 use App\Unit;
 use App\Waybill;
@@ -61,20 +67,33 @@ class TestController extends Controller
     public function lightOff()
     {
 
-    }
-    public function a($a){
-        $GLOBALS["test"] = "测试1";
-        //$a = new TestService();
-        sleep($a);
-        app("TestService")->test();
-        dump([$GLOBALS["test"],$a]);
     }
     public function test()
     {
-        $this->dispatch(new TestJob(5));
-        $this->dispatch(new TestJob(4));
-        $this->dispatch(new TestJob(3));
-        $this->dispatch(new TestJob(2));
-        $this->dispatch(new TestJob(1));
+        ini_set('max_execution_time',2500);
+        $stores = Store::query()->where("status","已入库")->limit(1)->get();
+        foreach ($stores as $store){
+            /** @var OwnerPriceOperationService $service */
+            $service = app("OwnerPriceOperationService");
+            $GLOBALS["FEE_INFO"] = [];
+            list($id,$money,$taxFee) = $service->matching($store, Feature::MAPPING["store"], $store->owner_id, "入库");
+            $defaultInfo = [
+                "worked_at" => $store->updated_at,
+                "owner_id" => $store->owner_id,
+                "model_id"  => $id,
+                "source_number"=> null,
+                "doc_number"   => $store->asn_code,
+                "commodity_id" => 0,
+                "total_fee"    =>0,
+                "tax_rate"     =>0,
+                "fee_description"=>'',
+            ];
+            foreach ($GLOBALS["FEE_INFO"] as $info){
+                $operation = $defaultInfo;
+                foreach ($operation as $key=>$val)if (isset($info[$key]))$operation[$key] = $info[$key];
+                dump($operation);
+            }
+        }
+
     }
 }

+ 19 - 0
app/OwnerFeeExpress.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App;
+
+use Illuminate\Database\Eloquent\Model;
+
+use App\Traits\ModelLogChanging;
+
+class OwnerFeeExpress extends Model
+{
+    use ModelLogChanging;
+
+    public $timestamps = false;
+    protected $fillable = [
+        "province_id", "logistic_id", "logistic_number",
+        "weight", "initial_weight","initial_weight_price","additional_weight","additional_weight_amount", "additional_weight_price",
+        "total_fee","tax_rate", "created_at","owner_id"
+    ];
+}

+ 38 - 0
app/OwnerFeeLogistic.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App;
+
+use Illuminate\Database\Eloquent\Model;
+
+use App\Traits\ModelLogChanging;
+
+class OwnerFeeLogistic extends Model
+{
+    use ModelLogChanging;
+
+    public $timestamps=false;
+    protected $fillable = [
+        "province_id",
+        "owner_id",
+        "city_id",
+        "logistic_id",
+        "order_number",
+        "recipient_name",
+        "recipient_phone",
+        "quantity",
+        "unit_id",
+        "interval",
+        "price",
+        "delivery_fee",
+        "pick_fee",
+        "fuel_fee",
+        "info_fee",
+        "other_fee",
+        "initial_fee",
+        "initial_amount",
+        "total_fee",
+        "tax_rate",
+        "remark",
+        "created_at",
+    ];
+}

+ 30 - 0
app/OwnerFeeOperation.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App;
+
+use Illuminate\Database\Eloquent\Model;
+
+use App\Traits\ModelLogChanging;
+
+class OwnerFeeOperation extends Model
+{
+    use ModelLogChanging;
+
+    public $timestamps = false;
+    protected $fillable = [
+        "worked_at",
+        "model_id",
+        "source_number",
+        "doc_number",
+        "commodity_id",
+        "total_fee",
+        "tax_rate",
+        "fee_description",
+        "owner_id",
+    ];
+
+    public function details()
+    {
+        return $this->hasMany(OwnerFeeOperationDetail::class);
+    }
+}

+ 21 - 0
app/OwnerFeeOperationDetail.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace App;
+
+use Illuminate\Database\Eloquent\Model;
+
+use App\Traits\ModelLogChanging;
+
+class OwnerFeeOperationDetail extends Model
+{
+    use ModelLogChanging;
+
+    public $timestamps = false;
+    protected $fillable = [
+        "owner_fee_operation_id",
+        "name",
+        "amount",
+        "price",
+        "unit_id",
+    ];
+}

+ 1 - 1
app/OwnerFeeStorage.php

@@ -13,6 +13,6 @@ class OwnerFeeStorage extends Model
     protected $primaryKey = 'area_id';
     public $timestamps = false;
     protected $fillable = [
-        "area_id", "counting_type", "using_type", "fee_description", "total"
+        "area_id", "counting_type", "using_type", "fee_description", "total_fee", "tax_rate"
     ];
 }

+ 1 - 1
app/OwnerPriceOperation.php

@@ -22,7 +22,7 @@ class OwnerPriceOperation extends Model
         "total_discount_price",//按单计价减免 array
         "operation",        //操作
         "target_id",        //目标ID
-        "type_mark",        //类型标记
+        "type_mark",        //类型标记 用于某些特殊项的匹配限制 0:退货 例:退货模块的单据进入模型匹配时仅匹配为0的项
         "surcharge",        //附加费
         "surcharge_unit_id",//附加费单位
         "max_fee",          //封顶费

+ 94 - 52
app/Services/OrderService.php

@@ -17,6 +17,7 @@ use App\OrderIssue;
 use App\Owner;
 use App\OwnerFeeDetail;
 use App\OwnerFeeDetailLogistic;
+use App\OwnerFeeExpress;
 use App\OwnerReport;
 use App\Province;
 use App\RejectedBill;
@@ -1137,12 +1138,17 @@ sql
     public function getLogisticFeeInfo(Order $order):array
     {
         //预定义返回参数
-        $result = [
-            "amount" => 0, "logisticBill" => null, "volume" => 0,
-            "weight" => 0, "logisticFee" => null, "logisticTaxFee" => null,
-            "items" => [],
-        ];
+        $default = function (){
+            return [
+                "amount" => 0, "logisticBill" => null, "volume" => 0,
+                "weight" => 0, "logisticFee" => null, "logisticTaxFee" => null,
+                "items"  => [],"fee_info" => [],
+            ];
+        };
+        $result = $default();
         if (!$order->logistic)return $result;
+        //21-8-12 询问业务方(周旭)确定物流单都会在运输管理推单 所以此处直接排除物流单
+        if ($order->logistic->type=='物流')return $result;
         //获取城市
         $province = app("ProvinceService")->getProvince($order->province);
         $unit = app("UnitService")->getUnit();
@@ -1160,7 +1166,26 @@ sql
                     return $service->matching($amount,$ownerId,$logisticId,$unit->id,$province->id,$city->id);
             }
         };
-        foreach ($order->packages as &$package){
+        //默认的提取信息模板
+        $defaultInfo = function ($number, $weight)use($province,$order){
+            return [
+                "province_id" => $province->id,
+                "owner_id"=>$order->owner_id,
+                "logistic_id" => $order->logistic->id,
+                "logistic_number" => $number,
+                "weight" => $weight,
+                "initial_weight" => 0,
+                "initial_weight_price" => 0,
+                "additional_weight" => 0,
+                "additional_weight_amount" => 0,
+                "additional_weight_price" => 0,
+                "total_fee" => 0,
+                "tax_rate" => 0,
+                "created_at" => $order->wms_edittime ?: $order->updated_at,
+            ];
+        };
+        foreach ($order->packages as $package){
+            if (!$package->weight)return $default(); //任一包裹不存在重量 放弃所有计算 直接跳出
             $tax = $fee = null;
             $result["logisticBill"] .= $package->logistic_number.",";
             $result["volume"] += $package->bulk;
@@ -1169,10 +1194,13 @@ sql
             foreach($package->commodities as $commodity)$partAmount += $commodity->amount;
             $result["amount"] += $partAmount;
 
-            if ($province && !$isBunched){
+            if (!$isBunched){
+                $GLOBALS["FEE_INFO"] = $defaultInfo($package->logistic_number,$package->weight);
                 list($fee,$tax) = $exe($order->logistic->type,$order->owner_id, $order->logistic_id, $partAmount, $package->weight);
                 $result["logisticFee"] += $fee;
                 $result["logisticTaxFee"] += $tax;
+                $GLOBALS["FEE_INFO"]["total_fee"] = $fee;
+                if ($order->logistic->type=='快递')$result["fee_info"][] = $GLOBALS["FEE_INFO"];
             }
             $result["items"][] = [
                 "amount" => $partAmount,
@@ -1183,9 +1211,15 @@ sql
                 "tax_fee" => $tax,
             ];
         }
-        /* 为子母单 且 重量与省份完整 且 重量大于0 且 省份存在 进入子母单计算 */
-        if ($province && $isBunched)list($result["logisticFee"],$result["logisticTaxFee"]) =
-            $exe($order->logistic->type,$order->owner_id, $order->logistic_id, $result["amount"], $result["weight"]);
+        /* 子母单计算 */
+        if ($isBunched){
+            $GLOBALS["FEE_INFO"] = $defaultInfo($result["logisticBill"],$result["weight"]);
+
+            list($result["logisticFee"],$result["logisticTaxFee"]) =
+                $exe($order->logistic->type,$order->owner_id, $order->logistic_id, $result["amount"], $result["weight"]);
+            $GLOBALS["FEE_INFO"]["total_fee"] = $result["logisticFee"];
+            if ($order->logistic->type=='快递')$result["fee_info"][] = $GLOBALS["FEE_INFO"];
+        }
         if ($result["logisticFee"]<0)$result["logisticFee"] = null;
         if ($result["logisticTaxFee"]<0)$result["logisticTaxFee"] = null;
         $result["logisticBill"] = rtrim($result["logisticBill"],",");
@@ -1209,15 +1243,31 @@ sql
         //获取运输费
         $logisticInfo = $this->getLogisticFeeInfo($order);
 
+        //信息仍然不完整
+        if (!$logisticInfo["fee_info"])return false;
+        //向指定表插入标记
+        OwnerFeeExpress::query()->insert($logisticInfo["fee_info"]);
         //获取作业费
         /** @var OwnerPriceOperationService $service */
         $service = app("OwnerPriceOperationService");
+        $GLOBALS["FEE_INFO"] = [];
         list($id,$money,$workTaxFee) = $service->matching($order,Feature::MAPPING["order"],$order->owner_id);
+        if ($money>0)app("StoreService")->constructFeeInfo([
+            "worked_at" => $order->wms_edittime ?: $order->updated_at,
+            "owner_id" => $order->owner_id,
+            "model_id"  => $id,
+            "source_number"=> $order->client_code,
+            "doc_number"   => $order->code,
+            "commodity_id" => 0,
+            "total_fee"    =>0,
+            "tax_rate"     =>0,
+            "fee_description"=>'',
+        ]);
 
         //数据组装
         $detail = OwnerFeeDetail::query()->create([
             "owner_id"          => $order->owner_id,
-            "worked_at"         => $order->wms_edittime ?? $order->updated_at,
+            "worked_at"         => $order->wms_edittime ?: $order->updated_at,
             "type"              => "发货",
             "shop_id"           => $order->shop_id,
             "operation_bill"    => $order->code,
@@ -1335,50 +1385,42 @@ sql
         if (!$feeBill)return false; //是否已有即时账单,没有跳出
         $order->loadMissing("packages","owner");//加载包裹
         if (!$order->packages->count() || !$order->owner)return false;
+        //获取运输费
+        $logisticInfo = $this->getLogisticFeeInfo($order);
+        //向指定表插入标记
+        if ($logisticInfo["fee_info"])OwnerFeeExpress::query()->insert($logisticInfo["fee_info"]);
+        foreach ($logisticInfo["items"] as &$item)$item["owner_fee_detail_id"] = $feeBill->id;
+        if (count($logisticInfo["items"])>1)OwnerFeeDetailLogistic::query()->insert($logisticInfo["items"]);
 
-        foreach ($order->packages as $package)if (!$package->weight)return false; //包裹存在且全部存在数量
-
-        $logistic_fee = 0;
-        $volume = 0;
-        $weight = 0;
-        $isBunched = false;
-        if (!$order->logistic || $order->logistic->type != "快递")$logistic_fee = null;
-        else $isBunched = $order->logistic->is_bunched=='Y';
-        $weightExceptionMark = false;
-        $provinceId = null;
-        $taxFee = 0;
-        foreach ($order->packages as $package){
-            $tax = 0;
-
-            $volume += $package->bulk;
-            $weight += $package->weight;
-            if (!$weightExceptionMark && (!$package->weight || $package->weight<0))$weightExceptionMark = true;
-            $fee = null;
-
-            $provinceName = mb_substr($order->province,0,2);
-            $province = app(CacheService::class)->getOrExecute("province_".$provinceName,function ()use($provinceName){
-                return Province::query()->where("name","like",$provinceName."%")->first();
-            },86400);
-            $fee = null;
-            if ($province){
-                if (!$provinceId)$provinceId = $province->id;
-                else if ($provinceId!=$province->id)$weightExceptionMark = true;
-                if (!$isBunched)list($fee,$tax) = app("OwnerPriceExpressService")->matching($package->weight, $order->owner_id, $order->logistic_id, $province->id);
-            }else $logistic_fee = null;
-
-            OwnerFeeDetailLogistic::query()->where("owner_fee_detail_id",$feeBill->id)->where("logistic_bill",$package->logistic_number)->update([
-                "volume"=>$package->bulk,
-                "weight"=>$package->weight,
-                "logistic_fee" => $fee,
+        //获取作业费
+        $GLOBALS["FEE_INFO"] = [];
+        list($id,$money,$workTaxFee) = app("OwnerPriceOperationService")->matching($order,Feature::MAPPING["order"],$order->owner_id);
+        if ($money>0){
+            app("StoreService")->clearFeeInfo($order->code);
+            app("StoreService")->constructFeeInfo([
+                "worked_at" => $order->wms_edittime ?: $order->updated_at,
+                "owner_id" => $order->owner_id,
+                "model_id"  => $id,
+                "source_number"=> $order->client_code,
+                "doc_number"   => $order->code,
+                "commodity_id" => 0,
+                "total_fee"    =>0,
+                "tax_rate"     =>0,
+                "fee_description"=>'',
             ]);
-            if ($logistic_fee!==null){
-                if ($fee<0)$logistic_fee = null;
-                else $logistic_fee += $fee;
-            }
-            $taxFee += $tax;
         }
-        if ($isBunched && !$weightExceptionMark && $weight>0 && $provinceId)list($logistic_fee,$taxFee) = app("OwnerPriceExpressService")->matching($weight, $order->owner_id, $order->logistic_id, $provinceId);
-        $feeBill->update(["logistic_fee"=>$logistic_fee,"volume"=>$volume,"weight"=>$weight,"logistic_tax_fee"=>$taxFee]);
+        //数据组装
+        $feeBill->update([
+            "commodity_amount"  => $logisticInfo["amount"],
+            "logistic_bill"     => $logisticInfo["logisticBill"],
+            "volume"            => $logisticInfo["volume"],
+            "weight"            => $logisticInfo["weight"],
+            "logistic_fee"      => $logisticInfo["logisticFee"],
+            "logistic_tax_fee"  => $logisticInfo["logisticTaxFee"],
+            "work_fee"          => $money,
+            "owner_price_operation_id"  => $id,
+            "work_tax_fee"      => $workTaxFee,
+        ]);
         return true;
     }
 

+ 10 - 3
app/Services/OwnerPriceExpressService.php

@@ -284,10 +284,17 @@ sql
         $additionalPrice = $model->details[0]->additional_weight_price[$to1][$to2];
         if ($weight>$model->initial_weight){
             $weight -= $model->initial_weight;
-            $money = (ceil($weight/$model->additional_weight)*$additionalPrice)+$initPrice;
+            $amount = ceil($weight/$model->additional_weight);
+            $GLOBALS["FEE_INFO"]["additional_weight_amount"] = $amount; //续重量向上取整 例:不足1为1
+            $money = ($amount*$additionalPrice)+$initPrice;
         }else $money = $initPrice;
-
-        $taxFee = app("OwnerService")->getTaxRateFee($model, $ownerId, $money);
+        $GLOBALS["FEE_INFO"]["initial_weight"] = $model->initial_weight;
+        $GLOBALS["FEE_INFO"]["additional_weight"] = $model->additional_weight;
+        $GLOBALS["FEE_INFO"]["initial_weight_price"] = $model->initial_weight_price;
+        $GLOBALS["FEE_INFO"]["additional_weight_price"] = $model->additional_weight_price;
+        $taxRate = app("OwnerService")->getTaxRateFee($model, $ownerId);//获取税率
+        $taxFee = $money*($taxRate/100);
+        $GLOBALS["FEE_INFO"]["tax_rate"] = $taxRate;
         return array($money,$taxFee);
     }
 }

+ 13 - 1
app/Services/OwnerPriceLogisticService.php

@@ -214,6 +214,10 @@ class OwnerPriceLogisticService
         })->first();
         if (!$model || !$model->details)return array(null,null);
         $money = null;
+        $GLOBALS["FEE_INFO"]["pick_fee"] = $model->pick_up_price;
+        $GLOBALS["FEE_INFO"]["fuel_fee"] = $model->fuel_price;
+        $GLOBALS["FEE_INFO"]["info_fee"] = $model->service_price;
+        $GLOBALS["FEE_INFO"]["other_fee"] = 0;
         $fee = $model->pick_up_price + $model->fuel_price + $model->service_price; //服务费
         foreach ($model->details as $detail){
             if ($unitId != $detail->unit_id)continue;
@@ -225,12 +229,20 @@ class OwnerPriceLogisticService
             }
             if ($money)break;
         }
-        $taxFee = app("OwnerService")->getTaxRateFee($model, $ownerId, $money);
+        $taxRate = app("OwnerService")->getTaxRateFee($model, $ownerId);
+        $taxFee = $money*($taxRate/100);
+        $GLOBALS["FEE_INFO"]["tax_rate"] = $taxRate;
+        $GLOBALS["FEE_INFO"]["total_fee"] = $money;
         return array($money,$taxFee);
     }
 
     private function calculation($amount, $detail, $fee)
     {
+        $GLOBALS["FEE_INFO"]["interval"] = $detail->range;
+        $GLOBALS["FEE_INFO"]["price"] = $detail->unit_price;
+        $GLOBALS["FEE_INFO"]["delivery_fee"] = $detail->delivery_fee;
+        $GLOBALS["FEE_INFO"]["initial_fee"] = $detail->initial_fee;
+        $GLOBALS["FEE_INFO"]["initial_amount"] = $detail->initial_amount;
         if ($amount < $detail->initial_amount)$amount = $detail->initial_amount; //小于起始数以起始数为准
         $money = $amount * $detail->unit_price;
         if ($money < $detail->initial_fee)$money = $detail->initial_fee; //小于起始计费以起始计费为准

+ 181 - 64
app/Services/OwnerPriceOperationService.php

@@ -343,25 +343,84 @@ class OwnerPriceOperationService
             $result = $this->getDiscount($rule->discount_count,$total); //满减信息
             $this->handleDiscount($rule,$ownerId,$result);
 
-            if ($rule->total_price)$money = $result ? explode(",",$rule->total_discount_price)[key($result)] : $rule->total_price;//按单计价存在,直接返回单总价或减免总价
-            else $money = $this->matchItem($rule,$columnMapping,$matchObject,$units,$ownerId,$result);//匹配子项获取详细报价
+            $taxRate = app("OwnerService")->getTaxRateFee($rule, $ownerId);//获取税率
+
+            if (!$rule->total_price){
+                $money = $this->matchItem($rule,$columnMapping,$matchObject,$units,$ownerId,$result);//匹配子项获取详细报价
+                if ($rule->max_fee&&$money>$rule->max_fee){
+                    $money = $rule->max_fee;//封顶费
+                    foreach ($GLOBALS["FEE_INFO"] as $index=>$info){
+                        foreach ($GLOBALS["FEE_INFO"][$index]["details"] as &$item)$item["price"] = 0;
+                        $GLOBALS["FEE_INFO"][$index]["tax_rate"] = $taxRate;
+                        if ($index==0){
+                            $GLOBALS["FEE_INFO"][$index]["total_fee"] = $rule->max_fee;
+                            $GLOBALS["FEE_INFO"][$index]["fee_description"] = "订单费用超出封顶费,封顶费:".$rule->max_fee
+                                ."(详:".$GLOBALS["FEE_INFO"][$index]["fee_description"].")";
+                            $GLOBALS["FEE_INFO"][$index]["details"][] = [
+                                "name"      => "封顶费",
+                                "amount"    => 1,
+                                "price"     => $rule->max_fee,
+                                "unit_id"   => array_flip($units)["单"],
+                            ];
+                        }else{
+                            $GLOBALS["FEE_INFO"][$index]["total_fee"] = 0;
+                            $GLOBALS["FEE_INFO"][$index]["fee_description"] = "封顶费平摊"
+                                ."(详:".$GLOBALS["FEE_INFO"][$index]["fee_description"].")";
+                        }
+                    }
+                }
+            } else{
+                $money = $result ? explode(",",$rule->total_discount_price)[key($result)] : $rule->total_price;//按单计价存在,直接返回单总价或减免总价
+                $arr = $this->resetChildNodeMapping($matchObject->toArray(),$columnMapping);
+                if ($arr)$this->extractInfo($arr,$money,$result,array_flip($units),$taxRate);
+            }
 
-            $money = $rule->max_fee&&$money>$rule->max_fee ? $rule->max_fee : $money;//封顶费
             if ($money<=0)$money=null;//计算失误
-            $taxFee = app("OwnerService")->getTaxRateFee($rule, $ownerId, $money);
+            $taxFee = $money*($taxRate/100);
             return array($rule->id,$money,$taxFee);
         }
         return array(null,null,null);
     }
+
+    /**
+     * 提取信息插入超全局变量中
+     */
+    private function extractInfo(array $arr, $money, $result, $flip, $taxRate)
+    {
+        foreach ($arr as $index => $item){
+            $details = [
+                "name"      => "单价",
+                "amount"    => $item["amount"] ?? 0,
+                "price"     => 0,
+                "unit_id"   => $flip["件"],
+            ];
+            if ($index==0){
+                $feeDescription = "按单计价".($result ? '('.value($result).')' : '').':'.$money.'元';
+                $details[] = [
+                    "name"      => "按单计费",
+                    "amount"    => 1,
+                    "price"     => $money,
+                    "unit_id"   => $flip["单"],
+                ];
+            }else $feeDescription = '该单已被按单计费,续费0元';
+            $GLOBALS["FEE_INFO"][] = [
+                "commodity_id"  => $item["commodity_id"] ?? 0,
+                "total_fee"     => $money,
+                "tax_rate"      => $taxRate,
+                "fee_description"  => $feeDescription,
+                "details" => $details
+            ];
+        }
+    }
     /**
      * 根据货主 sku寻找箱规并将指定数量切换为箱 返回箱规
      *
      * @param integer $ownerId
-     * @param null|object $commodity
+     * @param null|object|array $commodity
      *
      * @return int
      */
-    private function changeUnit($ownerId,$commodity)
+    private function changeUnit(int $ownerId,$commodity):int
     {
         if (!$commodity)return -4;
         if ($commodity["pack_spec"])return $commodity["pack_spec"];
@@ -414,97 +473,155 @@ class OwnerPriceOperationService
     {
         $matchObject = $this->resetChildNodeMapping($matchObject->toArray(),$columnMapping);
         if (!$matchObject)return -1;
-        $total = $surcharge = 0; //商品总数 附加费
-        $unitName = "";
+        $total = $surcharge = $oddMoney = $surchargeAmount = 0; //商品总数 附加费 零头附加费
 
         foreach ($matchObject as $commodity)$total += $commodity[$columnMapping[8]]; //取对象内商品数量总数将其当作子属性插入原对象
         if ($obj->surcharge_unit_id && $obj->surcharge){
-            if ($units[$obj->surcharge_unit_id] == '件')$surcharge += $obj->surcharge*$total;
-            else $surcharge += $obj->surcharge;
+            $surchargeAmount = $units[$obj->surcharge_unit_id] == '件' ? $total : 1;
+            $surcharge += $obj->surcharge*$surchargeAmount;
         }//耗材附加费
-
+        $flip = array_flip($units);
+        $exe = function ($package,$index,$partMoney,$startNumber,$rule)use($columnMapping,$flip,$surcharge,$surchargeAmount,$obj,$units){
+            $details = $package["fee_info"] ?? []; //获取在匹配过程中记录的费用,例:零头费
+            $fee_description = $details ? "箱装包含零头附加费" : '';
+            $details[] = [
+                "name"      => "单价",
+                "amount"    => $package[$columnMapping[8]],
+                "price"     => $package["price"],
+                "unit_id"   => $package["unitId"] ?? $flip["件"],
+            ];
+            if ($index==0){
+                if ($surcharge){
+                    $details[] = [
+                        "name"      => "耗材附加费",
+                        "amount"    => $surchargeAmount,
+                        "price"     => $obj->surcharge,
+                        "unit_id"   => $obj->surcharge_unit_id,
+                    ];
+                    $fee_description .= ",包含耗材附加费".$surcharge."元";
+                    $partMoney += $surcharge;
+                }
+                if ($startNumber){
+                    $details[] = [
+                        "name"      => "起步费",
+                        "amount"    => $startNumber,
+                        "price"     => $rule->unit_price,
+                        "unit_id"   => $rule->unit_id,
+                    ];
+                    $fee_description .= ",包含起步费({$startNumber}/{$units[$rule->unit_id]})".$rule->unit_price."元";
+                    $partMoney += $rule->unit_price;
+                }
+            }else if ($startNumber) $fee_description .= "数量被起步数平摊";
+            $GLOBALS["FEE_INFO"][] = [
+                "commodity_id"  => $package["commodity_id"] ?? 0,
+                "total_fee"     => $partMoney,
+                "tax_rate"      => 0,
+                "fee_description"  => ltrim($fee_description,","),
+                "details" => $details
+            ];
+        };
         foreach ($obj->items as $rule){
             if ($result)$rule->unit_price = explode(",",$rule->discount_price)[key($result)]; //满足满减条件,单价调整为满减单价
 
             if ($rule->strategy=='起步'){
                 $startNumber = $rule->amount;
                 $money = 0;
-                if ($unitName && $startNumber && $rule->unit_id && $unitName != $units[$rule->unit_id])return -3; //校验单位是否一致
-
-                if ($startNumber){
+                if ($startNumber){ //起步数存在 重设数量
                     $money = $rule->unit_price;
-                    $matchObject=$this->settingCount($matchObject,$columnMapping[8],$startNumber);
+                    $matchObject=$this->settingCount($matchObject,$columnMapping[8],$startNumber,$rule->unit_id);
+                }
+                //费用计算
+                if ($matchObject)foreach ($matchObject as $index=>$package){
+                    if (!isset($package["price"]))$package["price"] = 0;
+                    $partMoney = $package[$columnMapping[8]] * $package["price"];
+                    $money += $partMoney;
+                    $exe($package,$index,$partMoney,$startNumber,$rule); //向信息提取器输入信息
+                }
+                //起步费存在 验证重设
+                if (!$startNumber && $money<$rule->unit_price){
+                    $diffMoney = $rule->unit_price-$money;
+                    if ($GLOBALS["FEE_INFO"]){
+                        $GLOBALS["FEE_INFO"][0]["fee_description"] .= ",低于起步费".$rule->unit_price."元,加收差费".$diffMoney;
+                        $GLOBALS["FEE_INFO"][0]["details"][] = [
+                            "name"      => "起步费补差",
+                            "amount"    => 1,
+                            "price"     => $diffMoney,
+                            "unit_id"   => $flip["单"],
+                        ];
+                    }
+                    $money += $diffMoney;
                 }
-                if ($matchObject)foreach ($matchObject as $package)if ($package["price"] ?? false)$money += $package[$columnMapping[8]] * $package["price"];
-                if (!$startNumber && $money<$rule->unit_price)$money = $rule->unit_price;
-                return $money+$surcharge;
+                return $money+$surcharge+$oddMoney;
             }
             foreach ($matchObject as &$package){
-                if ($package["price"] ?? false)continue;
-                if (!isset($units[$rule->unit_id]))return -3;
-                if (!$unitName)$unitName = $units[$rule->unit_id];
-                else if ($unitName != $units[$rule->unit_id]) return -3;
+                if (isset($package["price"]))continue; //单价存在 跳过
+                if (!isset($units[$rule->unit_id]))return -3;//单位未知 跳出
                 if ($rule->strategy=='特征'){
                     $package[$columnMapping[10]] = $total; //设置一个不存在的总数进入原对象
                     if (!app("FeatureService")->matchFeature($rule->feature,$columnMapping,$package)) continue;
                 }
                 $package["price"] = $rule->unit_price;
-            }
-            if ($units[$rule->unit_id] != '件'){ //非件时改变商品数量 此时数量可能为小数
-                foreach ($matchObject as &$commodity){
-                    switch ($units[$rule->unit_id]){
-                        case "箱"://为箱时同步商品寻找箱规并改变商品数量
-                            $pack = $this->changeUnit($ownerId,$commodity[$columnMapping[9]]);
-                            if ($rule->odd_price){
-                                $amount = floor($commodity[$columnMapping[8]]/$pack);
-                                $surcharge += $rule->odd_price * ($amount%$pack); //零头附加费
-                            }else$amount = ceil($commodity[$columnMapping[8]]/$pack);
-                            if ($amount<0)return $amount;
-                            $commodity[$columnMapping[8]] = $amount;
-                            break;
-                        case "m³":
-                            $commodity[$columnMapping[8]] = $commodity["bulk"] ?? 0;
-                            break;
-                        case "kg":
-                            $commodity[$columnMapping[8]] = $commodity["weight"] ?? 0;
-                            break;
-                        case "T":
-                            $commodity[$columnMapping[8]] = ($commodity["weight"]/1000) ?? 0;
-                            break;
-                    }
+                $package["unitId"] = $rule->unit_id;
+                $package["fee_info"] = [];
+                switch ($units[$rule->unit_id]){
+                    case "箱"://为箱时同步商品寻找箱规并改变商品数量
+                        $pack = $this->changeUnit($ownerId,$package[$columnMapping[9]]);
+                        if ($pack<=0)return $pack;
+                        if ($rule->odd_price){
+                            $amount = $package[$columnMapping[8]];
+                            $odd = $amount%$pack;
+                            $amount = floor($amount/$pack);
+                            $oddMoney += $rule->odd_price * $odd; //零头附加费
+                            $package["fee_info"][] = [
+                                "name"      => "零头附加费",
+                                "amount"    => $odd,
+                                "price"     => $rule->odd_price,
+                                "unit_id"   => $flip["件"],
+                            ];
+                        }else $amount = ceil($package[$columnMapping[8]]/$pack);
+                        if ($amount<0)return $amount;
+                        $package[$columnMapping[8]] = $amount;
+                        break;
+                    case "m³":
+                        $package[$columnMapping[8]] = $package["bulk"] ?? 0;
+                        break;
+                    case "kg":
+                        $package[$columnMapping[8]] = $package["weight"] ?? 0;
+                        break;
+                    case "T":
+                        $package[$columnMapping[8]] = ($package["weight"]/1000) ?? 0;
+                        break;
                 }
             }
         }
-        $money = $surcharge;
-        foreach ($matchObject as $mo)if ($mo["price"] ?? false)$money += $mo[$columnMapping[8]] * $mo["price"];
-        return $money ?? -7;
+        $money = $surcharge+$oddMoney;
+        foreach ($matchObject as $index=>$mo){
+            if (!isset($mo["price"]))$mo["price"] = 0;
+            $partMoney = $mo[$columnMapping[8]] * $mo["price"];
+            $money += $partMoney;
+            $exe($mo,$index,$partMoney,0,null);
+        }
+        return $money ?: -7;
     }
-    //递归式重新设置数量
-    private function settingCount($packages,$amountColumn,$startNumber)
+    //递归式重新设置数量 只设置单位匹配对象
+    private function settingCount($packages,$amountColumn,$startNumber,$unitId)
     {
         if (!$packages) return null;
         $maxPrice = 0;
-        $index = null;
         foreach ($packages as $i => $package){
-            if ($package[$amountColumn] <= 0){
-                unset($packages[$i]);continue;
-            }
-            if (!($package["price"] ?? false)){
-                $package["price"] = 0;
-                $packages[$i]["price"] = 0;
-            }
-            if ($package["price"] > $maxPrice || ($package["price"]==0 && $maxPrice==0)){
-                $maxPrice = $package["price"];
-                $index = $i;
-            }
+            if ($package[$amountColumn] <= 0){$package["price"] = 0;$packages[$i]["price"] = 0;continue;}
+            if (!isset($package["price"])){$package["price"] = 0;$packages[$i]["price"] = 0;}
+            if (isset($package["unitId"]) && $package["unitId"]!=$unitId)continue;//单位不一致 跳过
+            if ($package["price"] > $maxPrice || ($package["price"]==0 && $maxPrice==0)){$maxPrice = $package["price"];$index = $i;}
         }
+        if (!isset($index))return $packages;
         if ($packages[$index][$amountColumn] >= $startNumber){
             $packages[$index][$amountColumn] -= $startNumber;
             return $packages;
         }else{
             $startNumber -= $packages[$index][$amountColumn];
-            unset($packages[$index]);
-            $this->settingCount($packages,$amountColumn,$startNumber);
+            $packages[$index]["price"] = 0;
+            $this->settingCount($packages,$amountColumn,$startNumber,$unitId);
         }
         return $packages;
     }

+ 4 - 4
app/Services/OwnerService.php

@@ -500,17 +500,16 @@ sql;
     }
 
     /**
-     * 获取税费
+     * 获取税率 或 税
      *
      * @param Model|\stdClass $model
      * @param int $ownerId
-     * @param float $money
+     * @param float|null $money
      *
      * @return float|null
      */
-    public function getTaxRateFee(Model $model, int $ownerId, float $money):?float
+    public function getTaxRateFee(Model $model, int $ownerId, ?float $money = null):?float
     {
-        if (!$money)return 0;
         $taxRate = null;
         if ($model->tax_rate_id){
             $model->loadMissing("taxRate");
@@ -524,6 +523,7 @@ sql;
             $taxRate = $owner->taxRate;
         }
         if (!$taxRate)return null;
+        if ($money===null)return $taxRate->value;
         return $money*($taxRate->value/100);
     }
 }

+ 3 - 1
app/Services/OwnerStoragePriceModelService.php

@@ -160,8 +160,10 @@ class OwnerStoragePriceModelService
         }
         $GLOBALS["FEE_INFO"]["fee_description"] .= ",单价: ".$model->price[$index]."/".($model->unit->name ?? 'm²')."/".$model->timeUnit->name;
         $money = $area>0 ? $area*$model->price[$index] : 0;
-        $taxFee = app("OwnerService")->getTaxRateFee($model, $owner_id, $money);
+        $taxRate = app("OwnerService")->getTaxRateFee($model, $owner_id);
+        $taxFee = $money*($taxRate/100);
         $GLOBALS["FEE_INFO"]["fee_description"] .= ",税费: ".$taxFee;
+        $GLOBALS["FEE_INFO"]["tax_rate"] = $taxRate;
         return array($money,$taxFee);
     }
 }

+ 15 - 1
app/Services/RejectedBillService.php

@@ -353,16 +353,19 @@ class RejectedBillService
         foreach (Store::query()->with("storeItems")->whereIn("id",$number)->get() as $store){
             /** @var OwnerPriceOperationService $service */
             $service = app("OwnerPriceOperationService");
+            $GLOBALS["FEE_INFO"] = [];
             list($id,$money,$taxFee) = $service->matching($store, Feature::MAPPING["store"], $store->owner_id, "入库",0);
             $bill = OwnerFeeDetail::query()->where("outer_id",$store->id)->where("outer_table_name","stores")->first();
+            if ($bill)app("StoreService")->clearFeeInfo($store->asn_code);
             if ($bill) $bill->update([
                     "work_fee" => $money,
+                    "worked_at" => $rejectedBill->updated_at,
                     "owner_price_operation_id" => $id,
                     "outer_id" => $rejectedBill->id,
                     "outer_table_name" => "rejected_bills",
             ]); else app("OwnerFeeDetailService")->create([
                 "owner_id" => $store->owner_id,
-                "worked_at" => $store->created_at,
+                "worked_at" => $rejectedBill->updated_at,
                 "type" => "收货",
                 "operation_bill" => $store->asn_code,
                 "commodity_amount" => array_sum(array_column($store->storeItems->toArray(), "amount")),
@@ -373,6 +376,17 @@ class RejectedBillService
                 "outer_table_name" => "rejected_bills",
                 "work_tax_fee" => $taxFee,
             ]);
+            app("StoreService")->constructFeeInfo([
+                "worked_at" => $rejectedBill->updated_at,
+                "owner_id" => $rejectedBill->id_owner,
+                "model_id"  => $id,
+                "source_number"=> null,
+                "doc_number"   => $store->asn_code,
+                "commodity_id" => 0,
+                "total_fee"    =>0,
+                "tax_rate"     =>0,
+                "fee_description"=>'',
+            ]);
         }
     }
 }

+ 56 - 138
app/Services/StoreService.php

@@ -6,6 +6,8 @@ use App\Feature;
 use App\Jobs\StoreCreateInstantBill;
 use App\Order;
 use App\OwnerFeeDetail;
+use App\OwnerFeeOperation;
+use App\OwnerFeeOperationDetail;
 use App\Services\common\BatchUpdateService;
 use App\Services\common\DataHandlerService;
 use App\Services\common\QueryService;
@@ -325,9 +327,21 @@ class StoreService
         /** @var OwnerPriceOperationService $service */
         $service = app("OwnerPriceOperationService");
 
+        $GLOBALS["FEE_INFO"] = [];
         list($id,$money,$taxFee) = $service->matching($store, Feature::MAPPING["store"], $store->owner_id, "入库");
+        if ($money>0)$this->constructFeeInfo([
+                "worked_at" => $store->updated_at,
+                "owner_id" => $store->owner_id,
+                "model_id"  => $id,
+                "source_number"=> null,
+                "doc_number"   => $store->asn_code,
+                "commodity_id" => 0,
+                "total_fee"    =>0,
+                "tax_rate"     =>0,
+                "fee_description"=>'',
+            ]);
 
-        if (app("OwnerFeeDetailService")->create([
+        if (!app("OwnerFeeDetailService")->create([
             "owner_id" => $store->owner_id,
             "worked_at" => $store->updated_at,
             "type" => "收货",
@@ -339,15 +353,48 @@ class StoreService
             "outer_id" => $store->id,
             "outer_table_name" => "stores",
             "work_tax_fee" => $taxFee,
-        ])){
-            $amount = 0;
-            if ($store->storeItems)foreach ($store->storeItems as $item)$amount += $item->amount;
-            $this->setStoreAmount($store->owner_id,$amount);
-            Cache::put("owner_fee_details:stores_".$store->id,1,86400);
-            return true;
+        ])) return false;
+        $amount = 0;
+        if ($store->storeItems)foreach ($store->storeItems as $item)$amount += $item->amount;
+        $this->setStoreAmount($store->owner_id,$amount);
+        Cache::put("owner_fee_details:stores_".$store->id,1,86400);
+        return true;
+    }
+
+    /**
+     * 构建费用信息
+     *
+     * @param array $defaultInfo
+     *
+     * @return void
+     */
+    public function constructFeeInfo(array $defaultInfo)
+    {
+        foreach ($GLOBALS["FEE_INFO"] as $info){
+            $operation = $defaultInfo;
+            foreach ($operation as $key=>$val)if (isset($info[$key]))$operation[$key] = $info[$key];
+            $model = OwnerFeeOperation::query()->create($operation);
+            foreach ($info['details'] as &$detail)$detail["owner_fee_operation_id"] = $model->id;
+            OwnerFeeOperationDetail::query()->insert($info['details']);
         }
-        return false;
     }
+    /**
+     * 清除费用信息
+     *
+     * @param string $docNumber
+     */
+    public function clearFeeInfo(string $docNumber)
+    {
+        $models = OwnerFeeOperation::query()->where("doc_number",$docNumber)->get();
+        if ($models->count()==0)return;
+        OwnerFeeOperationDetail::query()->whereIn("owner_fee_operation_id",array_column($models->toArray(),"id"))->delete();
+        OwnerFeeOperation::query()->where("doc_number",$docNumber)->delete();
+    }
+
+    /**
+     * @param $asnHerders
+     * @return null
+     */
     public function createStoreRejected($asnHerders){
         if (!$asnHerders) return null;
         $stores = $this->getByWms($asnHerders);
@@ -388,7 +435,7 @@ SELECT sum(amount) total FROM `store_items` LEFT JOIN stores ON store_items.stor
 sql
         );
         $statistics = DB::selectOne($query,[$owner,date("Y-m")."%"]);
-        Cache::put(date("Y-m")."|A|".$owner,$statistics->total ? $statistics->total : 0,2764800);
+        Cache::put(date("Y-m")."|A|".$owner,$statistics->total ?: 0,2764800);
     }
 
     /**
@@ -417,133 +464,4 @@ sql
         if (!Cache::has($date."|A|".$owner))$this->storeAmountCompensationLogic($owner);
         return Cache::get($date."|A|".$owner);
     }
-
-    public function warehousing(array $params)
-    {
-        $conn = oci_connect(config('database.connections.oracle.username'),
-            config('database.connections.oracle.password'),
-            config('database.connections.oracle.host'). '/' . config('database.connections.oracle.service_name'),"utf8");
-        $sp = "begin SPASN_Receiving_Process(:IN_Warehouse, :In_Process_Action, :In_ASNNo_C, :In_ASNLineNo_C, :In_FMTraceID_C, :In_New_TraceID_C, :In_ProductStatus," .
-            ":In_ProductStatus_Descr, :In_HoldRejectCode_C, :In_HoldRejectReason_C, :In_PONo_C, :In_CustomerID, :In_SKU, :In_ReceivedQty, :In_RejectedQty,:In_UOM, :In_PackID," .
-            " :In_ContainerID, :In_LotAtt01_C, :In_LotAtt02_C, :In_LotAtt03_C, :In_LotAtt04_C, :In_LotAtt05_C, :In_LotAtt06_C," .
-            ":In_LotAtt07_C, :In_LotAtt08_C, :In_LotAtt09_C, :In_LotAtt10_C, :In_LotAtt11_C, :In_LotAtt12_C," .
-            ":In_TotalCubic, :In_TotalGrossWeight, :In_TotalNetWeight, :In_TotalPrice, :In_UserDefine1, :In_UserDefine2,:In_UserDefine3, :In_UserDefine4, :In_UserDefine5, :In_FMLocation," .
-            ":In_TOLocation_C,:In_QC_Type_C, :In_PlanToLoc_C,:In_ReceivingTime, :In_LPN, :In_Operator, :IN_RCVModule, :IN_RCVStation, :In_Language, :In_UserID, :OUT_Return_Code); end;";
-        $inParams = array(
-            "IN_Warehouse"=>"",
-            "In_Process_Action"=>"",
-            "In_ASNNo_C"=>"",
-            "In_ASNLineNo_C"=>"",
-            "In_FMTraceID_C"=>"",
-            "In_New_TraceID_C"=>"",
-            "In_ProductStatus"=>"00",
-            "In_ProductStatus_Descr"=>"正常",
-            "In_HoldRejectCode_C"=>"OK",
-            "In_HoldRejectReason_C"=>"正常",
-            "In_PONo_C"=>"",
-            "In_CustomerID"=>"",
-            "In_SKU"=>"",
-            "In_ReceivedQty"=>"",
-            "In_RejectedQty"=>"",
-            "In_UOM"=>"EA",
-            "In_PackID"=>"",
-            "In_ContainerID"=>"",
-            "In_LotAtt01_C"=>"",
-            "In_LotAtt02_C"=>"",
-            "In_LotAtt03_C"=>"",
-            "In_LotAtt04_C"=>"",
-            "In_LotAtt05_C"=>"",
-            "In_LotAtt06_C"=>"",
-            "In_LotAtt07_C"=>"",
-            "In_LotAtt08_C"=>"",
-            "In_LotAtt09_C"=>"",
-            "In_LotAtt10_C"=>"",
-            "In_LotAtt11_C"=>"",
-            "In_LotAtt12_C"=>"",
-            "In_TotalCubic"=>"0.00",
-            "In_TotalGrossWeight"=>"0.00",
-            "In_TotalNetWeight"=>"0.00",
-            "In_TotalPrice"=>"0.00",
-            "In_UserDefine1"=>"",
-            "In_UserDefine2"=>"",
-            "In_UserDefine3"=>"",
-            "In_UserDefine4"=>"",
-            "In_UserDefine5"=>"",
-            "In_FMLocation"=>"",
-            "In_TOLocation_C"=>"",
-            "In_QC_Type_C"=>"OK",
-            "In_PlanToLoc_C"=>"",
-            "In_ReceivingTime"=>"",
-            "In_LPN"=>"*",
-            "In_Operator"=>"WCS",
-            "IN_RCVModule"=>"",
-            "IN_RCVStation"=>"",
-            "In_Language"=>"cn",
-            "In_UserID"=>"WCS",
-            "result"=>""
-        );
-        foreach ($params as $key=>$val)$inParams[$key] = $val;
-        list($IN_Warehouse,$In_Process_Action,$In_ASNNo_C,$In_ASNLineNo_C,$In_FMTraceID_C,$In_New_TraceID_C,$In_ProductStatus,
-            $In_ProductStatus_Descr,$In_HoldRejectCode_C,$In_HoldRejectReason_C,$In_PONo_C,$In_CustomerID,$In_SKU,$In_ReceivedQty,
-            $In_RejectedQty,$In_UOM,$In_PackID,$In_ContainerID,$In_LotAtt01_C,$In_LotAtt02_C,$In_LotAtt03_C,$In_LotAtt04_C,$In_LotAtt05_C,
-            $In_LotAtt06_C,$In_LotAtt07_C,$In_LotAtt08_C,$In_LotAtt09_C,$In_LotAtt10_C,$In_LotAtt11_C,$In_LotAtt12_C,$In_TotalCubic,
-            $In_TotalGrossWeight,$In_TotalNetWeight,$In_TotalPrice,$In_UserDefine1,$In_UserDefine2,$In_UserDefine3,$In_UserDefine4,
-            $In_UserDefine5,$In_FMLocation,$In_TOLocation_C,$In_QC_Type_C,$In_PlanToLoc_C,$In_ReceivingTime,$In_LPN,$In_Operator,
-            $IN_RCVModule,$IN_RCVStation,$In_Language,$In_UserID,$result) = array_values($inParams);
-        $stmt = oci_parse($conn, $sp);
-        oci_bind_by_name($stmt, ':IN_Warehouse', $IN_Warehouse);
-        oci_bind_by_name($stmt, ':In_Process_Action', $In_Process_Action);
-        oci_bind_by_name($stmt, ':In_ASNNo_C', $In_ASNNo_C);
-        oci_bind_by_name($stmt, ':In_ASNLineNo_C', $In_ASNLineNo_C);
-        oci_bind_by_name($stmt, ':In_FMTraceID_C', $In_FMTraceID_C);
-        oci_bind_by_name($stmt, ':In_New_TraceID_C', $In_New_TraceID_C);
-        oci_bind_by_name($stmt, ':In_ProductStatus', $In_ProductStatus);
-        oci_bind_by_name($stmt, ':In_ProductStatus_Descr', $In_ProductStatus_Descr);
-        oci_bind_by_name($stmt, ':In_HoldRejectCode_C', $In_HoldRejectCode_C);
-        oci_bind_by_name($stmt, ':In_HoldRejectReason_C', $In_HoldRejectReason_C);
-        oci_bind_by_name($stmt, ':In_PONo_C', $In_PONo_C);
-        oci_bind_by_name($stmt, ':In_CustomerID', $In_CustomerID);
-        oci_bind_by_name($stmt, ':In_SKU', $In_SKU);
-        oci_bind_by_name($stmt, ':In_ReceivedQty', $In_ReceivedQty);
-        oci_bind_by_name($stmt, ':In_RejectedQty', $In_RejectedQty);
-        oci_bind_by_name($stmt, ':In_UOM', $In_UOM);
-        oci_bind_by_name($stmt, ':In_PackID', $In_PackID);
-        oci_bind_by_name($stmt, ':In_ContainerID', $In_ContainerID);
-        oci_bind_by_name($stmt, ':In_LotAtt01_C', $In_LotAtt01_C);
-        oci_bind_by_name($stmt, ':In_LotAtt02_C', $In_LotAtt02_C);
-        oci_bind_by_name($stmt, ':In_LotAtt03_C', $In_LotAtt03_C);
-        oci_bind_by_name($stmt, ':In_LotAtt04_C', $In_LotAtt04_C);
-        oci_bind_by_name($stmt, ':In_LotAtt05_C', $In_LotAtt05_C);
-        oci_bind_by_name($stmt, ':In_LotAtt06_C', $In_LotAtt06_C);
-        oci_bind_by_name($stmt, ':In_LotAtt07_C', $In_LotAtt07_C);
-        oci_bind_by_name($stmt, ':In_LotAtt08_C', $In_LotAtt08_C);
-        oci_bind_by_name($stmt, ':In_LotAtt09_C', $In_LotAtt09_C);
-        oci_bind_by_name($stmt, ':In_LotAtt10_C', $In_LotAtt10_C);
-        oci_bind_by_name($stmt, ':In_LotAtt11_C', $In_LotAtt11_C);
-        oci_bind_by_name($stmt, ':In_LotAtt12_C', $In_LotAtt12_C);
-        oci_bind_by_name($stmt, ':In_TotalCubic', $In_TotalCubic);
-        oci_bind_by_name($stmt, ':In_TotalGrossWeight', $In_TotalGrossWeight);
-        oci_bind_by_name($stmt, ':In_TotalNetWeight', $In_TotalNetWeight);
-        oci_bind_by_name($stmt, ':In_TotalPrice', $In_TotalPrice);
-        oci_bind_by_name($stmt, ':In_UserDefine1', $In_UserDefine1);
-        oci_bind_by_name($stmt, ':In_UserDefine2', $In_UserDefine2);
-        oci_bind_by_name($stmt, ':In_UserDefine3', $In_UserDefine3);
-        oci_bind_by_name($stmt, ':In_UserDefine4', $In_UserDefine4);
-        oci_bind_by_name($stmt, ':In_UserDefine5', $In_UserDefine5);
-        oci_bind_by_name($stmt, ':In_FMLocation', $In_FMLocation);
-        oci_bind_by_name($stmt, ':In_TOLocation_C', $In_TOLocation_C);
-        oci_bind_by_name($stmt, ':In_QC_Type_C', $In_QC_Type_C);
-        oci_bind_by_name($stmt, ':In_PlanToLoc_C', $In_PlanToLoc_C);
-        oci_bind_by_name($stmt, ':In_ReceivingTime', $In_ReceivingTime);
-        oci_bind_by_name($stmt, ':In_LPN', $In_LPN);
-        oci_bind_by_name($stmt, ':In_Operator', $In_Operator);
-        oci_bind_by_name($stmt, ':IN_RCVModule', $IN_RCVModule);
-        oci_bind_by_name($stmt, ':IN_RCVStation', $IN_RCVStation);
-        oci_bind_by_name($stmt, ':In_Language', $In_Language);
-        oci_bind_by_name($stmt, ':In_UserID', $In_UserID);
-        oci_bind_by_name($stmt, ':OUT_Return_Code', $result,300);
-        oci_execute($stmt);
-        oci_close($conn);
-        return $result;
-    }
 }

+ 30 - 3
app/Services/WaybillService.php

@@ -5,6 +5,7 @@ namespace App\Services;
 use App\Http\Controllers\api\thirdPart\flux\WaybillController;
 use App\Order;
 use App\OwnerFeeDetail;
+use App\OwnerFeeLogistic;
 use App\Services\common\BatchUpdateService;
 use App\Services\common\QueryService;
 use App\Traits\ModelSearchWay;
@@ -212,7 +213,7 @@ class WaybillService
      *
      * @param Waybill|\stdClass $waybill
      * @param array $param
-     * @param $id
+     *
      * @return Model
      */
     public function update(Waybill $waybill,array $param)
@@ -252,11 +253,28 @@ class WaybillService
         if ($detail && $detail->logistic_fee !== null)return false;
 
         if ($waybill->type == "专线"){
+            $provinceId = $waybill->order ? app("ProvinceService")->getProvince($waybill->order->province) : $waybill->destinationCity->province_id;
+            $cityId = $waybill->destination_city_id;
+            $consigneeName = $waybill->order ? $waybill->order->consignee_name : $waybill->recipient;
+            $consigneePhone = $waybill->order ? $waybill->order->consignee_phone : $waybill->recipient_mobile;
+            $GLOBALS["FEE_INFO"] = [
+                "province_id" => $provinceId,
+                "owner_id"  => $waybill->owner_id,
+                "city_id"   => $cityId,
+                "logistic_id" => $waybill->logistic_id,
+                "order_number" => $waybill->wms_bill_number,
+                "recipient_name"=>$consigneeName,
+                "recipient_phone"=>$consigneePhone,
+                "quantity"=>$waybill->carrier_weight_other,
+                "unit_id"=>$waybill->carrier_weight_unit_id_other,
+                "remark"=>$waybill->ordering_remark,
+                "created_at"=>$waybill->updated_at,
+            ];
             /** @var OwnerPriceLogisticService $service */
             $service = app("OwnerPriceLogisticService");
             list($fee,$taxFee) = $service->matching($waybill->carrier_weight_other,$owner_id,$waybill->logistic_id,
-                $waybill->carrier_weight_unit_id_other,$waybill->order ? app("ProvinceService")->getProvince($waybill->order->province) : $waybill->destinationCity->province_id,
-                $waybill->destination_city_id);
+                $waybill->carrier_weight_unit_id_other,$provinceId, $cityId);
+            $this->buildWaybillFeeInfo();
         }else{
             /** @var OwnerPriceDirectLogisticService $service */
             $service = app("OwnerPriceDirectLogisticService");
@@ -286,6 +304,15 @@ class WaybillService
         return true;
     }
 
+    /**
+     * 构建运输费用信息
+     */
+    public function buildWaybillFeeInfo()
+    {
+        if (!isset($GLOBALS["FEE_INFO"]))return;
+        OwnerFeeLogistic::query()->create($GLOBALS["FEE_INFO"]);
+    }
+
     /**
      * 生成德邦单据
      *

+ 2 - 1
database/migrations/2021_08_11_173608_create_owner_fee_storages_table.php

@@ -18,7 +18,8 @@ class CreateOwnerFeeStoragesTable extends Migration
             $table->string("counting_type")->comment("计费类型");
             $table->string("using_type")->comment("用仓类型");
             $table->text("fee_description")->comment("费用描述");
-            $table->decimal("total",10,3)->comment("总金额");
+            $table->decimal("total_fee",10,3)->comment("总金额");
+            $table->decimal("tax_rate",10,3)->nullable()->comment("税率");
         });
     }
 

+ 43 - 0
database/migrations/2021_08_12_140948_create_owner_fee_expresses_table.php

@@ -0,0 +1,43 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOwnerFeeExpressesTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('owner_fee_expresses', function (Blueprint $table) {
+            $table->id();
+            $table->bigInteger("province_id")->index()->comment("外联省份");
+            $table->bigInteger("logistic_id")->index()->comment("快递公司");
+            $table->bigInteger("owner_id")->index()->comment("货主ID");
+            $table->string("logistic_number")->comment("快递单号");
+            $table->decimal("weight",10,3)->comment("重量");
+            $table->decimal("initial_weight",10,3)->comment("首重重量");
+            $table->decimal("initial_weight_price",10,3)->comment("首重价格");
+            $table->decimal("additional_weight",10,3)->comment("续重重量");
+            $table->decimal("additional_weight_amount",10,3)->comment("续重量");
+            $table->decimal("additional_weight_price",10,3)->comment("续重价格");
+            $table->decimal("total_fee",10,3)->comment("快递费");
+            $table->decimal("tax_rate",10,3)->nullable()->comment("税率");
+            $table->timestamp("created_at")->comment("建立时间");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('owner_fee_expresses');
+    }
+}

+ 52 - 0
database/migrations/2021_08_12_141004_create_owner_fee_logistics_table.php

@@ -0,0 +1,52 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOwnerFeeLogisticsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('owner_fee_logistics', function (Blueprint $table) {
+            $table->id();
+            $table->bigInteger("province_id")->index()->comment("外联省份");
+            $table->bigInteger("owner_id")->index()->comment("货主ID");
+            $table->bigInteger("city_id")->index()->comment("外联城市");
+            $table->bigInteger("logistic_id")->index()->comment("快递公司");
+            $table->string("order_number")->nullable()->comment("订单号");
+            $table->string("recipient_name")->nullable()->comment("收件人姓名");
+            $table->string("recipient_phone")->nullable()->comment("收件人电话");
+            $table->decimal("quantity",10,3)->comment("计量");
+            $table->bigInteger("unit_id")->comment("单位");
+            $table->string("interval")->comment("区间");
+            $table->decimal("price",10,3)->comment("单价");
+            $table->decimal("delivery_fee",10,3)->nullable()->comment("送货费");
+            $table->decimal("pick_fee",10,3)->nullable()->comment("提货费");
+            $table->decimal("fuel_fee",10,3)->nullable()->comment("燃油附加费");
+            $table->decimal("info_fee",10,3)->nullable()->comment("信息费");
+            $table->decimal("other_fee",10,3)->nullable()->comment("其他费用");
+            $table->decimal("initial_fee",10,3)->default(0)->comment("起始计费");
+            $table->decimal("initial_amount",10,3)->default(0)->comment("起始计数");
+            $table->decimal("total_fee",10,3)->comment("总费用");
+            $table->decimal("tax_rate",10,3)->nullable()->comment("税率");
+            $table->text("remark")->nullable()->comment("备注");
+            $table->timestamp("created_at")->comment("建立时间");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('owner_fee_logistics');
+    }
+}

+ 39 - 0
database/migrations/2021_08_13_093747_create_owner_fee_operations.php

@@ -0,0 +1,39 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOwnerFeeOperations extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('owner_fee_operations', function (Blueprint $table) {
+            $table->id();
+            $table->bigInteger("owner_id")->index()->comment("货主ID");
+            $table->date("worked_at")->comment("作业时间");
+            $table->bigInteger("model_id")->comment("外联计费模型");
+            $table->string("source_number")->nullable()->comment("上游单号");
+            $table->string("doc_number")->comment("单据单号");
+            $table->bigInteger("commodity_id")->comment("外键商品");
+            $table->decimal("total_fee",10,3)->comment("总价");
+            $table->decimal("tax_rate",10,3)->nullable()->comment("税率");
+            $table->text("fee_description")->nullable()->comment("描述");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('owner_fee_operations');
+    }
+}

+ 35 - 0
database/migrations/2021_08_13_093836_create_owner_fee_operation_details.php

@@ -0,0 +1,35 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOwnerFeeOperationDetails extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('owner_fee_operation_details', function (Blueprint $table) {
+            $table->id();
+            $table->bigInteger("owner_fee_operation_id")->comment("外键父级");
+            $table->string("name")->comment("名称");
+            $table->decimal("amount",10,3)->comment("数量");
+            $table->decimal("price",10,3)->comment("单价");
+            $table->bigInteger("unit_id")->comment("外键单位");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('owner_fee_operation_details');
+    }
+}

+ 1 - 1
resources/views/customer/project/index.blade.php

@@ -74,7 +74,7 @@
                         <button class="btn btn-sm btn-info text-white" @click="showModal(owner)">各项计价</button>
                     </td>
                     <td>
-                        <a :href="'{{url('customer/project')}}/'+owner.id+'/edit'"><button class="btn btn-sm btn0sm btn-outline-info">编辑</button></a>
+                        @can("项目管理-项目-编辑")<a :href="'{{url('customer/project')}}/'+owner.id+'/edit'"><button class="btn btn-sm btn0sm btn-outline-info">编辑</button></a>@endcan
                         @can('客户管理-项目-停用')
                             <button class="btn btn-sm btn-outline-danger" @click="destroy(owner)">停用</button>
                         @endcan

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

@@ -79,7 +79,7 @@
         <label class="col-4 text-secondary">@{{ value ? (model.operation.discount_count[i+1] ? value+'-'+(model.operation.discount_count[i+1]-1)+' '+(model.operation.operation_type=='入库' ? '件' : '单')+'/月' : value+'+ '+(model.operation.operation_type=='入库' ? '件' : '单')+'/月') : '' }}</label>
     </div>
 </div>
-<div class="row mt-3">
+<div class="row mt-3" v-if="!model.operation.isSingle">
     <label class="col-2" for="max_fee">封顶费</label>
     <input type="number" id="max_fee" step="0.01" min="0" class="form-control col-6" v-model="model.operation.max_fee">
 </div>
@@ -170,7 +170,7 @@
         </div>
     </div>
 </div>
-<div class="row mt-3" v-if="model.operation.operation_type=='出库'">
+<div class="row mt-3" v-if="model.operation.operation_type=='出库' && !model.operation.isSingle">
     <label for="surcharge" class="col-2">耗材附加费</label>
     <input id="surcharge" type="number" step="0.01" min="0" class="form-control col-3" :class="errors.surcharge ? 'is-invalid' : ''" v-model="model.operation.surcharge">
     <label for="surcharge_unit_id" class="col-2 text-right">单位</label>
@@ -189,4 +189,4 @@
         <option> </option>
         <option v-for="tax in pool.taxRates" :value="tax.id">@{{ tax.value }}%</option>
     </select>
-</div>
+</div>