accounting modules

This commit is contained in:
Thanakorn S
2026-05-13 15:11:24 +07:00
parent 511360faa2
commit 04a683bd02
70 changed files with 4451 additions and 42 deletions
+28 -6
View File
@@ -264,13 +264,27 @@ class OrderManager {
if (!$row) {
throw new Exception("Order not found.");
}
if ((int)$row['status'] !== 0) {
throw new Exception("Only draft orders can be edited.");
$cur_status = (int)$row['status'];
if ($cur_status !== 0 && $cur_status !== -2) {
throw new Exception("Only draft or pending orders can be edited.");
}
$log = json_decode($row['log'] ?? '[]', true) ?: [];
$log[] = $logging;
// Auto-promote Pending → Draft when all items have a warehouse assigned
$new_status = $cur_status;
if ($cur_status === -2) {
$all_have_warehouse = !empty($items) && array_reduce(
$items,
fn($ok, $item) => $ok && (int)($item['warehouse_id'] ?? 0) > 0,
true
);
if ($all_have_warehouse) {
$new_status = 0;
}
}
$this->pdo->prepare(
"UPDATE td_order SET
contact_id = :contact_id,
@@ -283,6 +297,7 @@ class OrderManager {
shipping_tracking_number = :shipping_tracking_number,
grand_total = :grand_total,
notes = :notes,
status = :status,
`log` = :log
WHERE id = :id AND company_id = :company_id"
)->execute([
@@ -296,6 +311,7 @@ class OrderManager {
':shipping_tracking_number' => $tracking_no,
':grand_total' => $grand_total,
':notes' => $data['notes'] ?? '',
':status' => $new_status,
':log' => json_encode($log),
':id' => $id,
':company_id' => $this->company_id,
@@ -305,23 +321,28 @@ class OrderManager {
} else {
$log = [$logging];
$log = [$logging];
$quotation_id = (int)($data['quotation_id'] ?? 0);
// Quotation-converted orders start as Pending (-2); direct orders as Draft (0)
$init_status = $quotation_id > 0 ? -2 : 0;
$this->pdo->prepare(
"INSERT INTO td_order
(company_id, uuid, order_number, contact_id, order_date,
(company_id, uuid, quotation_id, order_number, contact_id, order_date,
status, payment_status, subtotal, discount, tax,
shipping_fee, shipping_tracking_number, grand_total, items, notes, `log`, created_at)
VALUES
(:company_id, :uuid, :order_number, :contact_id, :order_date,
0, 0, :subtotal, :discount, :tax,
(:company_id, :uuid, :quotation_id, :order_number, :contact_id, :order_date,
:status, 0, :subtotal, :discount, :tax,
:shipping_fee, :shipping_tracking_number, :grand_total, :items, :notes, :log, :created_at)"
)->execute([
':company_id' => $this->company_id,
':uuid' => bin2hex(random_bytes(16)),
':quotation_id' => $quotation_id,
':order_number' => $this->generateOrderNumber(),
':contact_id' => (int)($data['contact_id'] ?? 0),
':order_date' => $data['order_date'] ?? date('Y-m-d'),
':status' => $init_status,
':subtotal' => $subtotal,
':discount' => $discount,
':tax' => $tax,
@@ -539,6 +560,7 @@ class OrderManager {
"Cannot cancel an order that is processing or completed."
);
}
// Pending orders (-2) have no stock rows — skip the stock reversal loop below
// ── Guard: no active invoice ──────────────────────────────────────
$sth = $this->pdo->prepare(
@@ -0,0 +1,37 @@
<?php
/**
* PostingManager
*
* The ONLY bridge between WMS and the accounting engine.
* WMS API endpoints call methods here — nothing in WMS imports
* accounting classes directly.
*
* Usage in a WMS API endpoint (add at the end, after business doc saves):
* require_once '../../../assets/utils/classes/PostingManager.php';
* (new PostingManager($pdo2, $company_id))->postInvoice($invoice_id);
*
* If posting fails it logs silently — the business document is already saved.
*/
class PostingManager
{
private PDO $pdo;
private int $companyId;
public function __construct(PDO $pdo, int $company_id)
{
$this->pdo = $pdo;
$this->companyId = $company_id;
}
// TODO: postInvoice(int $invoice_id): void
// TODO: voidInvoice(int $invoice_id): void
// TODO: postPurchaseReceive(int $po_id): void
// TODO: voidPurchaseReceive(int $po_id): void
// TODO: postReceipt(int $receipt_id): void
// TODO: voidReceipt(int $receipt_id): void
// TODO: postPayment(int $payment_id): void
// TODO: voidPayment(int $payment_id): void
}