cqp 2 månader sedan
förälder
incheckning
325a913b54

+ 7 - 0
app/Model/PurchaseOrderInfoForOutBound.php

@@ -14,4 +14,11 @@ class PurchaseOrderInfoForOutBound extends Model
     const is_use = 1;
     const type_one = 1;
     const prefix = 'CGCk';
+
+    const from_type_zero = 0; // 采购单
+    const from_type_one = 1;  // 盘点单
+    const from_type = [
+        self::from_type_zero,
+        self::from_type_one,
+    ];
 }

+ 146 - 4
app/Service/InventoryService.php

@@ -8,6 +8,7 @@ use App\Model\Inventory;
 use App\Model\InventorySub;
 use App\Model\OrderInventoryStock;
 use App\Model\Product;
+use App\Model\PurchaseOrderInfoForOutBound;
 use App\Model\Storehouse;
 use Illuminate\Support\Facades\DB;
 
@@ -301,10 +302,10 @@ class InventoryService extends Service
                 if(! $bool) return [false, '盘点单价不合法,需是大于等于0的两位数值'];
             }
 
-            if(isset($value['final_amount'])){
-                $bool = $this->checkNumber($value['final_amount']);
-                if(! $bool) return [false, '盈亏金额不合法,需是大于等于0的两位数值'];
-            }
+            if(! isset($value['final_amount'])) return [false, '盈亏金额不存在'];
+            if(! is_numeric($value['final_amount'])) return [false, '盈亏金额不合法'];
+            $formattedNumber = number_format($value['final_amount'], 2, '.', '');
+            if($formattedNumber != $value['final_amount']) return [false, '盈亏金额请填写不超过两位小数的数字'];
 
             $key = $value['product_id'] . ',' .$data['storehouse_id'];
             if(! isset($product_submit[$key])) $product_submit[$key] = 0;
@@ -422,4 +423,145 @@ class InventoryService extends Service
 
         return [true, ''];
     }
