- Upgraded all plain `require` to `require_once` across 172 api/engine and api/engine_report files to prevent class-redeclaration errors - Added issue button, issue_invoice() with GL toastr, and delete_invoice() to expense/manage_purchase_invoice.php, bringing it in line with po/manage_purchase_invoice.php - Added can_delete role guard (admin/owner only) to trash icons on revenue/invoice.php and expense/purchase_invoice.php, matching the existing pattern in finance/receipt.php and finance/payment.php Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
82 lines
3.1 KiB
PHP
82 lines
3.1 KiB
PHP
<?php
|
|
session_start();
|
|
require_once '../../../assets/utils/db_auth.php';
|
|
require_once '../../../assets/utils/classes_ac/PostingWindowGuard.php';
|
|
require_once '../../../assets/utils/classes_ac/GlManager.php';
|
|
require_once '../../../assets/utils/classes_ac/posting/BasePosting.php';
|
|
require_once '../../../assets/utils/classes_ac/posting/InvoicePosting.php';
|
|
require_once '../../../assets/utils/classes_ac/posting/CreditNotePosting.php';
|
|
require_once '../../../assets/utils/classes_ac/posting/PurchaseInvoicePosting.php';
|
|
require_once '../../../assets/utils/classes_ac/posting/SupplierCreditNotePosting.php';
|
|
require_once '../../../assets/utils/classes_ac/posting/ReceiptPosting.php';
|
|
require_once '../../../assets/utils/classes_ac/posting/PaymentPosting.php';
|
|
require_once '../../../assets/utils/classes_ac/posting/PurchasePosting.php';
|
|
|
|
require_role($user_role, ['owner', 'admin']);
|
|
require_once '../../../assets/utils/notify_node.php';
|
|
|
|
$doc_type = trim((string)($data['doc_type'] ?? ''));
|
|
$id = (int)($data['id'] ?? 0);
|
|
$formula_id = (int)($data['formula_id'] ?? 0) ?: null;
|
|
|
|
$posting_map = [
|
|
'invoice' => InvoicePosting::class,
|
|
'credit_note' => CreditNotePosting::class,
|
|
'purchase_invoice' => PurchaseInvoicePosting::class,
|
|
'supplier_credit_note' => SupplierCreditNotePosting::class,
|
|
'receipt' => ReceiptPosting::class,
|
|
'payment' => PaymentPosting::class,
|
|
'purchase_order' => PurchasePosting::class,
|
|
];
|
|
|
|
if (!isset($posting_map[$doc_type]) || $id <= 0) {
|
|
$answer['message'] = 'Invalid doc_type or id.';
|
|
exit(json_encode($answer));
|
|
}
|
|
|
|
try {
|
|
$posting_class = $posting_map[$doc_type];
|
|
$posting = new $posting_class($pdo2, $company_id);
|
|
$built = $posting->build($id, $formula_id);
|
|
|
|
$guard = new PostingWindowGuard($pdo1, $company_id);
|
|
$gl = new GlManager($pdo2, $company_id, $guard);
|
|
$meta = ['journal_date' => $built['doc_date'] ?? null];
|
|
|
|
$pdo2->beginTransaction();
|
|
|
|
$existing = $gl->getBySource($doc_type, $id);
|
|
if ($existing) {
|
|
$gl->replace($doc_type, $id, $built['formula_id'], $built['period'], $built['lines'], $meta);
|
|
} else {
|
|
$gl->post($doc_type, $id, $built['formula_id'], $built['period'], $built['lines'], $meta);
|
|
}
|
|
|
|
$pdo2->commit();
|
|
|
|
$answer['success'] = 1;
|
|
$answer['message'] = $existing ? 'GL entry replaced.' : 'GL entry posted.';
|
|
|
|
$has_revenue = false;
|
|
$has_expense = false;
|
|
foreach ($built['lines'] as $line) {
|
|
$code = (int)($line['account_code'] ?? 0);
|
|
if ($code >= 4000 && $code < 5000) $has_revenue = true;
|
|
if ($code >= 5000) $has_expense = true;
|
|
}
|
|
|
|
notify_node('gl_posted', [
|
|
'doc_type' => $doc_type,
|
|
'id' => $id,
|
|
'action' => $existing ? 'replaced' : 'posted',
|
|
'has_revenue' => $has_revenue,
|
|
'has_expense' => $has_expense,
|
|
], $company_id);
|
|
|
|
} catch (Exception $e) {
|
|
if ($pdo2->inTransaction()) $pdo2->rollBack();
|
|
$answer['message'] = $e->getMessage();
|
|
}
|
|
|
|
exit(json_encode($answer));
|