softDelete features
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../classes_ac/PostingWindowGuard.php';
|
||||
|
||||
/**
|
||||
* PurchaseOrderManager
|
||||
@@ -851,4 +852,123 @@ class PurchaseOrderManager {
|
||||
)->execute([':id' => $source_id, ':cid' => $this->company_id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Soft-delete a purchase order by negating company_id on the header, items, and all
|
||||
* linked draft stock-in rows. Blocked if any purchase invoice, supplier return, or
|
||||
* approved (received) stock-in rows exist.
|
||||
*/
|
||||
public function softDelete(int $po_id): void
|
||||
{
|
||||
$sth = $this->pdo->prepare(
|
||||
"SELECT * FROM td_purchase_order WHERE company_id = :cid AND id = :id"
|
||||
);
|
||||
$sth->execute([':cid' => $this->company_id, ':id' => $po_id]);
|
||||
$po = $sth->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$po) throw new Exception('Purchase order not found.');
|
||||
|
||||
global $pdo1;
|
||||
if (isset($pdo1) && $pdo1 instanceof PDO) {
|
||||
$guard = new PostingWindowGuard($pdo1, $this->company_id);
|
||||
$guard->assertOpenDate($po['po_date'] ?: date('Y-m-d'), 'Purchase order deletion');
|
||||
}
|
||||
|
||||
$sth2 = $this->pdo->prepare(
|
||||
"SELECT COUNT(*) FROM td_invoice
|
||||
WHERE company_id = :cid AND source = 'po' AND source_id = :id AND doc_type = 'purchase_invoice'"
|
||||
);
|
||||
$sth2->execute([':cid' => $this->company_id, ':id' => $po_id]);
|
||||
if ((int)$sth2->fetchColumn() > 0) {
|
||||
throw new Exception('Cannot delete — this PO has linked purchase invoices. Delete the invoices first.');
|
||||
}
|
||||
|
||||
$sth3 = $this->pdo->prepare(
|
||||
"SELECT COUNT(*) FROM td_supplier_return
|
||||
WHERE company_id = :cid AND po_id = :id AND status != -1"
|
||||
);
|
||||
$sth3->execute([':cid' => $this->company_id, ':id' => $po_id]);
|
||||
if ((int)$sth3->fetchColumn() > 0) {
|
||||
throw new Exception('Cannot delete — this PO has linked supplier returns. Delete or cancel the returns first.');
|
||||
}
|
||||
|
||||
$sth4 = $this->pdo->prepare(
|
||||
"SELECT table_name FROM information_schema.tables
|
||||
WHERE table_schema = DATABASE() AND table_name LIKE 'td_stock_%'"
|
||||
);
|
||||
$sth4->execute();
|
||||
$tables = $sth4->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
foreach ($tables as $table) {
|
||||
$sth5 = $this->pdo->prepare(
|
||||
"SELECT COUNT(*) FROM `{$table}`
|
||||
WHERE company_id = :cid AND source = 'po' AND source_id = :id AND status = 1"
|
||||
);
|
||||
$sth5->execute([':cid' => $this->company_id, ':id' => $po_id]);
|
||||
if ((int)$sth5->fetchColumn() > 0) {
|
||||
throw new Exception('Cannot delete — received stock from this PO must be reversed via ICS first.');
|
||||
}
|
||||
}
|
||||
|
||||
// Release racks from draft stock-in rows and negate them
|
||||
$whMgmt = new WarehouseManager($this->pdo, $this->company_id);
|
||||
foreach ($tables as $table) {
|
||||
if (!preg_match('/^td_stock_(\d+)$/', (string)$table, $matches)) continue;
|
||||
$warehouse_id = (int)$matches[1];
|
||||
|
||||
$row_sth = $this->pdo->prepare(
|
||||
"SELECT id, zone, aisle, rack FROM `{$table}`
|
||||
WHERE company_id = :cid AND source = 'po' AND source_id = :id AND status = 0"
|
||||
);
|
||||
$row_sth->execute([':cid' => $this->company_id, ':id' => $po_id]);
|
||||
$draft_rows = $row_sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($draft_rows as $row) {
|
||||
$whMgmt->releaseRack($warehouse_id, $row['zone'], $row['aisle'], $row['rack']);
|
||||
}
|
||||
|
||||
$this->pdo->prepare(
|
||||
"UPDATE `{$table}` SET company_id = company_id * -1
|
||||
WHERE company_id = :cid AND source = 'po' AND source_id = :id"
|
||||
)->execute([':cid' => $this->company_id, ':id' => $po_id]);
|
||||
}
|
||||
|
||||
// Release converted_qty on source purchase request
|
||||
$source = (string)($po['source'] ?? '');
|
||||
$source_id = (int)($po['source_id'] ?? 0);
|
||||
if ($source === 'purchase_request' && $source_id > 0) {
|
||||
$sth6 = $this->pdo->prepare(
|
||||
"SELECT item_id, quantity FROM td_purchase_order_item
|
||||
WHERE order_id = :id AND company_id = :cid ORDER BY item_id"
|
||||
);
|
||||
$sth6->execute([':id' => $po_id, ':cid' => $this->company_id]);
|
||||
$po_items = $sth6->fetchAll(PDO::FETCH_ASSOC);
|
||||
$dec = $this->pdo->prepare(
|
||||
"UPDATE td_purchase_request_item
|
||||
SET converted_qty = GREATEST(0, converted_qty - :qty)
|
||||
WHERE request_id = :rid AND item_id = :item_id AND company_id = :cid"
|
||||
);
|
||||
foreach ($po_items as $item) {
|
||||
$dec->execute([
|
||||
':qty' => (float)($item['quantity'] ?? 0),
|
||||
':rid' => $source_id,
|
||||
':item_id' => (int)($item['item_id'] ?? 0),
|
||||
':cid' => $this->company_id,
|
||||
]);
|
||||
}
|
||||
$this->pdo->prepare(
|
||||
"UPDATE td_purchase_request SET status = 2
|
||||
WHERE id = :id AND company_id = :cid AND status = 5"
|
||||
)->execute([':id' => $source_id, ':cid' => $this->company_id]);
|
||||
}
|
||||
|
||||
$this->pdo->prepare(
|
||||
"UPDATE td_purchase_order_item SET company_id = company_id * -1
|
||||
WHERE order_id = :id AND company_id = :cid"
|
||||
)->execute([':id' => $po_id, ':cid' => $this->company_id]);
|
||||
|
||||
$this->pdo->prepare(
|
||||
"UPDATE td_purchase_order SET company_id = company_id * -1
|
||||
WHERE id = :id AND company_id = :cid"
|
||||
)->execute([':id' => $po_id, ':cid' => $this->company_id]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user