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

@@ -0,0 +1,448 @@
<?php
/**
* 审批流API控制器
*
* @author shopex开发团队
* @version 2025.07.10
*/
class ticket_ctl_admin_workflow_flow extends desktop_controller {
var $title = '审批流API';
var $workground = 'ticket_center';
public function __construct($app)
{
parent::__construct($app);
}
/**
* 获取审批流场景类型列表
*/
public function getSceneTypeList() {
try {
$templateMdl = app::get('ticket')->model('workflow_template');
// 定义场景类型(写死)
$sceneTypes = [
[
'scene_type' => 'add_gift',
'scene_name' => '加赠',
'scene_memo' => '加赠商品审批流程'
]
];
$sceneList = [];
foreach($sceneTypes as $sceneType){
// 查询该场景类型的模板配置
$templateInfo = $templateMdl->dump(['scene_type' => $sceneType['scene_type']], 'id,is_enabled');
// 根据查询结果设置status
if(empty($templateInfo)){
// 没有数据,未配置
$status = '0';
} elseif($templateInfo['is_enabled'] == 'true'){
// 已配置
$status = '1';
} else {
// 已禁用
$status = '2';
}
$sceneList[] = [
'scene_type' => $sceneType['scene_type'],
'scene_name' => $sceneType['scene_name'],
'scene_memo' => $sceneType['scene_memo'],
'status' => $status // 0未配置1已配置2已禁用
];
}
$this->returnJson($sceneList, true, '获取审批流场景类型列表成功');
} catch (Exception $e) {
$this->returnJson([], false, '获取审批流场景类型列表失败:' . $e->getMessage());
}
}
/**
* 根据场景类型获取审批流配置
*/
public function getWorkflowBySceneType() {
try {
// 获取JSON数据
$input = file_get_contents('php://input');
$data = json_decode($input, true);
// 如果JSON解析失败尝试从$_POST获取
if(empty($data)){
$data = $_POST;
}
$scene_type = $data['scene_type'] ?? '';
if(empty($scene_type)){
$this->returnJson([], false, '场景类型不能为空');
}
// 查询模板信息
$templateMdl = app::get('ticket')->model('workflow_template');
$templateInfo = $templateMdl->dump(['scene_type' => $scene_type], '*');
if(empty($templateInfo)){
$this->returnJson(['nodes'=>[]], true, '获取审批流配置成功');
}
// 查询节点信息
$nodeMdl = app::get('ticket')->model('workflow_node');
$nodeList = $nodeMdl->getList('*', ['template_id' => $templateInfo['id']], 0, -1, 'step_order ASC');
// 格式化节点数据
$nodes = [];
foreach($nodeList as $node){
$nodes[] = [
'node_id' => $node['id'],
'node_name' => $node['node_name'],
'node_type' => $node['node_type'],
'step_order' => $node['step_order'],
'assignee_type' => $node['assignee_type'],
'assignee_id' => $node['assignee_id'],
'assignee_name' => $node['assignee_name']
];
}
// 组装返回数据
$result = [
'template_id' => $templateInfo['id'],
'template_bn' => $templateInfo['template_bn'],
'template_name' => $templateInfo['template_name'],
'scene_type' => $templateInfo['scene_type'],
'description' => $templateInfo['description'],
'version' => '1', // 固定版本号
'status' => $templateInfo['is_enabled'] == 'true' ? '1' : '2', // 1已配置2已禁用
'nodes' => $nodes
];
$this->returnJson($result, true, '获取审批流配置成功');
} catch (Exception $e) {
$this->returnJson([], false, '获取审批流配置失败:' . $e->getMessage());
}
}
/**
* 保存审批流(包含模板和节点信息)
* 支持新建和更新两种场景
*/
public function saveWorkflow() {
try {
// 获取JSON数据
$input = file_get_contents('php://input');
$data = json_decode($input, true);
// 如果JSON解析失败尝试从$_POST获取
if(empty($data)){
$data = $_POST;
}
// 验证必要参数
if(empty($data['template_name'])){
$this->returnJson([], false, '模板名称不能为空');
}
if(empty($data['scene_type'])){
$this->returnJson([], false, '场景类型不能为空');
}
if(empty($data['nodes']) || !is_array($data['nodes'])){
$this->returnJson([], false, '节点数据不能为空');
}
$templateMdl = app::get('ticket')->model('workflow_template');
$nodeMdl = app::get('ticket')->model('workflow_node');
// 开启事务
$db = kernel::database();
$tran = $db->beginTransaction();
// 处理status转is_enabled
// status: 1启用, 2禁用 -> is_enabled: true启用, false禁用
$is_enabled = 'true'; // 默认启用
if(isset($data['status'])){
$is_enabled = ($data['status'] == '1' || $data['status'] == 1) ? 'true' : 'false';
} elseif(isset($data['is_enabled'])){
$is_enabled = $data['is_enabled'];
}
// 准备模板数据
$templateData = [
'template_name' => $data['template_name'],
'scene_type' => $data['scene_type'],
'description' => is_array($data['description']) ? implode('', $data['description']) : $data['description'],
'is_enabled' => $is_enabled
];
// 判断是新建还是更新
$is_edit = !empty($data['template_id']);
$old_template_data = null; // 用于存储更新前的数据
if(!$is_edit){
// 新建模板
// 生成模板编号
$templateData['template_bn'] = 'TPL_' . strtoupper(uniqid());
$insertResult = $templateMdl->insert($templateData);
if(!$insertResult){
$db->rollBack();
$this->returnJson([], false, '创建模板失败');
}
$template_id = $templateData['id'];
// 新建时直接插入节点数据
foreach($data['nodes'] as $nodeData){
if(empty($nodeData['node_name']) || empty($nodeData['node_type'])){
continue; // 跳过无效节点
}
$insertNodeData = [
'template_id' => $template_id,
'node_name' => $nodeData['node_name'],
'node_type' => $nodeData['node_type'],
'step_order' => $nodeData['step_order'] ?? 1,
'assignee_type' => $nodeData['assignee_type'] ?? 'user',
'assignee_id' => $nodeData['assignee_id'] ?? 0,
'assignee_name' => $nodeData['assignee_name'] ?? ''
];
$insertResult = $nodeMdl->insert($insertNodeData);
if(!$insertResult){
$db->rollBack();
$this->returnJson([], false, '插入节点数据失败');
}
}
} else {
// 更新模板 - 先获取更新前的数据
$template_id = $data['template_id'];
$old_template_data = $templateMdl->dump(['id' => $template_id], '*, id as template_id');
// 获取更新前的节点数据
$old_nodes = $nodeMdl->getList('*, id as node_id', ['template_id' => $template_id], 0, -1, 'step_order ASC');
$old_template_data['nodes'] = $old_nodes;
$updateResult = $templateMdl->update($templateData, ['id' => $template_id]);
if($updateResult === false){
$db->rollBack();
$this->returnJson([], false, '更新模板信息失败');
}
// 精细处理节点更新
$this->updateWorkflowNodes($template_id, $data['nodes'], $old_nodes, $db);
}
// 提交事务
$db->commit($tran);
// 记录操作日志
$this->recordWorkflowLog($template_id, $data, $old_template_data, $is_edit);
$this->returnJson([], true, '保存审批流成功');
} catch (Exception $e) {
$this->returnJson([], false, '保存审批流失败:' . $e->getMessage());
}
}
/**
* 获取审批人列表
*/
public function getAssigneeList() {
try {
// 获取JSON数据
$input = file_get_contents('php://input');
$data = json_decode($input, true);
// 如果JSON解析失败尝试从$_POST获取
if(empty($data)){
$data = $_POST;
}
$assignee_type = $data['assignee_type'] ?? 'user';
// 根据审批人类型返回不同数据
if($assignee_type == 'user'){
// 获取用户列表
$userMdl = app::get('desktop')->model('users');
$userList = $userMdl->getList('user_id,name', ['status'=>1], 0, -1);
// 格式化数据
$assigneeList = [];
foreach($userList as $user){
$assigneeList[] = [
'id' => $user['user_id'],
'name' => $user['name']
];
}
$result = [
'assignee' => $assigneeList
];
} elseif($assignee_type == 'role'){
// 角色类型暂时返回空数组
$result = [
'assignee' => []
];
} elseif($assignee_type == 'dept'){
// 部门类型暂时返回空数组
$result = [
'assignee' => []
];
} else {
// 其他类型返回空数组
$result = [
'assignee' => []
];
}
$this->returnJson($result, true, '获取审批人列表成功');
} catch (Exception $e) {
$this->returnJson([], false, '获取审批人列表失败:' . $e->getMessage());
}
}
/**
* 精细处理节点更新(增删改)
*/
private function updateWorkflowNodes($template_id, $new_nodes, $old_nodes, $db)
{
$nodeMdl = app::get('ticket')->model('workflow_node');
$caseMdl = app::get('ticket')->model('workflow_case');
// 将旧节点按node_id建立索引
$old_nodes_map = [];
foreach($old_nodes as $old_node){
$old_nodes_map[$old_node['id']] = $old_node;
}
// 将新节点按node_id建立索引如果有node_id的话
$new_nodes_map = [];
foreach($new_nodes as $new_node){
if(!empty($new_node['node_id'])){
$new_nodes_map[$new_node['node_id']] = $new_node;
}
}
// 1. 处理需要删除的节点
$nodes_to_delete = [];
foreach($old_nodes_map as $old_node_id => $old_node){
if(!isset($new_nodes_map[$old_node_id])){
$nodes_to_delete[] = $old_node_id;
}
}
// 检查删除的节点是否被使用中
if(!empty($nodes_to_delete)){
$used_nodes = $caseMdl->getList('distinct current_node_id', [
'template_id' => $template_id,
'current_node_id|in' => $nodes_to_delete,
'status|in' => ['pending', 'processing', 'approved']
]);
if(!empty($used_nodes)){
$db->rollBack();
$used_node_ids = array_column($used_nodes, 'current_node_id');
$used_node_names = [];
foreach($used_node_ids as $used_node_id){
$used_node_names[] = $old_nodes_map[$used_node_id]['node_name'] ?? '未知节点';
}
$this->returnJson([], false, "节点「" . implode('、', $used_node_names) . "」正在被审批流程使用中,无法删除");
}
// 执行删除
$deleteResult = $nodeMdl->delete(['id' => $nodes_to_delete]);
if($deleteResult === false){
$db->rollBack();
$this->returnJson([], false, '删除节点失败');
}
}
// 2. 处理需要更新的节点
foreach($new_nodes_map as $node_id => $new_node){
if(isset($old_nodes_map[$node_id])){
// 更新节点
$updateNodeData = [
'node_name' => $new_node['node_name'],
'node_type' => $new_node['node_type'],
'step_order' => $new_node['step_order'] ?? 1,
'assignee_type' => $new_node['assignee_type'] ?? 'user',
'assignee_id' => $new_node['assignee_id'] ?? 0,
'assignee_name' => $new_node['assignee_name'] ?? ''
];
$updateResult = $nodeMdl->update($updateNodeData, ['id' => $node_id]);
if($updateResult === false){
$db->rollBack();
$node_name = $new_node['node_name'] ?? '未知节点';
$this->returnJson([], false, "更新节点「{$node_name}」失败");
}
}
}
// 3. 处理需要新增的节点
foreach($new_nodes as $new_node){
if(empty($new_node['node_id']) || !isset($old_nodes_map[$new_node['node_id']])){
// 新增节点
if(empty($new_node['node_name']) || empty($new_node['node_type'])){
continue; // 跳过无效节点
}
$insertNodeData = [
'template_id' => $template_id,
'node_name' => $new_node['node_name'],
'node_type' => $new_node['node_type'],
'step_order' => $new_node['step_order'] ?? 1,
'assignee_type' => $new_node['assignee_type'] ?? 'user',
'assignee_id' => $new_node['assignee_id'] ?? 0,
'assignee_name' => $new_node['assignee_name'] ?? ''
];
$insertResult = $nodeMdl->insert($insertNodeData);
if(!$insertResult){
$db->rollBack();
$this->returnJson([], false, '插入新节点数据失败');
}
}
}
}
/**
* 记录审批流操作日志
*/
private function recordWorkflowLog($template_id, $data, $old_template_data, $is_edit = false)
{
// 获取操作日志模型
$omeLogMdl = app::get('ome')->model('operation_log');
// 准备日志数据
$log_key = $is_edit ? 'ticket_workflow_edit@ticket' : 'ticket_workflow_add@ticket';
$operation_type = $is_edit ? '编辑' : '新建';
// 构建memo信息
$memo = "审批流{$operation_type}:模板名称={$data['template_name']},场景类型={$data['scene_type']},节点数量=" . count($data['nodes']);
// 记录日志
$log_id = $omeLogMdl->write_log($log_key, $template_id, $memo);
// 生成操作快照
if ($log_id) {
$shootMdl = app::get('ome')->model('operation_log_snapshoot');
// snapshoot是更新前的数据updated是更新后的数据
$snapshoot = $is_edit && $old_template_data ? json_encode($old_template_data, JSON_UNESCAPED_UNICODE) : '';
$updated = json_encode($data, JSON_UNESCAPED_UNICODE);
$tmp = [
'log_id' => $log_id,
'snapshoot' => $snapshoot,
'updated' => $updated
];
$shootMdl->insert($tmp);
}
}
}