Skip to Content
Go Realm v1 is released 🎉
Accountingবই (Print Edition)অধ্যায় ১৫: Purchase

অধ্যায় ১৫ — 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,000

A/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,000

Customer 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

ঘটনাDebitCredit
বাকিতে ক্রয় (খরচ)Expense (net), VAT ReceivableA/P [supplier]
বাকিতে ক্রয় (asset)Fixed Asset (net), VAT ReceivableA/P [supplier]
বাকিতে ক্রয় (inventory)Inventory (net), VAT ReceivableA/P [supplier]
TDS সহExpense (পুরো)TDS Payable, A/P [supplier] (নিট)
নগদ ক্রয়Expense/Asset, VAT ReceivableCash/Bank
Advance to supplierAdvance to SupplierBank
Payment (অধ্যায় ১৬)A/P [supplier]Bank

Dr কোথায়

এখনই ব্যবহার → Expense (5xxx) বহু বছর → Asset (15xx), threshold-এর উপরে আবার বিক্রি → Inventory (114x) সিদ্ধান্ত item master-এ, bill-এ copy

VAT

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,000

Income 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,000

A/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-এর সিদ্ধান্তের ফল — এক নজরে

ক্রয়DrIncome Statement (অক্টোবর)Balance Sheet
ভাড়া ৬৫,০০০Expense−৬৫,০০০A/P +৬১,৭৫০, TDS +৩,২৫০
Internet ৮,০০০Expense (সেপ্টেম্বর)০ (সেপ্টেম্বরে −৮,০০০)A/P +৯,২০০, VAT Rec +১,২০০
Laptop ৩,৬০,০০০ (নিট ২টা)AssetAsset +২,৪০,০০০, A/P +২,৭৬,০০০, VAT Rec +৩৬,০০০
Hosting ২৫,০০০Expense−২৫,০০০Bank −২৫,০০০
Advance ৪০,০০০AssetAdvance +৪০,০০০, 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_iddebit_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 = −signed

Sales-এ 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, দুবার paymentUNIQUE (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, দুটো bugbuildDocumentEntry(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_lines schema — sales-এর সাথে পাশাপাশি রেখে: কোন column অভিন্ন, কোনটা আয়না (revenue_account_iddebit_account_id), কোনটা শুধু এক পাশে (tds_*, supplier_bill_no_norm, fixed_asset_id)। দুটো আলাদা table রাখবেন, নাকি একটা documents table-এ type column? দুটোর 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_limits table), নিজের তৈরি 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 supplier

Dr কোথায়

এখনই ব্যবহার → 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 report

Developer 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-এর সেই নিয়ন্ত্রণটা।