m0_70156489 1 vecka sedan
förälder
incheckning
2bbc90ed48

+ 110 - 22
application/admin/controller/Procuremen.php

@@ -746,6 +746,19 @@ class Procuremen extends Backend
             ->whereRaw('(status_name IS NULL OR TRIM(status_name) = \'\' OR status_name <> \'' . ProcuremenStatus::POD_VOID . '\')');
             ->whereRaw('(status_name IS NULL OR TRIM(status_name) = \'\' OR status_name <> \'' . ProcuremenStatus::POD_VOID . '\')');
     }
     }
 
 
+    /**
+     * @param array<string, mixed> $detailRow
+     */
+    protected function isActivePurchaseOrderDetailRow(array $detailRow): bool
+    {
+        if (ProcuremenStatus::isPodVoid($detailRow['status'] ?? '')) {
+            return false;
+        }
+        $statusName = trim((string)($detailRow['status_name'] ?? ''));
+
+        return $statusName === '' || $statusName !== ProcuremenStatus::POD_VOID;
+    }
+
     /**
     /**
      * 废弃退回初选:下发明细标记归档,不物理删除
      * 废弃退回初选:下发明细标记归档,不物理删除
      *
      *
@@ -1278,7 +1291,7 @@ class Procuremen extends Backend
                         ProcuremenStatus::wflowPendingApprovalValues()
                         ProcuremenStatus::wflowPendingApprovalValues()
                     ))
                     ))
                         ->whereOr(function ($q1) {
                         ->whereOr(function ($q1) {
-                            $q1->whereIn('status', ProcuremenStatus::poCompletedValues());
+                            $q1->whereRaw(ProcuremenStatus::sqlPoCompleted('status'));
                         })
                         })
                         ->whereOr(function ($q2) {
                         ->whereOr(function ($q2) {
                             $q2->whereNotNull('pick_time')
                             $q2->whereNotNull('pick_time')
@@ -1494,6 +1507,69 @@ class Procuremen extends Backend
         ];
         ];
     }
     }
 
 
+    /**
+     * 初选行对应的 purchase_order 与是否应从初选列表隐藏
+     *
+     * @return array{po:?array<string,mixed>, hidden:bool}
+     */
+    protected function resolvePickRowPoContext(int $sid): array
+    {
+        $po = null;
+        try {
+            $found = Db::table('purchase_order')->where('scydgy_id', $sid)->find();
+            if (is_array($found)) {
+                $po = $found;
+            }
+        } catch (\Throwable $e) {
+        }
+        $hideSet = $this->loadPickHiddenScydgySet();
+
+        return ['po' => $po, 'hidden' => isset($hideSet[$sid])];
+    }
+
+    /**
+     * 初选删除前校验(已删除幂等跳过;已下发/已完结禁止)
+     */
+    protected function assertPickRowCanDelete(int $sid, array $row): void
+    {
+        $ctx = $this->resolvePickRowPoContext($sid);
+        $po = $ctx['po'];
+        if (is_array($po) && $this->isPurchaseOrderSoftDeleted($po['mod_rq'] ?? null)) {
+            return;
+        }
+        if (is_array($po)) {
+            if (ProcuremenStatus::isPoCompleted($po['status'] ?? '')) {
+                throw new \InvalidArgumentException('该工序已完结,无法删除');
+            }
+            if (ProcuremenStatus::wflowAtLeastConfirm($po['wflow_status'] ?? '')) {
+                throw new \InvalidArgumentException('该工序已下发或进入后续流程,无法删除');
+            }
+        }
+        if ($ctx['hidden']) {
+            $ccydh = trim((string)($row['CCYDH'] ?? ''));
+            $label = $ccydh !== '' ? $ccydh : ('工序' . $sid);
+            throw new \InvalidArgumentException('订单号「' . $label . '」已下发或已进入后续流程,无法删除');
+        }
+    }
+
+    /**
+     * 初选直接完结前校验
+     */
+    protected function assertPickRowCanComplete(int $sid, array $row): void
+    {
+        $ctx = $this->resolvePickRowPoContext($sid);
+        $po = $ctx['po'];
+        if (is_array($po) && ProcuremenStatus::isPoCompleted($po['status'] ?? '')) {
+            throw new \Exception($this->formatProcuremenRowLabel($row) . '已完结,无需重复操作');
+        }
+        if (is_array($po) && $this->isPurchaseOrderSoftDeleted($po['mod_rq'] ?? null)) {
+            throw new \Exception($this->formatProcuremenRowLabel($row) . '已删除,无法完结');
+        }
+        if ($ctx['hidden'] || (is_array($po) && ProcuremenStatus::wflowAtLeastConfirm($po['wflow_status'] ?? ''))) {
+            throw new \Exception($this->formatProcuremenRowLabel($row) . '已下发或进入后续流程,不能直接完结');
+        }
+    }
+
     /**
     /**
      * 协助初选列表软删除(mod_rq 记删除时间;ERP 行无记录则插入 purchase_order)
      * 协助初选列表软删除(mod_rq 记删除时间;ERP 行无记录则插入 purchase_order)
      */
      */