+
+    //获取盘点单产品数量 出库 后最终产品数量 (通过产品以及仓库)
+    public function getInventoryProduct($product = [], $storehouse = 0){
+        if(empty($product) || empty($storehouse)) return [];
+
+        //盘点单
+        $purchase_id = Inventory::where('del_time',0)
+            ->where('state',Inventory::STATE_TWO)
+            ->where('storehouse_id',$storehouse)
+            ->select('id')
+            ->get()->toArray();
+        $purchase_id = array_column($purchase_id,'id');
+
+        //盘点单产品数量
+        $purchase_product = InventorySub::where('del_time',0)
+            ->whereIn('inventory_id',$purchase_id)
+            ->whereIn('product_id',$product)
+            ->where('final_num','>', 0)
+            ->select('id','final_num as number','price','inventory_id as purchase_order_id','order_number','product_id')
+            ->orderBy('id','asc')
+            ->get()->toArray();
+
+        //盘点单已出库产品(包含占用)
+        $purchase_product_outbound = PurchaseOrderInfoForOutBound::where('del_time',0)
+            ->whereIn('purchase_order_id',array_unique(array_column($purchase_product,'purchase_order_id')))
+            ->where('type',PurchaseOrderInfoForOutBound::type_one)
+            ->where('from_order_type',PurchaseOrderInfoForOutBound::from_type_one)
+            ->select('purchase_order_id','product_id','number')
+            ->get()->toArray();
+        $purchase_product_outbound_map = [];
+        foreach ($purchase_product_outbound as $value){
+            $key = $value['purchase_order_id'] . $value['product_id'];
+            if(isset($purchase_product_outbound_map[$key])){
+                $total_number = bcadd($purchase_product_outbound_map[$key], $value['number'],2);
+                $purchase_product_outbound_map[$key] = $total_number;
+            }else{
+                $purchase_product_outbound_map[$key] = $value['number'];
+            }
+        }
+
+        $return = [];
+        foreach ($purchase_product as $value){
+            $key = $value['purchase_order_id'] . $value['product_id'];
+            $purchase_number_lock_tmp = $purchase_product_outbound_map[$key] ?? 0; //盘点单产品锁定未释放的数量
+
+            //最终盘点单下某个产品的实际数量
+            $number = bcsub($value['number'], $purchase_number_lock_tmp,2);
+
+            if($number <= 0) continue;
+
+            $return[$value['product_id']][] = [
+                'id' => $value['id'],
+                'purchase_order_id' => $value['purchase_order_id'],
+                'number' => $number,
+                'price' => $value['price'],
+                'order_number' => $value['order_number'],
+                'product_id' => $value['product_id'],
+                'from_order_type' => PurchaseOrderInfoForOutBound::from_type_one
+            ];
+        }
+
+        return $return;
+    }
+
+    //校验盘点单产品数量 出库 后最终产品数量 (通过盘点单明细id)
+    public function checkInventoryeProductByPurchaseInfoID($id, $product, $inventory_id){
+        if(empty($inventory_id)) return [true, []];
+        if(empty($product)) return [false, "出库产品校验产品不能为空"];
+        $product_id = array_keys($product);
+
+        //盘点单产品数量
+        $purchase_product = InventorySub::where('del_time',0)
+            ->whereIn('inventory_id',$inventory_id)
+            ->whereIn('product_id',$product_id)
+            ->where('final_num','>', 0)
+            ->select('id','final_num as number','price','inventory_id as purchase_order_id','order_number','product_id')
+            ->orderBy('id','asc')
+            ->get()->toArray();
+        $purchase_product_map = [];
+        foreach ($purchase_product as $value){
+            $key = $value['purchase_order_id'] . $value['product_id'];
+            if(isset($purchase_product_map[$key])){
+                $total_number = bcadd($purchase_product_map[$key], $value['number'],2);
+                $purchase_product_map[$key] = $total_number;
+            }else{
+                $purchase_product_map[$key] = $value['number'];
+            }
+        }
+
+        //盘点单占用未释放数据
+        $purchase_product_outbound = PurchaseOrderInfoForOutBound::where('del_time',0)
+            ->whereIn('purchase_order_id',array_column($purchase_product,'purchase_order_id'))
+//            ->where('is_use',PurchaseOrderInfoForOutBound::is_not_use)
+            ->where('type',PurchaseOrderInfoForOutBound::type_one)
+            ->where('from_order_type',PurchaseOrderInfoForOutBound::from_type_one)
+            ->when(! empty($id), function ($query) use ($id) {
+                return $query->where('data_id', '<>', $id);
+            })
+            ->select('purchase_order_id','product_id','number')
+            ->get()->toArray();
+        $purchase_product_outbound_map = [];
+        foreach ($purchase_product_outbound as $value){
+            $key = $value['purchase_order_id'] . $value['product_id'];
+            if(isset($purchase_product_outbound_map[$key])){
+                $total_number = bcadd($purchase_product_outbound_map[$key], $value['number'],2);
+                $purchase_product_outbound_map[$key] = $total_number;
+            }else{
+                $purchase_product_outbound_map[$key] = $value['number'];
+            }
+        }
+
+        //校验
+        $count = [];
+        foreach ($product as $value){
+            $product_id = $value['product_id'];
+            $total = $value['total'];
+            foreach ($value['from'] as $f_v){
+                if(! $f_v['id'] || ! $f_v['purchase_order_id'] || $f_v['from_order_type'] != PurchaseOrderInfoForOutBound::from_type_one) continue;
+
+                $key = $f_v['purchase_order_id'] . $product_id;
+                $total_tmp = $purchase_product_map[$key] ?? 0; // 盘点单产品总数
+                $purchase_number_lock_tmp = $purchase_product_outbound_map[$key] ?? 0; // 盘点单产品锁定未释放的数量
+
+                //最终采购单下某个产品的实际数量
+//                $number = bcsub($value['number'], $value['outbound_number'],2);
+                $number = bcsub($total_tmp, $purchase_number_lock_tmp,2);
+
+                //比较
+                if($number < $f_v['number']) return [false, "盘点单:" . $f_v['order_number'] . "实际可以出库的数量" . $number];
+
+                if(isset($count[$value['product_id']])){
+                    $num_tmp = bcadd($count[$value['product_id']], $f_v['number'],2);
+                    $count[$value['product_id']] = $num_tmp;
+                }else{
+                    $count[$value['product_id']] = $f_v['number'];
+                }
+            }
+        }
+
+        return [true, $count];
+    }
 }

+ 97 - 22
app/Service/OutBoundOrderService.php

