validator; } protected function buildQueryConfig(Request $request, string $scene = 'index'): array { $p = $request->all(); $config = []; $config['model'] = $this->modelClass; switch ($scene) { case 'index': // ====== ====== 筛选 ====== ====== // 业务id if (isset($p['salesperson_id']) && $p['salesperson_id']) { $config['where']['salesperson_id'] = $p['salesperson_id']; } // 初、终版 $config['where']['is_final'] = $p['is_final'] ?? 0; // 关键字 if (isset($p['keyword']) && $p['keyword']) { $k = '%' . $p['keyword'] . '%'; foreach (['pi_no', 'order_no', 'customer_snapshot'] as $col) { $config['orWhere'][] = [$col, 'like', $k]; } } $config['order']['id'] = 'desc'; // $config['where']['salesperson_id'] = $request->user->uid; break; case 'print': case 'approval': $config['where']['id'] = $p['id']; $config['with'][] = 'files'; // 添加文件附件关联 break; case 'detail': case 'show': $config['where']['id'] = $p['id']; $config['with'][] = 'items'; $config['with'][] = 'items.options'; $config['with'][] = 'items.moneyValues'; $config['with'][] = 'accounts'; $config['with'][] = 'moneyValues'; $config['with'][] = 'salesperson'; $config['with'][] = 'files'; // 添加文件附件关联 break; case 'store': break; case 'update': $config['where']['id'] = $p['id']; break; case 'destroy': $config['where']['id'] = $p['id']; break; } return $config; } public function beforeServiceStore($data, Request $request) { $userId = $request->user->uid; // 检查绑定 (new UserService())->checkBind($userId); // 保存不检查文件上传 if ($data['approval_status'] != 0) { $this->validateRequiredFiles($data); } // 终版备货单时,至少一个车辆填写了vin if ($data['is_final'] == 1) { $hasVin = false; foreach ($data['veh_list'] as $k => $v) { if ($v['vin'] != '') { $hasVin = true; break; } } if (!$hasVin) { throw new BusinessException('至少需要为一辆车辆填写vin,才能提交审核'); } } $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) { // 处理原单 if ($res->is_final == 1 && $res->object_id > 0) { $order = StockOrders::find($res->object_id); $order->is_use = 1; $order->object_id = $res->id; if (!$order->save()) { flg('备货单【'.$order->order_no.'】创建终版成功,但更新原单失败'); } } // 启动审批 if ($res->approval_status == 1) { $this->startApproval($res); } return $res; } /** * 启动审批 */ public function startApproval($item) { // 启动审批 $appro = new \app\common\utils\approval\service\ApprovalFlowService(); $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]); } /** * 创建PDF文件 */ public function createdPdfFile($id) { $config = []; $config['model'] = $this->modelClass; $config['where']['id'] = $id; $config['with'][] = 'items'; $config['with'][] = 'items.options'; $config['with'][] = 'items.moneyValues'; $config['with'][] = 'accounts'; $config['with'][] = 'moneyValues'; $config['with'][] = 'salesperson'; $item = $this->logicShow($config); $pdfData = $this->formatData($item); // 渲染模板为最终HTML $tplPath = app_path('common/utils/pdf/template/stockOrder.stub'); $html = \app\common\utils\pdf\service\PdfHelper::render($tplPath, ['data' => $pdfData]); // 生成PDF $driver = new \app\common\utils\pdf\service\MpdfDriver(); $pdfBin = $driver->htmlToPdf($html); // 存储 $dir = public_path('pdf').'/'; $fileName = ($pdfData['order_no'] ?? date('YmdHis')) . '.pdf'; // 本地保存 \app\common\utils\pdf\service\PdfStorage::saveBinary( $pdfBin, $dir, $fileName ); // 上传云端 $param = [ 'path' => $dir . $fileName, 'scene' => 'stock_orders', 'category' => 'pdf', 'original_name' => $fileName ]; $up = new \app\common\service\UploadService(); $res = $up->uploadLocalFile($param); @unlink($dir . $fileName); // 更新文件地址 $item->file_url = $res['file_name']; $item->save(); return $res; } /** * 查询审批 */ public function queryAppro($bizId) { $instances = ApprovalInstances::where('biz_id', $bizId)->where('biz_type', 'stock_orders')->where('status', 'approved')->first(); if (!$instances) { return []; } $records = ApprovalRecords::where('instance_id', $instances->id)->where('action', 'approve')->orderBy('step_index', 'asc')->pluck('approver_id')->toArray(); if (count($records) == 0) { return []; } $signImgs = []; foreach ($records as $k => $v) { $signImg = User::where('id', $v)->value('sign_img'); $signImgs[$k] = (!empty($signImg))?(new \app\common\service\OssService)->generatePrivateUrl($signImg):''; } return $signImgs; } /** * 打印数据 */ public function servicePrint(Request $request) { $config = $this->buildQueryConfig($request, 'show'); $item = $this->logicShow($config); return $this->postProcess('Print', $item); } public function serviceDetail(Request $request) { $config = $this->buildQueryConfig($request, 'detail'); $item = $this->logicShow($config); $detail = $this->formatData($item); return $this->postProcess('Detail', $detail); } /** * 审批 */ public function serviceApproval(Request $request) { $config = $this->buildQueryConfig($request, 'approval'); $item = $this->logicShow($config); // 检查备货单是否包含必需的文件 $this->validateRequiredFilesForApproval($item); $this->logicUpdateBy($config, [ 'approval_status' => 1 ]); $this->startApproval($item); return $this->postProcess('Approval', $item); } /** * 作废审批 */ public function serviceApprovalNullify(Request $request) { $config = $this->buildQueryConfig($request, 'approval'); $item = $this->logicShow($config); $this->approvalNullify($item); return $this->postProcess('Approval', $item); } /** * 审批作废 */ public function approvalNullify($item) { $appro = new \app\common\utils\approval\service\ApprovalFlowService(); $formData = $this->checkNewOrUsedVehicles($item->id); $appro->startNullify('stock_orders_nullify', 'stock_orders', $item->id, $formData, $item->salesperson_id); } /** * 撤销审批 */ public function serviceApprovalRevoke(Request $request) { $config = $this->buildQueryConfig($request, 'approval'); $item = $this->logicShow($config); $this->approvalRevoke($item); return $this->postProcess('Approval', $item); } public function approvalRevoke($item) { $instance = \app\common\model\ApprovalInstances::where('biz_id', $item->id)->where('flow_type', 'stock_orders')->first(); $appro = new \app\common\utils\approval\service\ApprovalFlowService(); $appro->revoke($instance->id, $item->salesperson_id); } /** * 创建 * * @param Request $request * @param array $data * @return mixed */ public function serviceStore(Request $request, array $data = []) { // 关联表较多,增加事务处理 return Db::transaction(function () use ($request, $data) { $data = $this->preProcess('Store', $data, $request); $dl = $this->getDataLimitFromRequest($request); $created = $this->logicCreate($data, $dl); // 添加金额 $created->addMoney('cif_total', $data['cif_total']['currency'], $data['cif_total']['amount'], $data['cif_total']['rate'], '合计到岸价'); // 处理车辆和账户信息 $this->processOrderItems($created, $data); // 处理文件附件 $this->processOrderFiles($created, $data); return $this->postProcess('Store', $created); }); } protected function onlyFillableData(Model|string $model, array $data, array $extraWhitelist = []): array { $m = \is_string($model) ? new $model : $model; $keys = $m->getFillable(); if (empty($keys)) { $keys = $m->getConnection() ->getSchemaBuilder() ->getColumnListing($m->getTable()); } if ($extraWhitelist) { $keys = array_merge($keys, $extraWhitelist); } return array_intersect_key($data, array_flip($keys)); } /** * 更新前处理 * * @param array $data * @param Request $request * @return array */ 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']); $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 mixed $res * @return mixed */ protected function afterServiceUpdate($res) { // 启动审批 if ($res->approval_status == 1) { $this->startApproval($res); } return $res; } /** * 更新 * * @param Request $request * @param array $data * @return mixed */ public function serviceUpdate(Request $request, array $data = []) { // 关联表较多,增加事务处理 return Db::transaction(function () use ($request, $data) { $data = $this->preProcess('Update', $data, $request); $config = $this->buildQueryConfig($request, 'update'); // 过滤掉非库字段 $dbData = $this->onlyFillableData($config['model'], $data); // 更新主表 $this->logicUpdateBy($config, $dbData); // 获取更新后的数据 $order = $this->logicShow($config); // 处理车辆和账户信息 $this->processOrderItems($order, $data, true); // 添加金额 $order->addMoney('cif_total', $data['cif_total']['currency'], $data['cif_total']['amount'], $data['cif_total']['rate'], '合计到岸价'); // 处理文件附件 $this->processOrderFiles($order, $data, true); return $this->postProcess('Update', $order); }); } /** * 处理订单项(车辆和账户) * @param StockOrders $order 订单对象 * @param array $data 数据 * @param bool $isUpdate 是否为更新操作 */ private function processOrderItems($order, array $data, bool $isUpdate = false): void { // 如果是更新操作,先删除原有的关联数据 if ($isUpdate) { $this->clearExistingOrderItems($order->id); } // 处理车辆项 $this->processVehicleItems($order, $data['veh_list'] ?? []); // 处理账户项 $this->processAccountItems($order, $data['account_list'] ?? []); } /** * 处理订单文件附件 * @param StockOrders $order 订单对象 * @param array $data 数据 * @param bool $isUpdate 是否为更新操作 */ private function processOrderFiles($order, array $data, bool $isUpdate = false): void { // 如果是更新操作,先删除原有的文件附件 if ($isUpdate) { $this->clearExistingOrderFiles($order->id); } // 处理文件附件项 $this->processFileItems($order, $data); } /** * (更新时)清除已存在的订单文件附件 * @param int $orderId 订单ID */ private function clearExistingOrderFiles(int $orderId): void { StockOrdersFiles::where('order_id', $orderId)->delete(); } /** * 处理文件附件项 */ private function processFileItems($order, array $data): void { // 定义支持的文件类型 $fileTypes = [ 'contract' => StockOrdersFiles::CONTRACT, 'transaction_slip' => StockOrdersFiles::TRANSACTION_SLIP, 'pi_doc' => StockOrdersFiles::PI_DOC ]; // 遍历每种文件类型 foreach ($fileTypes as $field => $fileCode) { // 检查数据中是否存在该字段且为数组 if (!empty($data[$field]) && is_array($data[$field])) { // 处理该字段下的每个文件 foreach ($data[$field] as $fileInfo) { $fileData = [ 'order_id' => $order->id, 'file_code' => $fileCode, '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); } } } } } /** * (更新时)清除已存在的订单项 * @param int $orderId 订单ID */ private function clearExistingOrderItems(int $orderId): void { // 删除车辆改装项 StockOrderItemOptions::whereHas('item', function ($query) use ($orderId) { $query->where('order_id', $orderId); })->delete(); // 删除车辆项及其相关金额记录 $orderItems = StockOrderItems::where('order_id', $orderId)->get(); foreach ($orderItems as $item) { // 删除车辆项的金额记录 Db::table('veh_money_value') ->where('object_scene', 'stock_order_items') ->where('object_id', $item->id) ->delete(); } // 删除车辆项 StockOrderItems::where('order_id', $orderId)->delete(); // 删除订单本身的金额记录 Db::table('veh_money_value') ->where('object_scene', 'stock_orders') ->where('object_id', $orderId) ->delete(); // 删除账户项 StockOrderAccounts::where('order_id', $orderId)->delete(); } /** * 处理车辆项 */ private function processVehicleItems($order, array $vehList): void { $profitTotalAmount = 0.00; $profitCurrency = ''; $profitRate = 0; foreach ($vehList as $veh) { $veh['order_id'] = $order->id; $veh['unique_id'] = $this->generateVehicleUniqueId($veh); $item = StockOrderItems::create($veh); // 处理金额信息 $this->processVehiclePrices($item, $veh); // 累计到岸价 $profitCurrency === '' ? $profitCurrency = $veh['profit']['currency'] ?? '' : ''; $profitRate === 0 ? $profitRate = $veh['profit']['rate'] ?? 0 : ''; $profitTotalAmount += $veh['profit']['amount'] ?? 0; // 处理改装项 $this->processModificationItems($item->id, $veh['modify_list'] ?? []); } // 利润 $order->addMoney('profit_total', $profitCurrency, $profitTotalAmount, $profitRate, '总利润'); } /** * 生成车辆唯一标识 */ private function generateVehicleUniqueId(array $veh): string { $keysToRemove = ['vin', 'remark', 'modify_list', 'order_id']; $array = array_diff_key($veh, array_flip($keysToRemove)); $uniqueIdStr = json_encode($array); return md5($uniqueIdStr); } /** * 处理车辆价格信息 */ private function processVehiclePrices($item, array $veh): void { // unit_price 单价/成交价/收款价 // total_price 总价 // handling_fee 手续费 // fob_transport_fee FOB运输费 // port_misc_fee 港杂 // retrofit_fee 改装费 // ocean_freight 海运费 // commission 佣金 // purchase_tax 购置税 // tax_refund 预估退税 // clearance_price 报关价 // profit 利润 // official_price 官方指导价 // discount_price 优惠价 // listing_price 二手挂牌价 // reduction_price 二手减价/优惠价 // retention_price 留款/挂账 // car_price 车价 // accessory_price 配件费 // increase_price 加价 // 基础费用 $priceFields = [ 'unit_price' => '收款价', 'total_price' => '总价', 'handling_fee' => '手续费', 'fob_transport_fee' => 'FOB运输费', 'port_misc_fee' => '港杂', 'retrofit_fee' => '改装费', 'ocean_freight' => '海运费', 'commission' => '佣金', 'purchase_tax' => '购置税', 'tax_refund' => '预估退税', 'clearance_price' => '报关价', 'profit' => '利润', 'retention_price' => '挂账', 'car_price' => '车价', 'accessory_price' => '配件费', 'increase_price' => '加价' ]; foreach ($priceFields as $field => $description) { $item->addMoney( $field, $veh[$field]['currency'], (float)$veh[$field]['amount'], $veh[$field]['rate'], $description ); } // 根据里程处理新车或二手车价格 if (!empty($veh['mileage']) && $veh['mileage'] > 0) { // 二手车 $item->addMoney( 'listing_price', $veh['listing_price']['currency'], (float)$veh['listing_price']['amount'], $veh['listing_price']['rate'], '二手挂牌价' ); $item->addMoney( 'reduction_price', $veh['reduction_price']['currency'], (float)$veh['reduction_price']['amount'], $veh['reduction_price']['rate'], '二手优惠价' ); } else { // 新车 $item->addMoney( 'official_price', $veh['official_price']['currency'], (float)$veh['official_price']['amount'], $veh['official_price']['rate'], '官方指导价' ); $item->addMoney( 'discount_price', $veh['discount_price']['currency'], (float)$veh['discount_price']['amount'], $veh['discount_price']['rate'], '优惠价' ); } } /** * 处理改装项 */ private function processModificationItems(int $orderItemId, array $modifyList): void { if (empty($modifyList)) { return; } foreach ($modifyList as $modify) { $modify['order_item_id'] = $orderItemId; StockOrderItemOptions::create($modify); } } /** * 处理账户项 */ private function processAccountItems($order, array $accountList): void { if (empty($accountList)) { return; } foreach ($accountList as $account) { $account['order_id'] = $order->id; if (!empty($account['remit_date'])) { $account['remit_date'] = strtotime($account['remit_date']); } StockOrderAccounts::create($account); } } // ====== ======= ====== ======= ====== 信息处理 ======= ====== ======= ====== ======= // PDF数据 public function formatData($item) { // 提取车辆列表信息 $vehListData = $this->prepareVehicleListData($item); // 提取订单金额信息 $moneyValues = $this->prepareOrderMoneyValues($item); // 提取账户列表信息 $accountList = $this->prepareAccountList($item); // 提取文件附件列表信息 $fileList = $this->prepareFileList($item); // 构建返回数据 $veh = [ // 基本信息 'order_no' => $item->order_no, 'salesperson_snapshot' => $item->salesperson_snapshot, 'sign_img_url' => $this->getSignatureImageUrl($item->salesperson->sign_img ?? null), 'created_at' => date('Y-m-d', strtotime($item->created_at)), 'pi_no' => $item->pi_no, 'biz_date' => date('Y-m-d', $item->biz_date), 'clearance_country_snapshot' => $item->clearance_country_snapshot, 'customer_source_snapshot' => $item->customer_source_snapshot, 'customer_snapshot' => $item->customer_snapshot, 'customer_country_snapshot' => $item->customer_country_snapshot, // 订单项 'veh_list' => array_values($vehListData['list']), 'contract_exchange_rate' => $item->contract_exchange_rate, 'profit_total' => $moneyValues['profit_total'] ?? [], 'cif_total' => $moneyValues['cif_total'] ?? [], // 运输和交付信息 'declarant_name' => $item->declarant_name, 'eta_ship_date' => date('Y-m-d', $item->eta_ship_date), 'shipping_method_snapshot' => $item->shipping_method_snapshot, 'domestic_port_snapshot' => $item->domestic_port_snapshot, 'trade_term_snapshot' => $item->trade_term_snapshot, 'clearance_port_snapshot' => $item->clearance_port_snapshot, 'latest_arrival_date' => date('Y-m-d', $item->latest_arrival_date), 'pick_up_date' => date('Y-m-d', $item->pick_up_date), 'collect_all_date' => date('Y-m-d', $item->collect_all_date), 'is_final' => $item->is_final, // 账户信息 'account_list' => $accountList, 'acc_index' => count($accountList) + 1, 'currency_symbol' => $item->settlement_currency, 'sign_imgs' => $this->queryAppro($item->id), 'contract_url' => $this->getContractUrl($item->contract ?? null), // 文件附件信息 'file_list' => $fileList ]; return $veh; } /** * 准备车辆列表数据 */ private function prepareVehicleListData($item): array { $vehList = []; $index = 0; foreach ($item->items as $v) { // 如果已存在相同车辆,增加数量 if (isset($vehList[$v->unique_id])) { $this->incrementVehicleCount($vehList[$v->unique_id]); // 拼接 remark 值 if (!empty($v->remark)) { if (!empty($vehList[$v->unique_id]['remark'])) { $vehList[$v->unique_id]['remark'] .= "
" . $v->remark; } else { $vehList[$v->unique_id]['remark'] = $v->remark; } } continue; } $index++; // 处理金额信息 $moneyValues = $this->processItemMoneyValues($v); // 构建车辆信息 $vehList[$v->unique_id] = [ 'index' => $index, 'model_snapshot' => $v->model_snapshot, 'color_interior_snapshot' => $v->color_interior_snapshot, 'color_exterior_snapshot' => $v->color_exterior_snapshot, 'num' => 1, 'mileage' => $v->mileage, 'remark' => $v->remark, ] + $moneyValues; } return ['list' => $vehList]; } /** * 处理单项金额值 */ private function processItemMoneyValues($item): array { $moneyValues = []; foreach ($item->moneyValues as $money) { $moneyValues[$money->field] = [ 'currency' => $money->currency, 'amount' => $money->amount, 'rate' => $money->exchange_rate, 'currency_info' => $this->formatCurrency($money->amount, $money->currency) ]; } return $moneyValues; } /** * 获取改装文本 */ private function getModificationText($options): string { $modificationText = ''; foreach ($options as $option) { $modificationText .= $option->option_name_snapshot . ' '; } return trim($modificationText); } /** * 增加车辆数量并更新相关金额显示 */ private function incrementVehicleCount(array &$vehicleData): void { $vehicleData['num'] += 1; $fieldList = [ 'fob_transport_fee', 'car_price', 'ocean_freight', 'commission', 'retention_price', 'port_misc_fee', 'total_price', 'clearance_price', 'profit' ]; foreach ($vehicleData as $field => $value) { if (in_array($field, $fieldList)) { $amount = $vehicleData[$field]['amount'] * $vehicleData['num']; $currencySymbol = SysCurrency::where('currency_code', $vehicleData[$field]['currency'])->value('currency_symbol'); $vehicleData[$field]['currency_info'] = $currencySymbol . number_format($amount, 2, '.', ','); } } } /** * 准备订单金额值 */ private function prepareOrderMoneyValues($item): array { $moneyValues = []; foreach ($item->moneyValues as $money) { $moneyValues[$money->field] = [ 'currency' => $money->currency, 'amount' => $money->amount, 'rate' => $money->exchange_rate, 'currency_info' => $this->formatCurrency($money->amount, $money->currency) ]; } return $moneyValues; } /** * 准备账户列表 */ private function prepareAccountList($item): array { $accountList = []; foreach ($item->accounts as $k => $account) { $accountList[] = [ 'index' => '收款' . ($k + 1), 'remit_country_name_snapshot' => $account->remit_country_name_snapshot, 'remit_date' => date('Y-m-d', $account->remit_date), 'currency_name_snapshot' => $account->currency_name_snapshot, 'account_name_snapshot' => $account->account_name_snapshot, 'remitter_name' => $account->remitter_name, 'amount' => $account->amount, ]; } return $accountList; } /** * 准备文件附件列表 */ private function prepareFileList($item): array { $fileList = []; // 按file_code分组文件 $groupedFiles = []; foreach ($item->files as $file) { if (!isset($groupedFiles[$file->file_code])) { $groupedFiles[$file->file_code] = []; } $groupedFiles[$file->file_code][] = [ 'id' => $file->id, 'file_url' => $file->file_url, 'file_full_url' => $this->getFileUrl($file->file_url), 'original_name' => $file->original_name, ]; } // 定义支持的文件类型 $fileTypes = [ 'contract' => StockOrdersFiles::CONTRACT, 'transaction_slip' => StockOrdersFiles::TRANSACTION_SLIP, 'pi_doc' => StockOrdersFiles::PI_DOC ]; // 按前端需要的字段组织数据 foreach ($fileTypes as $field => $fileCode) { if (isset($groupedFiles[$fileCode])) { $fileList[$field] = $groupedFiles[$fileCode]; } else { $fileList[$field] = []; } } return $fileList; } /** * 获取货币信息 */ private function getCurrencyInfo(string $currencyCode): array { return SysCurrency::where('currency_code', $currencyCode) ->first(['currency_symbol', 'currency_name']) ->toArray(); } /** * 格式化货币显示 */ private function formatCurrency(float $amount, string $currencyCode): string { $currencySymbol = SysCurrency::where('currency_code', $currencyCode)->value('currency_symbol'); return $currencySymbol . number_format($amount, 2, '.', ','); } /** * 获取签名图片URL */ private function getSignatureImageUrl(?string $signImg): string { if (empty($signImg)) { return ''; } return (new \app\common\service\OssService)->generatePrivateUrl($signImg); } /** * 获取合同URL */ private function getContractUrl(?string $contract): string { if (empty($contract)) { return ''; } return (new \app\common\service\OssService)->generatePrivateUrl($contract); } /** * 获取文件URL */ private function getFileUrl(?string $fileUrl): string { if (empty($fileUrl)) { return ''; } 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 ]; } }