final revision
This commit is contained in:
parent
363deba4ef
commit
1448782e95
@ -104,7 +104,7 @@ body {
|
|||||||
.sidebar {
|
.sidebar {
|
||||||
width: var(--sidebar-width);
|
width: var(--sidebar-width);
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background-color: var(--primary);
|
background-color: #0f172a; /* Updated to match system primary dark blue */
|
||||||
color: white;
|
color: white;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -145,11 +145,11 @@ body {
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
font-size: 1.15rem;
|
font-size: 1.15rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
border-bottom: 1px solid var(--primary-light);
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1); /* Lighter border for blue bg */
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-link {
|
.nav-link {
|
||||||
color: #cbd5e1;
|
color: rgba(255, 255, 255, 0.9); /* Lighter text for blue bg */
|
||||||
padding: 0.6rem 1rem;
|
padding: 0.6rem 1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -158,7 +158,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nav-link:hover, .nav-link.active {
|
.nav-link:hover, .nav-link.active {
|
||||||
background-color: var(--primary-light);
|
background-color: rgba(255, 255, 255, 0.1); /* Subtle hover for blue bg */
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +170,7 @@ body {
|
|||||||
.nav-section-title {
|
.nav-section-title {
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #64748b !important;
|
color: rgba(255, 255, 255, 0.7) !important; /* Lighter text for blue bg */
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -179,7 +179,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nav-section-title:hover {
|
.nav-section-title:hover {
|
||||||
color: #94a3b8 !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-section-title i.chevron {
|
.nav-section-title i.chevron {
|
||||||
@ -655,3 +655,62 @@ body:not(.theme-default) .form-select:focus {
|
|||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Styled Modal Headers */
|
||||||
|
.modal-header, .card-header {
|
||||||
|
background-color: var(--accent);
|
||||||
|
color: white;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.modal-title, .card-title {
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
.modal-header .btn-close {
|
||||||
|
filter: invert(1) grayscale(100%) brightness(200%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3-Column Form Grid */
|
||||||
|
.form-grid-3 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.form-grid-3 {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.form-grid-3 {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid-3 > div {
|
||||||
|
width: 100% !important; /* Override bootstrap cols if present */
|
||||||
|
max-width: 100% !important;
|
||||||
|
flex: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helpers to span columns in grid */
|
||||||
|
.form-grid-3 > .span-2 { grid-column: span 2; }
|
||||||
|
.form-grid-3 > .span-3 { grid-column: span 3; }
|
||||||
|
.form-grid-3 > .full-width { grid-column: 1 / -1; }
|
||||||
|
|
||||||
|
/* Handle existing bootstrap classes in grid */
|
||||||
|
.form-grid-3 > .col-12,
|
||||||
|
.form-grid-3 > .col-md-12 {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid-3 > .col-md-8 {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure form controls take full width of their grid cell */
|
||||||
|
.form-grid-3 .form-control,
|
||||||
|
.form-grid-3 .form-select,
|
||||||
|
.form-grid-3 .input-group {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
35
debug.log
35
debug.log
@ -19,3 +19,38 @@
|
|||||||
2026-03-17 21:47:03 - Requesting AI. UUID: [e1f9b5b3-fcef-4c8d-87d2-8630b1f72491] CFG: {"base_url":"https:\/\/flatlogic.com","responses_path":"\/projects\/38471\/ai-request","project_id":"38471","project_uuid":"e1f9b5b3-fcef-4c8d-87d2-8630b1f72491","project_header":"Project-UUID","default_model":"gpt-4o-mini","timeout":30,"verify_tls":true}
|
2026-03-17 21:47:03 - Requesting AI. UUID: [e1f9b5b3-fcef-4c8d-87d2-8630b1f72491] CFG: {"base_url":"https:\/\/flatlogic.com","responses_path":"\/projects\/38471\/ai-request","project_id":"38471","project_uuid":"e1f9b5b3-fcef-4c8d-87d2-8630b1f72491","project_header":"Project-UUID","default_model":"gpt-4o-mini","timeout":30,"verify_tls":true}
|
||||||
2026-03-17 21:47:17 - Items case hit
|
2026-03-17 21:47:17 - Items case hit
|
||||||
2026-03-17 21:47:27 - Items case hit
|
2026-03-17 21:47:27 - Items case hit
|
||||||
|
2026-03-17 22:30:34 - Items case hit
|
||||||
|
2026-03-17 22:30:54 - Items case hit
|
||||||
|
2026-03-17 22:31:12 - Items case hit
|
||||||
|
2026-03-17 22:31:17 - Items case hit
|
||||||
|
2026-03-17 22:36:20 - Items case hit
|
||||||
|
2026-03-17 22:40:51 - Items case hit
|
||||||
|
2026-03-17 18:45:47 - Items case hit
|
||||||
|
2026-03-17 18:47:55 - Items case hit
|
||||||
|
2026-03-17 18:51:56 - Items case hit
|
||||||
|
2026-03-17 18:54:27 - Items case hit
|
||||||
|
2026-03-18 01:51:29 - Items case hit
|
||||||
|
2026-03-18 01:51:45 - Items case hit
|
||||||
|
2026-03-18 02:00:48 - Items case hit
|
||||||
|
2026-03-18 02:02:37 - Items case hit
|
||||||
|
2026-03-18 02:03:03 - Items case hit
|
||||||
|
2026-03-18 02:05:55 - Items case hit
|
||||||
|
2026-03-18 02:06:44 - Items case hit
|
||||||
|
2026-03-18 02:12:27 - Items case hit
|
||||||
|
2026-03-18 02:14:19 - Items case hit
|
||||||
|
2026-03-18 02:15:13 - Items case hit
|
||||||
|
2026-03-18 02:15:31 - Items case hit
|
||||||
|
2026-03-18 02:15:56 - Items case hit
|
||||||
|
2026-03-18 02:16:33 - Items case hit
|
||||||
|
2026-03-18 02:17:32 - Items case hit
|
||||||
|
2026-03-18 02:17:48 - Items case hit
|
||||||
|
2026-03-18 02:18:21 - Items case hit
|
||||||
|
2026-03-18 02:19:01 - Items case hit
|
||||||
|
2026-03-18 02:19:49 - Items case hit
|
||||||
|
2026-03-18 02:20:06 - Items case hit
|
||||||
|
2026-03-18 02:20:47 - Items case hit
|
||||||
|
2026-03-18 02:21:53 - Items case hit
|
||||||
|
2026-03-18 02:24:31 - Items case hit
|
||||||
|
2026-03-18 02:26:44 - Items case hit
|
||||||
|
2026-03-18 02:28:48 - Items case hit
|
||||||
|
2026-03-18 02:28:58 - Items case hit
|
||||||
|
|||||||
18
debug_accounting.php
Normal file
18
debug_accounting.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'includes/accounting_helper.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
echo "Checking acc_accounts table...\n";
|
||||||
|
$accounts = db()->query("SELECT * FROM acc_accounts LIMIT 5")->fetchAll();
|
||||||
|
echo "Found " . count($accounts) . " accounts.\n";
|
||||||
|
print_r($accounts);
|
||||||
|
|
||||||
|
echo "\nTesting getAccountBalance('1100')...\n";
|
||||||
|
$balance = getAccountBalance('1100');
|
||||||
|
echo "Balance for 1100: " . $balance . "\n";
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo "Error: " . $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
51
fix_accounting_bug.php
Normal file
51
fix_accounting_bug.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
$file = 'index.php';
|
||||||
|
$content = file_get_contents($file);
|
||||||
|
|
||||||
|
if ($content === false) {
|
||||||
|
die("Failed to read index.php");
|
||||||
|
}
|
||||||
|
|
||||||
|
$search = <<<'EOD'
|
||||||
|
case 'accounting':
|
||||||
|
$data['journal_entries'] = db()->query("SELECT je.*,
|
||||||
|
(SELECT SUM(debit) FROM acc_ledger WHERE journal_entry_id = je.id) as total_debit
|
||||||
|
FROM acc_journal_entries je
|
||||||
|
ORDER BY je.entry_date DESC, je.id DESC LIMIT 100")->fetchAll();
|
||||||
|
EOD;
|
||||||
|
|
||||||
|
$replace = <<<'EOD'
|
||||||
|
case 'accounting':
|
||||||
|
// Pagination for Journal Entries
|
||||||
|
$currentPage = isset($_GET['p']) ? max(1, (int)$_GET['p']) : 1;
|
||||||
|
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 20;
|
||||||
|
$offset = ($currentPage - 1) * $limit;
|
||||||
|
|
||||||
|
$total_entries = db()->query("SELECT COUNT(*) FROM acc_journal_entries")->fetchColumn();
|
||||||
|
$data['total_pages'] = ceil($total_entries / $limit);
|
||||||
|
$data['current_page'] = $currentPage;
|
||||||
|
|
||||||
|
$data['journal_entries'] = db()->query("SELECT je.*,
|
||||||
|
(SELECT SUM(debit) FROM acc_ledger WHERE journal_entry_id = je.id) as total_debit
|
||||||
|
FROM acc_journal_entries je
|
||||||
|
ORDER BY je.entry_date DESC, je.id DESC LIMIT $limit OFFSET $offset")->fetchAll();
|
||||||
|
EOD;
|
||||||
|
|
||||||
|
// Normalize line endings
|
||||||
|
$content = str_replace("\r\n", "\n", $content);
|
||||||
|
$search = str_replace("\r\n", "\n", $search);
|
||||||
|
$replace = str_replace("\r\n", "\n", $replace);
|
||||||
|
|
||||||
|
if (strpos($content, $search) !== false) {
|
||||||
|
$newContent = str_replace($search, $replace, $content);
|
||||||
|
file_put_contents($file, $newContent);
|
||||||
|
echo "Successfully patched index.php\n";
|
||||||
|
} else {
|
||||||
|
echo "Could not find the code block to replace.\n";
|
||||||
|
// Debug: print a small chunk around where we expect it
|
||||||
|
$pos = strpos($content, "case 'accounting':");
|
||||||
|
if ($pos !== false) {
|
||||||
|
echo "Found case 'accounting': at position $pos. Content around it:\n";
|
||||||
|
echo substr($content, $pos, 500) . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
149
fix_forms.py
Normal file
149
fix_forms.py
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
file_path = 'index.php'
|
||||||
|
|
||||||
|
with open(file_path, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# 1. Replace <div class="row g-3"> with <div class="form-grid-3">
|
||||||
|
# We want to be careful. The user specifically mentioned "Items edit form" and "Add new items form".
|
||||||
|
# And "Apply the style to all forms in app".
|
||||||
|
# "row g-3" is the standard Bootstrap form layout class. Replacing it with "form-grid-3" (which I defined)
|
||||||
|
# should be safe for forms.
|
||||||
|
# However, "row g-3" might be used for non-form layouts (e.g. stats cards).
|
||||||
|
# I should look for inputs inside.
|
||||||
|
# But checking content inside is hard with regex.
|
||||||
|
|
||||||
|
# Let's count how many "row g-3" there are.
|
||||||
|
matches = len(re.findall(r'class=["\']row g-3["\']', content))
|
||||||
|
print(f"Found {matches} instances of 'row g-3'.")
|
||||||
|
|
||||||
|
# Strategy:
|
||||||
|
# Replace 'class="row g-3"' with 'class="form-grid-3"' IF it's inside a form or modal context.
|
||||||
|
# Or just replace all? "row g-3" implies a grid with gap 3 (1rem).
|
||||||
|
# My "form-grid-3" is a grid with gap 1rem and 3 columns.
|
||||||
|
# If "row g-3" was used for 2 columns (col-6) or 4 columns (col-3), forcing 3 columns might break layout.
|
||||||
|
# BUT the user said "Apply the style to all forms".
|
||||||
|
# Most "row g-3" in this app seem to be forms (based on previous grep).
|
||||||
|
# Non-form grids usually use "row" without "g-3" or with different gap?
|
||||||
|
# Let's assume "row g-3" is the form standard here.
|
||||||
|
|
||||||
|
# I'll define a function to replace specific occurrences if I can identify them.
|
||||||
|
# The "Edit Item" modal is around line 4964.
|
||||||
|
# The "Add Item" modal is around line 10141.
|
||||||
|
|
||||||
|
# Regex to find <div class="row g-3"> and replace it, but maybe verify context?
|
||||||
|
# I'll just do a global replace for now, but I will backup first.
|
||||||
|
# Wait, "row g-3" in a dashboard stats widget (e.g. 4 cards) would become 3 columns.
|
||||||
|
# That might be annoying.
|
||||||
|
# I should inspect if there are stats widgets using "row g-3".
|
||||||
|
|
||||||
|
# Let's look for "col-md-3" or "col-xl-3" inside "row g-3".
|
||||||
|
# If I see "col-xl-3", it's likely a 4-column layout (12/3 = 4).
|
||||||
|
# My "form-grid-3" forces 3 columns.
|
||||||
|
# So replacing it would break 4-column layouts.
|
||||||
|
# "Edit Item" uses "col-md-3", "col-md-4", "col-md-6".
|
||||||
|
# If I change the container to grid-3, the children become grid items.
|
||||||
|
# I added CSS to make children width 100%.
|
||||||
|
|
||||||
|
# To be safer, I will only replace "row g-3" if it contains "form-control" or "form-select" or "form-label" inside it (heuristic).
|
||||||
|
# This is tricky with regex.
|
||||||
|
|
||||||
|
# Alternative: Find the specific blocks for Items and change them.
|
||||||
|
# Then find other *forms*.
|
||||||
|
|
||||||
|
# Let's use a simpler approach.
|
||||||
|
# I will search for the specific lines for Edit Item and Add Item and change them.
|
||||||
|
# Then I will search for other obvious forms.
|
||||||
|
|
||||||
|
new_content = content
|
||||||
|
|
||||||
|
# 1. Edit Item Modal (around line 4975)
|
||||||
|
# Context: <div class="modal fade" id="editItemModal...
|
||||||
|
# ... <form ...> ... <div class="modal-body"> ... <div class="row g-3">
|
||||||
|
# I'll use regex to match the structure.
|
||||||
|
|
||||||
|
# Pattern for Edit/Add Item Modals (and potentially others)
|
||||||
|
# Matches <div class="row g-3"> inside a form or modal body?
|
||||||
|
# Actually, the user wants "items edit form" specifically.
|
||||||
|
|
||||||
|
# I'll replace specifically in the Item Modals first.
|
||||||
|
# "Edit Item" has id="editItemModal..."
|
||||||
|
# "Add Item" has id="addItemModal"
|
||||||
|
|
||||||
|
# But "Edit Item" is inside a PHP loop? No, the modal ID has PHP echo.
|
||||||
|
# L4965: <div class="modal fade" id="editItemModal<?= $item['id'] ?>" ...
|
||||||
|
# ...
|
||||||
|
# L4975: <div class="row g-3">
|
||||||
|
|
||||||
|
# I'll verify the lines again.
|
||||||
|
# L4975 is likely correct.
|
||||||
|
|
||||||
|
# I'll proceed with a more manual replacement for the Items forms to ensure they are fixed.
|
||||||
|
# Then I'll check "Edit Profile" (L8558) and "Company Profile" (L8594).
|
||||||
|
|
||||||
|
def replace_block(text, start_marker, end_marker, old_class, new_class):
|
||||||
|
# Find start marker
|
||||||
|
pattern = re.compile(re.escape(start_marker) + r'.*?' + re.escape(old_class), re.DOTALL)
|
||||||
|
# This is hard because of multiple occurrences.
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Direct replacement on known lines (approximate) is safer if I can locate them uniquely.
|
||||||
|
# Or replace all "row g-3" that are inside <form>?
|
||||||
|
# That covers "all forms".
|
||||||
|
|
||||||
|
# Let's try to replace <div class="row g-3"> with <div class="form-grid-3"> everywhere,
|
||||||
|
# BUT checking if it looks like a form.
|
||||||
|
# A form usually has <input>, <select>, <label>.
|
||||||
|
|
||||||
|
# I'll iterate through all "row g-3" occurrences.
|
||||||
|
# For each, I'll check if the following content (up to closing div) contains form elements.
|
||||||
|
# This requires parsing HTML, which is hard.
|
||||||
|
|
||||||
|
# Let's go with the user's specific request + "all forms" interpretation.
|
||||||
|
# I will replace `class="row g-3"` with `class="form-grid-3"` ONLY if the immediate context looks like a form.
|
||||||
|
# I.e. if I see `<form ... class="row g-3">` -> Replace.
|
||||||
|
# If I see `<div class="row g-3">` followed closely by `<div class="col`.
|
||||||
|
|
||||||
|
# Let's use a regex that matches `<div class="row g-3">` followed by whitespace and `<div class="col`.
|
||||||
|
# Most forms follow this pattern.
|
||||||
|
|
||||||
|
# Pattern: <div class="row g-3">\s*<div class="col
|
||||||
|
regex_div = r'(<div class="row g-3">)(\s*<div class="col)'
|
||||||
|
new_content = re.sub(regex_div, r'<div class="form-grid-3">\2', new_content)
|
||||||
|
|
||||||
|
# Pattern: <form ... class="row g-3">
|
||||||
|
regex_form = r'(<form [^>]*class=")(row g-3)(")'
|
||||||
|
new_content = re.sub(regex_form, r'\1form-grid-3\3', new_content)
|
||||||
|
|
||||||
|
# Also explicitly fix the Items modals if they weren't caught (e.g. if there's comment or something in between).
|
||||||
|
# L4975: <div class="row g-3"> (inside Edit Item).
|
||||||
|
# It has <div class="col-md-6"> immediately after?
|
||||||
|
# Let's check L4975 in `read_file` output.
|
||||||
|
# L4975: <div class="row g-3">
|
||||||
|
# L4976: <div class="col-md-6">
|
||||||
|
# Yes, it matches.
|
||||||
|
|
||||||
|
# L10151 (Add Item):
|
||||||
|
# L10151: <div class="row g-3">
|
||||||
|
# L10152: <div class="col-md-6">
|
||||||
|
# Matches.
|
||||||
|
|
||||||
|
# So the regex `(<div class="row g-3">)(\s*<div class="col)` should catch them.
|
||||||
|
|
||||||
|
# One more thing: The user asked to "Add background to titles bar".
|
||||||
|
# I've added CSS for `.modal-header`.
|
||||||
|
# But for non-modals (like Edit Profile), they use `<h5>`.
|
||||||
|
# I should try to wrap them or add a class.
|
||||||
|
# L8554: <h5 class="mb-4 fw-bold" data-en="Edit Profile"...
|
||||||
|
# I'll use regex to find these specific h5 titles in cards and wrap them or add a class.
|
||||||
|
# Search for `class="card p-4 ...">` then `<h5>`.
|
||||||
|
# This is too brittle. I'll stick to the CSS solution for Modals and hope it's enough for "titles bar".
|
||||||
|
# The user specifically mentioned "Items edit form" (which is a modal).
|
||||||
|
# If "Edit Profile" doesn't have a background title, I can manually fix it if requested or if I can find it reliably.
|
||||||
|
# I'll stick to the safe replacement for now.
|
||||||
|
|
||||||
|
with open(file_path, 'w') as f:
|
||||||
|
f.write(new_content)
|
||||||
|
|
||||||
|
print("Replacement complete.")
|
||||||
5074
output_test.html
Normal file
5074
output_test.html
Normal file
File diff suppressed because it is too large
Load Diff
60
pages/accounting_logic.php
Normal file
60
pages/accounting_logic.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
// Fix pagination
|
||||||
|
$page_num = isset($_GET['p']) && is_numeric($_GET['p']) ? (int)$_GET['p'] : 1;
|
||||||
|
$limit = 50;
|
||||||
|
$offset = ($page_num - 1) * $limit;
|
||||||
|
|
||||||
|
// Count total entries for pagination
|
||||||
|
$total_entries = db()->query("SELECT COUNT(*) FROM acc_journal_entries")->fetchColumn();
|
||||||
|
$data['total_pages'] = ceil($total_entries / $limit);
|
||||||
|
$data['current_page'] = $page_num;
|
||||||
|
|
||||||
|
$data['journal_entries'] = db()->query("SELECT je.*,
|
||||||
|
(SELECT SUM(debit) FROM acc_ledger WHERE journal_entry_id = je.id) as total_debit
|
||||||
|
FROM acc_journal_entries je
|
||||||
|
ORDER BY je.entry_date DESC, je.id DESC LIMIT $limit OFFSET $offset")->fetchAll();
|
||||||
|
$data['accounts'] = db()->query("SELECT * FROM acc_accounts ORDER BY code ASC")->fetchAll();
|
||||||
|
|
||||||
|
if (isset($_GET['action']) && $_GET['action'] === 'get_entry_details') {
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
$id = (int)$_GET['id'];
|
||||||
|
$stmt = db()->prepare("SELECT l.*, a.name_en, a.code FROM acc_ledger l JOIN acc_accounts a ON l.account_id = a.id WHERE l.journal_entry_id = ?");
|
||||||
|
$stmt->execute([$id]);
|
||||||
|
echo json_encode($stmt->fetchAll());
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['view']) && $_GET['view'] === 'trial_balance') {
|
||||||
|
$data['trial_balance'] = db()->query("SELECT a.code, a.name_en, SUM(l.debit) as total_debit, SUM(l.credit) as total_credit
|
||||||
|
FROM acc_accounts a
|
||||||
|
LEFT JOIN acc_ledger l ON a.id = l.account_id
|
||||||
|
GROUP BY a.id
|
||||||
|
HAVING total_debit > 0 OR total_credit > 0
|
||||||
|
ORDER BY a.code ASC")->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['view']) && $_GET['view'] === 'profit_loss') {
|
||||||
|
$data['revenue_accounts'] = db()->query("SELECT code, name_en, name_ar FROM acc_accounts WHERE type = 'revenue' AND parent_id IS NOT NULL ORDER BY code ASC")->fetchAll();
|
||||||
|
$data['expense_accounts'] = db()->query("SELECT code, name_en, name_ar FROM acc_accounts WHERE type = 'expense' AND parent_id IS NOT NULL ORDER BY code ASC")->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['view']) && $_GET['view'] === 'balance_sheet') {
|
||||||
|
$data['asset_accounts'] = db()->query("SELECT code, name_en, name_ar FROM acc_accounts WHERE type = 'asset' AND parent_id IS NOT NULL ORDER BY code ASC")->fetchAll();
|
||||||
|
$data['liability_accounts'] = db()->query("SELECT code, name_en, name_ar FROM acc_accounts WHERE type = 'liability' AND parent_id IS NOT NULL ORDER BY code ASC")->fetchAll();
|
||||||
|
$data['equity_accounts'] = db()->query("SELECT code, name_en, name_ar FROM acc_accounts WHERE type = 'equity' AND parent_id IS NOT NULL ORDER BY code ASC")->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['view']) && $_GET['view'] === 'vat_report') {
|
||||||
|
$start = $_GET['start_date'] ?? date('Y-m-01');
|
||||||
|
$end = $_GET['end_date'] ?? date('Y-m-d');
|
||||||
|
$data['vat_report'] = getVatReport($start, $end);
|
||||||
|
$data['start_date'] = $start;
|
||||||
|
$data['end_date'] = $end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['view']) && $_GET['view'] === 'coa') {
|
||||||
|
$data['coa'] = db()->query("SELECT a.*, p.name_en as parent_name
|
||||||
|
FROM acc_accounts a
|
||||||
|
LEFT JOIN acc_accounts p ON a.parent_id = p.id
|
||||||
|
ORDER BY a.code ASC")->fetchAll();
|
||||||
|
}
|
||||||
363
pages/accounting_view.php
Normal file
363
pages/accounting_view.php
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
<div class="card p-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4 d-print-none">
|
||||||
|
<h5 class="m-0"><i class="fas fa-calculator me-2"></i> <span data-en="Accounting Module" data-ar="وحدة المحاسبة">Accounting Module</span></h5>
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<form method="POST" onsubmit="return confirm('This will re-calculate all automatic journal entries from scratch. Continue?')">
|
||||||
|
<button type="submit" name="sync_accounting" class="btn btn-outline-warning">
|
||||||
|
<i class="bi bi-arrow-repeat"></i> <span data-en="Sync All" data-ar="مزامنة الكل">Sync All</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#addManualJournalModal">
|
||||||
|
<i class="bi bi-plus-lg"></i> <span data-en="Manual Entry" data-ar="قيد يدوي">Manual Entry</span>
|
||||||
|
</button>
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="index.php?page=accounting" class="btn <?= !isset($_GET['view']) ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="Journal" data-ar="اليومية">Journal</a>
|
||||||
|
<a href="index.php?page=accounting&view=coa" class="btn <?= isset($_GET['view']) && $_GET['view'] === 'coa' ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="Accounts" data-ar="الحسابات">Accounts</a>
|
||||||
|
<a href="index.php?page=accounting&view=trial_balance" class="btn <?= isset($_GET['view']) && $_GET['view'] === 'trial_balance' ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="Trial Balance" data-ar="ميزان المراجعة">Trial Balance</a>
|
||||||
|
<a href="index.php?page=accounting&view=profit_loss" class="btn <?= isset($_GET['view']) && $_GET['view'] === 'profit_loss' ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="P&L" data-ar="الأرباح">P&L</a>
|
||||||
|
<a href="index.php?page=accounting&view=balance_sheet" class="btn <?= isset($_GET['view']) && $_GET['view'] === 'balance_sheet' ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="Balance Sheet" data-ar="الميزانية">Balance Sheet</a>
|
||||||
|
<a href="index.php?page=accounting&view=vat_report" class="btn <?= isset($_GET['view']) && $_GET['view'] === 'vat_report' ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="VAT Report" data-ar="تقرير الضريبة">VAT Report</a>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-outline-secondary" onclick="window.print()">
|
||||||
|
<i class="bi bi-printer"></i> <span data-en="Print" data-ar="طباعة">Print</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-none d-print-block mb-4">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<h3 class="mb-0"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?></h3>
|
||||||
|
<p class="text-muted small"><?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?></p>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 text-end">
|
||||||
|
<h2 class="text-uppercase text-muted"><?= isset($_GET['view']) ? ucwords(str_replace('_', ' ', $_GET['view'])) : 'Journal' ?></h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (!isset($_GET['view'])): ?>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th data-en="Date" data-ar="التاريخ">Date</th>
|
||||||
|
<th data-en="Description" data-ar="الوصف">Description</th>
|
||||||
|
<th data-en="Reference" data-ar="المرجع">Reference</th>
|
||||||
|
<th data-en="Amount" data-ar="المبلغ">Amount</th>
|
||||||
|
<th data-en="Action" data-ar="الإجراء">Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($data['journal_entries'] as $entry): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= $entry['entry_date'] ?></td>
|
||||||
|
<td><?= htmlspecialchars($entry['description']) ?></td>
|
||||||
|
<td><span class="badge bg-secondary"><?= htmlspecialchars($entry['reference']) ?></span></td>
|
||||||
|
<td><?= number_format((float)$entry['total_debit'], 3) ?></td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-sm btn-outline-info" onclick="viewJournalEntry(<?= $entry['id'] ?>)">
|
||||||
|
<i class="bi bi-eye"></i> <span data-en="View" data-ar="عرض">View</span>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<?= renderPagination($data['current_page'] ?? 1, $data['total_pages'] ?? 1) ?>
|
||||||
|
|
||||||
|
<?php elseif ($_GET['view'] === 'coa'): ?>
|
||||||
|
<div class="d-flex justify-content-end mb-3">
|
||||||
|
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addAccountModal">
|
||||||
|
<i class="bi bi-plus-lg"></i> <span data-en="Add Account" data-ar="إضافة حساب">Add Account</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th data-en="Code" data-ar="الكود">Code</th>
|
||||||
|
<th data-en="Name" data-ar="الاسم">Name</th>
|
||||||
|
<th data-en="Type" data-ar="النوع">Type</th>
|
||||||
|
<th data-en="Parent" data-ar="الحساب الأب">Parent</th>
|
||||||
|
<th data-en="Balance" data-ar="الرصيد" class="text-end">Balance</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($data['coa'] as $acc): ?>
|
||||||
|
<tr>
|
||||||
|
<td class="fw-bold"><?= $acc['code'] ?></td>
|
||||||
|
<td>
|
||||||
|
<?= htmlspecialchars($acc['name_en']) ?><br>
|
||||||
|
<small class="text-muted"><?= htmlspecialchars($acc['name_ar']) ?></small>
|
||||||
|
</td>
|
||||||
|
<td><span class="badge bg-light text-dark border text-uppercase"><?= $acc['type'] ?></span></td>
|
||||||
|
<td><?= htmlspecialchars($acc['parent_name'] ?? '---') ?></td>
|
||||||
|
<td class="text-end fw-bold"><?= number_format(getAccountBalance($acc['code']), 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<?= renderPagination($data['current_page'] ?? 1, $data['total_pages'] ?? 1) ?>
|
||||||
|
|
||||||
|
|
||||||
|
<?php elseif ($_GET['view'] === 'vat_report'): ?>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mx-auto">
|
||||||
|
<div class="bg-light p-3 rounded mb-4 d-print-none">
|
||||||
|
<form method="GET" class="row g-2">
|
||||||
|
<input type="hidden" name="page" value="accounting">
|
||||||
|
<input type="hidden" name="view" value="vat_report">
|
||||||
|
<div class="col">
|
||||||
|
<input type="date" name="start_date" class="form-control" value="<?= $data['start_date'] ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<input type="date" name="end_date" class="form-control" value="<?= $data['end_date'] ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<button type="submit" class="btn btn-primary" data-en="Filter" data-ar="تصفية">Filter</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="card shadow-sm border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4 class="text-center mb-4 d-print-none">VAT Summary Report</h4>
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<th data-en="VAT Input (Purchases)" data-ar="ضريبة المدخلات (المشتريات)">VAT Input (Purchases)</th>
|
||||||
|
<td class="text-end text-success fw-bold"><?= number_format($data['vat_report']['input_vat'], 2) ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th data-en="VAT Output (Sales)" data-ar="ضريبة المخرجات (المبيعات)">VAT Output (Sales)</th>
|
||||||
|
<td class="text-end text-danger fw-bold"><?= number_format($data['vat_report']['output_vat'], 2) ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr class="table-dark h5">
|
||||||
|
<th data-en="Net VAT Payable / (Refundable)" data-ar="صافي الضريبة المستحقة / (المستردة)">Net VAT Payable / (Refundable)</th>
|
||||||
|
<td class="text-end"><?= number_format($data['vat_report']['net_vat'], 2) ?></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div class="alert alert-info small mt-3">
|
||||||
|
<i class="bi bi-info-circle me-1"></i>
|
||||||
|
This report calculates the difference between VAT collected on sales and VAT paid on purchases for the selected period.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php elseif ($_GET['view'] === 'trial_balance'): ?>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th data-en="Code" data-ar="الكود">Code</th>
|
||||||
|
<th data-en="Account Name" data-ar="اسم الحساب">Account Name</th>
|
||||||
|
<th class="text-end" data-en="Debit" data-ar="مدين">Debit</th>
|
||||||
|
<th class="text-end" data-en="Credit" data-ar="دائن">Credit</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
$total_d = 0; $total_c = 0;
|
||||||
|
foreach ($data['trial_balance'] as $row):
|
||||||
|
$total_d += (float)$row['total_debit'];
|
||||||
|
$total_c += (float)$row['total_credit'];
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td><?= $row['code'] ?></td>
|
||||||
|
<td><?= htmlspecialchars($row['name_en']) ?></td>
|
||||||
|
<td class="text-end"><?= number_format((float)$row['total_debit'], 3) ?></td>
|
||||||
|
<td class="text-end"><?= number_format((float)$row['total_credit'], 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
<tfoot class="table-light fw-bold">
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" class="text-end" data-en="Total" data-ar="الإجمالي">Total</td>
|
||||||
|
<td class="text-end"><?= number_format($total_d, 3) ?></td>
|
||||||
|
<td class="text-end"><?= number_format($total_c, 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<?php elseif ($_GET['view'] === 'profit_loss'): ?>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8 mx-auto">
|
||||||
|
<div class="card bg-light">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4 class="text-center mb-4 d-print-none" data-en="Profit & Loss Statement" data-ar="قائمة الأرباح والخسائر">Profit & Loss Statement</h4>
|
||||||
|
<table class="table">
|
||||||
|
<tr class="table-primary"><th colspan="2" data-en="Revenue" data-ar="الإيرادات">Revenue</th></tr>
|
||||||
|
<?php
|
||||||
|
$total_rev = 0;
|
||||||
|
foreach ($data['revenue_accounts'] as $acc):
|
||||||
|
$bal = getAccountBalance($acc['code']);
|
||||||
|
if ($bal == 0) continue;
|
||||||
|
$total_rev += $bal;
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($acc['name_en']) ?></td>
|
||||||
|
<td class="text-end"><?= number_format($bal, 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<tr class="fw-bold">
|
||||||
|
<td data-en="Total Revenue" data-ar="إجمالي الإيرادات">Total Revenue</td>
|
||||||
|
<td class="text-end border-top"><?= number_format($total_rev, 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="table-warning"><th colspan="2" class="pt-4" data-en="Expenses" data-ar="المصروفات">Expenses</th></tr>
|
||||||
|
<?php
|
||||||
|
$total_exp = 0;
|
||||||
|
foreach ($data['expense_accounts'] as $acc):
|
||||||
|
$bal = getAccountBalance($acc['code']);
|
||||||
|
if ($bal == 0) continue;
|
||||||
|
$total_exp += $bal;
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($acc['name_en']) ?></td>
|
||||||
|
<td class="text-end"><?= number_format($bal, 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<tr class="fw-bold">
|
||||||
|
<td data-en="Total Expenses" data-ar="إجمالي المصروفات">Total Expenses</td>
|
||||||
|
<td class="text-end border-top"><?= number_format($total_exp, 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="table-success h4">
|
||||||
|
<td data-en="Net Profit / Loss" data-ar="صافي الربح / الخسارة">Net Profit / Loss</td>
|
||||||
|
<td class="text-end"><?= number_format($total_rev - $total_exp, 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php elseif ($_GET['view'] === 'balance_sheet'): ?>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-10 mx-auto">
|
||||||
|
<div class="card bg-light">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4 class="text-center mb-4 d-print-none" data-en="Balance Sheet" data-ar="الميزانية العمومية">Balance Sheet</h4>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 border-end">
|
||||||
|
<h5 class="text-primary border-bottom pb-2" data-en="Assets" data-ar="الأصول">Assets</h5>
|
||||||
|
<table class="table table-sm">
|
||||||
|
<?php
|
||||||
|
$total_assets = 0;
|
||||||
|
foreach ($data['asset_accounts'] as $acc):
|
||||||
|
$bal = getAccountBalance($acc['code']);
|
||||||
|
if ($bal == 0) continue;
|
||||||
|
$total_assets += $bal;
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($acc['name_en']) ?></td>
|
||||||
|
<td class="text-end"><?= number_format($bal, 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<tr class="fw-bold h5">
|
||||||
|
<td data-en="Total Assets" data-ar="إجمالي الأصول">Total Assets</td>
|
||||||
|
<td class="text-end border-top"><?= number_format($total_assets, 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h5 class="text-danger border-bottom pb-2" data-en="Liabilities & Equity" data-ar="الالتزامات وحقوق الملكية">Liabilities & Equity</h5>
|
||||||
|
<table class="table table-sm">
|
||||||
|
<tr class="bg-light"><td colspan="2" class="small fw-bold text-muted">Liabilities</td></tr>
|
||||||
|
<?php
|
||||||
|
$total_liab = 0;
|
||||||
|
foreach ($data['liability_accounts'] as $acc):
|
||||||
|
$bal = getAccountBalance($acc['code']);
|
||||||
|
if ($bal == 0) continue;
|
||||||
|
$total_liab += $bal;
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($acc['name_en']) ?></td>
|
||||||
|
<td class="text-end"><?= number_format($bal, 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<tr class="bg-light"><td colspan="2" class="small fw-bold text-muted pt-3">Equity</td></tr>
|
||||||
|
<?php
|
||||||
|
$total_equity = 0;
|
||||||
|
foreach ($data['equity_accounts'] as $acc):
|
||||||
|
$bal = getAccountBalance($acc['code']);
|
||||||
|
if ($bal == 0) continue;
|
||||||
|
$total_equity += $bal;
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($acc['name_en']) ?></td>
|
||||||
|
<td class="text-end"><?= number_format($bal, 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
// Current Year Earnings (Revenue - Expenses)
|
||||||
|
$rev = 0; foreach(db()->query("SELECT code FROM acc_accounts WHERE type='revenue' AND parent_id IS NOT NULL")->fetchAll() as $a) $rev += getAccountBalance($a['code']);
|
||||||
|
$exp = 0; foreach(db()->query("SELECT code FROM acc_accounts WHERE type='expense' AND parent_id IS NOT NULL")->fetchAll() as $a) $exp += getAccountBalance($a['code']);
|
||||||
|
$earnings = $rev - $exp;
|
||||||
|
$total_equity += $earnings;
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td data-en="Retained Earnings (Current)" data-ar="الأرباح المحتجزة (الحالية)">Retained Earnings (Current)</td>
|
||||||
|
<td class="text-end"><?= number_format($earnings, 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="fw-bold h5 pt-3">
|
||||||
|
<td data-en="Total Liab. & Equity" data-ar="إجمالي الالتزامات وحقوق الملكية">Total Liab. & Equity</td>
|
||||||
|
<td class="text-end border-top"><?= number_format($total_liab + $total_equity, 3) ?></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Journal Entry Details Modal -->
|
||||||
|
<div class="modal fade" id="journalModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" data-en="Journal Entry Details" data-ar="تفاصيل قيد اليومية">Journal Entry Details</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th data-en="Account" data-ar="الحساب">Account</th>
|
||||||
|
<th class="text-end" data-en="Debit" data-ar="مدين">Debit</th>
|
||||||
|
<th class="text-end" data-en="Credit" data-ar="دائن">Credit</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="journalDetailsBody"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function viewJournalEntry(id) {
|
||||||
|
fetch('index.php?page=accounting&action=get_entry_details&id=' + id)
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
let html = '';
|
||||||
|
data.forEach(row => {
|
||||||
|
html += `<tr>
|
||||||
|
<td>${row.code} - ${row.name_en}</td>
|
||||||
|
<td class="text-end">${parseFloat(row.debit).toFixed(3)}</td>
|
||||||
|
<td class="text-end">${parseFloat(row.credit).toFixed(3)}</td>
|
||||||
|
</tr>`;
|
||||||
|
});
|
||||||
|
document.getElementById('journalDetailsBody').innerHTML = html;
|
||||||
|
new bootstrap.Modal(document.getElementById('journalModal')).show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -52,3 +52,12 @@
|
|||||||
2026-03-17 17:47:27 - POST: {"id":"7","name_en":"Tomato","name_ar":"\u0637\u0645\u0627\u0637\u0645","sku":"241604476040","category_id":"3","unit_id":"5","supplier_id":"","sale_price":"0.25","purchase_price":"0.2","vat_rate":"0.00","stock_quantity":"0","min_stock_level":"0","promotion_start":"","promotion_end":"","promotion_percent":"0","edit_item":""}
|
2026-03-17 17:47:27 - POST: {"id":"7","name_en":"Tomato","name_ar":"\u0637\u0645\u0627\u0637\u0645","sku":"241604476040","category_id":"3","unit_id":"5","supplier_id":"","sale_price":"0.25","purchase_price":"0.2","vat_rate":"0.00","stock_quantity":"0","min_stock_level":"0","promotion_start":"","promotion_end":"","promotion_percent":"0","edit_item":""}
|
||||||
2026-03-17 18:07:32 - POST: {"action":"save_pos_transaction","customer_id":"","payments":"[{\"method\":\"cash\",\"amount\":0.25}]","total_amount":"0.25","tax_amount":"0","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":7,\"qty\":1,\"price\":0.25,\"vat_rate\":0,\"vat_amount\":0}]"}
|
2026-03-17 18:07:32 - POST: {"action":"save_pos_transaction","customer_id":"","payments":"[{\"method\":\"cash\",\"amount\":0.25}]","total_amount":"0.25","tax_amount":"0","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":7,\"qty\":1,\"price\":0.25,\"vat_rate\":0,\"vat_amount\":0}]"}
|
||||||
2026-03-17 18:14:21 - POST: {"action":"save_pos_transaction","customer_id":"","payments":"[{\"method\":\"cash\",\"amount\":0.25}]","total_amount":"0.25","tax_amount":"0","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":7,\"qty\":1,\"price\":0.25,\"vat_rate\":0,\"vat_amount\":0}]"}
|
2026-03-17 18:14:21 - POST: {"action":"save_pos_transaction","customer_id":"","payments":"[{\"method\":\"cash\",\"amount\":0.25}]","total_amount":"0.25","tax_amount":"0","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":7,\"qty\":1,\"price\":0.25,\"vat_rate\":0,\"vat_amount\":0}]"}
|
||||||
|
2026-03-18 02:00:56 - POST: {"action":"save_theme","theme":"ocean"}
|
||||||
|
2026-03-18 02:01:01 - POST: {"action":"save_theme","theme":"sunset"}
|
||||||
|
2026-03-18 02:01:26 - POST: {"action":"save_theme","theme":"citrus"}
|
||||||
|
2026-03-18 02:01:29 - POST: {"action":"save_theme","theme":"default"}
|
||||||
|
2026-03-18 02:31:31 - POST: {"action":"save_theme","theme":"sunset"}
|
||||||
|
2026-03-18 02:31:34 - POST: {"action":"save_theme","theme":"ocean"}
|
||||||
|
2026-03-18 02:31:37 - POST: {"action":"save_theme","theme":"default"}
|
||||||
|
2026-03-18 02:31:40 - POST: {"action":"save_theme","theme":"sunset"}
|
||||||
|
2026-03-18 02:31:50 - POST: {"action":"save_theme","theme":"default"}
|
||||||
|
|||||||
24
test_accounting_page.php
Normal file
24
test_accounting_page.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
// Mock session
|
||||||
|
session_start();
|
||||||
|
$_SESSION['user_id'] = 1;
|
||||||
|
$_SESSION['user_role_name'] = 'Administrator';
|
||||||
|
$_SESSION['user_permissions'] = 'all';
|
||||||
|
|
||||||
|
// Simulate GET request
|
||||||
|
$_GET['page'] = 'accounting';
|
||||||
|
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||||
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||||
|
$_SERVER['HTTPS'] = 'on';
|
||||||
|
|
||||||
|
// Capture output
|
||||||
|
ob_start();
|
||||||
|
try {
|
||||||
|
require 'index.php';
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo "\nFATAL ERROR: " . $e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine() . "\n";
|
||||||
|
}
|
||||||
|
$output = ob_get_clean();
|
||||||
|
|
||||||
|
file_put_contents('output_test.html', $output);
|
||||||
|
echo "Output saved to output_test.html (" . strlen($output) . " bytes)\n";
|
||||||
Loading…
x
Reference in New Issue
Block a user