@@ -68,7 +68,7 @@ class OutBoundOrderService extends Service
                 ->where('type', PurchaseOrderInfoForOutBound::type_one)
                 ->update(['del_time' => $time]);
 
-            //增加采购占用
+            //增加占用
             $purchase_return = $msg[2] ?? [];
             if(! empty($purchase_return)){
                 foreach ($purchase_return as $key => $value){
@@ -135,7 +135,7 @@ class OutBoundOrderService extends Service
                 ProductInventoryService::changeLockNumber($user,$msg[0],[]);
             }
 
-            //增加采购占用
+            //增加占用
             $purchase_return = $msg[2] ?? [];
             if(! empty($purchase_return)){
                 foreach ($purchase_return as $key => $value){
@@ -232,7 +232,7 @@ class OutBoundOrderService extends Service
             ]);
             PurchaseOrderInfoForOutBound::where('del_time',0)
                 ->where('data_id', $order['id'])
-                ->where('type', 1)
+                ->where('type', PurchaseOrderInfoForOutBound::type_one)
                 ->update(['del_time' => $time]);
 //            (new RangeService())->RangeDelete($order['id'],SeeRange::type_three);
 
@@ -354,7 +354,7 @@ class OutBoundOrderService extends Service
                 if($number > $s_number) return [false,'出库产品数量不能超过合同产品数量'];
             }
 
-            //校验采购单
+            //校验产品
             list($status, $msg) = $this->checkPurchase($id,$data,$user);
             if(! $status) return [false, $msg];
 
@@ -414,9 +414,12 @@ class OutBoundOrderService extends Service
             ->where('id', $data_id)
             ->first();
         if(empty($sale)) return [false, '合同不存在或已被删除'];
-        $sale = $sale->toArray();
-        //仓库ID
-        $storehouse = Storehouse::where('top_depart_id', $sale['top_depart_id'])->where('del_time',0)->value('id');
+
+        //当前所在门店
+        $top_depart_id = $user['depart_top'][0] ?? [];
+        $top_depart_id = $top_depart_id['depart_id'] ?? 0;
+        //门店所在仓库
+        $storehouse = Storehouse::where('top_depart_id', $top_depart_id)->where('del_time',0)->value('id');
 
         $product = SalesOrderProductInfo::where('del_time',0)
             ->where('sales_order_id', $data_id)
@@ -429,6 +432,25 @@ class OutBoundOrderService extends Service
         $service = new PurchaseOrderService();
         $purchase = $service->getPurchaseProduct($product_id, $storehouse);
 
+        //盘点单产品
+        $service = new InventoryService();
+        $inventory = $service->getInventoryProduct($product_id, $storehouse);
+        $return_product = [];
+        foreach ($inventory as $key => $value){
+            if(! empty($value)){
+                foreach ($value as $val){
+                    $return_product[$key][] = $val;
+                }
+            }
+        }
+        foreach ($purchase as $key => $value){
+            if(! empty($value)){
+                foreach ($value as $val){
+                    $return_product[$key][] = $val;
+                }
+            }
+        }
+
         //合同出库产品
         $product_map = [];
         $save = OutBoundOrderInfo::where('del_time',0)
@@ -491,6 +513,7 @@ class OutBoundOrderService extends Service
             }
 
             $tmp = $map[$value['product_id']] ?? [];
+
             $return[] = [
                 'number' => $number, //可出数量
                 'out_number' => $p1, //已出库数量
@@ -504,7 +527,7 @@ class OutBoundOrderService extends Service
                 'code' => $tmp['code'] ?? "",
                 'size' => $tmp['size'] ?? "",
                 'unit' => $tmp['unit'] ?? "",
-                'purchase_product' => $purchase[$value['product_id']] ?? [],
+                'purchase_product' => $return_product[$value['product_id']] ?? [],
             ];
         }
 
@@ -519,14 +542,12 @@ class OutBoundOrderService extends Service
             ->where('id', $data_id)
             ->first();
         if(empty($sale)) return [false, '合同不存在或已被删除'];
-        $sale = $sale->toArray();
 
+        //当前所在门店
         $top_depart_id = $user['depart_top'][0] ?? [];
         $top_depart_id = $top_depart_id['depart_id'] ?? 0;
