1. 【新增】售后单售后原因类型支持搜索

2. 【新增】手工创建订单折扣可输入正数

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

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

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

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

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

8. 【修复】基础物料分类管理问题
This commit is contained in:
chenping
2026-04-01 11:59:17 +08:00
parent 9341122827
commit 61783b7d01
754 changed files with 46179 additions and 5700 deletions

View File

@@ -38,6 +38,17 @@ class material_basic_check
//新增标记
$is_new_add = $params['edit'] ? false : true;
unset($params['edit']);
// 去除基础物料编码前后空格
if (isset($params['material_bn'])) {
$params['material_bn'] = trim($params['material_bn']);
}
if (isset($params['material_spu'])) {
$params['material_spu'] = trim($params['material_spu']);
}
if (isset($params['material_code'])) {
$params['material_code'] = trim($params['material_code']);
}
//检查物料名称
if(empty($params['material_name'])){
@@ -67,13 +78,16 @@ class material_basic_check
if($is_new_add)
{
//判断物料编码和物料条码只能是由数字英文下划线组成
$reg_bn_code = "/^[0-9a-zA-Z\_\#\-\/]*$/";
if(!preg_match($reg_bn_code,$params["material_bn"])){
$err_msg = "物料编码只支持(数字、英文、_下划线、-横线、#井号、/斜杠)";
// 物料编号:支持数字、英文、下划线、横线、井号、斜杠、空格
$reg_bn = "/^[0-9a-zA-Z\_\#\-\/ ]*$/";
if(!preg_match($reg_bn,$params["material_bn"])){
$err_msg = "物料编码只支持(数字、英文、_下划线、-横线、#井号、/斜杠、空格)";
return false;
}
if(!preg_match($reg_bn_code,$params["material_code"])){
$err_msg = "物料条码只支持[数字英文_-#\]组成";
// 物料条码:支持数字、英文、下划线、横线、井号、斜杠(不支持空格)
$reg_code = "/^[0-9a-zA-Z\_\#\-\/]*$/";
if(!preg_match($reg_code,$params["material_code"])){
$err_msg = "物料条码只支持(数字、英文、_下划线、-横线、#井号、/斜杠)组成";
return false;
}

View File

@@ -425,4 +425,30 @@ class material_basic_material{
}
return $smIds;
}
/**
* 获取指定不需要管控库存的基础物料
*
* @param $bmIds
* @return void
*/
public function getNotCtrlStoreProducts($bmIds)
{
$basicMaterialObj = app::get('material')->model('basic_material');
// check
if(empty($bmIds)){
return [];
}
// 不需要管控库存的基础物料
$materialList = $basicMaterialObj->getList('bm_id,material_bn,type,is_ctrl_store', array('bm_id'=>$bmIds, 'is_ctrl_store'=>2));
if(empty($materialList)){
return [];
}
$materialList = array_column($materialList, null, 'bm_id');
return $materialList;
}
}

View File

@@ -794,6 +794,9 @@ class material_basic_material_stock extends ome_redis{
$dateline = 'UNIX_TIMESTAMP()';
if ($opt == '+') {
$store = "store=IFNULL(store, 0)+" . $item['quantity'] . ',';
// 库存增加时,记录“库存最后添加时间”
$store .= " inc_store_lastmodify=" . $dateline . ",";
} else {
// opt='-'的时候,$item['quantity']为负,所以用+
if ($item['negative_stock'] == 'true'){

View File

@@ -258,11 +258,18 @@ class material_basic_material_stock_freeze{
$obj_bn = $freezeData['obj_bn'] ? : '';
$sub_bill_type = $freezeData['sub_bill_type'] ? : '';
$log_type = $freezeData['log_type'] ? $freezeData['log_type'] : '';
// check
if(empty($bm_id) || empty($obj_type) || empty($bmsq_id)){
$error_msg = '冻结基础数据缺失';
return false;
}
// 基础物料不管控库存,则跳过
if (isset($freezeData['is_product_ctrl_store']) && $freezeData['is_product_ctrl_store'] === false) {
continue;
}
$num = intval($num);
// 是否增加基础物料的冻结
@@ -442,6 +449,12 @@ class material_basic_material_stock_freeze{
$obj_id = $obj_type = $bill_type = '';
$obj_type_arr = $obj_id_arr = [];
foreach ($items as $item) {
// 基础物料不管控库存,则跳过
if (isset($item['is_product_ctrl_store']) && $item['is_product_ctrl_store'] === false) {
continue;
}
$bm_id = $item['bm_id'];
$obj_type = $item['obj_type'];
$bill_type = $item['bill_type'] ? $item['bill_type'] : 0;

View File

@@ -418,6 +418,7 @@ class material_basic_select
//根据仓库ID、基础物料ID获取该物料仓库级的预占
$branch_product[$key]['store_freeze'] = $basicMStockFreezeLib->getBranchFreeze($val['product_id'], $val['branch_id']);
$branch_product[$key]['available_store'] = max(0, $val['store'] - $branch_product[$key]['store_freeze']);
}
$pro['branch_product'] = $branch_product;

View File

@@ -0,0 +1,32 @@
<?php
/**
* ============================
* @Author: yaokangming
* @describe: 销售人员
* ============================
*/
class material_finder_seller {
public $addon_cols = "";
public $column_edit = "操作";
public $column_edit_width = 120;
public $column_edit_order = 1;
public function column_edit($row){
$btn = [];
$btn[] = '<a class="lnk" target="dialog::{width:450,height:200,title:\'编辑\'}" href="index.php?app=material&ctl=admin_seller&act=edit&p[0]='.$row['id'].'&finder_id='.$_GET['_finder']['finder_id'].'&finder_vid='.$_GET['finder_vid'].'">编辑</a>';
return implode('|', $btn);
}
public $detail_oplog = "操作记录";
public function detail_oplog($id){
$render = app::get('console')->render();
$opObj = app::get('ome')->model('operation_log');
$logdata = $opObj->read_log(array('obj_id'=>$id,'obj_type'=>'seller@material'), 0, -1);
foreach($logdata as $k=>$v){
$logdata[$k]['operate_time'] = date('Y-m-d H:i:s',$v['operate_time']);
$logdata[$k]['memo'] = str_replace('查看快照', '<a class="lnk" target="dialog::{width:450,height:200,title:\'查看\'}" href="index.php?app=material&ctl=admin_seller&act=oplog&p[0]='.$v['log_id'].'&finder_id='.$_GET['_finder']['finder_id'].'&finder_vid='.$_GET['finder_vid'].'">查看快照</a>', $v['memo']);
}
$render->pagedata['log'] = $logdata;
return $render->fetch('admin/oplog.html');
}
}

View File

@@ -0,0 +1,18 @@
<?php
class material_operation_log{
/**
* 定义当前APP下的操作日志的所有操作名称列表
* type键值由表名@APP名称组成
* @access public
* @return Array
*/
function get_operations(){
$operations = array(
'seller' => array('name'=>'销售人员', 'type'=>'seller@material'),
);
return array('material'=>$operations);
}
}
?>

View File

@@ -39,6 +39,11 @@ class material_sales_check
$is_new_add = $params['edit'] ? false : true;
unset($params['edit']);
// 去除销售物料编码前后空格
if (isset($params['sales_material_bn'])) {
$params['sales_material_bn'] = trim($params['sales_material_bn']);
}
if(empty($params['sales_material_name'])){
$err_msg ="销售物料名称不能为空";
return false;
@@ -53,9 +58,10 @@ class material_sales_check
if($is_new_add)
{
//判断物料编码只能是由数字英文下划线组成
$reg_bn_code = "/^[0-9a-zA-Z\_\#\-\/]*$/";
// 销售物料编码:支持数字、英文、下划线、横线、井号、斜杠、空格
$reg_bn_code = "/^[0-9a-zA-Z\_\#\-\/ ]*$/";
if(!preg_match($reg_bn_code,$params["sales_material_bn"])){
$err_msg = "物料编码只支持(数字、英文、_下划线、-横线、#井号、/斜杠)";
$err_msg = "物料编码只支持(数字、英文、_下划线、-横线、#井号、/斜杠、空格)";
return false;
}

View File

@@ -143,7 +143,7 @@ class material_sales_material{
* @return Boolean
*/
public function getBasicMBySalesMId($sm_id){
$salesBasicMInfos = $this->_salesBasicMaterialObj->getList('bm_id,sm_id,number,rate',array('sm_id'=>$sm_id), 0, -1);
$salesBasicMInfos = $this->_salesBasicMaterialObj->getList('*',array('sm_id'=>$sm_id), 0, -1);
if($salesBasicMInfos){
foreach($salesBasicMInfos as $k => $salesBasicMInfo){
$bmIds[] = $salesBasicMInfo['bm_id'];

View File

@@ -0,0 +1,55 @@
<?php
class material_seller_import {
const IMPORT_TITLE = [
'seller_code' => '销售人员编码',
'seller_name' => '销售人员名称',
];
public function getExcelTitle()
{
return ['销售人员导入模板.xlsx',[
self::IMPORT_TITLE,
]];
}
public function processExcelRow($import_file, $post)
{
$format = [];
// 读取文件
return kernel::single('omecsv_phpoffice')->import($import_file, function ($line, $buffer, $post, $highestRow) {
static $title;
if ($line == 1) {
$title = $buffer;
// 验证模板是否正确
if (array_filter($title) != array_values(self::IMPORT_TITLE)) {
return [false, '导入模板不正确'];
}
return [true];
}
$buffer = array_combine(array_keys(self::IMPORT_TITLE), array_slice($buffer, 0, count(self::IMPORT_TITLE)));
$require = ['seller_code', 'seller_name'];
foreach($require as $v) {
if(empty($buffer[$v])) {
return [true, self::IMPORT_TITLE[$v] . '不能为空', 'warnning'];
}
}
$data = [
'seller_code' => trim($buffer['seller_code']),
'seller_name' => trim($buffer['seller_name']),
];
$seller = app::get('material')->model('seller');
if($seller->db_dump(['seller_code'=>$data['seller_code']], 'id')) {
return [true, '销售人员已经存在', 'warnning'];
}
$seller->insert($data);
if($data['id']) {
app::get('ome')->model('operation_log')->write_log('seller@material', $data['id'], '导入销售人员信息:'.json_encode($data, JSON_UNESCAPED_UNICODE));
}
return [true, '导入成功'];
}, $post, $format);
}
}