リクエスト詳細
🐛 バグ報告
対応完了
対象アプリ: WorkOrder Pro
actual_hours が NULL のとき h((string)null) で空文字になり実績h欄が空白のまま送信されると 0.00 で上書きされる
## 1. 不具合の内容
view.php の工程フォームで `actual_hours` 入力欄に値を設定する際、`$step['actual_hours']` が NULL の場合
```php
value="<?= h((string)$step['actual_hours']) ?>"
```
は空文字になるため、フォーム上では空欄として表示される。これ自体は正しい。
しかし `action=complete` 処理では
```php
$stmt->execute(['completed', $actual_hours, $good_qty, $ng_qty, $memo, $step_id]);
```
の SQL が
```sql
actual_hours = COALESCE(?, actual_hours)
```
となっており、ユーザーが実績hを空欄のまま「完了」を押した場合は `$actual_hours = null` が渡されるため `COALESCE(NULL, actual_hours)` = 既存値が保持される。ここは問題ない。
一方、`action=actual`(実績入力)処理では
```php
$stmt = app_db()->prepare('UPDATE work_order_steps SET actual_hours = ?, good_qty = ?, ng_qty = ?, comment = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?');
$stmt->execute([$actual_hours, $good_qty, $ng_qty, $memo, $step_id]);
```
`COALESCE` が使われていないため、ユーザーが実績hを空欄のまま「実績保存」ボタンを押すと `$actual_hours = null` が直接セットされ、**既存の actual_hours 値が NULL で上書きされる**。
さらに good_qty / ng_qty は `max(0, (int)(...))` で処理されるため、空欄送信時は必ず 0 になる。実績入力フォームで良品数・不良数を空欄のまま送信すると、入力済みの値が 0 に戻ってしまう。
## 2. 根拠・発生しそうな条件
- `view.php` 内 `action=actual` の UPDATE 文(`pages/view.php` の `elseif ($action === 'actual')` ブロック)に `COALESCE` がない
- `good_qty = max(0, (int)($_POST['good_qty'] ?? 0))` は空文字入力時に 0 になる
- 担当者が「コメントだけ更新したい」ときに実績hや良品数を空欄のまま送信すると既存実績が消える
## 3. 期待動作
- `action=actual` で実績hが空欄の場合は既存値を保持する(NULL で上書きしない)
- 良品数・不良数が未入力(空文字)の場合も既存値を保持する
## 4. 修正方針
`pages/view.php` の `action=actual` ブロックを以下のように修正する。
```php
// 修正前
$stmt = app_db()->prepare('UPDATE work_order_steps SET actual_hours = ?, good_qty = ?, ng_qty = ?, comment = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?');
$stmt->execute([$actual_hours, $good_qty, $ng_qty, $memo, $step_id]);
// 修正後
$actual_hours_value = $_POST['actual_hours'] ?? '';
$actual_hours = ($actual_hours_value === '') ? null : (float)$actual_hours_value;
$good_qty_raw = $_POST['good_qty'] ?? '';
$ng_qty_raw = $_POST['ng_qty'] ?? '';
$stmt = app_db()->prepare(
'UPDATE work_order_steps SET '
. 'actual_hours = CASE WHEN ? IS NULL THEN actual_hours ELSE ? END, '
. 'good_qty = CASE WHEN ? = -1 THEN good_qty ELSE ? END, '
. 'ng_qty = CASE WHEN ? = -1 THEN ng_qty ELSE ? END, '
. 'comment = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?'
);
// good_qty/ng_qty が空文字なら -1 をセンチネルとして渡し既存値保持
$good_qty_send = ($good_qty_raw === '') ? -1 : max(0, (int)$good_qty_raw);
$ng_qty_send = ($ng_qty_raw === '') ? -1 : max(0, (int)$ng_qty_raw);
$stmt->execute([
$actual_hours, $actual_hours,
$good_qty_send, $good_qty_send,
$ng_qty_send, $ng_qty_send,
$memo, $step_id
]);
```
またはよりシンプルに、フォームの `actual_hours` / `good_qty` / `ng_qty` 欄を空送信した場合は UPDATE 対象カラムから除外するロジックに切り替えても良い(動的SQL組み立て方式)。どちらでも既存機能を壊さずに修正できる。
view.php の工程フォームで `actual_hours` 入力欄に値を設定する際、`$step['actual_hours']` が NULL の場合
```php
value="<?= h((string)$step['actual_hours']) ?>"
```
は空文字になるため、フォーム上では空欄として表示される。これ自体は正しい。
しかし `action=complete` 処理では
```php
$stmt->execute(['completed', $actual_hours, $good_qty, $ng_qty, $memo, $step_id]);
```
の SQL が
```sql
actual_hours = COALESCE(?, actual_hours)
```
となっており、ユーザーが実績hを空欄のまま「完了」を押した場合は `$actual_hours = null` が渡されるため `COALESCE(NULL, actual_hours)` = 既存値が保持される。ここは問題ない。
一方、`action=actual`(実績入力)処理では
```php
$stmt = app_db()->prepare('UPDATE work_order_steps SET actual_hours = ?, good_qty = ?, ng_qty = ?, comment = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?');
$stmt->execute([$actual_hours, $good_qty, $ng_qty, $memo, $step_id]);
```
`COALESCE` が使われていないため、ユーザーが実績hを空欄のまま「実績保存」ボタンを押すと `$actual_hours = null` が直接セットされ、**既存の actual_hours 値が NULL で上書きされる**。
さらに good_qty / ng_qty は `max(0, (int)(...))` で処理されるため、空欄送信時は必ず 0 になる。実績入力フォームで良品数・不良数を空欄のまま送信すると、入力済みの値が 0 に戻ってしまう。
## 2. 根拠・発生しそうな条件
- `view.php` 内 `action=actual` の UPDATE 文(`pages/view.php` の `elseif ($action === 'actual')` ブロック)に `COALESCE` がない
- `good_qty = max(0, (int)($_POST['good_qty'] ?? 0))` は空文字入力時に 0 になる
- 担当者が「コメントだけ更新したい」ときに実績hや良品数を空欄のまま送信すると既存実績が消える
## 3. 期待動作
- `action=actual` で実績hが空欄の場合は既存値を保持する(NULL で上書きしない)
- 良品数・不良数が未入力(空文字)の場合も既存値を保持する
## 4. 修正方針
`pages/view.php` の `action=actual` ブロックを以下のように修正する。
```php
// 修正前
$stmt = app_db()->prepare('UPDATE work_order_steps SET actual_hours = ?, good_qty = ?, ng_qty = ?, comment = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?');
$stmt->execute([$actual_hours, $good_qty, $ng_qty, $memo, $step_id]);
// 修正後
$actual_hours_value = $_POST['actual_hours'] ?? '';
$actual_hours = ($actual_hours_value === '') ? null : (float)$actual_hours_value;
$good_qty_raw = $_POST['good_qty'] ?? '';
$ng_qty_raw = $_POST['ng_qty'] ?? '';
$stmt = app_db()->prepare(
'UPDATE work_order_steps SET '
. 'actual_hours = CASE WHEN ? IS NULL THEN actual_hours ELSE ? END, '
. 'good_qty = CASE WHEN ? = -1 THEN good_qty ELSE ? END, '
. 'ng_qty = CASE WHEN ? = -1 THEN ng_qty ELSE ? END, '
. 'comment = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?'
);
// good_qty/ng_qty が空文字なら -1 をセンチネルとして渡し既存値保持
$good_qty_send = ($good_qty_raw === '') ? -1 : max(0, (int)$good_qty_raw);
$ng_qty_send = ($ng_qty_raw === '') ? -1 : max(0, (int)$ng_qty_raw);
$stmt->execute([
$actual_hours, $actual_hours,
$good_qty_send, $good_qty_send,
$ng_qty_send, $ng_qty_send,
$memo, $step_id
]);
```
またはよりシンプルに、フォームの `actual_hours` / `good_qty` / `ng_qty` 欄を空送信した場合は UPDATE 対象カラムから除外するロジックに切り替えても良い(動的SQL組み立て方式)。どちらでも既存機能を壊さずに修正できる。
💬 返信 (3)
🛠 開発を開始しました (バグ修正 (workorder-pro))
ご要望ありがとうございます。AI 開発ワーカーが実装を開始します。
通常 5〜30 分で Pull Request を作成し、レビュー後にリリースされます。
ご要望ありがとうございます。AI 開発ワーカーが実装を開始します。
通常 5〜30 分で Pull Request を作成し、レビュー後にリリースされます。
📝 開発が完了しました
ご要望いただいた内容の実装が完了し、最終チェック段階に入りました。
レビュー (自動) → リリース、の流れで進みます。
もう少々お待ちください。
ご要望いただいた内容の実装が完了し、最終チェック段階に入りました。
レビュー (自動) → リリース、の流れで進みます。
もう少々お待ちください。
✅ リリース完了のお知らせ
ご要望いただいた「WorkOrder Pro」を実装し、リリースいたしました。
【ご利用方法】
ダッシュボード: https://www.aiapps.jp/?action=dashboard
アプリ詳細: https://www.aiapps.jp/apps/show.php?slug=workorder-pro
デモ環境は 1 時間以内に自動構築されます:
https://www.aiapps.jp/demo/workorder-pro/
ご利用ありがとうございます!
ご要望いただいた「WorkOrder Pro」を実装し、リリースいたしました。
【ご利用方法】
ダッシュボード: https://www.aiapps.jp/?action=dashboard
アプリ詳細: https://www.aiapps.jp/apps/show.php?slug=workorder-pro
デモ環境は 1 時間以内に自動構築されます:
https://www.aiapps.jp/demo/workorder-pro/
ご利用ありがとうございます!
Echo
Iris