mirror of
https://gitee.com/ShopeX/OMS
synced 2026-03-22 18:35:35 +08:00
412 lines
17 KiB
PHP
412 lines
17 KiB
PHP
<?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);
|
||
}
|
||
|
||
}
|