-        list($status, $msg) = $this->returnOrderEditErrorCommon($top_depart_id,$sale['top_depart_id']);
-        if(! $status) return [false, $msg];
-
-        $storehouse = Storehouse::where('top_depart_id', $sale['top_depart_id'])->where('del_time',0)->value('id');
+        //门店所在仓库
+        $storehouse = Storehouse::where('top_depart_id', $top_depart_id)->where('del_time',0)->value('id');
         if($storehouse_id && $storehouse_id != $storehouse) return [false, '出库仓库错误'];
 
         $product = SalesOrderProductInfo::where('del_time',0)
@@ -630,25 +651,27 @@ class OutBoundOrderService extends Service
         $purchase_product = [];
         foreach ($data['product'] as $value){
             $purchase = $value['purchase_product'] ?? [];
-            if(empty($purchase)) return [false, '出库操作时,请选择出库的产品来源采购单'];
+            if(empty($purchase)) return [false, '出库操作时,请选择出库的产品来源单'];
 
+            //产品明细校验
             foreach ($purchase as $p_v){
                 //必须校验的内容
-                if(empty($p_v['number'])) return [false, '采购单产品数量不能为空'];
+                if(empty($p_v['number'])) return [false, '单产品数量不能为空'];
                 $res = $this->checkNumber($p_v['number']);
-                if(! $res) return [false,'请输入正确的采购单产品数量'];
-                if(empty($p_v['product_id'])) return [false, '采购单产品ID不能为空'];
+                if(! $res) return [false,'请输入正确的订单产品数量'];
+                if(empty($p_v['product_id'])) return [false, '订单产品ID不能为空'];
+                if(! isset($p_v['from_order_type']) || ! in_array($p_v['from_order_type'], PurchaseOrderInfoForOutBound::from_type)) return [false, '来源单据类型不存在或不正确'];
 
                 if($is_check_stock != ProductInventorySet::type_two){
                     //库存校验开启时 校验 需要采购单明细子表id
                     if(! isset($p_v['id'])) return [false, 'ID不能为空'];
                     if(! empty($p_v['id'])) {
-                        list($status, $msg) = $this->limitingSendRequestBackgExpire("purchaseOrderInfo" . $p_v['id']);
-                        if(! $status) return [false, '采购单产品处于出库操作中,请稍后'];
+                        list($status, $msg) = $this->limitingSendRequestBackgExpire("ckOrderFromInfo" . $p_v['id'] . $p_v['from_order_type']);
+                        if(! $status) return [false, '单产品处于出库操作中,请稍后'];
                     }
                     if(! isset($p_v['purchase_order_id'])) return [false, 'purchaseOrderId不能为空'];
                     if(! isset($p_v['price'])) return [false, '采购单产品单价不能为空'];
-                    if(! isset($p_v['order_number'])) return [false, '采购单单号不能为空'];
+                    if(! isset($p_v['order_number'])) return [false, '单单号不能为空'];
                 }
 
                 $purchase_product[$value['product_id']] = [
@@ -660,8 +683,22 @@ class OutBoundOrderService extends Service
         }
 
         if($is_check_stock != ProductInventorySet::type_two){
-            //库存校验开启时 校验 需要采购单产品数量
-            list($status, $msg) = (new PurchaseOrderService())->checkPurchaseProductByPurchaseInfoID($id, $purchase_product);
+            list($status, $msg) = $this->checkOrderProductCommon($purchase_product);
+            if(! $status) return [false, $msg];
+            //采购 盘点
+            list($purchase_id, $inventory_id) = $msg;
+
+            //库存校验开启时 校验 需要采购产品数量
+            list($status, $msg) = (new PurchaseOrderService())->checkPurchaseProductByPurchaseInfoID($id, $purchase_product,$purchase_id);
+            if(! $status) return [false, $msg];
+            $purchase_count = $msg;
+
+            //库存校验开启时 校验 需要盘点盘盈产品数量
+            list($status, $msg) = (new InventoryService())->checkInventoryeProductByPurchaseInfoID($id, $purchase_product,$inventory_id);
+            if(! $status) return [false, $msg];
+            $inventory_count = $msg;
+
+            list($status, $msg) = $this->checkOrderProductCommon2($purchase_count, $inventory_count, $purchase_product);
             if(! $status) return [false, $msg];
         }
 
@@ -671,6 +708,42 @@ class OutBoundOrderService extends Service
         return [true, $return];
     }
 
+    public function checkOrderProductCommon($product){
+        if(empty($product)) return [false, "出库产品来源单据不能为空"];
+
+        $purchase_id = $inventory_id = [];
+        foreach ($product as $value){
+            foreach ($value['from'] as $f_v){
+                if($f_v['from_order_type'] == PurchaseOrderInfoForOutBound::from_type_zero){
+                    if(! in_array($f_v['purchase_order_id'], $purchase_id)) $purchase_id[] = $f_v['purchase_order_id'];
+                }elseif($f_v['from_order_type'] == PurchaseOrderInfoForOutBound::from_type_one){
+                    if(! in_array($f_v['purchase_order_id'], $inventory_id)) $inventory_id[] = $f_v['purchase_order_id'];
+                }else{
+                    return [false, '来源单据类型不正确'];
+                }
+            }
+        }
+        if(empty($purchase_id) && empty($inventory_id)) return [false, "出库产品来源单据数据不能为空"];
+
+        return [true, [$purchase_id, $inventory_id]];
+    }
+
+    public function checkOrderProductCommon2($purchase_count, $inventory_count, $product){
+        if(empty($purchase_count) && empty($inventory_count)) return [false, '来源单据产品汇总数据为空'];
+
+        foreach ($product as $value){
+            $product_id = $value['product_id'];
+            $total = $value['total'];
+            $p_tmp = $purchase_count[$product_id] ?? 0;
+            $i_tmp = $inventory_count[$product_id] ?? 0;
+            $count_tmp = bcadd($p_tmp, $i_tmp, 2);
+
+            if(floatval($total) != floatval($count_tmp)) return [false, '出库数量需等于来源单据选择产品数量'];
+        }
+
+        return [true, ''];
+    }
+
     public function returnProductData($product, $user, $storehouse_id){
         $top_depart_id = $user['depart_top'][0] ?? [];
         $my_top_depart_id = $top_depart_id['id'] ?? 0;
@@ -738,6 +811,7 @@ class OutBoundOrderService extends Service
                         'storehouse_id' => $storehouse_id,
                         'type' => PurchaseOrderInfoForOutBound::type_one,
                         'is_use' => PurchaseOrderInfoForOutBound::is_not_use,
+                        'from_order_type' => PurchaseOrderInfoForOutBound::from_type_zero
                     ];
                 }else{
                     $return[] = [
@@ -750,6 +824,7 @@ class OutBoundOrderService extends Service
                         'storehouse_id' => $storehouse_id,
                         'type' => PurchaseOrderInfoForOutBound::type_one,
                         'is_use' => PurchaseOrderInfoForOutBound::is_not_use,
+                        'from_order_type' => $p_v['from_order_type']
                     ];
                 }
             }