@@ -1503,25 +1579,13 @@ class Procuremen extends Backend
         if (!$this->isValidScydgyRowId($sid)) {
         if (!$this->isValidScydgyRowId($sid)) {
             throw new \InvalidArgumentException('无效的行主键');
             throw new \InvalidArgumentException('无效的行主键');
         }
         }
-        $hideSet = $this->loadPickHiddenScydgySet();
-        if ($sid > 0 && isset($hideSet[$sid])) {
-            throw new \InvalidArgumentException('订单号「' . trim((string)($row['CCYDH'] ?? '')) . '」已下发或已进入后续流程,无法删除');
+        $this->assertPickRowCanDelete($sid, $row);
+        $po = $this->resolvePickRowPoContext($sid)['po'];
+        if (is_array($po) && $this->isPurchaseOrderSoftDeleted($po['mod_rq'] ?? null)) {
+            return;
         }
         }
-        if ($sid < 0) {
-            try {
-                $po = Db::table('purchase_order')->where('scydgy_id', $sid)->find();
-                if (is_array($po)) {
-                    if (ProcuremenStatus::wflowAtLeastConfirm($po['wflow_status'] ?? '')) {
-                        throw new \InvalidArgumentException('手工新增工序已下发,无法删除');
-                    }
-                    if ($this->isPurchaseOrderSoftDeleted($po['mod_rq'] ?? null)) {
-                        return;
-                    }
-                }
-            } catch (\InvalidArgumentException $e) {
-                throw $e;
-            } catch (\Throwable $e) {
-            }
+        if ($sid < 0 && is_array($po) && ProcuremenStatus::wflowAtLeastConfirm($po['wflow_status'] ?? '')) {
+            throw new \InvalidArgumentException('手工新增工序已下发,无法删除');
         }
         }
 
 
         $now = date('Y-m-d H:i:s');
         $now = date('Y-m-d H:i:s');
