Files
OMS/app/inventorydepth/lib/stock.php
chenping 61783b7d01 1. 【新增】售后单售后原因类型支持搜索
2. 【新增】手工创建订单折扣可输入正数

3. 【优化】盘点申请单确认

4. 【修复】采购退货单模拟出库失败问题

5. 【新增】订单金额客户实付与结算金额

6. 【优化】仓库发货统计报表物料名称显示

7. 【优化】自有仓储虚拟发货逻辑

8. 【修复】基础物料分类管理问题
2026-04-01 11:59:17 +08:00

281 lines
9.4 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 2012-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.
*/
/**
* 库存同步处理类
*
* @author chenping<chenping@shopex.cn>
*/
class inventorydepth_stock {
//const PUBL_LIMIT = 100; //批量发布的最大上限数
//const SYNC_LIMIT = 50; //批量下载的最大上限数
protected $type;
public function __construct($app)
{
if(is_array($app)) {
$this->app = $app[0];
$this->type = $app[1];
} else {
$this->app = $app;
}
}
public function get_benchmark($key=null)
{
$return = array(
'actual_stock' => '可售库存',
//'release_stock' => '发布库存',
'branch_actual_stock' => '仓库可售',
'md_actual_stock' => '门店可售',
'shop_freeze' => '店铺预占',
'sales_material_shop_freeze' => '销售物料店铺冻结',
//'globals_freeze' => '全局预占',
'actual_safe_stock' => '可售库存-安全库存',
'branch_actual_safe_stock' => '仓库可售-安全库存',
'md_actual_safe_stock' => '门店可售-安全库存',
);
if($this->type == '3') {//代表门店库存回传
$return = array(
'actual_stock' => '可售库存',
'safe_stock' => '安全库存',
);
}
return $key ? $return[$key] : $return;
}
public function get_benchobj($key=null)
{
$return = array(
'actual_stock' => '可售库存',
//'release_stock' => $this->app->_('发布库存'),
//'shop_freeze' => $this->app->_('店铺预占'),
//'globals_freeze' => $this->app->_('全局预占'),
);
return $key ? $return[$key] : $return;
}
public function update_release_stock($merchandise_id, $result)
{
$r = $this->app->model('viewProduct_stock')->update(array('release_stock'=>$result,'release_status'=>'sleep'),array('merchandise_id'=>$merchandise_id));
return $r;
}
public function update_check($data, $result, &$msg)
{
foreach($data as $d){
$merchandise_id = $d['merchandise_id'];
$resultVal = $this->check_and_build($merchandise_id, $result, $msg);
if ($resultVal === false) {
if (strpos($msg, '小于零') !== false)
$msg = $this->app->_('部分商品调整后的库存已经小于零,请重新填写');
return false;
}
$this->update_release_stock($merchandise_id,$resultVal);
}
return true;
}
/**
* 通过公式更新发布库存 弃用
* @return void
* @author
**/
public function updateReleaseByformula($filter,$result,&$errormsg)
{
return false;
}
public function storeNeedUpdateSku($order_id, $shop_id) {
$prefix = 'inventorydepth_stock-';
$objs = app::get('ome')->model('order_objects')->getList('bn', ['order_id'=>$order_id]);
foreach($objs as $v) {
$index = $prefix.$shop_id.'-'.$v['bn'];
cachecore::store($index, 1, 600);
}
}
/**
* 运行公式
*
* @param Array $sku 商品明细
* @param String $result 公式
* @param String $msg 错信息
* @return void
* @author
**/
public function formulaRun($result,$sku=array(),&$msg,$type='')
{
if (is_numeric($result)) {
if ($result < 0) {
$msg = $this->app->_('库存已经小于零,请重新填写');
return false;
}
return (int)$result;
}
# 过滤掉敏感字符
$dange = array('select', 'update', 'drop', 'delete', 'insert', 'alter');
$tmp = strtolower($result);
foreach ($dange as $val){
if (strpos($tmp, $val) !== false) {
$msg = $this->app->_('what are you doing? go away!');
return false;
}
}
if (!$sku) {
foreach ($this->get_benchmark() as $key => $val) {
$result = str_replace('{'.$val.'}', '0', $result);
}
try {
$result = @kernel::database()->selectrow('select ' . $result . ' as val');
} catch (Exception $e) {
$msg = '公式错误';
return false;
}
if ($result !== false) $result = $result['val'];
if (!is_numeric($result)) {
$msg = $this->app->_('公式错误,请重新填写。');
return false;
}
return true;
}
//-------------------变量实际替换校验------------------//
preg_match_all('/{(.*?)}/',$result,$matches);
$benchmark = $this->get_benchmark();
# 符合条件的所有货品
$calLib = kernel::single('inventorydepth_stock_calculation');
if($this->type == '3') {//代表门店库存回传
$calLib = kernel::single('inventorydepth_offline_calculation');
}
if($matches) {
//按仓库级回写库存
if($sku['sync_mode'] == 'warehouse'){
$stock = call_user_func_array(array($calLib,'get_'.$type.'actual_stock'),$sku);
if($stock === false) {
$msg = $this->app->_('公式有误!');
return false;
}
return $stock; //以branch_bn仓库编码为下标的多维数组
}
$calLib->actual_stock_make = '';
$msg = 'quantity=' . $result;
foreach($matches[1] as $match){
$m = array_search($match,$benchmark);
if(false === $m) {
$msg = $this->app->_('公式错误!');
return false;
}
$stock = call_user_func_array(array($calLib,'get_'.$type.$m),$sku);
$result = str_replace('{'.$match.'}', $stock, $result);
$msg = str_replace('{'.$match.'}', $match.':'.$stock, $msg);
}
if (method_exists($calLib, 'get_'.$type.'actual_stock_make')) {
$msg .= ' 其中可售库存(' . call_user_func_array(array($calLib,'get_'.$type.'actual_stock_make'),$sku) . ')';
} elseif ($calLib->actual_stock_make) {
$msg .= $calLib->actual_stock_make;
}
}
# 验证 $result
$result = @kernel::database()->selectrow('select ' . $result . ' as val');
//@eval("\$result = $result;");
if($result === false) {
$msg = $this->app->_('公式有误!');
return false;
}
$result = $result['val'];
if (!is_numeric($result)) {
$msg = $this->app->_('计算结果异常:可能仓库未绑定店铺!');
return false;
}else if (floor($result) < 0) {
//$msg = $sku['shop_product_bn'] . ' ' . $this->app->_('调整后的库存已经小于零,请重新填写');
return 0;
}
return (int)$result;
}
public function getNeedUpdateSku($shop_id, $bn) {
$prefix = 'inventorydepth_stock-';
$index = $prefix.$shop_id.'-'.$bn;
return cachecore::fetch($index);
}
/**
* 公式安全计算
* 如公式为{可售库存} + {安全库存},则需要将可售库存、安全库存替换为实际值
*
* @param string $formula 公式
* @param array $params 参数
* @return array [bool, string]
*/
public function cal($formula, $params)
{
$benchmark = $this->get_benchmark();
// 正则
$pattern = '/\{('.implode('|', $benchmark).')\}/';
// 替换变量为数值(使用正则防止变量名被错误替换,比如 "ab" 替换成 a 的值)
$replacedFormula = preg_replace_callback(
$pattern,
function ($matches) use ($params, $benchmark) {
$key = array_search($matches[1], $benchmark);
return (int)$params[$key];
},
$formula
);
// 使用简单的白名单验证数学的四则运算表达式是否合法
if (!preg_match('/^[0-9+\-*\/\.\s\(\)]+$/', $replacedFormula)) {
throw new \Exception('公式包含非法字符!原始公式: ' . $formula . ', 替换后公式: ' . $replacedFormula);
}
// 安全计算表达式(不使用 eval
// 可使用安全的 eval 替代函数或第三方库
$result = eval("return $replacedFormula;");
return $result;
}
}