অধ্যায় ১৫ — Purchase
Volume 1 · Part 2 — Core Business Accounting · Chapter 15
পূর্বশর্ত: অধ্যায় ১৩ (Sales ও Revenue), অধ্যায় ১৪ (Accounts Receivable), অধ্যায় ৩ (পাঁচ প্রকার Account)
১. Learning Objective
এই অধ্যায় শেষে আপনি পারবেন:
Purchase-কে sales-এর আয়না হিসেবে দেখতে — কোথায় একই, কোথায় আলাদা
Supplier bill থেকে entry লিখতে: খরচ, asset, না inventory — তা ঠিক করতে
Input VAT (VAT Receivable) কেন asset, আর output VAT-এর সাথে তার সম্পর্ক বলতে
Withholding tax (TDS) — supplier-কে কম দিয়ে সরকারকে দেওয়া — entry লিখতে
Bill date, receipt date, posting date — তিনটি তারিখ আলাদা করতে
Supplier-এর bill নম্বর দিয়ে duplicate bill আটকাতে
নগদ ক্রয়, বাকিতে ক্রয়, advance to supplier — তিনটির entry লিখতে
Purchase order → goods receipt → bill — three-way match-এর ধারণা বুঝতে (বিস্তারিত অধ্যায় ২৮)
Purchase register ও VAT input report তৈরি করতে, GL-এর সাথে মেলাতে
Purchase invoice-এর posting rule লিখতে যা sales-এর rule-এর সাথে একই কাঠামোয়সময়: পড়া ৪৫ মিনিট + অনুশীলন ৫০ মিনিট।
২. Concept Explanation
আয়না
অধ্যায় ১৩ ও ১৪ পুরোটা এক দিক থেকে — আপনি বিক্রেতা। এবার ক্রেতা। প্রতিটি নিয়ম একই থাকে, শুধু দিক উল্টে যায়:
SALES (অধ্যায় ১৩–১৪) PURCHASE (অধ্যায় ১৫–১৬)
───────────────────── ────────────────────────
invoice আপনি লেখেন bill supplier লেখেন
নম্বর আপনার, gapless নম্বর তার, আপনার নিয়ন্ত্রণে নয়
Cr Revenue Dr Expense / Asset / Inventory
Cr VAT Payable (2140) Dr VAT Receivable (1160)
Dr A/R [গ্রাহক] (1130) Cr A/P [supplier] (2110)
receipt payment
settlement discount allowed settlement discount received
customer advance (liability) advance to supplier (asset)
credit note (আপনি দেন) debit note (আপনি দেন) — অধ্যায় ১৯
aging: কে কত দেবে aging: কাকে কত দিতে হবেDeveloper-এর দৃষ্টিতে: এটাই অধ্যায় ১৩-এর Developer Challenge-এর ৪ নম্বর — posting rule এমনভাবে লেখা যাতে একই কোড দিক উল্টে চলে। এই অধ্যায়ে সেটা করে দেখাব।
Bill-এ Dr কোথায় — তিনটি প্রশ্ন
Sales-এ credit পাশ সবসময় revenue। Purchase-এ debit পাশটা তিন রকম হতে পারে, আর এটাই এই অধ্যায়ের প্রধান সিদ্ধান্ত:
কী কিনলেন?
│
├── এখনই ব্যবহার হয়ে যায় (ভাড়া, বিদ্যুৎ, internet, বেতন)
│ → EXPENSE (5xxx) Income Statement-এ, এই মাসে
│
├── বহু বছর ব্যবহার হবে (laptop, গাড়ি, আসবাব)
│ → ASSET (15xx) Balance Sheet-এ, মাসে মাসে অবচয় (অধ্যায় ৩০)
│
└── আবার বিক্রি করবেন (দোকানের মাল, কাঁচামাল)
→ INVENTORY (114x) Balance Sheet-এ, বিক্রির সময় খরচ (অধ্যায় ২৭)অধ্যায় ৩-এর প্রকার এখানে সরাসরি কাজে লাগছে। ভুল করলে কী হয়:
laptop-কে expense লিখলে এ মাসে ৩,৬০,০০০ খরচ, লাভ ধসে গেল,
পরের ৩ বছর laptop "বিনামূল্যে"
ভাড়াকে asset লিখলে খরচ লুকাল, লাভ ফুললসিদ্ধান্তটা item master-এ থাকে (items.purchase_account_id), sales-এর revenue_account_id-র মতো — ব্যবহারকারী প্রতিবার বাছেন না। তবে asset-এর জন্য একটা capitalization threshold থাকে: ৫,০০০ টাকার mouse asset নয়, expense — নীতি হিসেবে (অধ্যায় ৩০)।
Input VAT — এবার আপনার পাওনা
Supplier ৮,০০০ টাকার internet-এ ১,২০০ VAT ধরল। এই ১,২০০ আপনার খরচ নয় — সরকারের কাছে আপনার পাওনা, যা output VAT থেকে বাদ যাবে:
Dr 5240 Internet & Telephone 8,000 ← খরচ, net
Dr 1160 VAT Receivable 1,200 ← asset
Cr 2110 A/P [ISP] 9,200মাস শেষে:
output VAT (2140, বিক্রিতে সংগ্রহ) 86,400
input VAT (1160, ক্রয়ে দেওয়া) 37,200
──────
সরকারকে দেওয়ার 49,200 (অধ্যায় ৫৫)শর্ত: input VAT claim করতে supplier-এর বৈধ VAT invoice লাগে। না থাকলে VAT-টা খরচের অংশ (Dr 5240 ৯,২০০)। তাই bill-এ একটা পতাকা: vat_claimable।
Withholding tax — supplier-কে কম, সরকারকে বাকিটা
কিছু payment-এ আইন বলে: supplier-কে পুরোটা দিও না, একটা অংশ কেটে সরকারকে দাও (Tax Deducted at Source)। ভাড়া ৬৫,০০০, TDS ৫%:
Dr 5220 Office Rent 65,000 ← খরচ পুরোটা
Cr 2150 TDS Payable 3,250 ← সরকারের কাছে দেনা
Cr 2110 A/P [বাড়িওয়ালা] 61,750 ← supplier-এর কাছে দেনাখরচ ৬৫,০০০-ই — TDS supplier-এর tax, আপনার নয়; আপনি শুধু সংগ্রাহক (output VAT-এর মতো)। Supplier পান ৬১,৭৫০ + একটা certificate। বিস্তারিত অধ্যায় ৫৬; এখন শুধু কাঠামো: bill-এর credit পাশ দুই ভাগে ভাঙতে পারে।
তিনটি তারিখ
Sales-এ invoice date আপনি ঠিক করেন। Purchase-এ:
bill_date supplier যেদিন bill লিখেছেন ২৮ সেপ্টেম্বর
received_date আপনার হাতে যেদিন এল ০৬ অক্টোবর
posting_date খাতায় যেদিন বসবে ?
service period খরচটা কোন মাসের সেপ্টেম্বরকোনটা posting_date? যে মাসের খরচ, সেই মাস — যদি period খোলা থাকে। সেপ্টেম্বরের bill অক্টোবরে এলে সেপ্টেম্বরে post (অধ্যায় ১৭-এর matching নীতি)। সেপ্টেম্বর বন্ধ হয়ে গেলে অক্টোবরে post, আর সেটা মেনে নেওয়া — অথবা সেপ্টেম্বরে accrual করা ছিল (অধ্যায় ১৮)।
VAT-এর জন্য আলাদা নিয়ম: input VAT claim হয় bill_date-এর মাসে (দেশভেদে received_date)। তাই bill-এ দুটো তারিখই রাখতে হয়, আর VAT report bill_date দিয়ে, expense report posting_date দিয়ে।
Duplicate bill — নম্বর আপনার নয়
Sales-এ gapless নম্বর আপনি দেন। Purchase-এ নম্বর supplier-এর — আর তারা একই bill দুবার পাঠায়: email-এ একবার, কাগজে একবার, “reminder” হিসেবে আরেকবার। দুবার post হলে দুবার payment হয়, আর supplier চুপ থাকেন।
সমাধান database-এ:
UNIQUE (company_id, supplier_id, supplier_bill_no)তিনটি সূক্ষ্মতা:
১. নম্বর normalize করুন — "INV-0042", "inv 42", "0042" এক
২. supplier-ধরে unique, সারা company-তে নয় — দুই supplier-এর
bill নম্বর 42 হতেই পারে
৩. নম্বর নেই (রসিদ, নগদ)? → bill_date + amount + supplier দিয়ে
সতর্কতা, block নয়নগদ ক্রয় ও advance
নগদ ক্রয় — bill আর payment একই মুহূর্তে (card, নগদ, online):
Dr 5120 Cloud & Hosting 25,000
Cr 1120 Bank 25,000A/P স্পর্শ হয় না — অধ্যায় ১৩-এর cash sale-এর আয়না। বিদেশি supplier হলে VAT-এর একটা আলাদা গল্প আছে (reverse charge) — অধ্যায় ৫৫।
Advance to supplier — কাজের আগে টাকা, bill পরে:
Dr 1140 Advance to Supplier 40,000 ← ASSET (supplier আপনাকে দেবে: সেবা)
Cr 1120 Bank 40,000
bill এলে (অধ্যায় ১৯):
Dr 5xxx Expense 40,000
Cr 1140 Advance to Supplier 40,000Customer advance ছিল liability; supplier advance asset — আয়না।
PO → GRN → Bill — three-way match
বড় ক্রয়ে bill-ই শুরু নয়:
Purchase Order আপনি চাইলেন: ৩টা laptop, ১,২০,০০০ করে
│
▼
Goods Receipt (GRN) এল: ৩টা, ১০ অক্টোবর ← এখানে দেনা জন্মায়
│
▼
Supplier Bill bill এল: ৩টা, ১,২০,০০০ করে ← এখানে A/P বসেThree-way match: PO-র পরিমাণ ও দর == GRN-এর পরিমাণ == bill-এর পরিমাণ ও দর। না মিললে bill আটকে যায়। মাল এসেছে কিন্তু bill আসেনি — মাঝের সময়টার জন্য একটা account (GRNI — Goods Received Not Invoiced) — অধ্যায় ২৮।
এই অধ্যায়ে bill-ভিত্তিক পথটাই: bill এলে entry। ছোট প্রতিষ্ঠান ও সব সেবা-ক্রয়ে এটাই যথেষ্ট।
Bill-এর জীবনচক্র
DRAFT / RECEIVED হাতে এসেছে, যাচাই হচ্ছে
│
▼
APPROVED কে অনুমোদন দিলেন — bill ঠিক, খরচ বৈধ
│
▼
POSTED journal entry, A/P-এ দেনা
│
▼
PARTIALLY PAID ──▶ PAID (অধ্যায় ১৬)
│
└──▶ CANCELLED / debit note (অধ্যায় ১৯)Sales-এর সাথে একটা পার্থক্য: approval ধাপটা এখানে বাধ্যতামূলক — কারণ bill-টা বাইরে থেকে এসেছে, আর post মানে “আমরা এই টাকা দেব”। কে কত টাকার bill অনুমোদন দিতে পারেন — সেটা অধ্যায় ৪১ ও ৪৮।
৩. Accounting Rule
Entry
| ঘটনা | Debit | Credit |
|---|---|---|
| বাকিতে ক্রয় (খরচ) | Expense (net), VAT Receivable | A/P [supplier] |
| বাকিতে ক্রয় (asset) | Fixed Asset (net), VAT Receivable | A/P [supplier] |
| বাকিতে ক্রয় (inventory) | Inventory (net), VAT Receivable | A/P [supplier] |
| TDS সহ | Expense (পুরো) | TDS Payable, A/P [supplier] (নিট) |
| নগদ ক্রয় | Expense/Asset, VAT Receivable | Cash/Bank |
| Advance to supplier | Advance to Supplier | Bank |
| Payment (অধ্যায় ১৬) | A/P [supplier] | Bank |
Dr কোথায়
এখনই ব্যবহার → Expense (5xxx)
বহু বছর → Asset (15xx), threshold-এর উপরে
আবার বিক্রি → Inventory (114x)
সিদ্ধান্ত item master-এ, bill-এ copyVAT
input VAT → 1160 VAT Receivable (ASSET), বৈধ VAT invoice থাকলে
নইলে → খরচের অংশ
claim মাস → bill_date (দেশভেদে received_date)তারিখ
posting_date = খরচের মাস (period খোলা থাকলে), নইলে খোলা period
bill_date = VAT-এর জন্য
দুটোই সংরক্ষণDuplicate
UNIQUE (company_id, supplier_id, normalize(supplier_bill_no))অলঙ্ঘনীয়
Post মানে "আমরা দেব" — তাই post-এর আগে অনুমোদন।৪. Real Business Example
অক্টোবর ২০২৫ — ক্রয়ের মাস
একই company। প্রতিটিতে প্রথম প্রশ্ন: Dr কোথায় — expense, asset, না inventory?
০১-১০ — বাড়িওয়ালার ভাড়ার bill, অক্টোবর, ৬৫,০০০; TDS ৫%; VAT নেই (ব্যক্তি)
Dr কোথায়? এ মাসেই ব্যবহার → Expense
PB-10-0001 (supplier bill: "Oct-2025", বাড়িওয়ালা)
Dr 5220 Office Rent 65,000
Cr 2150 TDS Payable 3,250
Cr 2110 A/P [বাড়িওয়ালা] 61,750০৬-১০ — ISP-র bill, সেপ্টেম্বরের internet, ৮,০০০ + VAT ১,২০০; bill_date ২৮-০৯
Dr কোথায়? Expense
কোন মাস? সেপ্টেম্বর — খোলা আছে (এখনো বন্ধ হয়নি)
PB-10-0002 (supplier bill: "INV-88213", ISP)
posting_date 30-09, bill_date 28-09, received 06-10
Dr 5240 Internet & Telephone 8,000
Dr 1160 VAT Receivable 1,200
Cr 2110 A/P [ISP] 9,200সেপ্টেম্বরের খরচ সেপ্টেম্বরে গেল — যদিও bill অক্টোবরে এসেছে। সেপ্টেম্বরের Income Statement এখন আবার বদলাল; এটা স্বাভাবিক যতক্ষণ period খোলা (অধ্যায় ২৬, ৪২)।
১০-১০ — ৩টা laptop, ১,২০,০০০ করে + VAT, টেক সাপ্লাই থেকে
Dr কোথায়? ৩ বছর ব্যবহার, threshold-এর অনেক উপরে → Asset
PB-10-0003 (supplier bill: "TS/2025/1190")
Dr 1510 Computer Equipment 3,60,000
Dr 1160 VAT Receivable 54,000
Cr 2110 A/P [টেক সাপ্লাই] 4,14,000Income Statement-এ কিছুই না — ৩,৬০,০০০ Balance Sheet-এ asset। নভেম্বর থেকে মাসে ১০,০০০ অবচয় (অধ্যায় ৩০)।
১৫-১০ — Cloud hosting, card-এ সাথে সাথে, ২৫,০০০, বিদেশি supplier
Dr কোথায়? Expense
নগদ ক্রয় — A/P নেই
PV-10-0004 (receipt: card statement)
Dr 5120 Cloud & Hosting 25,000
Cr 1120 Bank — Prime 25,000২০-১০ — একজন contractor-কে ভবিষ্যৎ কাজের advance ৪০,০০০
Dr কোথায়? এখনো কিছু পাননি → Asset (Advance)
PV-10-0005
Dr 1140 Advance to Supplier 40,000
Cr 1120 Bank — Prime 40,000২৫-১০ — ISP আবার “INV-88213” পাঠাল, email-এ
INSERT ... supplier_id = ISP, supplier_bill_no = 'INV-88213'
→ UNIQUE violation → "এই bill ০৬-১০-এ PB-10-0002 হিসেবে post হয়েছে"কিছুই হলো না — এটাই সাফল্য।
২৮-১০ — একটা laptop ত্রুটিপূর্ণ, ফেরত; supplier credit দিল
DN-10-0006 debit note (অধ্যায় ১৯-এর আগাম)
Dr 2110 A/P [টেক সাপ্লাই] 1,38,000
Cr 1510 Computer Equipment 1,20,000
Cr 1160 VAT Receivable 18,000A/P কমল, asset কমল, input VAT কমল — bill-এর ঠিক উল্টো, এক-তৃতীয়াংশ।
৩১-১০ — অক্টোবরের বিদ্যুৎ bill এখনো আসেনি
খরচ হয়েছে, bill নেই। এখানে কিছু লিখছি না — অধ্যায় ১৮-এ accrual: Dr 5230 Electricity, Cr 2135 Accrued Expenses, আনুমানিক অঙ্কে। এখন শুধু জেনে রাখুন bill না এলেও খরচ থেমে থাকে না।
Purchase Register — অক্টোবর
PURCHASE REGISTER — অক্টোবর ২০২৫ (posting_date অনুযায়ী)
তারিখ Ref Supplier Bill No Net VAT TDS A/P
───── ─── ──────── ─────── ─── ─── ─── ───
01-10 PB-10-0001 বাড়িওয়ালা Oct-2025 65,000 — 3,250 61,750
10-10 PB-10-0003 টেক সাপ্লাই TS/2025/1190 3,60,000 54,000 — 4,14,000
28-10 DN-10-0006 টেক সাপ্লাই (return) (1,20,000) (18,000) — (1,38,000)
───────── ─────── ───── ────────
3,05,000 36,000 3,250 3,37,750
(PB-10-0002 সেপ্টেম্বরের register-এ — posting_date 30-09)
(নগদ ক্রয় PV-10-0004 Cash Book-এ, register-এ নয় — A/P নেই)VAT input — bill_date অনুযায়ী
VAT INPUT — অক্টোবর ২০২৫ (bill_date অনুযায়ী)
PB-10-0003 TS/2025/1190 10-10 54,000
DN-10-0006 return 28-10 (18,000)
───────
36,000
(PB-10-0002-এর 1,200 সেপ্টেম্বরের VAT return-এ — bill_date 28-09)দুটো register, দুটো তারিখ — একই bill দুই report-এ দুই মাসে থাকতে পারে, আর সেটা ঠিক।
Dr-এর সিদ্ধান্তের ফল — এক নজরে
| ক্রয় | Dr | Income Statement (অক্টোবর) | Balance Sheet |
|---|---|---|---|
| ভাড়া ৬৫,০০০ | Expense | −৬৫,০০০ | A/P +৬১,৭৫০, TDS +৩,২৫০ |
| Internet ৮,০০০ | Expense (সেপ্টেম্বর) | ০ (সেপ্টেম্বরে −৮,০০০) | A/P +৯,২০০, VAT Rec +১,২০০ |
| Laptop ৩,৬০,০০০ (নিট ২টা) | Asset | ০ | Asset +২,৪০,০০০, A/P +২,৭৬,০০০, VAT Rec +৩৬,০০০ |
| Hosting ২৫,০০০ | Expense | −২৫,০০০ | Bank −২৫,০০০ |
| Advance ৪০,০০০ | Asset | ০ | Advance +৪০,০০০, Bank −৪০,০০০ |
অক্টোবরে মোট ৪,৯৮,০০০ টাকার “কেনাকাটা”, অথচ Income Statement-এ খরচ মাত্র ৯০,০০০। বাকিটা asset — সময়ের সাথে খরচ হবে। “কত খরচ হলো” আর “কত কিনলাম” আলাদা প্রশ্ন — অধ্যায় ১৩-এর “আয় বনাম নগদ”-এর ক্রয়-সংস্করণ।
৫. Implementation — Software ও Database
Schema — sales-এর আয়না
purchase_invoices
id BIGINT PK
company_id BIGINT FK
internal_no VARCHAR(40) -- PB-10-0001 (আপনার, gapless)
supplier_id BIGINT FK
supplier_bill_no VARCHAR(60) -- তার
supplier_bill_no_norm VARCHAR(60) -- normalize করা, UNIQUE-এর জন্য
bill_date DATE -- VAT-এর জন্য
received_date DATE
posting_date DATE -- খরচের মাস
due_date DATE
currency CHAR(3)
kind VARCHAR(10) -- credit | cash
cash_bank_account_id BIGINT FK NULL
subtotal, tax_total, tds_total, grand_total DECIMAL(18,4)
payable_total DECIMAL(18,4) -- grand_total − tds_total → A/P
vat_claimable BOOLEAN NOT NULL
status VARCHAR(20) -- received | approved | posted | partially_paid | paid | cancelled
approved_by / approved_at
journal_entry_id BIGINT FK NULL
attachment_url TEXT -- bill-এর scan (object storage — অধ্যায় ৭)
UNIQUE (company_id, internal_no)
UNIQUE (company_id, supplier_id, supplier_bill_no_norm) ← duplicate আটকায়
INDEX (company_id, supplier_id, status)
INDEX (company_id, posting_date), (company_id, bill_date)purchase_invoice_lines
id, invoice_id, line_no
item_id BIGINT FK NULL
description TEXT
quantity, unit_price, line_net DECIMAL(18,4)
debit_account_id BIGINT FK -- 5xxx | 15xx | 114x — item থেকে copy
tax_code_id BIGINT FK NULL
tax_amount DECIMAL(18,4)
tds_code_id BIGINT FK NULL -- অধ্যায় ৫৬
tds_amount DECIMAL(18,4) DEFAULT 0
-- ভবিষ্যতের মাত্রা
cost_center_id, project_id (অধ্যায় ৩৪, ৩৫)
fixed_asset_id BIGINT FK NULL -- asset হলে, register-এ link (অধ্যায় ৩০)
po_line_id BIGINT FK NULL -- three-way match (অধ্যায় ২৮)sales_invoice_lines-এর সাথে পার্থক্য দেখুন: revenue_account_id → debit_account_id, একটা tds_* জোড়া, আর তিনটি link column। কাঠামো এক।
Normalize
normalizeBillNo(s):
s = uppercase(s)
s = remove all except [A-Z0-9] -- "INV-0042" → "INV0042", "inv 42" → "INV42"
s = strip leading zeros in digit runs -- "INV0042" → "INV42"
return sসীমা আছে — “INV42” আর “42” আলাদা থাকবে। Normalize-এ যত বেশি চতুর হবেন, তত বেশি মিথ্যা duplicate। সরল রাখুন, আর UNIQUE ব্যর্থ হলে বার্তায় আগের bill-টা দেখান — মানুষ এক নজরে বুঝবেন।
একটাই posting rule, দুই দিক
অধ্যায় ১৩-এর issueInvoice()-এর credit পাশ ছিল account-ধরে যোগ। সেটাকে সাধারণ করুন:
buildDocumentEntry(doc, direction):
-- direction = +1 (sales: party Dr, lines Cr)
-- −1 (purchase: party Cr, lines Dr)
entry = JournalEntry(voucher_type = doc.voucher_type,
posting_date = doc.posting_date,
source_type = doc.type, source_id = doc.id)
-- party পাশ
partyAcct = doc.kind == 'cash' ? doc.cash_bank.gl_account_id
: doc.control_account -- 1130 বা 2110
entry.signedLine(partyAcct, direction × doc.payable_total,
party = doc.kind == 'cash' ? null : doc.party)
-- line পাশ, account-ধরে যোগ
sums = {}
প্রতিটি line l: sums[l.line_account_id] += l.line_net -- revenue / expense / asset
প্রতিটি line l: sums[l.tax_account_id] += l.tax_amount -- 2140 / 1160
প্রতিটি line l: sums[l.tds_account_id] −= l.tds_amount -- 2150 (party পাশে, উল্টো)
প্রতিটি (acct, amt) in sums:
entry.signedLine(acct, −direction × amt)
assert entry.balanced()
return entry
signedLine(acct, signed, party):
signed > 0 → debit = signed
signed < 0 → credit = −signedSales-এ direction = +1: party Dr, revenue Cr, VAT Cr। Purchase-এ direction = −1: party Cr, expense Dr, VAT Dr। TDS-এর চিহ্ন আলাদা কারণ সেটা party পাশের ভাগ — sums-এ ঋণাত্মক ঢুকে −direction দিয়ে party-র দিকেই যায়।
ভাড়ার bill-এ চালিয়ে দেখুন (direction = −1):
party: 2110 −1 × 61,750 = −61,750 → Cr 61,750 ✓
sums: 5220 +65,000 → −(−1) × 65,000 = +65,000 → Dr 65,000 ✓
2150 −3,250 → −(−1) × −3,250 = −3,250 → Cr 3,250 ✓
balanced: 65,000 = 61,750 + 3,250 ✓একটাই function, credit note আর debit note-ও এতেই চলবে (direction উল্টে) — অধ্যায় ১৯। এটাই অধ্যায় ৩৮-এর rule engine-এর সরলতম রূপ।
Post — অনুমোদনের পরে
postBill(bill, by):
যাচাই:
bill.status == 'approved'
recompute(lines) == totals
প্রতিটি line: debit_account সক্রিয়, পাতা, প্রকার IN (EXPENSE, ASSET) বা inventory
asset line হলে: line_net ≥ capitalization_threshold, নইলে সতর্কতা
vat_claimable == false হলে: tax_amount সব line_net-এ মিশে গেছে
posting_date-এর period খোলা; নইলে খোলা period-এর প্রথম দিন, log সহ
entry = buildDocumentEntry(bill, −1)
post(entry)
bill.journal_entry_id = entry.id; status = 'posted'Asset line-এ একটা বাড়তি কাজ: fixed asset register-এ একটা সারি জন্মায় (অধ্যায় ৩০) — bill-এর line-এর fixed_asset_id সেখানে। এই অধ্যায়ে শুধু link-টা রাখা।
Register ও VAT report
Purchase register — posting_date দিয়ে; VAT input — bill_date দিয়ে (vat_claimable = true)। দুটোর যাচাই GL-এর সাথে:
২৪. SUM(posted bill payable_total) − SUM(debit note)
== 2110-এ source_type IN ('purchase_invoice','debit_note') line-এর যোগফল
২৫. SUM(bill line tax_amount WHERE claimable)
== 1160-এ purchase-সূত্রের debit
২৬. SUM(bill line tds_amount) == 2150-এ purchase-সূত্রের credit
২৭. status = 'posted' কিন্তু journal_entry_id IS NULL → ০ সারি
২৮. status = 'received' ৭ দিনের বেশি → সতর্কতা (অনুমোদন আটকে আছে)শেষটা accounting নয়, কিন্তু accounting-এর ফল: অনুমোদনে আটকে থাকা bill মানে খরচ খাতায় নেই, মাসের লাভ বেশি দেখাচ্ছে।
Test হিসেবে
test "expense bill: সঠিক তিন account":
bill = draft(ISP, line(5240, 8,000, VAT15))
approve(bill); post(bill)
assert Δ 5240 == +8,000
assert Δ 1160 == +1,200
assert Δ 2110 == −9,200 (party ISP)
test "TDS: খরচ পুরো, A/P নিট":
bill = draft(বাড়িওয়ালা, line(5220, 65,000, TDS 5%))
post(bill)
assert Δ 5220 == +65,000
assert Δ 2150 == −3,250
assert Δ 2110 == −61,750
test "asset bill Income Statement স্পর্শ করে না":
post(draft(টেক, line(1510, 3,60,000, VAT15)))
assert Δ (all 5xxx) == 0
assert Δ 1510 == +3,60,000
test "duplicate bill নম্বর reject":
post(draft(ISP, bill_no 'INV-88213', ...))
assert rejects draft(ISP, bill_no 'inv 88213', ...)
assert ok draft(অন্য supplier, bill_no 'INV-88213', ...)
test "একই rule দুই দিক":
s = buildDocumentEntry(sales_invoice, +1)
p = buildDocumentEntry(purchase_invoice, −1)
assert s.balanced() and p.balanced()
assert s.line(1130).debit > 0
assert p.line(2110).credit > 0
test "unapproved bill post হয় না":
assert rejects post(draft(...)) -- status = received৬. Financial Statement Impact
INCOME STATEMENT (অক্টোবর)
5220 Office Rent 65,000
5120 Cloud & Hosting 25,000
(5240 Internet — সেপ্টেম্বরে)
(1510 laptop — কোথাও না; নভেম্বর থেকে 5290 Depreciation)
BALANCE SHEET (৩১ অক্টোবর, নড়াচড়া)
1510 Computer Equipment +2,40,000
1160 VAT Receivable +37,200 (1,200 + 54,000 − 18,000)
1140 Advance to Supplier +40,000
2110 Accounts Payable +3,46,950 (61,750 + 9,200 + 4,14,000 − 1,38,000)
2150 TDS Payable +3,250
1120 Bank −65,000
CASH FLOW
operating: hosting −25,000, advance −40,000
investing: (laptop — bill এসেছে, টাকা যায়নি; payment-এর মাসে)Sales-এর মতোই তিন report তিন গল্প। আর একটা নতুন বিষয় — investing vs operating: laptop-এর টাকা যেদিন যাবে, সেটা operating cash flow নয়, investing (অধ্যায় ২২)। ক্রয়ের প্রকার (asset) সেটা ঠিক করে দেয় — আরেকটা কারণ কেন Dr-এর সিদ্ধান্ত প্রথমেই ঠিক হওয়া দরকার।
৭. Common Developer Mistakes
| ভুল | কী ঘটে | সঠিক পথ |
|---|---|---|
| সব ক্রয় expense-এ | asset কেনার মাসে লাভ ধসে, পরে “বিনামূল্যে” | item master-এ account, threshold |
| VAT খরচে মিশিয়ে | সরকারের কাছে পাওনা হারায় | 1160, vat_claimable |
| TDS বাদ দিয়ে খরচ ৬১,৭৫০ | খরচ কম, TDS দেনা নেই, supplier-এর certificate ভুল | খরচ পুরো, credit দুই ভাগ |
| Duplicate যাচাই নেই | একই bill দুবার post, দুবার payment | UNIQUE (supplier, bill_no_norm) |
| Company-wide unique bill_no | দুই supplier-এর 42 নম্বর সংঘর্ষ | supplier-ধরে |
| posting_date = received_date | সেপ্টেম্বরের খরচ অক্টোবরে | খরচের মাস, period খোলা থাকলে |
| bill_date সংরক্ষণ নেই | VAT return ভুল মাসে | দুটো তারিখই |
| Approval ছাড়া post | যে কেউ দেনা তৈরি করতে পারে | approved → posted |
| Purchase-এর জন্য আলাদা posting কোড | দুটো rule, দুটো bug | buildDocumentEntry(doc, ±1) |
| Advance-কে expense | কাজ না পেয়েই খরচ | 1140 asset, bill-এ সমন্বয় |
| নগদ ক্রয় A/P হয়ে | A/P-তে শূন্য-দিনের দেনা, register ফোলে | kind = cash, সরাসরি Bank |
| Bill-এর scan database-এ | backup ফুলে যায় | object storage, URL (অধ্যায় ৭) |
| Register আর GL না মেলানো | post না হওয়া bill, দেনা লুকানো | রাতের যাচাই ২৪–২৮ |
প্রথম আর চতুর্থ সবচেয়ে ব্যয়বহুল। প্রথমটা Income Statement-কে মাসের পর মাস ভুল রাখে; চতুর্থটা আসল টাকা হারায় — আর যে supplier দুবার টাকা পান, তিনি সাধারণত ফোন করেন না।
৮. Exercises
সেট ক — Dr কোথায়, entry লিখুন
১। অফিসের জন্য ৬টা চেয়ার, ৪,৫০০ করে + VAT। capitalization threshold ২০,০০০।
২। একটা server, ২,৫০,০০০ + VAT, ৫ বছর চলবে।
৩। Software license, বার্ষিক, ১,২০,০০০ + VAT, ১ নভেম্বর থেকে।
(ইঙ্গিত: অধ্যায় ১৩-এর deferred-এর আয়না — অধ্যায় ১৮)
৪। Consultant-এর fee ৮০,০০০, TDS ১০%, VAT ১৫% (VAT TDS-এর আগের অঙ্কে)।
৫। দোকানের জন্য ১০০টা পণ্য, ৫০০ করে + VAT, বিক্রির জন্য।
৬। Supplier-কে ভবিষ্যৎ কাজের advance ৩০,০০০; পরে ৫০,০০০-এর bill এল।
দুটো entry।
৭। বিদেশি SaaS, card-এ $100 = ১১,০০০ টাকা, VAT invoice নেই।সেট খ — তারিখ ও duplicate
৮। Bill date ২৯-০৯, received ০৮-১০, সেপ্টেম্বরের সেবা, সেপ্টেম্বর
খোলা। posting_date? VAT কোন মাসে?
৯। একই bill, কিন্তু সেপ্টেম্বর ০৫-১০-এ বন্ধ হয়ে গেছে। এবার?
সেপ্টেম্বরের Income Statement-এ খরচটা নেই — কী করা উচিত ছিল?
১০। Supplier-এর bill "INV/2025/0042" post হয়েছে। এখন এল:
(ক) "INV-2025-42" (খ) "INV/2025/0043" (গ) "42"
normalizeBillNo() কোনটাকে duplicate ধরবে? (গ) সম্পর্কে কী করবেন?
১১। নগদ রসিদ, নম্বর নেই, ১,২০০ টাকা, চায়ের দোকান। duplicate যাচাই
কীভাবে?সেট গ — কোনটা ভুল
১২। Dr 5240 Internet 9,200 / Cr A/P 9,200 — VAT invoice ছিল
১৩। Dr 5220 Rent 61,750 / Cr A/P 61,750 — TDS ৫% কাটা হয়েছে
১৪। Dr 5250 Office Supplies 3,60,000 / Dr 1160 54,000 / Cr A/P 4,14,000 — laptop
১৫। Dr 5xxx Expense 40,000 / Cr Bank 40,000 — advance, কাজ শুরু হয়নি
১৬। purchase_invoices-এ UNIQUE (company_id, supplier_bill_no)
১৭। status: received → posted, approved ধাপ নেই, "ছোট প্রতিষ্ঠান"সেট ঘ — নকশা
১৮। buildDocumentEntry(doc, direction) — credit note (sales-এর উল্টো)
আর debit note (purchase-এর উল্টো) এতে কীভাবে চলবে? direction কত?
party পাশ কী?
১৯। Three-way match: PO ৩টা × ১,২০,০০০; GRN ৩টা; bill ৩টা × ১,২৫,০০০।
match হবে? না হলে কী — bill আটকাবেন, নাকি tolerance? tolerance
কত, কে ঠিক করবেন?
২০। Section ৪-এর অক্টোবরে VAT output (অধ্যায় ১৩-এর সেপ্টেম্বরের
86,400 ধরে নিন অক্টোবরেও তাই) আর VAT input 36,000। net কত,
কোন account-এ কী entry দিয়ে সরকারকে দেবেন? (অধ্যায় ৫৫-এর আগাম)
২১। একটা bill-এ পাঁচটা line, তিনটা expense, দুটো asset। একটাই
journal entry, নাকি দুটো? asset register-এ কয়টা সারি?
cost center আলাদা হলে?উত্তর আছে Workbook-এর Answer Key, অধ্যায় ১৫-এ।
৯. Developer Challenge
একটি PurchaseInvoiceService নকশা করুন — আর সাথে অধ্যায় ১৩-এর SalesInvoiceService-কে refactor করে একটাই DocumentPostingService বানান।
যা যা নকশা করবেন:
১.
purchase_invoices/purchase_invoice_linesschema — sales-এর সাথে পাশাপাশি রেখে: কোন column অভিন্ন, কোনটা আয়না (revenue_account_id↔debit_account_id), কোনটা শুধু এক পাশে (tds_*,supplier_bill_no_norm,fixed_asset_id)। দুটো আলাদা table রাখবেন, নাকি একটাdocumentstable-এtypecolumn? দুটোর trade-off।২.
buildDocumentEntry(doc, direction)— sales, purchase, credit note, debit note — চারটিই একটা function-এ। TDS, deferred/prepaid line, cash vs credit — সব সহ। প্রতিটি ধরনের জন্য একটা test যা balanced ও সঠিক account যাচাই করে।৩. Duplicate প্রতিরোধ —
normalizeBillNo(),UNIQUE, নম্বরহীন bill-এর জন্য fuzzy সতর্কতা (supplier + date ± 3 + amount), আর UNIQUE ব্যর্থ হলে ব্যবহারকারীকে আগের bill দেখানো।৪. তারিখের নীতি —
posting_dateনির্ধারণের যুক্তি (খরচের মাস → period খোলা? → নইলে খোলা period + log),bill_dateদিয়ে VAT report, দুটো report-এ একই bill দুই মাসে — এটা ব্যবহারকারীকে কীভাবে বোঝাবেন?৫. Approval workflow — received → approved → posted; কে কত টাকার bill অনুমোদন দিতে পারেন (একটা
approval_limitstable), নিজের তৈরি bill নিজে অনুমোদন নয় (segregation of duties — অধ্যায় ৪৮)।৬. Item master —
purchase_account_id,capitalization_threshold, asset হলে register link। একটা item কখনো expense কখনো asset হতে পারে (একটা mouse বনাম ১০০টা mouse)? নিয়ম কী?৭. Register, VAT input, TDS report — তিনটি query, আর রাতের যাচাই ২৪–২৮।
৮. Three-way match-এর জন্য এখন কী রেখে দেবেন (
po_line_id, GRNI-র account) যাতে অধ্যায় ২৮-এ schema ভাঙতে না হয়?২ নম্বরটাই আসল পরীক্ষা। যদি sales আর purchase-এর posting এক function-এ না আনতে পারেন, তাহলে অধ্যায় ১৯-এ credit/debit note-এর জন্য তৃতীয় ও চতুর্থ copy লিখবেন, আর অধ্যায় ২৮-এ পঞ্চম। একটা rule, একটা direction parameter — এটা পারলে Part 5-এর Posting Rule Engine আপনার কাছে নতুন কিছু মনে হবে না।
১০. Summary Card
আয়না
SALES PURCHASE
party Dr 1130 A/R Cr 2110 A/P
line Cr Revenue Dr Expense / Asset / Inventory
VAT Cr 2140 Payable Dr 1160 Receivable
TDS — Cr 2150 (party পাশ ভাগ)
advance Cr 2160 (liab.) Dr 1140 (asset)
নম্বর আপনার, gapless তার, UNIQUE per supplierDr কোথায়
এখনই ব্যবহার → Expense → Income Statement, এই মাসে
বহু বছর → Asset → Balance Sheet, অবচয়ে খরচ
আবার বিক্রি → Inventory → Balance Sheet, বিক্রিতে খরচ
item master ঠিক করে; threshold-এর নিচে asset নয়Entry
বাকিতে Dr Expense/Asset (net) Dr 1160 VAT Cr 2110 A/P [supplier]
TDS সহ Dr Expense (পুরো) Cr 2150 TDS Cr 2110 A/P (নিট)
নগদ Dr Expense/Asset Dr 1160 Cr Bank
advance Dr 1140 Cr Bankতারিখ
posting_date = খরচের মাস (খোলা থাকলে) → expense report
bill_date = supplier-এর তারিখ → VAT reportDeveloper checklist
□ debit_account_id item master থেকে, line-এ copy
□ capitalization_threshold
□ 1160 শুধু vat_claimable হলে; নইলে খরচে
□ TDS: খরচ পুরো, credit দুই ভাগ
□ UNIQUE (supplier, normalize(bill_no)); নম্বরহীনে fuzzy সতর্কতা
□ bill_date + received_date + posting_date, তিনটিই
□ received → approved → posted; approval_limits
□ buildDocumentEntry(doc, ±1) — sales ও purchase এক rule
□ নগদ ক্রয় A/P বাদ দিয়ে
□ advance 1140 asset
□ asset line → fixed asset register link
□ scan object storage-এ
□ রাতে: register == GL 2110, VAT == 1160, TDS == 2150, posted-unlinked, আটকে থাকা approvalপরবর্তী অধ্যায়
অধ্যায় ১৬ — Accounts Payable: Bill post হলো, A/P-এ ৩,৪৬,৯৫০ দেনা বসল। এবার অধ্যায় ১৪-এর আয়না — payment allocation, supplier aging, settlement discount received, payment run। কিন্তু একটা বড় পার্থক্য: A/R-এ আপনি অপেক্ষা করেন, A/P-এ আপনি সিদ্ধান্ত নেন — কাকে কবে কত দেবেন, নগদ কতটা আছে, কোন discount নেওয়া লাভজনক। পরের অধ্যায়ে payable-এর সেই নিয়ন্ত্রণটা।