Finish mzl_dev
This commit is contained in:
@@ -81,19 +81,22 @@ class StockOrdersController extends BaseController
|
||||
if (!isset($groupedFiles[$file['file_code']])) {
|
||||
$groupedFiles[$file['file_code']] = [];
|
||||
}
|
||||
$groupedFiles[$file['file_code']][] = $file['file_url'];
|
||||
$groupedFiles[$file['file_code']][] = [
|
||||
'url' => $file['file_url'],
|
||||
'original_name' => $file['original_name']
|
||||
];
|
||||
}
|
||||
|
||||
// 映射到对应字段
|
||||
foreach ($fileTypes as $field => $fileCode) {
|
||||
if (isset($groupedFiles[$fileCode])) {
|
||||
// 原始URL数组
|
||||
// 文件信息数组,包含url和original_name
|
||||
$data[$field] = $groupedFiles[$fileCode];
|
||||
|
||||
// 完整URL数组
|
||||
$fullUrls = [];
|
||||
foreach ($groupedFiles[$fileCode] as $url) {
|
||||
$fullUrls[] = (new \app\common\service\OssService)->generatePrivateUrl($url);
|
||||
foreach ($groupedFiles[$fileCode] as $fileInfo) {
|
||||
$fullUrls[] = (new \app\common\service\OssService)->generatePrivateUrl($fileInfo['url']);
|
||||
}
|
||||
$data[$field . '_url'] = $fullUrls;
|
||||
}
|
||||
|
||||
@@ -118,6 +118,11 @@ class UserController extends BaseController
|
||||
$data['system_ids'][] = $system['id'];
|
||||
}
|
||||
}
|
||||
if ($data['reportToInfo']) {
|
||||
$data['report_to_name'] = $data['reportToInfo']['id'] == $data['id'] ? '/' : $data['reportToInfo']['name'];
|
||||
} else {
|
||||
$data['report_to_name'] = '-';
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +100,8 @@ class UserService
|
||||
$config['with']['roles'][] = 'name';
|
||||
$config['with']['systems'][] = 'id';
|
||||
$config['with']['systems'][] = 'name';
|
||||
$config['with']['reportToInfo'][] = 'id';
|
||||
$config['with']['reportToInfo'][] = 'name';
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
|
||||
@@ -40,7 +40,7 @@ class StockOrdersFiles extends Model
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'order_id', 'file_name', 'file_code', 'file_url', 'created_at', 'updated_at'];
|
||||
protected $fillable = ['id', 'order_id', 'file_name', 'file_code', 'file_url', 'original_name', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
|
||||
@@ -73,6 +73,7 @@ class StockOrdersService
|
||||
case 'print':
|
||||
case 'approval':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['with'][] = 'files'; // 添加文件附件关联
|
||||
break;
|
||||
case 'detail':
|
||||
case 'show':
|
||||
@@ -102,22 +103,14 @@ class StockOrdersService
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
$userId = $request->user->uid;
|
||||
|
||||
$data['order_no'] = generateStockNo();
|
||||
$data['biz_date'] = strtotime($data['biz_date']);
|
||||
$data['eta_ship_date'] = strtotime($data['eta_ship_date']);
|
||||
$data['latest_arrival_date'] = strtotime($data['latest_arrival_date']);
|
||||
$data['salesperson_id'] = $userId;
|
||||
$data['salesperson_snapshot'] = User::where('id', $userId)->value('name') ?? '';
|
||||
$data['approval_status'] = $data['approval_status'] == 1 ? 1 : 0;
|
||||
|
||||
// if ($data['is_final'] == 1) {
|
||||
$data['pick_up_date'] = $data['pick_up_date'] ? strtotime($data['pick_up_date']) : 0;
|
||||
$data['collect_all_date'] = $data['collect_all_date'] ? strtotime($data['collect_all_date']) : 0;
|
||||
// }
|
||||
|
||||
// 检查绑定
|
||||
(new UserService())->checkBind($userId);
|
||||
// 保存不检查文件上传
|
||||
if ($data['approval_status'] != 0) {
|
||||
$this->validateRequiredFiles($data);
|
||||
}
|
||||
// 终版备货单时,至少一个车辆填写了vin
|
||||
if ($data['is_final'] == 1) {
|
||||
// 检查是否至少有一个车辆填写了vin
|
||||
$hasVin = false;
|
||||
foreach ($data['veh_list'] as $k => $v) {
|
||||
if ($v['vin'] != '') {
|
||||
@@ -125,17 +118,105 @@ class StockOrdersService
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 如果没有任何车辆填写vin,则抛出异常
|
||||
if (!$hasVin) {
|
||||
throw new BusinessException('至少需要为一辆车辆填写vin,才能提交审核');
|
||||
}
|
||||
}
|
||||
|
||||
// 检查绑定
|
||||
(new UserService())->checkBind($userId);
|
||||
$data['order_no'] = generateStockNo();
|
||||
$data['biz_date'] = strtotime($data['biz_date']);
|
||||
$data['eta_ship_date'] = strtotime($data['eta_ship_date']);
|
||||
$data['latest_arrival_date'] = strtotime($data['latest_arrival_date']);
|
||||
$data['salesperson_id'] = $userId;
|
||||
$data['salesperson_snapshot'] = User::where('id', $userId)->value('name') ?? '';
|
||||
$data['approval_status'] = $data['approval_status'] == 1 ? 1 : 0;
|
||||
$data['pick_up_date'] = $data['pick_up_date'] ? strtotime($data['pick_up_date']) : 0;
|
||||
$data['collect_all_date'] = $data['collect_all_date'] ? strtotime($data['collect_all_date']) : 0;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证创建备货单时必需的文件是否已提供
|
||||
*
|
||||
* @param array $data 提交的数据
|
||||
* @throws BusinessException 当必需的文件缺失或为空时抛出异常
|
||||
*/
|
||||
private function validateRequiredFiles(array $data): void
|
||||
{
|
||||
$requiredFiles = [
|
||||
'contract' => '合同',
|
||||
'transaction_slip' => '水单',
|
||||
'pi_doc' => 'PI'
|
||||
];
|
||||
|
||||
foreach ($requiredFiles as $fileType => $fileLabel) {
|
||||
if (!isset($data[$fileType]) || !is_array($data[$fileType]) || empty($data[$fileType])) {
|
||||
throw new BusinessException("创建备货单时{$fileLabel}文件不能为空");
|
||||
}
|
||||
|
||||
// 检查文件数组中的每个条目是否都有有效的URL
|
||||
$hasValidFile = false;
|
||||
foreach ($data[$fileType] as $fileInfo) {
|
||||
if (isset($fileInfo['url']) && !empty($fileInfo['url'])) {
|
||||
$hasValidFile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$hasValidFile) {
|
||||
throw new BusinessException("创建备货单时{$fileLabel}文件不能为空");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证备货单审批时必需的文件是否存在
|
||||
*
|
||||
* @param StockOrders $item 备货单对象
|
||||
* @throws BusinessException 当必需的文件缺失或为空时抛出异常
|
||||
*/
|
||||
private function validateRequiredFilesForApproval($item): void
|
||||
{
|
||||
// 确保已加载文件关联
|
||||
if (!isset($item->files)) {
|
||||
$item->load('files');
|
||||
}
|
||||
|
||||
$requiredFiles = [
|
||||
\app\common\model\StockOrdersFiles::CONTRACT => '合同',
|
||||
\app\common\model\StockOrdersFiles::TRANSACTION_SLIP => '水单',
|
||||
\app\common\model\StockOrdersFiles::PI_DOC => 'PI'
|
||||
];
|
||||
|
||||
// 按文件类型分组现有文件
|
||||
$existingFiles = [];
|
||||
foreach ($item->files as $file) {
|
||||
if (!isset($existingFiles[$file->file_code])) {
|
||||
$existingFiles[$file->file_code] = [];
|
||||
}
|
||||
$existingFiles[$file->file_code][] = $file;
|
||||
}
|
||||
|
||||
// 检查每种必需文件是否存在
|
||||
foreach ($requiredFiles as $fileCode => $fileLabel) {
|
||||
if (!isset($existingFiles[$fileCode]) || empty($existingFiles[$fileCode])) {
|
||||
throw new BusinessException("提交审批前必须上传{$fileLabel}文件");
|
||||
}
|
||||
|
||||
// 检查文件中是否有有效的URL
|
||||
$hasValidFile = false;
|
||||
foreach ($existingFiles[$fileCode] as $file) {
|
||||
if (!empty($file->file_url)) {
|
||||
$hasValidFile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$hasValidFile) {
|
||||
throw new BusinessException("提交审批前必须上传有效的{$fileLabel}文件");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function afterServiceStore($res)
|
||||
{
|
||||
// 处理原单
|
||||
@@ -161,7 +242,8 @@ class StockOrdersService
|
||||
{
|
||||
// 启动审批
|
||||
$appro = new \app\common\utils\approval\service\ApprovalFlowService();
|
||||
$appro->start('stock_orders', 'stock_orders', $item->id, [], $item->salesperson_id);
|
||||
$formData = $this->checkNewOrUsedVehicles($item->id);
|
||||
$appro->start('stock_orders', 'stock_orders', $item->id, $formData, $item->salesperson_id);
|
||||
// 异步生成pdf文件
|
||||
\Webman\RedisQueue\Redis::send('stock-order-pdf', ['id'=>$item->id]);
|
||||
}
|
||||
@@ -270,10 +352,14 @@ class StockOrdersService
|
||||
public function serviceApproval(Request $request)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'approval');
|
||||
$item = $this->logicShow($config);
|
||||
|
||||
// 检查备货单是否包含必需的文件
|
||||
$this->validateRequiredFilesForApproval($item);
|
||||
|
||||
$this->logicUpdateBy($config, [
|
||||
'approval_status' => 1
|
||||
]);
|
||||
$item = $this->logicShow($config);
|
||||
$this->startApproval($item);
|
||||
return $this->postProcess('Approval', $item);
|
||||
}
|
||||
@@ -295,7 +381,8 @@ class StockOrdersService
|
||||
public function approvalNullify($item)
|
||||
{
|
||||
$appro = new \app\common\utils\approval\service\ApprovalFlowService();
|
||||
$appro->startNullify('stock_orders_nullify', 'stock_orders', $item->id, [], $item->salesperson_id);
|
||||
$formData = $this->checkNewOrUsedVehicles($item->id);
|
||||
$appro->startNullify('stock_orders_nullify', 'stock_orders', $item->id, $formData, $item->salesperson_id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,6 +451,9 @@ class StockOrdersService
|
||||
*/
|
||||
public function beforeServiceUpdate($data, Request $request)
|
||||
{
|
||||
// 检查必填文件是否已上传
|
||||
// $this->validateRequiredFiles($data);
|
||||
|
||||
$data['biz_date'] = strtotime($data['biz_date']);
|
||||
$data['eta_ship_date'] = strtotime($data['eta_ship_date']);
|
||||
$data['latest_arrival_date'] = strtotime($data['latest_arrival_date']);
|
||||
@@ -479,18 +569,23 @@ class StockOrdersService
|
||||
// 检查数据中是否存在该字段且为数组
|
||||
if (!empty($data[$field]) && is_array($data[$field])) {
|
||||
// 处理该字段下的每个文件
|
||||
foreach ($data[$field] as $fileUrl) {
|
||||
foreach ($data[$field] as $fileInfo) {
|
||||
$fileData = [
|
||||
'order_id' => $order->id,
|
||||
'file_code' => $fileCode,
|
||||
'file_url' => $fileUrl,
|
||||
'file_url' => $fileInfo['url'] ?? '',
|
||||
'file_name' => StockOrdersFiles::FILE_CODE[$fileCode],
|
||||
'original_name' => $fileInfo['original_name'] ?? StockOrdersFiles::FILE_CODE[$fileCode],
|
||||
];
|
||||
|
||||
// 只有当file_url不为空时才创建记录
|
||||
if (!empty($fileData['file_url'])) {
|
||||
StockOrdersFiles::create($fileData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (更新时)清除已存在的订单项
|
||||
@@ -905,6 +1000,7 @@ class StockOrdersService
|
||||
'id' => $file->id,
|
||||
'file_url' => $file->file_url,
|
||||
'file_full_url' => $this->getFileUrl($file->file_url),
|
||||
'original_name' => $file->original_name,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -978,4 +1074,45 @@ class StockOrdersService
|
||||
}
|
||||
return (new \app\common\service\OssService)->generatePrivateUrl($fileUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查备货单中的车辆是新车还是二手车
|
||||
* @param int $stockOrderId 备货单ID
|
||||
* @return array 返回包含has_new和has_used的数组
|
||||
*/
|
||||
public function checkNewOrUsedVehicles(int $stockOrderId): array
|
||||
{
|
||||
// 获取备货单关联的所有车辆项
|
||||
$vehicles = StockOrderItems::where('order_id', $stockOrderId)->get();
|
||||
|
||||
$hasNew = false;
|
||||
$hasUsed = false;
|
||||
$submitNote = '';
|
||||
|
||||
foreach ($vehicles as $vehicle) {
|
||||
// 判断是否为二手车(mileage > 0)
|
||||
if ($vehicle->mileage > 0) {
|
||||
$hasUsed = true;
|
||||
$submitNote = '本单只有二手车';
|
||||
} else {
|
||||
$hasNew = true;
|
||||
$submitNote = '本单只有新车';
|
||||
}
|
||||
|
||||
// 如果两种类型都已经存在,可以提前退出循环
|
||||
if ($hasNew && $hasUsed) {
|
||||
$submitNote = '本单包含新车和二手车';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'has_new' => $hasNew ? 1 : 0,
|
||||
'has_used' => $hasUsed ? 1 : 0,
|
||||
'submit_note' => $submitNote
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -68,7 +68,7 @@ class ApprovalFlowService
|
||||
}
|
||||
$this->sendNotification($approverIds, $instance, 'pending', false, $extra);
|
||||
|
||||
$this->notifyCCs($firstStep, $instance, 'pending');
|
||||
// $this->notifyCCs($firstStep, $instance, 'pending');
|
||||
|
||||
$this->pushTodoChanged($approverIds);
|
||||
|
||||
@@ -193,6 +193,12 @@ class ApprovalFlowService
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
$this->onFlowFinalized($instance, $finalStatus);
|
||||
|
||||
// 新增:在流程最终完成时才发本步骤的抄送
|
||||
if (!empty($step['cc'])) {
|
||||
$this->notifyCCs($step, $instance, $notifyAction);
|
||||
}
|
||||
|
||||
$this->sendNotification([$instance->initiator_id], $instance, $notifyAction, false);
|
||||
$this->pushTodoChanged([$approverId]);
|
||||
return ['status' => 'completed', 'msg' => ($finalStatus === 'voided' ? '已作废' : '同意')];
|
||||
@@ -215,7 +221,7 @@ class ApprovalFlowService
|
||||
$this->insertApprovalRecord($instance, $nextIndex, $uid);
|
||||
}
|
||||
$this->sendNotification($nextApprovers, $instance, 'pending', false);
|
||||
$this->notifyCCs($nextStep, $instance, 'pending');
|
||||
// $this->notifyCCs($nextStep, $instance, 'pending');
|
||||
$this->pushTodoChanged(array_merge([$approverId], $nextApprovers));
|
||||
return ['status' => 'next_step', 'msg' => '进行下一步:'.$nextStep['name'] ?? ('Step '.$nextIndex)];
|
||||
});
|
||||
|
||||
@@ -61,7 +61,7 @@ class StockOrdersController extends BaseController
|
||||
if (isset($data['pick_up_date']) && $data['pick_up_date'] > 0) $data['pick_up_date'] = date('Y-m-d', $data['pick_up_date']);
|
||||
if (isset($data['collect_all_date']) && $data['collect_all_date'] > 0) $data['collect_all_date'] = date('Y-m-d', $data['collect_all_date']);
|
||||
|
||||
// 处理文件附件
|
||||
// 处理文件附件:只允许 _url 字段调用 OSS 生成私有链接
|
||||
$fileTypes = [
|
||||
'contract' => \app\common\model\StockOrdersFiles::CONTRACT,
|
||||
'transaction_slip' => \app\common\model\StockOrdersFiles::TRANSACTION_SLIP,
|
||||
@@ -70,34 +70,40 @@ class StockOrdersController extends BaseController
|
||||
|
||||
// 初始化文件字段
|
||||
foreach (array_keys($fileTypes) as $field) {
|
||||
$data[$field] = [];
|
||||
$data[$field . '_url'] = [];
|
||||
$data[$field] = []; // 存储原始文件信息(不包含签名链接)
|
||||
$data[$field . '_url'] = []; // 存储通过OSS生成的私有链接
|
||||
}
|
||||
|
||||
// 按 file_code 分组文件
|
||||
if (!empty($data['files'])) {
|
||||
$groupedFiles = [];
|
||||
foreach ($data['files'] as $file) {
|
||||
if (!isset($groupedFiles[$file['file_code']])) {
|
||||
$groupedFiles[$file['file_code']] = [];
|
||||
$code = $file['file_code'];
|
||||
if (!isset($groupedFiles[$code])) {
|
||||
$groupedFiles[$code] = [];
|
||||
}
|
||||
$groupedFiles[$file['file_code']][] = $file['file_url'];
|
||||
$groupedFiles[$code][] = [
|
||||
'url' => $file['file_url'], // 原始路径
|
||||
'original_name' => $file['original_name'] // 原始文件名
|
||||
];
|
||||
}
|
||||
|
||||
// 映射到对应字段
|
||||
// 映射到对应字段,并仅对 _url 调用 OSS 服务
|
||||
foreach ($fileTypes as $field => $fileCode) {
|
||||
if (isset($groupedFiles[$fileCode])) {
|
||||
// 原始URL数组
|
||||
// 主字段存储基本信息(无签名链接)
|
||||
$data[$field] = $groupedFiles[$fileCode];
|
||||
|
||||
// 完整URL数组
|
||||
$fullUrls = [];
|
||||
foreach ($groupedFiles[$fileCode] as $url) {
|
||||
$fullUrls[] = (new \app\common\service\OssService)->generatePrivateUrl($url);
|
||||
// 只有 *_url 字段才生成带签名的完整 URL
|
||||
$signedUrls = [];
|
||||
foreach ($groupedFiles[$fileCode] as $fileInfo) {
|
||||
$signedUrls[] = (new \app\common\service\OssService)->generatePrivateUrl($fileInfo['url']);
|
||||
}
|
||||
$data[$field . '_url'] = $fullUrls;
|
||||
$data[$field . '_url'] = $signedUrls;
|
||||
}
|
||||
}
|
||||
|
||||
// 清理临时数据
|
||||
unset($data['files']);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user