@@ -2003,7 +2067,7 @@ class Procuremen extends Backend
         }
         }
         $byCompany = [];
         $byCompany = [];
         foreach ($details as $d) {
         foreach ($details as $d) {
-            if (!is_array($d)) {
+            if (!is_array($d) || !$this->isActivePurchaseOrderDetailRow($d)) {
                 continue;
                 continue;
             }
             }
             $cn = trim((string)($d['company_name'] ?? ''));
             $cn = trim((string)($d['company_name'] ?? ''));
@@ -2121,7 +2185,7 @@ class Procuremen extends Backend
     {
     {
         $out = [];
         $out = [];
         foreach ($details as $d) {
         foreach ($details as $d) {
-            if (!is_array($d)) {
+            if (!is_array($d) || !$this->isActivePurchaseOrderDetailRow($d)) {
                 continue;
                 continue;
             }
             }
             $sid = (int)($d['scydgy_id'] ?? 0);
             $sid = (int)($d['scydgy_id'] ?? 0);
@@ -2677,6 +2741,7 @@ class Procuremen extends Backend
         }
         }
         $finishRaw = $this->request->post('finish', '1');
         $finishRaw = $this->request->post('finish', '1');
         $asComplete = ($finishRaw === '1' || $finishRaw === 1 || $finishRaw === true);
         $asComplete = ($finishRaw === '1' || $finishRaw === 1 || $finishRaw === true);
+        $poIdLog = null;
 
 
         try {
         try {
             // 获取工序行 ID,对应 purchase_order.scydgy_id;有则改、无则插
             // 获取工序行 ID,对应 purchase_order.scydgy_id;有则改、无则插
@@ -2685,6 +2750,10 @@ class Procuremen extends Backend
                 throw new \Exception($this->formatProcuremenRowLabel($row) . '数据不完整,请刷新列表后重试');
                 throw new \Exception($this->formatProcuremenRowLabel($row) . '数据不完整,请刷新列表后重试');
             }
             }
 
 
+            if ($asComplete) {
+                $this->assertPickRowCanComplete($ids, $row);
+            }
+
             $exists = Db::table('purchase_order')->where('scydgy_id', $ids)->find();
             $exists = Db::table('purchase_order')->where('scydgy_id', $ids)->find();
 
 
             $data = [
             $data = [
@@ -2737,7 +2806,6 @@ class Procuremen extends Backend
         } catch (\Throwable $e) {
         } catch (\Throwable $e) {
             $this->error($e->getMessage());
             $this->error($e->getMessage());
         }
         }
-        $poIdLog = null;
         try {
         try {
             $rpo = Db::table('purchase_order')->where('scydgy_id', $ids)->find();
             $rpo = Db::table('purchase_order')->where('scydgy_id', $ids)->find();
             if (is_array($rpo)) {
             if (is_array($rpo)) {
@@ -2772,6 +2840,7 @@ class Procuremen extends Backend
                 $poIdLog
                 $poIdLog
             );
             );
         }
         }
+        $this->pickHiddenScydgySetCache = null;
         $this->success("操作成功");
         $this->success("操作成功");
     }
     }
 
 
@@ -2846,6 +2915,9 @@ class Procuremen extends Backend
         if (!$this->request->isPost() || !$this->request->isAjax()) {
         if (!$this->request->isPost() || !$this->request->isAjax()) {
             $this->error(__('Invalid parameters'));
             $this->error(__('Invalid parameters'));
         }
         }
+        if (!$this->hasProcuremenPerm(['purchaseconfirmpick', 'purchaseConfirmPick'])) {
+            $this->error(__('You have no permission'));
+        }
 
 
         $batchRaw = trim((string)$this->request->post('order_picks_json', ''));
         $batchRaw = trim((string)$this->request->post('order_picks_json', ''));
         if ($batchRaw !== '') {
         if ($batchRaw !== '') {
@@ -2889,6 +2961,7 @@ class Procuremen extends Backend
         } catch (\Throwable $e) {
         } catch (\Throwable $e) {
             $this->error($e->getMessage());
             $this->error($e->getMessage());
         }
         }
+        $this->pickHiddenScydgySetCache = null;
         $this->success('操作成功', '', $result);
         $this->success('操作成功', '', $result);
     }
     }
 
 
@@ -2949,6 +3022,7 @@ class Procuremen extends Backend
             $this->error($msg !== '' ? $msg : '提交失败');
             $this->error($msg !== '' ? $msg : '提交失败');
         }
         }
 
 
+        $this->pickHiddenScydgySetCache = null;
         $this->success('操作成功', '', ['batch' => $results]);
         $this->success('操作成功', '', ['batch' => $results]);
     }
     }
 
 
@@ -5679,6 +5753,7 @@ class Procuremen extends Backend
             $this->error($e->getMessage());
             $this->error($e->getMessage());
         }
         }
 
 
