softDelete features

This commit is contained in:
Thanakorn S
2026-05-22 14:07:22 +07:00
parent f04554793e
commit 2410f7bade
59 changed files with 1783 additions and 16 deletions
+34
View File
@@ -0,0 +1,34 @@
<?php
session_start();
require '../../../assets/utils/db_auth.php';
require_role($user_role, ['owner', 'admin']);
require '../../../assets/utils/classes/PurchaseOrderManager.php';
require '../../../assets/utils/classes/WarehouseManager.php';
$id = (int)($data['id'] ?? 0);
if (!$id) {
$answer['message'] = 'Invalid PO ID.';
http_response_code(400);
exit(json_encode($answer));
}
try {
dbTransaction($pdo2, function($pdo) use ($id, $company_id) {
$mgr = new PurchaseOrderManager($pdo, $company_id);
$mgr->softDelete($id);
});
$answer['success'] = 1;
$answer['message'] = 'Purchase order deleted.';
} catch (PDOException $e) {
$answer['message'] = 'Database error, please try again.';
http_response_code(500);
} catch (Exception $e) {
$answer['message'] = $e->getMessage();
http_response_code(400);
}
exit(json_encode($answer));
@@ -0,0 +1,33 @@
<?php
session_start();
require '../../../assets/utils/db_auth.php';
require_role($user_role, ['owner', 'admin']);
require '../../../assets/utils/classes/PurchaseRequestManager.php';
$id = (int)($data['id'] ?? 0);
if (!$id) {
$answer['message'] = 'Invalid purchase request ID.';
http_response_code(400);
exit(json_encode($answer));
}
try {
dbTransaction($pdo2, function($pdo) use ($id, $company_id) {
$mgr = new PurchaseRequestManager($pdo, $company_id);
$mgr->softDelete($id);
});
$answer['success'] = 1;
$answer['message'] = 'Purchase request deleted.';
} catch (PDOException $e) {
$answer['message'] = 'Database error, please try again.';
http_response_code(500);
} catch (Exception $e) {
$answer['message'] = $e->getMessage();
http_response_code(400);
}
exit(json_encode($answer));
@@ -0,0 +1,34 @@
<?php
session_start();
require '../../../assets/utils/db_auth.php';
require_role($user_role, ['owner', 'admin']);
require '../../../assets/utils/classes/SupplierReturnManager.php';
require '../../../assets/utils/classes/WarehouseManager.php';
$id = (int)($data['id'] ?? 0);
if (!$id) {
$answer['message'] = 'Invalid supplier return ID.';
http_response_code(400);
exit(json_encode($answer));
}
try {
dbTransaction($pdo2, function($pdo) use ($id, $company_id) {
$mgr = new SupplierReturnManager($pdo, $company_id);
$mgr->softDelete($id);
});
$answer['success'] = 1;
$answer['message'] = 'Supplier return deleted.';
} catch (PDOException $e) {
$answer['message'] = 'Database error, please try again.';
http_response_code(500);
} catch (Exception $e) {
$answer['message'] = $e->getMessage();
http_response_code(400);
}
exit(json_encode($answer));
+22
View File
@@ -156,6 +156,9 @@
<?php require '../include_ending.php'; ?>
<script>
const can_delete = ['admin', 'owner'].includes(user_role);
function doc_type_badge(doc_type) {
const map = {
'purchase_invoice': '<span class="badge bg-primary">Purchase Invoice</span>',
@@ -257,6 +260,7 @@
<a href="<?php echo $server_url?>po/manage_purchase_invoice.php?id=${inv.id}" title="View">
<i class="ti ti-eye fs-5"></i>
</a>
${can_delete ? `<a href="javascript:void(0);" class="link-danger ms-2" title="Delete" onclick="delete_invoice(${inv.id})"><i class="ti ti-trash fs-5"></i></a>` : ''}
</td>
</tr>`;
});
@@ -264,6 +268,24 @@
$('table#invoice_list tbody').html(body);
}
function delete_invoice(id) {
bootbox.confirm({
message: 'Delete this document? Any GL entry will be removed.',
buttons: { confirm: { label: 'Delete', className: 'btn-danger' }, cancel: { label: 'Back', className: 'btn-secondary' } },
callback: function(result) {
if (!result) return;
ajax_request({
url: '<?php echo $server_url?>order/api/engine/delete_invoice.php',
autoPrepare: false,
checkRequired: 0,
action: 'delete',
data: { id: id },
onSuccess: function() { retrieve_invoices(); }
});
}
});
}
$(async function() {
await load_dept_cache();
populate_dept_filter('filter_dept');
+26
View File
@@ -226,6 +226,10 @@
<i class="ti ti-x me-1"></i>Cancel PO
</button>
<button class="btn btn-outline-danger w-100 d-none" id="btn_delete" onclick="delete_po()">
<i class="ti ti-trash me-1"></i>Delete PO
</button>
</div>
</div>
@@ -240,6 +244,8 @@
<script>
// custom.js globals: remove_item(), load_location_config(), init_product_search_inputs(), init_lot_search_inputs(), escape_html(), format_number()
const can_delete = ['admin', 'owner'].includes(user_role);
var po_id = <?php echo $po_id; ?>;
var po_data = null;
var warehouses = [];
@@ -635,6 +641,7 @@
is_pending ? 'Assign a default warehouse and save first. The PO will move to Draft.' : 'PO must be in draft to confirm');
set_btn_state('#btn_cancel', can_cancel && !is_cancelled,
is_cancelled ? 'PO is already cancelled' : 'Only draft or confirmed POs can be cancelled');
$('#btn_delete').toggleClass('d-none', !can_delete || !po_id);
$('#receive_card').toggleClass('d-none', !can_receive);
$('#btn_close_po').toggleClass('d-none', !can_close);
@@ -878,6 +885,25 @@
});
}
function delete_po() {
bootbox.confirm({
message: 'Delete this PO? Unconfirmed stock-in reservations will be released.',
buttons: { confirm: { label: 'Delete', className: 'btn-danger' }, cancel: { label: 'Back', className: 'btn-secondary' } },
callback: function(result) {
if (!result) return;
ajax_request({
url: '<?php echo $server_url?>po/api/engine/delete_po.php',
autoPrepare: false,
checkRequired: 0,
action: 'delete',
data: { id: po_id },
onSuccess: function() { window.location.href = '<?php echo $server_url?>po/po.php'; }
});
}
});
}
function cancel_po() {
bootbox.confirm({
message: 'Cancel this purchase order? Any pending (unapproved) stock-in rows will be cancelled.',
+27
View File
@@ -140,6 +140,10 @@
<i class="ti ti-ban me-1"></i>Void
</button>
<button class="btn btn-outline-danger w-100 d-none" id="btn_delete" onclick="delete_invoice()">
<i class="ti ti-trash me-1"></i>Delete
</button>
</div>
</div>
@@ -151,6 +155,9 @@
<?php require '../include_ending.php'; ?>
<script>
const can_delete = ['admin', 'owner'].includes(user_role);
var invoice_id = <?php echo $invoice_id; ?>;
var invoice_data = null;
@@ -199,6 +206,7 @@
!is_pi ? 'Only purchase invoices can be voided'
: status === 0 ? 'Issue the document before voiding'
: status === 4 ? 'Already void' : '');
$('#btn_delete').toggleClass('d-none', !can_delete || !invoice_id);
}
function retrieve_invoice() {
@@ -362,6 +370,25 @@
});
}
function delete_invoice() {
bootbox.confirm({
message: 'Delete this document? Any GL entry will be removed.',
buttons: { confirm: { label: 'Delete', className: 'btn-danger' }, cancel: { label: 'Back', className: 'btn-secondary' } },
callback: function(result) {
if (!result) return;
ajax_request({
url: '<?php echo $server_url?>order/api/engine/delete_invoice.php',
autoPrepare: false,
checkRequired: 0,
action: 'delete',
data: { id: invoice_id },
onSuccess: function() { window.location.href = '<?php echo $server_url?>po/invoice.php'; }
});
}
});
}
function void_invoice() {
bootbox.confirm({
message: '<strong>Void this purchase invoice?</strong><br>This action cannot be undone.',
+26
View File
@@ -182,6 +182,10 @@
<i class="ti ti-x me-1"></i>Cancel Return
</button>
<button class="btn btn-outline-danger w-100 d-none" id="btn_delete" onclick="delete_supplier_return()">
<i class="ti ti-trash me-1"></i>Delete Return
</button>
</div>
</div>
@@ -193,6 +197,8 @@
<?php require '../include_ending.php'; ?>
<script>
const can_delete = ['admin', 'owner'].includes(user_role);
var return_id = <?php echo $return_id; ?>;
var return_data = null;
var po_data = null;
@@ -404,6 +410,7 @@
set_btn_state('#btn_cancel', is_draft || status === 1,
status === -1 ? 'Return is already cancelled' : 'Cannot cancel');
$('#btn_delete').toggleClass('d-none', !can_delete || !return_id);
}
@@ -587,6 +594,25 @@
});
}
function delete_supplier_return() {
bootbox.confirm({
message: 'Delete this return? Unconfirmed stock rows will be removed.',
buttons: { confirm: { label: 'Delete', className: 'btn-danger' }, cancel: { label: 'Back', className: 'btn-secondary' } },
callback: function(result) {
if (!result) return;
ajax_request({
url: '<?php echo $server_url?>po/api/engine/delete_supplier_return.php',
autoPrepare: false,
checkRequired: 0,
action: 'delete',
data: { id: return_id },
onSuccess: function() { window.location.href = '<?php echo $server_url?>po/supplier_returns.php'; }
});
}
});
}
function cancel_return() {
bootbox.confirm({
message: 'Cancel this supplier return?',
+22
View File
@@ -158,6 +158,8 @@
<script>
const can_delete = ['admin', 'owner'].includes(user_role);
function po_status_badge(status) {
status = parseInt(status);
const map = {
@@ -251,6 +253,7 @@
onclick="cancel_po(${o.id})">
<i class="ti ti-x fs-5"></i>
</a>` : ''}
${can_delete ? `<a href="javascript:void(0);" class="link-danger ms-2" title="Delete" onclick="delete_po(${o.id})"><i class="ti ti-trash fs-5"></i></a>` : ''}
</td>
</tr>`;
});
@@ -283,6 +286,25 @@
}
function delete_po(id) {
bootbox.confirm({
message: 'Delete this PO? Unconfirmed stock-in reservations will be released.',
buttons: { confirm: { label: 'Delete', className: 'btn-danger' }, cancel: { label: 'Back', className: 'btn-secondary' } },
callback: function(result) {
if (!result) return;
ajax_request({
url: '<?php echo $server_url?>po/api/engine/delete_po.php',
autoPrepare: false,
checkRequired: 0,
action: 'delete',
data: { id: id },
onSuccess: function() { retrieve_pos(); }
});
}
});
}
$(async function() {
await load_dept_cache();
populate_dept_filter('filter_dept');
+22
View File
@@ -148,6 +148,9 @@
<?php require '../include_ending.php'; ?>
<script>
const can_delete = ['admin', 'owner'].includes(user_role);
function return_status_badge(status) {
const map = {
'-1': '<span class="badge bg-secondary">Cancelled</span>',
@@ -238,6 +241,7 @@
onclick="show_stock_rows('supplier_return', ${r.id}, '${escape_html(r.return_number || '')}')">
<i class="ti ti-packages fs-5"></i>
</a>
${can_delete ? `<a href="javascript:void(0);" class="link-danger ms-2" title="Delete" onclick="delete_supplier_return(${r.id})"><i class="ti ti-trash fs-5"></i></a>` : ''}
</td>
</tr>`;
});
@@ -245,6 +249,24 @@
$('table#return_list tbody').html(body);
}
function delete_supplier_return(id) {
bootbox.confirm({
message: 'Delete this return? Unconfirmed stock rows will be removed.',
buttons: { confirm: { label: 'Delete', className: 'btn-danger' }, cancel: { label: 'Back', className: 'btn-secondary' } },
callback: function(result) {
if (!result) return;
ajax_request({
url: '<?php echo $server_url?>po/api/engine/delete_supplier_return.php',
autoPrepare: false,
checkRequired: 0,
action: 'delete',
data: { id: id },
onSuccess: function() { retrieve_returns(); }
});
}
});
}
$(async function() {
await load_dept_cache();
populate_dept_filter('filter_dept');