jobs_update.php 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. <?php
  2. require_once __DIR__ . '/../lib/identity.php';
  3. require_once __DIR__ . '/../lib/jobs.php';
  4. [$actor, $vendor_id] = resolve_request_actor();
  5. $pdo = db();
  6. $job_id = (int) ($_POST['job_id'] ?? 0);
  7. $action = $_POST['action'] ?? '';
  8. $column = $_POST['column'] ?? '';
  9. $value = $_POST['value'] ?? '';
  10. if ($job_id <= 0) {
  11. http_response_code(400);
  12. echo 'Bad job_id';
  13. return;
  14. }
  15. $stmt = $pdo->prepare('SELECT * FROM jobs WHERE id = ?');
  16. $stmt->execute([$job_id]);
  17. $job = $stmt->fetch();
  18. if (!$job) {
  19. http_response_code(404);
  20. echo 'Job not found';
  21. return;
  22. }
  23. // Vendor-side requests are scoped to their own jobs.
  24. if ($actor !== 'ICG' && (int) $job['vendor_id'] !== $vendor_id) {
  25. http_response_code(403);
  26. echo 'Wrong vendor';
  27. return;
  28. }
  29. // --- Button-driven state transitions ---
  30. // Undo is dynamic: it reverses one step based on current status. Vendors only.
  31. // Once ICG marks Received, undo is no longer available (vendor would need to
  32. // message ICG to get them to back it out).
  33. if ($action === 'undo') {
  34. if ($actor === 'ICG') {
  35. http_response_code(403);
  36. echo 'Undo is a vendor action';
  37. return;
  38. }
  39. if ($job['status'] === 'Finished') {
  40. apply_job_change($job, 'status', '', $actor);
  41. } elseif ($job['status'] === 'Shipped') {
  42. apply_job_change($job, 'status', 'Finished', $actor);
  43. } else {
  44. http_response_code(400);
  45. echo 'Nothing to undo from current status';
  46. return;
  47. }
  48. echo 'Success';
  49. return;
  50. }
  51. if ($action !== '') {
  52. $allowed = [
  53. 'acknowledge' => ['ack', '', ['vendor']],
  54. 'mark_finished' => ['status', 'Finished', ['vendor']],
  55. 'mark_shipped' => ['status', 'Shipped', ['vendor']],
  56. 'mark_received' => ['status', 'Received', ['ICG']],
  57. ];
  58. if (!isset($allowed[$action])) {
  59. http_response_code(400);
  60. echo 'Unknown action';
  61. return;
  62. }
  63. [$col, $new, $roles] = $allowed[$action];
  64. $role = $actor === 'ICG' ? 'ICG' : 'vendor';
  65. if (!in_array($role, $roles, true)) {
  66. http_response_code(403);
  67. echo 'Action not allowed for this role';
  68. return;
  69. }
  70. apply_job_change($job, $col, $new, $actor);
  71. echo 'Success';
  72. return;
  73. }
  74. // --- Field edits (ICG only) ---
  75. if ($actor !== 'ICG') {
  76. http_response_code(403);
  77. echo 'Edits restricted to ICG';
  78. return;
  79. }
  80. $editable = ['job', 'material', 'description', 'qty', 'due_date'];
  81. if (!in_array($column, $editable, true)) {
  82. http_response_code(400);
  83. echo 'Unknown column';
  84. return;
  85. }
  86. $value = trim($value);
  87. if ($column === 'qty') {
  88. if ($value === '' || !is_numeric($value)) {
  89. http_response_code(400);
  90. echo 'Qty must be a number';
  91. return;
  92. }
  93. $value = (string) (int) $value;
  94. } elseif ($column === 'due_date') {
  95. $value = parse_due_date($value);
  96. }
  97. apply_job_change($job, $column, $value, $actor);
  98. // An ICG edit to a content field bumps an already-acknowledged row back to
  99. // 'changed' so the vendor sees it at the top of their list. We leave 'new'
  100. // alone — the row still needs acknowledgement, just for a different reason.
  101. if ($job['ack'] === '') {
  102. apply_job_change($job, 'ack', 'changed', $actor);
  103. }
  104. echo 'Success';