+ 2 - 0
app/Service/ProductInventoryService.php

@@ -193,6 +193,8 @@ class ProductInventoryService extends Service
             }else{
                 $model->where('a.number','<=',0);
             }
+        }else{
+            $model->where('a.number','>',0);
         }
         if(! empty($data['crt_time'][0]) && ! empty($data['crt_time'][1])) {
             $return = $this->changeDateToTimeStampAboutRange($data['crt_time']);

+ 18 - 16
app/Service/PurchaseOrderService.php

@@ -834,8 +834,9 @@ class PurchaseOrderService extends Service
 
         //采购单已出库产品(包含占用)
         $purchase_product_outbound = PurchaseOrderInfoForOutBound::where('del_time',0)
-            ->whereIn('purchase_order_id',array_column($purchase_product,'purchase_order_id'))
+            ->whereIn('purchase_order_id',array_unique(array_column($purchase_product,'purchase_order_id')))
             ->where('type',PurchaseOrderInfoForOutBound::type_one)
+            ->where('from_order_type',PurchaseOrderInfoForOutBound::from_type_zero)
             ->select('purchase_order_id','product_id','number')
             ->get()->toArray();
         $purchase_product_outbound_map = [];
@@ -901,6 +902,7 @@ class PurchaseOrderService extends Service
                 'price' => $value['price'],
                 'order_number' => $value['order_number'],
                 'product_id' => $value['product_id'],
+                'from_order_type' => PurchaseOrderInfoForOutBound::from_type_zero
 //                'title' => $tmp['title'],
 //                'code' => $tmp['code'],
 //                'size' => $tmp['size'],
@@ -911,16 +913,10 @@ class PurchaseOrderService extends Service
     }
 
     //校验采购单产品数量 含退货 以及 出库 后最终产品数量 (通过采购单明细id)
