Feature → Journal → Tax Forms / Financial Statements — Architecture Diagram
flowchart TB
subgraph SOURCE["📄 Source Documents"]
INV["Invoices (AR)"]
BILL["Bills (AP)
whtRate, whtAmount,
expensePeriod, taxPeriod"]
PAY["Payroll
calcMonthlyPIT"]
MAN["Manual Journal"]
BANK["Bank Transactions"]
end
subgraph JOURNAL["📒 Journal Entries (GL) — Single Source of Truth"]
direction TB
JE["<b>journal_entries</b>
sourceType: invoice/bill/payroll/manual
status: draft→posted
taxPeriod, isCrossMonth"]
JL["<b>journal_lines</b>
accountId → Chart of Accounts
debit / credit
vatRate/vatAmount
whtRate/whtAmount
costCenterId"]
JE -->|1:N| JL
end
subgraph ENGINES["🧮 Computation Engines"]
TE["tax-engine.ts
computePP30 / computePND1/3/53
computePP36 / computePor40"]
CIT["cit-rules.ts
12 Add-back Rules
CIT_ADD_BACK_RULES"]
BTR["book-tax-recon.ts
Build Book-Tax Differences"]
RE["ratio-engine.ts
Financial Ratios"]
EE["etax-engine.ts
validateForETax"]
end
subgraph REPORTS["📊 Financial Reports"]
TB["Trial Balance"]
WP["Working Paper"]
PL["P&L"]
BS["Balance Sheet"]
CF["Cash Flow"]
RATIO["Ratios"]
end
subgraph TAX["📋 Tax Forms"]
PP30["ภ.พ.30 VAT"]
PND3["ภ.ง.ด.3 WHT Indiv"]
PND53["ภ.ง.ด.53 WHT Corp"]
PND1["ภ.ง.ด.1 WHT Summary"]
PP36["ภ.พ.36 CIT Half-Yr"]
POR40["ภ.ย.40 CIT Annual"]
PND50["ภ.ง.ด.50 Annual WHT"]
end
subgraph SPECIAL["🔖 Special"]
ETAX["e-Tax Invoice/Receipt"]
WHTCERT["50 ทวิ Cert"]
HOTEL["ภ.ร.1/2 Hotel"]
MISC["ภ.บ.จ./ภ.ธ.
Misc"]
end
INV ==>|auto-post| JE
BILL ==>|auto-post| JE
PAY ==>|auto-post| JE
MAN ==>|sourceType manual| JE
BANK ==>|reconcile| JE
INV -.-> PP30
BILL -.-> PP30
BILL -.->|indiv vendor| PND3
BILL -.->|corp vendor| PND53
PND3 & PND53 -.-> PND1
JE ==>|journals wht lines| PND1
BILL -.-> PND50
JE ==>|revenue - expense - CIT| PP36
JE ==>|revenue - expense - CIT| POR40
JE & JL ==> PL
JE & JL ==> BS
JE & JL ==> CF
JE & JL ==> TB
TB & PL & BS ==> WP
JE & JL ==o RATIO
JE & JL & CIT ==> BTR
INV -.->|generate| ETAX
BILL -.->|group vendor| WHTCERT
style SOURCE fill:#e8f4f8,stroke:#2c7fa0
style JOURNAL fill:#f8d7da,stroke:#b33,stroke-width:3
style ENGINES fill:#fff3cd,stroke:#d4a02b
style REPORTS fill:#d4edda,stroke:#28a745
style TAX fill:#d1ecf1,stroke:#17a2b8
style SPECIAL fill:#d1ecf1,stroke:#6c757d
เอกสารต้นทางแต่ละประเภท → ส่งข้อมูลเข้าสู่ Journal Entries (GL)
โครงสร้างของ journal_entries และ journal_lines ที่เชื่อมโยงทุก Feature สู่ Tax Forms และ Reports
แผนภาพรวมการไหลของข้อมูลจากทุก Feature สู่ Journal Entries และปลายทางทั้งหมด
flowchart TD
subgraph DOCS["📦 Source Documents"]
Q["Quotations
(ใบเสนอราคา)"]
PO["Purchase Orders
(ใบสั่งซื้อ)"]
INV1["Invoices (AR)
subtotal, vatAmount"]
BILL1["Bills (AP)
whtRate, whtAmount,
expensePeriod, taxPeriod"]
PAY1["Payroll
salary, PIT, WHT"]
INV2["Inventory
Stock Movements"]
BANK1["Bank Statements"]
FA["Fixed Assets
Depreciation"]
VENDOR["Vendors / Customers
taxId, branch"]
end
Q -->|convert| INV1
PO -->|convert| BILL1
DOCS -.->|auto-post| JE1["📒 Journal Entries
Single Source of Truth
sourceType: invoice/bill/payroll/manual
status: draft→posted"]
BILL1 -.->|WHT individual| PND3_1["ภ.ง.ด.3"]
BILL1 -.->|WHT corporate| PND53_1["ภ.ง.ด.53"]
BILL1 & JE1 -.->|PND1 combine| PND1_1["ภ.ง.ด.1"]
BILL1 -.->|annual WHT| PND50_1["ภ.ง.ด.50"]
INV1 & BILL1 -.->|VAT| PP30_1["ภ.พ.30"]
JE1 ==>|CIT half-year| PP36_1["ภ.พ.36"]
JE1 ==>|CIT annual| POR40_1["ภ.ย.40"]
BILL1 & VENDOR -.->|cert| CERT1["50 ทวิ Cert"]
FA -.->|depreciation| DEP1["Depreciation Sched"]
BANK1 -.->|reconcile| RECON1["Bank Recon"]
INV2 -.->|valuation| IVAL1["Inventory Val"]
INV1 -.->|ETDA/RD| ETAX1["e-Tax Invoice"]
JE1 ==>|period filter| PL1["📊 P&L"]
JE1 ==>|as-of date| BS1["📊 Balance Sheet"]
JE1 ==>|activity class| CF1["📊 Cash Flow"]
JE1 ==>|all lines| TB1["📊 Trial Balance"]
TB1 & PL1 & BS1 ==> WP1["📊 Working Paper"]
PL1 & BS1 ==> RATIO1["📊 Ratios"]
style DOCS fill:#e8f4f8,stroke:#2c7fa0
style JE1 fill:#f8d7da,stroke:#b33,stroke-width:3
style PL1,BS1,CF1,TB1,WP1,RATIO1 fill:#d4edda,stroke:#28a745
style PP30_1,PND3_1,PND53_1,PND1_1,PND50_1,PP36_1,POR40_1 fill:#d1ecf1,stroke:#17a2b8
style ETAX1,CERT1 fill:#d1ecf1,stroke:#6c757d
รายละเอียดการคำนวณฟอร์มภาษีแต่ละประเภท — Source Data, Engine, Logic
Invoices (AR) — output VAT ฝั่งขาย
Bills (AP) — input VAT ฝั่งซื้อ
Vendors/Customers — taxId (export check)
computePP30(period, invoices, bills, vendors, customers)
outputVat = Σ invoice.vatAmount (filter: ไม่ใช่ void)
inputVatAllowed = Σ bill.vatAmount — forbidden (entertainment/gift)
vatPayable = outputVat — inputVatAllowed
Bills (AP) only — filter vendor.type = 'individual'
WHT สำหรับบุคคลธรรมดา (รับเหมา/บริการ/ค่าโฆษณา ฯลฯ)
computePND3(period, bills, vendors)
= computeWHTBase(period, bills, vendors, 'individual')
filter bills ในงวด where whtAmount > 0, vendor.type='individual'
จัดกลุ่มตาม IncomeType40 (1-6)
Bills (AP) only — filter vendor.type = 'corporate'
WHT สำหรับนิติบุคคล (ค่าจ้างทำของ/บริการ)
computePND53(period, bills, vendors)
= computeWHTBase(period, bills, vendors, 'corporate')
filter bills ในงวด where whtAmount > 0, vendor.type='corporate'
จัดกลุ่มตาม IncomeType40 (1-6)
Bills → PND3 + PND53 (sub-ledger)
Journal Entries (GL) → computeWHTFromJournals()
รวม payroll + manual WHT entries
computePND1(period, bills, vendors, branchId, journals)
1️⃣ computePND3() → pnd3
2️⃣ computePND53() → pnd53
3️⃣ computeWHTFromJournals() → journalWHT
4️⃣ Combine all breakdowns by IncomeType40
totalRemitted = pnd3.totalWht + pnd53.totalWht + journalWHT.wht
Journal Entries (GL) 100% — ครึ่งปี
ภ.พ.36 ยื่นภาษีเงินได้นิติบุคคลครึ่งปี (ภายใน 2 เดือนหลังรอบ 6 เดือน)
computePP36(year, half, journals, accounts, estimatedTaxPaid, manualAdjustments)
= computeCIT(year, 'mid_year', journals, accounts, half, ...)
journals → totalRevenue - totalExpense → accountingNetProfit
+ addBacks (CIT_ADD_BACK_RULES auto-detect)
- deductions
= taxNetProfit → calculateCITProgressive() → CIT Amount
Journal Entries (GL) 100% — รอบปี
computePor40(year, journals, accounts, exemptions, manualAdjustments, manualDeductions)
= computeCIT(year, 'annual', journals, accounts, undefined, 0, exemptions, ...)
เหมือน PP36 แต่ full year + exemptions
Bills (AP) only — รวบรวมทั้งปี
computePND50Annual(year, bills, vendors)
รวบรวมผู้ถูกหักภาษี ณ ที่จ่ายทั้งหมดในปี (ภ.ง.ด.50 ประจำปี)
Invoices (AR) + Customers + Company
generateETaxFromInvoice() → ETaxInvoicevalidateForETax() → ETaxValidation
Validation rules:
✅ customer.taxId = 13 digits
✅ customer.branch = 5 digits
✅ company.vatRegistered = true
✅ invoice.total > 0, lines > 0
simulateRDSubmission() → Mock RD Gateway
Tax Forms แต่ละประเภทใช้เส้นทางการคำนวณที่แตกต่างกัน—ขึ้นอยู่กับว่า Source Data อยู่ที่ใด
อ่านจาก Bills/Invoices โดยตรง (เร็วที่สุด—ไม่ต้อง query journals)
คำนวณจาก Journal Entries 100% — revenue, expense, add-backs
Sub-ledger + Journals — รวมผลลัพธ์จากทั้งสองเส้นทาง
กฎการบวกกลับสำหรับคำนวณกำไรทางภาษี — auto-detect จาก account code ใน journal lines
| Rule ID | รายการ (Thai) | Account Pattern | Auto? | กฎหมาย |
|---|---|---|---|---|
| AB-DEP-EXCESS | ค่าเสื่อมราคาเกินกว่าอัตราที่กฎหมายกำหนด | 15165010-5030 | Manual | มาตรา 18 ตรี |
| AB-ENTERTAINMENT | ค่ารับรอง/เลี้ยงรับรอง | 5220-5240 | ✅ Auto | มาตรา 65 ตรี (4) |
| AB-DONATION | เงินบริจาคเกิน 2% ของกำไรสุทธิ | 5310-5320 | Manual | มาตรา 65 ตรี (5) |
| AB-BAD-DEBT | หนี้สูญที่ตัดบัญชีโดยขาดหลักฐาน | 5410-5420 | Manual | มาตรา 65 |
| AB-PROVISIONS | ค่าเผื่อ/เงินสำรองที่หักไม่ได้ทางภาษี | 5440-5450 | ✅ Auto | มาตรา 65 |
| AB-AMORT-EXCESS | ค่าตัดจำหน่ายสินทรัพย์ไม่มีตัวตนเกิน | 5070-5080 | Manual | มาตรา 18 ตรี |
| AB-PENALTY | ค่าปรับและเบี้ยปรับ | 5500-5510 | ✅ Auto | มาตรา 65 ตรี (6) |
| AB-INTEREST-EXCESS | ดอกเบี้ยจ่ายเกินอัตราส่วนทุน | 5610-5620 | Manual | มาตรา 65 ตรี (5) |
| AB-CONTRIBUTION | เงินสมทบกองทุนสำรองเลี้ยงชีพเกิน 15% | 5520 | Manual | มาตรา 47 ทวิ |
| AB-LOSS-SALE | ขาดทุนจากการขายสินทรัพย์ | 5910 | ✅ Auto | มาตรา 18 ตรี |
| AB-RELATED-PARTY | รายการที่เกี่ยวข้องกันไม่เป็นไปตามราคาตลาด | — | Manual | มาตรา 65 ทวิ |
| AB-DEFERRED-INCOME | รายได้ที่ยังไม่เกิดขึ้นจริง | 4310-4320 | Manual | มาตรา 65 |
detectAdjustments(journalLineData) ← เปรียบเทียบ account.code กับ accountPatterns → ถ้า match → add-back
งบการเงินทั้ง 6 ประเภท — ทุก报告คำนวณจาก Journal Entries (GL) 100%
| Report | Function | Source | Filter Condition | Grouping Logic |
|---|---|---|---|---|
| 📊 P&L งบกำไรขาดทุน |
buildProfitLoss() |
journals | status=posted/approved date ∈ [periodStart, periodEnd] |
subCategory: operating_revenue, cost_of_sales, operating_expense, other_revenue, other_expense |
| 📊 Balance Sheet งบดุล |
buildBalanceSheet() |
journals | status=posted/approved date ≤ asOf |
category: asset=Dr-Cr, liability/equity=Cr-Dr subCategory: current_asset/fixed_asset... |
| 📊 Cash Flow งบกระแสเงินสด |
buildCashFlow() |
journals | status=posted/approved date ∈ [periodStart, periodEnd] |
subCategory: fixed_asset→investing long_term/equity→financing else→operating |
| 📊 Trial Balance งบทดลอง |
buildTrialBalance() |
journals | All journals | ทุก account → sum debit/credit |
| 📊 Working Paper กระดาษทำการ |
buildWorkingPaper() |
journals | TB → adjustments → adjusted TB | split rows to P&L / BS destination |
| 📊 Ratios อัตราส่วนทางการเงิน |
computeFinancialRatios() |
journals + accounts | balances + P&L totals | sumByPrefix(code) → current, D/E, ROA, ROE, DSO, DPO, DIO, CCC |
for each journal line:
net = debit - credit
if account.category == "asset" || "expense":
balance += net // Dr increases
else:
balance -= net // Cr increases
→ group by subCategory → current/fixed/other assets
→ section.total = sum(items) where balance ≠ 0
→ balanced = |totalAssets - (liabilities + equity)| < 1
for each journal line (period filter):
net = debit - credit
if account.category == "revenue":
balance -= net // Cr = income
else:
balance += net // Dr = expense
→ group by subCategory
→ revenue = Σ operating_revenue
→ cogs = Σ cost_of_sales
→ grossProfit = revenue - cogs
→ netProfit = grossProfit - expenses + otherIncome - otherExp
→ ebitda = operatingProfit + depreciation (acct code 55xx)
ทุก Feature → Tax Form / Financial Report ที่เกี่ยวข้อง
| Feature / Source | Auto-post → GL | Tax Forms ที่เกี่ยวข้อง | Financial Reports | บทบาทใน Journal |
|---|---|---|---|---|
| Invoices (AR) | ✅ | PP30PP36Por40e-Tax Invoice | P&L (revenue)BS (AR)Ratios (DSO) | sourceType='invoice' → output VAT, revenue |
| Bills (AP) | ✅ | PP30PND3/53PND1PND5050 ทวิ | P&L (cogs/exp)BS (AP)Ratios (DPO) | sourceType='bill' → input VAT, WHT, expense |
| Payroll | ✅ | PND1(via journals) | P&L (salary)BS (payable) | sourceType='payroll' → WHT §40(1) lines |
| Manual Journal | ✅ | PND1PP36Por40 | P&L / BS ใดๆ | sourceType='manual' — ปรับปรุง GL โดยตรง |
| Bank Transactions | ✅ (reconcile) | — | BS (cash)CF (operating) | reconcile → journal กระทบยอด |
| Fixed Assets | ✅ (depr.) | PP36/Por40 (add-back) | BS (fixed asset)P&L (depreciation) | ค่าเสื่อม → expense → CIT add-back |
| Inventory | ✅ (COGS) | — | P&L (COGS)BS (inventory)Ratios (DIO) | COGS → expense, stock → asset |
ทุก Tax Form ผ่านสถานะเดียวกัน — draft → ready → reviewing → approved → filed → acknowledged
stateDiagram-v2
[*] --> draft : create
draft --> ready : prepare / compute
ready --> reviewing : submit
reviewing --> approved : senior approve
reviewing --> rejected : reject
rejected --> ready : revise & resubmit
approved --> filed : file (paper or e-Filing)
filed --> acknowledged : receive RD number
acknowledged --> [*]
note right of filed
e-Filing: stub — awaiting RD Gateway
end note
Engines ทั้งหมดใน packages/shared/src/accounting/ — แยกตามหน้าที่