+        $this->pickHiddenScydgySetCache = null;
         $this->success('已删除 ' . $done . ' 条工序');
         $this->success('已删除 ' . $done . ' 条工序');
     }
     }
 
 
@@ -6403,6 +6478,9 @@ class Procuremen extends Backend
         if (!$this->request->isPost() || !$this->request->isAjax()) {
         if (!$this->request->isPost() || !$this->request->isAjax()) {
             $this->error(__('Invalid parameters'));
             $this->error(__('Invalid parameters'));
         }
         }
+        if (!$this->hasProcuremenPerm(['purchaseapprovalreject', 'purchaseApprovalReject'])) {
+            $this->error(__('You have no permission'));
+        }
 
 
         $batchRaw = trim((string)$this->request->post('order_picks_json', ''));
         $batchRaw = trim((string)$this->request->post('order_picks_json', ''));
         $decoded = json_decode($batchRaw, true);
         $decoded = json_decode($batchRaw, true);
@@ -6410,6 +6488,7 @@ class Procuremen extends Backend
             $this->error('提交数据无效');
             $this->error('提交数据无效');
         }
         }
 
 
+        $done = 0;
         Db::startTrans();
         Db::startTrans();
         try {
         try {
             foreach ($decoded as $item) {
             foreach ($decoded as $item) {
@@ -6421,6 +6500,10 @@ class Procuremen extends Backend
                     continue;
                     continue;
                 }
                 }
                 $this->runPurchaseApprovalRejectForSid($sid);
                 $this->runPurchaseApprovalRejectForSid($sid);
+                $done++;
+            }
+            if ($done < 1) {
+                throw new \Exception('所选订单均不在待审批状态');
             }
             }
             Db::commit();
             Db::commit();
         } catch (\Throwable $e) {
         } catch (\Throwable $e) {
@@ -6428,6 +6511,7 @@ class Procuremen extends Backend
             $this->error($e->getMessage() !== '' ? $e->getMessage() : '驳回失败');
             $this->error($e->getMessage() !== '' ? $e->getMessage() : '驳回失败');
         }
         }
 
 
+        $this->pickHiddenScydgySetCache = null;
         $this->success('已驳回并退回「协助审批下发」');
         $this->success('已驳回并退回「协助审批下发」');
     }
     }
 
 
@@ -6436,6 +6520,10 @@ class Procuremen extends Backend
      */
      */
     protected function runPurchaseApprovalRejectForSid(int $sid): void
     protected function runPurchaseApprovalRejectForSid(int $sid): void
     {
     {
+        $poRow = ProcuremenGuard::loadPurchaseOrderOrFail($sid, '未找到订单');
+        ProcuremenGuard::assertWflowPendingApproval($poRow, '该订单不在待审批状态,无法驳回');
+        ProcuremenGuard::assertNotCompleted($poRow, '订单已完结,无法驳回');
+
         $allIds = $this->purchaseOrderDetail($sid);
         $allIds = $this->purchaseOrderDetail($sid);
         if ($allIds === []) {
         if ($allIds === []) {
             throw new \Exception('未找到下发明细');
             throw new \Exception('未找到下发明细');

+ 2 - 2
application/common/library/ProcuremenStatus.php

@@ -197,9 +197,9 @@ class ProcuremenStatus
     public static function sqlPodNotVoid(string $column = 'status'): string
     public static function sqlPodNotVoid(string $column = 'status'): string
     {
     {
         $c = self::quoteSqlIdent($column);
         $c = self::quoteSqlIdent($column);
-        $void = self::POD_VOID;
+        $void = str_replace("'", "''", self::POD_VOID);
 
 
-        return "({$c} IS NULL OR TRIM(CAST({$c} AS CHAR)) NOT IN ('{$void}','2') AND CAST({$c} AS UNSIGNED) <> 2)";
+        return "({$c} IS NULL OR TRIM(CAST({$c} AS CHAR)) NOT IN ('{$void}','2'))";
     }
     }
 
 
     protected static function quoteSqlIdent(string $column): string
     protected static function quoteSqlIdent(string $column): string