| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- <?php
- require_once __DIR__ . '/../lib/identity.php';
- require_once __DIR__ . '/../lib/jobs.php';
- [$actor, $vendor_id] = resolve_request_actor();
- if ($actor === 'ICG') {
- http_response_code(403);
- echo 'Partial ship is a vendor action';
- return;
- }
- $pdo = db();
- $job_id = (int) ($_POST['job_id'] ?? 0);
- $partial = (int) ($_POST['partial_qty'] ?? 0);
- if ($job_id <= 0 || $partial <= 0) {
- http_response_code(400);
- echo 'Bad parameters';
- return;
- }
- $stmt = $pdo->prepare('SELECT * FROM jobs WHERE id = ?');
- $stmt->execute([$job_id]);
- $job = $stmt->fetch();
- if (!$job) {
- http_response_code(404);
- echo 'Job not found';
- return;
- }
- if ((int) $job['vendor_id'] !== $vendor_id) {
- http_response_code(403);
- echo 'Wrong vendor';
- return;
- }
- if (!in_array($job['status'], ['', 'Finished'], true)) {
- http_response_code(400);
- echo 'Can only partial-ship from open or finished status';
- return;
- }
- $current_qty = (int) $job['qty'];
- if ($partial >= $current_qty) {
- http_response_code(400);
- echo 'Partial quantity must be less than current quantity (' . $current_qty . ')';
- return;
- }
- // BEGIN IMMEDIATE + retry mirrors the apply_job_change pattern.
- $attempts = 0;
- while (true) {
- $attempts++;
- try {
- $pdo->exec('BEGIN IMMEDIATE');
- break;
- } catch (PDOException $e) {
- if ($attempts >= 50 || !is_busy_error($e)) throw $e;
- usleep(100000);
- }
- }
- try {
- $remaining = $current_qty - $partial;
- // The shipped portion as its own row.
- $ins = $pdo->prepare(
- "INSERT INTO jobs (vendor_id, job, material, description, qty, due_date, ack, status)
- VALUES (?, ?, ?, ?, ?, ?, '', 'Shipped')"
- );
- $ins->execute([
- $job['vendor_id'], $job['job'], $job['material'], $job['description'],
- $partial, $job['due_date']
- ]);
- $new_id = (int) $pdo->lastInsertId();
- // Deduct from the original; keep its current status.
- $upd = $pdo->prepare(
- "UPDATE jobs SET qty = ?, updated_at = datetime('now') WHERE id = ?"
- );
- $upd->execute([$remaining, $job_id]);
- // Audit trail: new row's status, and the qty deduction on the original.
- $hist = $pdo->prepare(
- 'INSERT INTO job_history (job_id, field, old_value, new_value, actor)
- VALUES (?, ?, ?, ?, ?)'
- );
- $hist->execute([$new_id, 'status', '', 'Shipped', $actor]);
- $hist->execute([$job_id, 'qty', (string) $current_qty, (string) $remaining, $actor]);
- $pdo->exec('COMMIT');
- echo 'Success';
- } catch (Throwable $e) {
- $pdo->exec('ROLLBACK');
- throw $e;
- }
|