accounting workflows
This commit is contained in:
@@ -2,60 +2,104 @@
|
||||
session_start();
|
||||
require '../../../assets/utils/db_auth.php';
|
||||
require '../../../assets/utils/classes/OrderManager.php';
|
||||
require '../../../assets/utils/classes/QuotationManager.php';
|
||||
|
||||
$quotation_id = (int)($data['quotation_id'] ?? 0);
|
||||
$convert_items = $data['convert_items'] ?? [];
|
||||
|
||||
$quotation_id = (int)($data['quotation_id'] ?? 0);
|
||||
if (!$quotation_id) {
|
||||
exit(json_encode(['success' => 0, 'message' => 'Quotation ID required']));
|
||||
exit(json_encode(['success' => 0, 'message' => 'Quotation ID required.']));
|
||||
}
|
||||
|
||||
// Load quotation — must be Accepted (status=2)
|
||||
$sth = $pdo2->prepare(
|
||||
"SELECT q.*, c.contact_name
|
||||
FROM ac_quotation q
|
||||
LEFT JOIN md_contact c ON c.id = q.contact_id
|
||||
WHERE q.id = :id AND q.company_id = :cid AND q.status = 2
|
||||
LIMIT 1"
|
||||
);
|
||||
$sth->execute([':id' => $quotation_id, ':cid' => $company_id]);
|
||||
$q = $sth->fetch(PDO::FETCH_ASSOC);
|
||||
$qm = new QuotationManager($pdo2, $company_id);
|
||||
|
||||
if (!$q) {
|
||||
exit(json_encode(['success' => 0, 'message' => 'Quotation not found or not in Accepted status']));
|
||||
// Load quotation — must be Accepted
|
||||
$q = $qm->getById($quotation_id);
|
||||
if (!$q || (int)$q['status'] !== 2) {
|
||||
exit(json_encode(['success' => 0, 'message' => 'Quotation not found or not in Accepted status.']));
|
||||
}
|
||||
|
||||
// Check not already converted
|
||||
if ((int)$q['order_id'] > 0) {
|
||||
exit(json_encode(['success' => 0, 'message' => 'Quotation has already been converted to an order']));
|
||||
$qt_items = $q['items'];
|
||||
if (empty($qt_items)) {
|
||||
exit(json_encode(['success' => 0, 'message' => 'Quotation has no items.']));
|
||||
}
|
||||
|
||||
// Map quotation items → order items (warehouse_id left 0 = to be filled by WMS)
|
||||
$qt_items = json_decode($q['items'] ?? '[]', true) ?: [];
|
||||
if ((float)$q['total_remaining'] <= 0.000001) {
|
||||
exit(json_encode(['success' => 0, 'message' => 'Quotation is already fully converted.']));
|
||||
}
|
||||
|
||||
// Index by item_id for validation
|
||||
$qt_by_id = [];
|
||||
foreach ($qt_items as $qi) {
|
||||
$qt_by_id[(int)$qi['item_id']] = $qi;
|
||||
}
|
||||
|
||||
// Default to all remaining when caller sends no selection
|
||||
if (empty($convert_items)) {
|
||||
$convert_items = [];
|
||||
foreach ($qt_items as $qi) {
|
||||
$remaining = (float)$qi['remaining_qty'];
|
||||
if ($remaining > 0.000001) {
|
||||
$convert_items[] = ['item_id' => (int)$qi['item_id'], 'quantity' => $remaining];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate quantities and build order items
|
||||
$ord_items = [];
|
||||
foreach ($qt_items as $i => $qi) {
|
||||
$validated = [];
|
||||
|
||||
foreach ($convert_items as $ci) {
|
||||
$item_id = (int)($ci['item_id'] ?? 0);
|
||||
$qty = (float)($ci['quantity'] ?? 0);
|
||||
|
||||
if ($qty <= 0) continue;
|
||||
if (!isset($qt_by_id[$item_id])) {
|
||||
exit(json_encode(['success' => 0, 'message' => "Item #{$item_id} not found in this quotation."]));
|
||||
}
|
||||
|
||||
$qi = $qt_by_id[$item_id];
|
||||
$remaining = (float)$qi['remaining_qty'];
|
||||
|
||||
if ($qty - $remaining > 0.000001) {
|
||||
$name = $qi['product_name'] ?: $qi['product_sku'];
|
||||
exit(json_encode([
|
||||
'success' => 0,
|
||||
'message' => "Cannot convert {$qty} for \"{$name}\": only {$remaining} remaining.",
|
||||
]));
|
||||
}
|
||||
|
||||
$unit_price = (float)$qi['unit_price'];
|
||||
$total_price = round($qty * $unit_price, 4);
|
||||
$tax_amount = round($total_price * (float)($qi['tax_amount'] / max((float)$qi['total_price'], 0.000001)), 4);
|
||||
|
||||
$ord_items[] = [
|
||||
'item_id' => $i,
|
||||
'product_sku' => $qi['product_sku'] ?? '',
|
||||
'product_name' => $qi['description'] ?? '',
|
||||
'warehouse_id' => 0,
|
||||
'zone' => '',
|
||||
'aisle' => '',
|
||||
'rack' => '',
|
||||
'lot_number' => '',
|
||||
'serial_number' => '',
|
||||
'quantity' => (float)($qi['quantity'] ?? 0),
|
||||
'price' => (float)($qi['unit_price'] ?? 0),
|
||||
'total_price' => (float)($qi['total_price'] ?? 0),
|
||||
'stock_out_id' => 0,
|
||||
'item_id' => $item_id - 1,
|
||||
'product_sku' => $qi['product_sku'],
|
||||
'product_name' => $qi['product_name'],
|
||||
'warehouse_id' => 0,
|
||||
'lot_number' => '',
|
||||
'quantity' => $qty,
|
||||
'unit_price' => $unit_price,
|
||||
'total_price' => $total_price,
|
||||
'tax_amount' => $tax_amount,
|
||||
'stock_out_id' => 0,
|
||||
];
|
||||
$validated[] = ['item_id' => $item_id, 'quantity' => $qty];
|
||||
}
|
||||
|
||||
if (empty($ord_items)) {
|
||||
exit(json_encode(['success' => 0, 'message' => 'No valid items to convert.']));
|
||||
}
|
||||
|
||||
$order_data = [
|
||||
'quotation_id' => $quotation_id,
|
||||
'source' => 'quotation',
|
||||
'source_id' => $quotation_id,
|
||||
'contact_id' => (int)$q['contact_id'],
|
||||
'department_id'=> (int)($q['department_id'] ?? 0),
|
||||
'order_date' => date('Y-m-d'),
|
||||
'items' => $ord_items,
|
||||
'discount' => (float)$q['discount'],
|
||||
'tax' => (float)$q['tax'],
|
||||
'discount' => 0,
|
||||
'shipping_fee' => 0,
|
||||
'shipping_tracking_number' => '',
|
||||
'notes' => $q['notes'] ?? '',
|
||||
@@ -64,21 +108,23 @@ $order_data = [
|
||||
try {
|
||||
$new_order_id = null;
|
||||
|
||||
dbTransaction($pdo2, function($pdo) use ($order_data, $company_id, $logging, $quotation_id, &$new_order_id) {
|
||||
$order = new OrderManager($pdo, $company_id);
|
||||
$new_order_id = $order->saveOrder($order_data, $logging);
|
||||
dbTransaction($pdo2, function($pdo) use (
|
||||
$order_data, $company_id, $logging, $quotation_id, $validated, $qm, &$new_order_id
|
||||
) {
|
||||
$om = new OrderManager($pdo, $company_id);
|
||||
$new_order_id = $om->saveOrder($order_data, $logging);
|
||||
|
||||
// Mark quotation as Converted and link order_id
|
||||
$pdo->prepare(
|
||||
"UPDATE ac_quotation SET status = 5, order_id = :oid
|
||||
WHERE id = :id AND company_id = :cid"
|
||||
)->execute([':oid' => $new_order_id, ':id' => $quotation_id, ':cid' => $company_id]);
|
||||
$qm2 = new QuotationManager($pdo, $company_id);
|
||||
$qm2->incrementConvertedQty($quotation_id, $validated);
|
||||
});
|
||||
|
||||
$answer['success'] = 1;
|
||||
$answer['message'] = 'Order created successfully';
|
||||
$answer['message'] = 'Order created successfully.';
|
||||
$answer['order_id'] = $new_order_id;
|
||||
|
||||
} 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);
|
||||
|
||||
Reference in New Issue
Block a user