Files
OMS/app/wms/lib/stockdump.php
2026-01-04 17:22:44 +08:00

412 lines
17 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Copyright 2026 ShopeX (https://www.shopex.cn)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* 库内转储
*
*
*/
class wms_stockdump{
/**
* 错误信息
*/
public $error_info = array(
'STOCKDUMP_BN_DOES_NOT_EXIST' => '转储单号不存在!',
'STOCKDUMP_BN_IN_STATUS' => '转储单状态不能为 已入库/失败/取消',
'SAVE_STOCKDUMP_RECORD_FAIL' => '保存转储单失败!',
'SAVE_STOCKDUMP_ACTUAL_SHORTAGE' => '出库数量大于调出仓库实际库存,无法出库!',
'STOCKDUMP_ACTUAL_SHORTAGE' => '出库数量大于调出仓库实际库存,无法出库,确认失败!',
);
/**
* 失败信息回传
*/
public function fail($msg=''){
$fail = array('rsp'=>'fail','msg'=>$msg);
return $fail;
}
/**
* 成功信息回传
*/
public function success($msg=''){
$success = array('rsp'=>'success','msg'=>$msg);
return $success;
}
/**
* 保存
*/
public function do_save($appro_bn,$options){
set_time_limit(0);
$oAppro = app::get('console')->model('stockdump');
$oAppro_items = app::get('console')->model('stockdump_items');
//验证转储单是否存在
$is_exist = $oAppro->dump(array('stockdump_bn'=>$appro_bn),'stockdump_bn,in_status,type,self_status');
if(!$is_exist['stockdump_bn']){
return $this->fail($this->error_info['STOCKDUMP_BN_DOES_NOT_EXIST']);
}
//判断转储单号不为已入库/失败/取消
if($is_exist['in_status'] == 9 or $is_exist['in_status'] == 10 or $is_exist['self_status'] == 0){
return $this->success($this->error_info['STOCKDUMP_BN_IN_STATUS']);
}
$appro_lists = $oAppro_items->getList(
'item_id,stockdump_id,stockdump_bn,product_id,bn,num,appro_price',
array('stockdump_bn'=>$appro_bn)
);
$item = array();
foreach($options['item'] as $k=>$v){
if($v['bn'] == ''){
unset($options['item'][$k]);
}
}
//格式化item
if(count($options['item'])>0){
foreach($options['item'] as $v){
$item[trim($v['bn'])] = array(
'normal_num' => $v['num'],
);
}
}
$options['item'] = null;
unset( $options['item'] );
$in_status = $options['in_status'];
kernel::database()->beginTransaction();
foreach($appro_lists as $key=>$value){
if( count($item) == 0){
$in_nums = $value['num'];
}else{
$in_nums = $item[$value['bn']]['normal_num'];
}
$appro_lists[$key]['in_nums'] = $in_nums;
$oAppro_items->update(array('in_nums'=>$in_nums),array('item_id'=>$value['item_id']));
}
kernel::database()->commit();
$appro_lists = $item = null;
unset($appro_lists,$item);
//更新转储单状态
$this->update_status($appro_bn,$options['in_status']);
$is_stock_diffnum_bool = $this->is_stock_diffnum($appro_bn);
//状态为FINISH已入库
if($options['status'] == 'FINISH' and $is_stock_diffnum_bool == false){
//执行出入库事务
$appro_lists = $oAppro_items->getList('stockdump_id,stockdump_bn,item_id,bn,num,in_nums,defective_num,appro_price',array('stockdump_bn'=>$appro_bn));
$ioResult = $this->save_iostock($appro_lists);
if($ioResult['rsp'] == 'fail'){
return $ioResult;
}
//如果无差异,更改确认状态为无需确认
$oAppro->update(array('confirm_type'=>0),array('stockdump_bn'=>$appro_bn));
}else{
//如果有差异,更改确认状态为未确认
$oAppro->update(array('confirm_type'=>1),array('stockdump_bn'=>$appro_bn));
}
//更新转储单备注
$oAppro->update(array('memo'=>$options['memo']),array('stockdump_bn'=>$appro_bn));
return $this->success();
}
/**
* 出入库事务
*/
public function save_iostock(&$appro_lists){
$basicMStockFreezeLib = kernel::single('material_basic_material_stock_freeze');
$oAppro = app::get('console')->model('stockdump');
$original_operator = $oAppro->dump(array('stockdump_id'=>$appro_lists[0]['stockdump_id']),'stockdump_bn ,type,operator_name,from_branch_id,to_branch_id,from_branch_name,to_branch_name');
$iostock = app::get('ome')->model('iostock');
$iostockObj = kernel::service('ome.iostock');
$iostock_bn = $original_operator['stockdump_bn'];
$oBranchProduct = app::get('ome')->model('branch_product');
$oBranch = app::get('ome')->model("branch");
kernel::database()->beginTransaction();
foreach($appro_lists as $key=>$value){
//入库数据
$iostockData_in[$key]['bn'] = $value['bn'];
$iostockData_in[$key]['iostock_price'] = $value['appro_price'];
$iostockData_in[$key]['branch_id'] = $original_operator['to_branch_id'];
$iostockData_in[$key]['original_bn'] = $iostock_bn;
$iostockData_in[$key]['original_id'] = $value['stockdump_id'];
$iostockData_in[$key]['operator'] = $original_operator['operator_name'];
$iostockData_in[$key]['type_id'] = 4; //入库类型
$iostockData_in[$key]['nums'] = $value['in_nums'];
//出库数据
$iostockData_out[$key]['bn'] = $value['bn'];
$iostockData_out[$key]['iostock_price'] = $value['appro_price'];
$iostockData_out[$key]['branch_id'] = $original_operator['from_branch_id'];
$iostockData_out[$key]['original_bn'] = $iostock_bn;
$iostockData_out[$key]['original_id'] = $value['stockdump_id'];
$iostockData_out[$key]['original_item_id'] = $value['item_id'];
$iostockData_out[$key]['operator'] = $original_operator['operator_name'];
$iostockData_out[$key]['type_id'] = 40; //出库类型
$iostockData_out[$key]['nums'] = $value['in_nums'];
//出库单 差异数量检测 判断实际库存与出库数量 防止出现负库存
$is_branch_product_data = $oBranchProduct->getList(
'store,store_freeze',
array(
'branch_id' => $original_operator['from_branch_id'],
'product_id' => $value['product_id']
)
);
//根据仓库ID、基础物料ID获取该物料仓库级的预占
$is_branch_product_data[0]['store_freeze'] = $basicMStockFreezeLib->getBranchFreeze($value['product_id'], $original_operator['from_branch_id']);
//实际可用库存
$branch_product_available_nums = $is_branch_product_data[0]['store'] - $is_branch_product_data[0]['store_freeze'];
//如果释放冻结库存后的实际库存仍然 小于 超出预计出库的数量 则确认失败
if( $branch_product_available_nums < ($value['in_nums'] - $value['num']) ){
return $this->fail($this->error_info['SAVE_STOCKDUMP_ACTUAL_SHORTAGE']);
}
}
//入库
$this->splitIostock($iostock_bn,$iostockData_in,4,$msg,0);
$iostockData_in = null;
unset($iostockData_in);
//出库,释放预占库存
$this->clear_stockout_store_freeze($iostock_bn);
$this->splitIostock($iostock_bn,$iostockData_out,40,$msg,1);
$iostockData_out = null;
unset($iostockData_out);
kernel::database()->commit();
return $this->success();
}
/**
* 更新状态
*/
public function update_status($appro_bn,$in_status){
$oAppro = app::get('console')->model('stockdump');
//修改调拨单的状态
$oAppro->update(array('in_status'=>$in_status),array('stockdump_bn'=>$appro_bn));
return true;
}
/**
* 转储单确认事务
*/
public function confirm_stock($appro_bn){
$basicMStockFreezeLib = kernel::single('material_basic_material_stock_freeze');
$oAppro = app::get('console')->model('stockdump');
$oAppro_items = app::get('console')->model('stockdump_items');
$oBranchProduct = app::get('ome')->model('branch_product');
$oBranch = app::get('ome')->model("branch");
$appro_lists = $oAppro_items->getList(
'item_id,stockdump_id,stockdump_bn,product_id,bn,num,in_nums,defective_num,appro_price',
array('stockdump_bn'=>$appro_bn)
);
$original_operator = $oAppro->dump(array('stockdump_bn'=>$appro_bn),'type,operator_name,from_branch_id,to_branch_id,from_branch_name,to_branch_name');
$iostock = app::get('ome')->model('iostock');
$iostockObj = kernel::service('ome.iostock');
$iostock_bn = $appro_bn;//编号
kernel::database()->beginTransaction();
//增加库存部分出入库剩余出入库记录
foreach($appro_lists as $key=>$value){
//入库数据
$iostockData_in[$key]['bn'] = $value['bn'];
$iostockData_in[$key]['iostock_price'] = $value['appro_price'];
$iostockData_in[$key]['branch_id'] = $original_operator['to_branch_id'];
$iostockData_in[$key]['original_id'] = $value['stockdump_id'];
$iostockData_in[$key]['original_bn'] = $iostock_bn;
$iostockData_in[$key]['operator'] = $original_operator['operator_name'];
$iostockData_in[$key]['type_id'] = 600; //入库类型
$iostockData_in[$key]['nums'] = $value['num'];
//出库数据
$iostockData_out[$key]['bn'] = $value['bn'];
$iostockData_out[$key]['iostock_price'] = $value['appro_price'];
$iostockData_out[$key]['branch_id'] = $original_operator['from_branch_id'];
$iostockData_out[$key]['original_bn'] = $iostock_bn; //出库的原始单号
$iostockData_out[$key]['original_id'] = $value['stockdump_id'];
$iostockData_out[$key]['original_item_id'] = $value['item_id'];
$iostockData_out[$key]['operator'] = $original_operator['operator_name'];
$iostockData_out[$key]['type_id'] = 500; //出库类型
$iostockData_out[$key]['nums'] = $value['num'];
//出库单 差异数量检测 判断实际库存与出库数量 防止出现负库存
$is_branch_product_data = $oBranchProduct->getList(
'store,store_freeze',
array(
'branch_id' => $original_operator['from_branch_id'],
'product_id' => $value['product_id']
)
);
//根据仓库ID、基础物料ID获取该物料仓库级的预占
$is_branch_product_data[0]['store_freeze'] = $basicMStockFreezeLib->getBranchFreeze($value['product_id'], $original_operator['from_branch_id']);
//实际可用库存
$branch_product_available_nums = $is_branch_product_data[0]['store'] - $is_branch_product_data[0]['store_freeze'];
//如果释放冻结库存后的实际库存仍然 小于 超出预计出库的数量 则确认失败
if( $branch_product_available_nums < ($value['in_nums'] - $value['num']) ){
kernel::database()->rollback();
return $this->fail($this->error_info['STOCKDUMP_ACTUAL_SHORTAGE']);
}
//更新入库数量
$appro_list_data = array(
'item_id'=>$value['item_id'],
'in_nums'=>$value['num'],
);
$oAppro_items->save($appro_list_data);
$parent_id = $to_branch_data = $defective_branch_data = null;
}
//入库操作
$this->splitIostock($iostock_bn,$iostockData_in,4,$msg,0);
//出库操作
$this->clear_stockout_store_freeze($iostock_bn);
$this->splitIostock($iostock_bn,$iostockData_out,40,$msg,1);
kernel::database()->commit();
//更新出入库单确认状态 增加确认人、确认时间
$confirm_data = array(
'confirm_type' => '2',
'confirm_name' => kernel::single('desktop_user')->get_name(),
'confirm_time' => time(),
'in_status'=>'9',
);
$result = $oAppro->update($confirm_data,array('stockdump_bn'=>$iostock_bn));
return $this->success();
}
/**
* 判断全部出入库时数量是否有差异
* false 无差异 true 有差异
*/
public function is_stock_diffnum($appro_bn = ''){
$result = false;//最终返回状态
if($appro_bn == '') return $result;
$sql = "SELECT COUNT(*) FROM sdb_console_stockdump_items WHERE stockdump_bn = '".$appro_bn."' AND in_nums != num";
$tmp = kernel::database()->select($sql);
if($tmp[0]['COUNT(*)']>0){
$result = true;
}else{
$result = false;
}
return $result;
}
/**
* 释放出库单预占库存量
*/
public function clear_stockout_store_freeze($appro_bn){
$oAppro = app::get('console')->model('stockdump');
$oAppro_items = app::get('console')->model('stockdump_items');
$pStockObj = kernel::single('console_stock_products');
$appro_lists = $oAppro_items->getList(
'item_id,stockdump_id,stockdump_bn,product_id,bn,num,in_nums,appro_price',
array('stockdump_bn'=>$appro_bn)
);
$appro_data = $oAppro->dump(array('stockdump_bn'=>$appro_bn),'from_branch_id,to_branch_id');
foreach($appro_lists as $value){
//释放出库单预占仓库库存量
$log_data = array(
'original_id'=> $value['stockdump_id'],
'original_type'=>'iostock',#kernel::single('ome_freeze_log')->get_original_type方法获取
'memo'=>'单据出库释放出库单预占仓库库存量',
);
$pStockObj->branch_unfreeze($appro_data['from_branch_id'],$value['product_id'],$value['num'],$log_data);
}
return true;
}
public function splitIostock($iostockBn = '',&$iostockData = array(),$type = '',$msg = '',$iotype = ''){
$iostockObj = kernel::service('ome.iostock');
$max = 200;#每次发送条数
$i = 1;
$data = array();
foreach($iostockData as $k=>$v){
$data[$k] = $v;
if($i == $max){
$stock = $iostockObj->set($iostockBn,$data,$type,$msg,$iotype);
$i = 1;
$data = array();
}else{
$i++;
}
}
if($i>1 && $i<=$max){
$stock = $iostockObj->set($iostockBn,$data,$type,$msg,$iotype);
}
$data = array();
}
/**
* 发起转储单请求
*
*/
function notify_stockdump($stockdump_bn,$method='confirm'){
$oStockdump = app::get('console')->model('stockdump');
$stockdump_detail = $oStockdump->dump(array('stockdump_bn'=>$stockdump_bn),'*');
$oStock_items = app::get('console')->model('stockdump_items');
$to_branch_id = $stockdump_detail['to_branch_id'];
$branch_detail = kernel::single('wms_iostockdata')->getBranchByid($to_branch_id);
$data = array(
'io_source'=>'selfwms',
'stockdump_bn'=>$stockdump_detail['stockdump_bn'],
'memo'=>$stockdump_detail['memo'],
'branch_bn'=>$branch_detail['branch_bn'],
'operate_time'=>$stockdump_detail['operator_name']
);
$items = $oStock_items->getList('bn,num',array('stockdump_bn'=>$appro_bn));
$data['items'] = $items;
$wms_id = kernel::single('ome_branch')->getWmsIdById($to_branch_id);
if ($method=='confirm'){
$data['status'] = 'FINISH';
}else if($method=='cancel'){
$data['status'] = 'CANCEL';
}
kernel::single('wms_event_trigger_stockdump')->inStorage($wms_id, $data, true);
}
}