orderRule($data, $user,false); if(!$status) return [$status,$msg]; try{ DB::beginTransaction(); $inventory_model = Inventory::where('order_number',$data['order_number'])->first(); $inventory_model->counted_id = $data['counted_id']; $inventory_model->counted_time = $data['counted_time']; $inventory_model->mark = $data['mark']; $inventory_model->save(); InventorySub::where('del_time',0) ->where('order_number',$data['order_number']) ->update(['del_time'=>time()]); if(! empty($data['sub'])){ $sub = []; foreach ($data['sub'] as $value){ $sub[] = [ 'product_id' => $value['product_id'], 'storehouse_id' => $data['storehouse_id'], 'order_number' => $data['order_number'], 'book_num' => $value['book_num'], 'counted_num' => $value['counted_num'], 'final_num' => $value['final_num'], 'price' => $value['price'] ?? 0, 'inventory_id' => $inventory_model->id, 'final_amount' => $value['final_amount'] ?? 0, ]; } InventorySub::insert($sub); $is_check_stock = OrderInventoryStock::where('order_number', $data['order_number']) ->where('del_time',0) ->value('is_check_stock') ?? 0; ProductInventoryService::changeLockNumber($user,$msg[0],$msg[1],$is_check_stock); } DB::commit(); }catch (\Throwable $e){ DB::rollBack(); return [false,$e->getMessage()]; } if(! empty($data['check'])) { list($status,$msg) = (new CheckService())->checkAll([ "id" => $inventory_model->id, "order_number" => $data['order_number'], "opt_case" => CheckService::fourteen, "menu_id" => $data['menu_id'] ],$user); // if(! $status) return [true, '保存成功,施工单确认失败,异常信息:' . $msg]; } return [true, '']; } public function add($data,$user){ list($status,$msg) = $this->orderRule($data, $user); if(!$status) return [$status,$msg]; try{ DB::beginTransaction(); $inventory_model = new Inventory(); $inventory_model->order_number = $data['order_number']; $inventory_model->storehouse_id = $data['storehouse_id']; $inventory_model->counted_id = $data['counted_id']; $inventory_model->counted_time = $data['counted_time']; $inventory_model->mark = $data['mark'] ?? ''; $inventory_model->depart_id = $data['depart_id'] ?? 0; $inventory_model->top_depart_id = $data['top_depart_id'] ?? 0; $inventory_model->crt_id = $user['id']; $inventory_model->save(); if(! empty($data['sub'])){ $sub = []; foreach ($data['sub'] as $value){ $sub[] = [ 'product_id' => $value['product_id'], 'storehouse_id' => $data['storehouse_id'], 'order_number' => $data['order_number'], 'book_num' => $value['book_num'], 'counted_num' => $value['counted_num'], 'final_num' => $value['final_num'], 'price' => $value['price'] ?? 0, 'inventory_id' => $inventory_model->id, 'final_amount' => $value['final_amount'] ?? 0, ]; } InventorySub::insert($sub); ProductInventoryService::changeLockNumber($user,$msg[0],[]); } //单据创建时是否校验库存 (new CheckService())->orderInventoryInsert(['order_number' => $data['order_number'], 'is_check_stock' => $data['is_check_stock']]); DB::commit(); }catch (\Throwable $exception){ DB::rollBack(); if (str_contains($exception->getMessage(), '1062') || str_contains($exception->getMessage(), 'Duplicate entry')) { return [false, '网络波动,请重新操作!']; } return [false,$exception->getMessage()]; } if(! empty($data['check'])) { list($status,$msg) = (new CheckService())->checkAll([ "id" => $inventory_model->id, "order_number" => $data['order_number'], "opt_case" => CheckService::fourteen, "menu_id" => $data['menu_id'] ],$user); // if(! $status) return [true, '保存成功,施工单确认失败,异常信息:' . $msg]; } return [true, '']; } public function detail($data,$user){ if(empty($data['id']) && empty($data['order_number'])) return [false,'请选择数据!']; if(! empty($data['id'])){ $inventory = Inventory::where('del_time',0) ->where('id',$data['id']) ->first(); }else{ $inventory = Inventory::where('del_time',0) ->where('order_number',$data['order_number']) ->first(); $data['id'] = empty($inventory->id) ? 0 : $inventory->id; } if(empty($inventory)) return [false,'盘点单不存在或已被删除']; $inventory = $inventory->toArray(); $inventory['state_title'] = Inventory::$name[$inventory['state']] ?? ''; $inventory['storehouse_title'] = Storehouse::where('id',$inventory['storehouse_id'])->value('title'); $emp_map = Employee::whereIn('id', [$inventory['crt_id'], $inventory['counted_id']]) ->pluck('emp_name','id') ->toArray(); $inventory['crt_name'] = $emp_map[$inventory['crt_id']] ?? ''; $inventory['counted_name'] = $emp_map[$inventory['counted_id']] ?? ''; $inventory['counted_time'] = $inventory['counted_time'] ? date("Y-m-d", $inventory['counted_time']): ''; $inventory['crt_time'] = $inventory['crt_time'] ? date("Y-m-d H:i:s", $inventory['crt_time']): ''; $sub = InventorySub::where('del_time',0) ->where('inventory_id', $data['id']) ->select('product_id','counted_num','final_num','price','book_num','final_amount') ->get()->toArray(); $map = (new ProductService())->getProductDetail(array_column($sub,'product_id')); foreach ($sub as $key => $value){ $tmp = $map[$value['product_id']] ?? []; $sub[$key]['title'] = $tmp['title'] ?? ""; $sub[$key]['code'] = $tmp['code'] ?? ""; $sub[$key]['size'] = $tmp['size'] ?? ""; } $inventory['sub'] = $sub; return [true, $inventory]; } public function del($data,$user){ if($this->isEmpty($data,'id')) return [false,'请选择数据!']; $inventory = Inventory::where('del_time',0)->where('id',$data['id'])->first(); if(empty($inventory)) return [false,'盘点单不存在或已被删除']; $inventory = $inventory->toArray(); if($inventory['state'] > Inventory::STATE_ZERO) return [false,'请确认盘点单状态,操作失败']; $time = time(); $product_save = $this->getSaveDetail($data['id']); try { DB::beginTransaction(); Inventory::where('id',$data['id'])->update([ 'del_time'=> $time ]); InventorySub::where('del_time',0)->where('inventory_id',$data['id'])->update([ 'del_time'=> $time ]); $is_check_stock = OrderInventoryStock::where('order_number', $inventory['order_number']) ->where('del_time',0) ->value('is_check_stock') ?? 0; //锁定库存释放 if(! empty($product_save)) ProductInventoryService::changeLockNumber($user,[],$product_save,$is_check_stock); DB::commit(); }catch (\Exception $exception){ DB::rollBack(); return [false, $exception->getMessage()]; } return [true, '']; } public function getList($data,$user){ $model = Inventory::Clear($user,$data); $model = $model->where('del_time',0) ->select('order_number','id','storehouse_id','state','counted_id','counted_time','crt_time') ->orderby('id', 'desc'); if(! empty($data['crt_time'][0]) && ! empty($data['crt_time'][1])) $model->whereBetween('crt_time',[$data['crt_time'][0],$data['crt_time'][1]]); if(! empty($data['order_number'])) $model->where('order_number', 'LIKE', '%'.$data['order_number'].'%'); if(! empty($data['storehouse_id'])) $model->where('storehouse_id', $data['storehouse_id']); if(! empty($data['counted_name'])) { $id = $this->forSearch($data); $model->whereIn('counted_id',$id); } if(isset($data['state'])) $model->where('state', $data['state']); if(! empty($data['product_code'])) { $id = $this->forSearch($data); $model->whereIn('id',$id); } $list = $this->limit($model,'',$data); $list = $this->fillListData($list); return [true, $list]; } public function fillListData($data){ if(empty($data['data'])) return $data; $storehouse_map = Storehouse::whereIn('id',array_column($data['data'],'storehouse_id')) ->pluck('title','id') ->toArray(); $emp_map = Employee::whereIn('id',array_unique(array_merge_recursive(array_column($data['data'],'counted_id'), array_column($data['data'],'crt_id')))) ->pluck('emp_name','id') ->toArray(); foreach ($data['data'] as $key => $value){ $data['data'][$key]['counted_time'] = $value['counted_time'] ? date("Y-m-d",$value['counted_time']) : ''; $data['data'][$key]['crt_time'] = $value['crt_time'] ? date("Y-m-d H:i:s",$value['crt_time']) : ''; $data['data'][$key]['storehouse_name'] = $storehouse_map[$value['storehouse_id']] ?? ''; $data['data'][$key]['counted_name'] = $emp_map[$value['counted_id']] ?? ''; $data['data'][$key]['state_name'] = Inventory::$name[$value['state']] ?? ''; } return $data; } public function forSearch($data){ if(! empty($data['product_code'])){ $product = Product::where('code', 'LIKE', '%'.$data['product_code'].'%') ->select('id') ->get()->toArray(); $inventory_id = InventorySub::where('del_time',0) ->whereIn('product_id', array_column($product,'id')) ->select('inventory_id') ->get()->toArray(); return array_column($inventory_id, 'inventory_id'); } if(! empty($data['counted_name'])){ $employee = Employee::where('emp_name', 'LIKE', '%'.$data['counted_name'].'%') ->select('id') ->get()->toArray(); return array_column($employee, 'id'); } return []; } public function orderRule(&$data, $user, $is_add = true){ if(empty($data['counted_id'])) $data['counted_id'] = $user['id']; if(empty($data['counted_time'])) return [false,'盘点日期不能为空']; $data['counted_time'] = $this->changeDateToDate($data['counted_time']); if(empty($data['storehouse_id'])) return [false,'仓库不能为空']; if(empty($data['sub'])) return [false, '盘点明细不能为空']; $product_submit = $product_submit_reduce = $product_id = []; foreach ($data['sub'] as $value){ if(empty($value['product_id'])) return [false,"盘点单产品ID不为空"]; if(! is_numeric($value['book_num'])) return [false, '账面数量不合法']; $bool = $this->checkNumber($value['counted_num']); if(! $bool) return [false, '盘点数量不合法,请输入大于等于0的两位数值']; if(! is_numeric($value['final_num'])) return [false, '盈亏数量不合法']; $num = bcsub($value['counted_num'],$value['book_num'],2); $num = floatval($num); $final_num = floatval($value['final_num']); if($num != $final_num) return [false,'盈亏数量计算错误']; if(isset($value['price'])){ $bool = $this->checkNumber($value['price']); 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; if($value['final_num'] < 0){ if(isset($product_submit_reduce[$key])){ $product_submit_reduce[$key] += $value['final_num']; }else{ $product_submit_reduce[$key] = $value['final_num']; } $product_id[] = $value['product_id']; } } //所属部门 以及 顶级部门 if(empty($data['depart_id'])) { $data['depart_id'] = $this->getDepart($user); $data['top_depart_id'] = $user['depart_map'][$data['depart_id']] ?? 0; } $data['is_check_stock'] = $user['is_check_stock']; if($is_add){ $order_number = (new OrderNoService())->createOrderNumber(Inventory::prefix); if(empty($order_number)) return [false,'盘点单号生成失败']; $data['order_number'] = $order_number; }else{ if(empty($data['order_number'])) return [false,'盘点单号不能为空']; $model = Inventory::where('order_number',$data['order_number'])->where('del_time',0)->first(); if(empty($model)) return [false, '盘点单不存在或已被删除']; $order = $model->toArray(); if($order['state'] != Inventory::STATE_ZERO) return [false, '请确认单据状态,编辑失败']; if($order['storehouse_id'] != $data['storehouse_id']) return [false, '仓库不允许编辑']; //订单编辑提交限制 $current_top_depart_id = $this->getMyTopDepart($user); list($status, $msg) = $this->returnOrderEditErrorCommon($current_top_depart_id, $order['top_depart_id']); if(! $status) return [false, $msg]; } //校验是否存在产品盘点 list($status, $msg) = $this->issetProduct($data, $product_submit); if(! $status) return [false, $msg]; $id = $data['id'] ?? 0; $product_save_reduce = $this->getSaveDetail($id); if(! empty($product_submit_reduce)){ //校验库存 list($status,$msg) = (new ProductInventoryService())->compareStock($user,$product_id, $product_submit_reduce, $product_save_reduce); if(! $status) return [false, $msg]; } return [true, [$product_submit_reduce, $product_save_reduce]]; } /** * 获取保存详情 * @param $id * @return array */ public function getSaveDetail($id){ $product_save = []; if(empty($id)) return []; $sub = InventorySub::where('inventory_id',$id) ->where('del_time',0) ->get()->toArray(); foreach ($sub as $value){ $key = $value['product_id'] . ',' . $value['storehouse_id']; if($value['final_num'] < 0){//盘亏 if(isset($product_save[$key])){ $product_save[$key] += $value['final_num']; }else{ $product_save[$key] = $value['final_num']; } } } return $product_save; } public function issetProduct($data, $product_submit){ $id = $data['id'] ?? 0; $inventory = Inventory::where('del_time',0) ->when(! empty($id), function ($query) use ($id) { return $query->where('id','<>',$id); }) ->where('top_depart_id',$data['top_depart_id']) ->where('state','<',Inventory::STATE_TWO) ->select('id') ->get()->toArray(); $sub = InventorySub::where('del_time', 0) ->whereIn('inventory_id', array_column($inventory,'id')) ->select('product_id', 'storehouse_id', 'order_number') ->get()->toArray(); $map = []; $product = Product::whereIn('id', array_unique(array_column($sub,'product_id'))) ->select('id','title','code') ->get()->toArray(); foreach ($product as $value){ $map[$value['id']] = $value; } foreach ($sub as $value){ $key = $value['product_id'] . ',' .$value['storehouse_id']; if(isset($product_submit[$key])){ $pro_tmp = $map[$value['product_id']] ?? []; $pro_str = $pro_tmp['title'] . "( ". $pro_tmp['code'] .")"; return [false, "产品:" . $pro_str . "在盘点单:" . $value['order_number'] . "已录入盘点"]; } } 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','return_number') ->get()->toArray(); $purchase_product_outbound_map = []; foreach ($purchase_product_outbound as $value){ $key = $value['purchase_order_id'] . $value['product_id']; $tmp = bcsub($value['number'],$value['return_number'],2); if($tmp <= 0) continue; if(isset($purchase_product_outbound_map[$key])){ $total_number = bcadd($purchase_product_outbound_map[$key], $tmp,2); $purchase_product_outbound_map[$key] = $total_number; }else{ $purchase_product_outbound_map[$key] = $tmp; } } $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','return_number') ->get()->toArray(); $purchase_product_outbound_map = []; foreach ($purchase_product_outbound as $value){ $key = $value['purchase_order_id'] . $value['product_id']; $tmp = bcsub($value['number'],$value['return_number'],2); if($tmp <= 0) continue; if(isset($purchase_product_outbound_map[$key])){ $total_number = bcadd($purchase_product_outbound_map[$key], $tmp,2); $purchase_product_outbound_map[$key] = $total_number; }else{ $purchase_product_outbound_map[$key] = $tmp; } } //校验 $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]; } }