-    public function checkPurchaseProductByPurchaseInfoID($id, $product){
+    public function checkPurchaseProductByPurchaseInfoID($id, $product, $purchase_id){
+        if(empty($purchase_id)) return [true, []];
         if(empty($product)) return [false, "出库产品校验产品不能为空"];
-
-        $purchase_id = [];
-        foreach ($product as $value){
-            foreach ($value['from'] as $f_v){
-                if(! in_array($f_v['purchase_order_id'], $purchase_id)) $purchase_id[] = $f_v['purchase_order_id'];
-            }
-        }
-        if(empty($purchase_id)) return [false, "出库产品来源采购单数据不能为空"];
+        //产品id
         $product_id = array_keys($product);
 
         //采购单产品数量
@@ -947,6 +943,7 @@ class PurchaseOrderService extends Service
             ->whereIn('purchase_order_id',array_column($purchase_product,'purchase_order_id'))
 //            ->where('is_use',PurchaseOrderInfoForOutBound::is_not_use)
             ->where('type',PurchaseOrderInfoForOutBound::type_one)
+            ->where('from_order_type',PurchaseOrderInfoForOutBound::from_type_zero)
             ->when(! empty($id), function ($query) use ($id) {
                 return $query->where('data_id', '<>', $id);
             })
@@ -995,12 +992,12 @@ class PurchaseOrderService extends Service
         }
 
         //校验
+        $count = [];
         foreach ($product as $value){
             $product_id = $value['product_id'];
             $total = $value['total'];
-            $num_tmp = 0;
             foreach ($value['from'] as $f_v){
-                if(! $f_v['id'] || ! $f_v['purchase_order_id']) continue;
+                if(! $f_v['id'] || ! $f_v['purchase_order_id'] || $f_v['from_order_type'] != PurchaseOrderInfoForOutBound::from_type_zero) continue;
 
                 $key = $f_v['purchase_order_id'] . $product_id;
                 $total_tmp = $purchase_product_map[$key] ?? 0; // 采购单产品总数
@@ -1014,13 +1011,17 @@ class PurchaseOrderService extends Service
 
                 //比较
                 if($number < $f_v['number']) return [false, "采购单:" . $f_v['order_number'] . "实际可以出库的数量" . $number];
-                $num_tmp = bcadd($num_tmp, $f_v['number'],2);
-            }
 
-            if(floatval($total) != floatval($num_tmp)) return [false, '出库数量需等于采购单选择产品数量'];
+                if(isset($count[$value['product_id']])){
+                    $num_tmp = bcadd($count[$value['product_id']], $f_v['number'],2);
+                    $count[$value['product_id']] = $num_tmp;
+                }else{
+                    $count[$value['product_id']] = $f_v['number'];
+                }
+            }
         }
 
-        return [true, ''];
+        return [true, $count];
     }
 
     //获取采购单产品数量 含退货 以及 出库 后最终产品数量 (在采购单列表页上,通过采购单id)
@@ -1055,6 +1056,7 @@ class PurchaseOrderService extends Service
         $purchase_product_outbound = PurchaseOrderInfoForOutBound::where('del_time',0)
             ->whereIn('purchase_order_id',array_column($purchase_product,'purchase_order_id'))
             ->where('type',PurchaseOrderInfoForOutBound::type_one)
+            ->where('from_order_type',PurchaseOrderInfoForOutBound::from_type_zero)
             ->select('purchase_order_id','product_id','number')
             ->get()->toArray();
         $purchase_product_outbound_map = [];

+ 1 - 0
app/Service/ReturnExchangeOrderService.php

@@ -828,6 +828,7 @@ class ReturnExchangeOrderService extends Service
         //出库
         $out_bound = PurchaseOrderInfoForOutBound::where('del_time',0)
             ->where('purchase_order_id',$purchase_id)
+            ->where('from_order_type',PurchaseOrderInfoForOutBound::from_type_zero)
             ->select('product_id','number')
             ->get()->toArray();
         $out_bound_map = [];