অধ্যায় ১৩ — Sales ও Revenue
Volume 1 · Part 2 — Core Business Accounting · Chapter 13
পূর্বশর্ত: অধ্যায় ১১ (Cash ও Bank), অধ্যায় ৭ (Journal Entry), অধ্যায় ৯ (General Ledger)
১. Learning Objective
এই অধ্যায় শেষে আপনি পারবেন:
বিক্রি আর টাকা পাওয়া — দুটো আলাদা ঘটনা — তা সমীকরণ দিয়ে ব্যাখ্যা করতে
আয় কখন "হয়" — invoice, delivery, নাকি receipt — এই প্রশ্নের উত্তর দিতে
নগদ বিক্রি ও বাকিতে বিক্রির entry লিখতে
VAT কেন আয় নয় — এবং invoice-এ তা কোথায় যায়, তা বলতে
Trade discount আর settlement discount আলাদা করতে
Deferred revenue ও customer advance — যে টাকা এসেছে কিন্তু আয় নয় — চিনতে
Invoice-কে source document হিসেবে নকশা করতে: header, line, tax, numbering
Issued invoice কেন অপরিবর্তনীয়, আর ভুল হলে কী করতে হয়, তা বলতে
Invoice থেকে journal entry — posting rule লিখতে
Sales register ও VAT output report তৈরি করতে, এবং GL-এর সাথে মেলাতেসময়: পড়া ৫০ মিনিট + অনুশীলন ৫৫ মিনিট।
২. Concept Explanation
দুটো প্রশ্ন, দুটো উত্তর
অধ্যায় ১১-এর শেষে একটা table ছিল — ABC Ltd-এর ৫,৭৫,০০০ আগস্টে ব্যাংকে ঢুকল, কিন্তু আয় গোনা হয়েছিল জুলাইয়ে। এই অধ্যায় সেই ফাঁকটা নিয়েই। প্রতিটি বিক্রিতে দুটো আলাদা প্রশ্ন আছে:
প্রশ্ন ১: আয়টা কখন হলো? → Income Statement-এর প্রশ্ন
প্রশ্ন ২: টাকাটা কখন এল? → Cash Flow-এর প্রশ্ননগদ বিক্রিতে দুটোর উত্তর একই দিন, তাই ফাঁক চোখে পড়ে না। বাকিতে বিক্রিতে দুটো আলাদা — আর মাঝখানের সময়টা হলো Accounts Receivable (পরের অধ্যায়)।
delivery / service invoice টাকা এল
│ │ │
▼ ▼ ▼
─────●────────────────────●─────────────────●──────▶ সময়
│ │
└── এখানে আয় ──────── A/R ────────────┘ এখানে নগদDeveloper-এর দৃষ্টিতে: বিক্রি একটা event, receipt আরেকটা event। দুটো আলাদা document, আলাদা journal entry, আলাদা তারিখ। যে system একটা “sale” record-এ
paid_atcolumn রেখে দুটোকে এক করে ফেলে, সে প্রথম দিন থেকেই Income Statement আর Cash Flow গুলিয়ে ফেলেছে।
আয় কখন “হয়”
তিনটি প্রার্থী তারিখ: invoice লেখার দিন, পণ্য/সেবা দেওয়ার দিন, টাকা পাওয়ার দিন। Accounting-এর উত্তর একটাই:
আয় হয় যেদিন আপনি আপনার দিকের কাজটা সম্পন্ন করেন — পণ্য হস্তান্তর, বা সেবা প্রদান। Invoice নয়, টাকা নয়।
একে বলে revenue recognition, আর নিয়মটার পুরো রূপ অধ্যায় ১৭-এ। এখন যা জানা দরকার:
বেশিরভাগ ক্ষেত্রে invoice-এর দিন == delivery-র দিন
→ তাই invoice date দিয়েই আয় ধরা হয়, আর সেটা ঠিক
কিন্তু দুটো আলাদা হলে delivery জেতে:
delivery আগে, invoice পরে → আয় delivery-র মাসে (accrued revenue, অধ্যায় ১৮)
invoice আগে, delivery পরে → আয় delivery-র মাসে (deferred revenue, নিচে)
টাকা আগে, delivery পরে → আয় delivery-র মাসে (customer advance, নিচে)এই অধ্যায়ে দুটো ক্ষেত্র আসবে যেখানে invoice হলো কিন্তু আয় হলো না — বাকিটা অধ্যায় ১৭ ও ১৮-এ।
নগদ বিক্রি ও বাকিতে বিক্রি
নগদ বিক্রি বাকিতে বিক্রি
────────── ─────────────
Dr Cash/Bank 115,000 Dr A/R [গ্রাহক] 115,000
Cr Sales 100,000 Cr Sales 100,000
Cr VAT Payable 15,000 Cr VAT Payable 15,000
... পরে টাকা এলে (অধ্যায় ১৪):
Dr Bank 115,000
Cr A/R [গ্রাহক] 115,000Credit পাশ অভিন্ন। শুধু debit পাশ বদলায় — টাকা এখনই, নাকি পাওনা। এটাই বলে দেয় বিক্রির entry-র আসল অংশ credit পাশ; debit পাশটা শুধু “কে দেবে”।
আর লক্ষ করুন বাকিতে বিক্রিতে দ্বিতীয় entry-তে Sales নেই। টাকা পাওয়ার entry আয় স্পর্শ করে না — আয় একবারই গোনা হয়, invoice-এর দিনে।
VAT — যে টাকা আপনার নয়
গ্রাহক ১,১৫,০০০ দিল, কিন্তু আয় ১,০০,০০০। বাকি ১৫,০০০ আপনি সরকারের হয়ে সংগ্রহ করেছেন — এটা আপনার টাকা নয়, একটা দেনা (2140 VAT Payable)।
গ্রাহক দেয় 1,15,000
আপনার আয় 1,00,000 → 4110 Sales (REVENUE)
সরকারের অংশ 15,000 → 2140 VAT Payable (LIABILITY)তিনটি নিয়ম:
১. Revenue account-এ কখনো VAT ঢুকবে না — সবসময় net-of-VAT
২. VAT-এর হার কোডে নয়, একটা table-এ (হার বদলায়, পণ্যভেদে আলাদা)
৩. VAT line ধরে হিসাব হয়, তারপর যোগ — নাকি মোটের উপর? একটা বেছে নিন,
আর সবখানে সেটাই (rounding-এর পার্থক্য ১ টাকা হলেও audit ধরে)কেনার সময় যে VAT আপনি দেন (1160 VAT Receivable) — সেটা উল্টো দিক, অধ্যায় ১৫-এ। মাস শেষে দুটোর পার্থক্যই সরকারকে দেওয়ার অঙ্ক (অধ্যায় ৫৫)।
Discount — দুই রকম, দুই জায়গায়
| Trade discount | Settlement (cash) discount | |
|---|---|---|
| কখন | বিক্রির সময়, invoice-এই | তাড়াতাড়ি টাকা দিলে, receipt-এর সময় |
| উদাহরণ | ”৫% ছাড়” দামের উপর | ”১০ দিনে দিলে ২% কম” |
| কোথায় লেখা | কোথাও না — দাম কমে যায় | আলাদা account, receipt-এর entry-তে |
| আয় | ছাড়ের পরের দাম | পুরো দাম, ছাড়টা খরচ/contra-revenue |
| VAT | ছাড়ের পরের দামের উপর | মূল দামের উপর (দেশভেদে ভিন্ন) |
Trade discount কখনো আলাদা account-এ যায় না। ৪,০০,০০০-এ ৫% ছাড় মানে দাম ৩,৮০,০০০ — আয় ৩,৮০,০০০, শেষ। Invoice-এ ছাড়টা দেখানো হয় গ্রাহকের জন্য, খাতার জন্য নয়।
Settlement discount বিক্রির নয়, টাকা তোলার ঘটনা — তাই অধ্যায় ১৪-এ।
Deferred revenue — invoice হলো, আয় হলো না
একটা বার্ষিক maintenance contract: ১ অক্টোবর থেকে ১২ মাস, ১,২০,০০০ টাকা, invoice সেপ্টেম্বরে। সেপ্টেম্বরে আয় কত?
শূন্য। সেবা এখনো শুরুই হয়নি। আপনি গ্রাহকের কাছে ১২ মাসের সেবা দেনা আছেন:
সেপ্টেম্বর, invoice:
Dr A/R [গ্রাহক] 1,38,000
Cr 2180 Deferred Revenue 1,20,000 ← LIABILITY, আয় নয়
Cr 2140 VAT Payable 18,000
অক্টোবর থেকে প্রতি মাসে (অধ্যায় ১৮):
Dr 2180 Deferred Revenue 10,000
Cr 4120 Maintenance Income 10,000 ← এবার আয়Invoice line-এ তাই একটা প্রশ্ন থাকা দরকার: এই line-এর সেবা কোন সময়কালের? এক দিনের হলে সরাসরি revenue; একাধিক মাসের হলে deferred।
Customer advance — টাকা এল, আয় হলো না
গ্রাহক কাজ শুরুর আগে ৫০,০০০ দিল। Invoice নেই, delivery নেই — শুধু টাকা।
Dr 1120 Bank 50,000
Cr 2160 Customer Advance 50,000 ← LIABILITYAdvance আর deferred revenue দেখতে একই রকম (দুটোই “গ্রাহকের কাছে দেনা”), কিন্তু আলাদা: deferred revenue invoice হয়ে গেছে, advance-এ invoice হয়নি। Invoice হলে advance-টা তার সাথে সমন্বয় হবে (অধ্যায় ১৯)।
চারটি account পাশাপাশি:
টাকা এসেছে? invoice হয়েছে? আয় হয়েছে?
───────────── ─────────── ────────────── ──────────
Sales — হ্যাঁ হ্যাঁ
A/R না হ্যাঁ হ্যাঁ
Deferred Revenue — হ্যাঁ না
Customer Advance হ্যাঁ না নাInvoice — source document
অধ্যায় ৭-এর নিয়ম: journal entry হাতে লেখা হয় না, document থেকে জন্মায়। বিক্রির document হলো invoice। তার গঠন:
INVOICE SV-09-0001 তারিখ 02-09-2025
গ্রাহক ABC Ltd due 02-10-2025
───────────────────────────────────────────────────────
# বিবরণ পরিমাণ দর ছাড় নিট
1 Software development 1 job 4,00,000 5% 3,80,000 → 4110
2 Maintenance, Sep 1 mo 50,000 — 50,000 → 4120
───────────────────────────────────────────────────────
subtotal 4,30,000
VAT 15% 64,500 → 2140
TOTAL 4,94,500 → 1130তিনটি স্তর: header (কে, কবে, মোট), line (কী, কত, কোন revenue account), tax (কোন হার, কত)। প্রতিটি line-এর নিজের revenue account — এক invoice-এ একাধিক আয়ের ধরন থাকতে পারে, আর সেটাই স্বাভাবিক।
line-এ revenue account কোথা থেকে আসে? পণ্য/সেবার master থেকে (items.revenue_account_id) — ব্যবহারকারী বাছেন না, system জানে। এটাই account mapping (অধ্যায় ৩৯)।
জীবনচক্র ও অপরিবর্তনীয়তা
DRAFT
│ লেখা হচ্ছে, বদলানো যায়, invoice নম্বর নেই
▼
ISSUED
│ নম্বর পেল, journal entry post হলো, গ্রাহককে পাঠানো হলো
│ এখন অপরিবর্তনীয়
▼
PARTIALLY PAID ──▶ PAID (অধ্যায় ১৪)
│
└──▶ CANCELLED (reversal বা credit note দিয়ে — অধ্যায় ১৯)Issued invoice বদলানো যায় না — একই কারণে যে কারণে posted entry বদলানো যায় না (অধ্যায় ৮): গ্রাহকের হাতে একটা কপি আছে, সরকারের VAT return-এ এর নম্বর আছে, আর এর journal entry খাতায় বসে গেছে। ভুল হলে নতুন document — credit note — যা উল্টো দিকে কাজ করে।
Invoice নম্বর নিয়ে দুটো নিয়ম, দুটোই আইনি:
১. ফাঁকহীন (gapless) — SV-09-0001-এর পরে SV-09-0002, মাঝে কিছু নেই।
তাই draft-এ নম্বর নয়; issue-র মুহূর্তে নম্বর।
(draft মুছে ফেললে নম্বর নষ্ট হবে — ফাঁক)
২. কখনো পুনর্ব্যবহার নয় — cancelled invoice-এর নম্বর cancelled-ই থাকে।৩. Accounting Rule
বিক্রি
| ঘটনা | Debit | Credit |
|---|---|---|
| নগদ বিক্রি | Cash/Bank (মোট) | Revenue (net), VAT Payable |
| বাকিতে বিক্রি | A/R [গ্রাহক] (মোট) | Revenue (net), VAT Payable |
| টাকা এল (পরে) | Bank | A/R [গ্রাহক] — Revenue নয় |
| ভবিষ্যতের সেবার invoice | A/R [গ্রাহক] | Deferred Revenue, VAT Payable |
| Deferred → আয় (মাসে মাসে) | Deferred Revenue | Revenue |
| অগ্রিম টাকা (invoice নেই) | Bank | Customer Advance |
VAT
Revenue = net of VAT, সবসময়
VAT = 2140 VAT Payable (LIABILITY), কখনো revenue-তে নয়
হার = tax_codes table, কোডে নয়
হিসাব = line ধরে, তারপর যোগ (একবার ঠিক করে সবখানে)Discount
Trade discount দাম কমায়, আলাদা account নেই, VAT ছাড়ের পরে
Settlement discount receipt-এর ঘটনা, আলাদা account (অধ্যায় ১৪)Invoice
নম্বর issue-র মুহূর্তে, ফাঁকহীন, পুনর্ব্যবহার নয়
issued অপরিবর্তনীয়; সংশোধন = credit note / reversal
line প্রতিটির নিজের revenue account, item master থেকে
যোগফল SUM(line_net) == subtotal, SUM(line_tax) == tax_total,
subtotal + tax_total == grand_total == A/R lineঅলঙ্ঘনীয়
আয় গোনা হয় একবার — delivery/invoice-এ। receipt-এ কখনো নয়।৪. Real Business Example
সেপ্টেম্বর ২০২৫ — বিক্রির মাস
একই software company, অধ্যায় ১১-১২-এর পরের মাস। পাঁচটি ঘটনা, প্রতিটিতে দুটো প্রশ্ন: আয় হলো? আর টাকা এল?
০২-০৯ — ABC Ltd-কে invoice: development কাজ + সেপ্টেম্বরের maintenance
Section ২-এর সেই invoice। Development-এ ৫% trade discount:
line 1 4,00,000 × 95% = 3,80,000 → 4110
line 2 = 50,000 → 4120
─────────
subtotal 4,30,000
VAT 15% 64,500
total 4,94,500
SV-09-0001
Dr 1130 A/R [ABC Ltd] 4,94,500
Cr 4110 Software Dev. Income 3,80,000
Cr 4120 Maintenance Income 50,000
Cr 2140 VAT Payable 64,500আয় হলো? হ্যাঁ, ৪,৩০,০০০ — কাজ delivered। টাকা এল? না। ছাড়ের ২০,০০০ কোথাও নেই — দামটাই ৩,৮০,০০০।
০৮-০৯ — নগদে consulting, ২০,০০০ + VAT
RV-09-0002 (cash invoice CI-09-0002 থেকে)
Dr 1110 Cash 23,000
Cr 4130 Consulting Income 20,000
Cr 2140 VAT Payable 3,000আয় হলো? হ্যাঁ, ২০,০০০। টাকা এল? হ্যাঁ, ২৩,০০০ — একই দিনে, একই entry-তে। Cash Book-এও যাবে (অধ্যায় ১১), sales register-এও যাবে।
১৫-০৯ — করিম ট্রেডার্সের সাথে বার্ষিক maintenance contract, ১ অক্টোবর থেকে
SV-09-0003
Dr 1130 A/R [করিম ট্রেডার্স] 1,38,000
Cr 2180 Deferred Revenue 1,20,000
Cr 2140 VAT Payable 18,000আয় হলো? না — শূন্য। সেবা অক্টোবরে শুরু। টাকা এল? না। Invoice হয়েছে, পাওনা হয়েছে, VAT-এর দেনা হয়েছে — কিন্তু Income Statement-এ কিছুই না।
২০-০৯ — সালমা আক্তার নতুন একটা কাজের জন্য ৫০,০০০ অগ্রিম দিলেন
RV-09-0004
Dr 1120 Bank — Prime 50,000
Cr 2160 Customer Advance 50,000আয় হলো? না। টাকা এল? হ্যাঁ। Invoice নেই, তাই A/R-ও নেই।
২৫-০৯ — ABC Ltd ৪,৯৪,৫০০ transfer করল
RV-09-0005
Dr 1120 Bank — Prime 4,94,500
Cr 1130 A/R [ABC Ltd] 4,94,500আয় হলো? না — ০২-০৯-এই হয়ে গেছে। টাকা এল? হ্যাঁ।
২৮-০৯ — রহিম এন্টারপ্রাইজকে invoice, তারপর ধরা পড়ল পরিমাণ ভুল
SV-09-0006 (ভুল — ১০টার জায়গায় ১০০টা)
Dr 1130 A/R [রহিম] 69,000
Cr 4130 Consulting Income 60,000
Cr 2140 VAT Payable 9,000Issued হয়ে গেছে — বদলানো যাবে না। একই দিনে, টাকা আসেনি, গ্রাহককে পাঠানোর আগেই ধরা পড়েছে — তাই reversal, আর নতুন invoice:
JV-09-0007 reversal of SV-09-0006
Dr 4130 Consulting Income 60,000
Dr 2140 VAT Payable 9,000
Cr 1130 A/R [রহিম] 69,000
SV-09-0006 → status = cancelled, নম্বর থাকল
SV-09-0008 (ঠিক — ১০টা)
Dr 1130 A/R [রহিম] 6,900
Cr 4130 Consulting Income 6,000
Cr 2140 VAT Payable 900গ্রাহকের হাতে চলে গেলে, বা অন্য মাসে ধরা পড়লে — reversal নয়, credit note (অধ্যায় ১৯)। নম্বর SV-09-0006 cancelled হিসেবে register-এ থেকে যাবে, SV-09-0007 জানতে চাইলে বলা যাবে “ওটা JV, invoice নয়” — কারণ invoice আর JV-র sequence আলাদা।
মাসের হিসাব — দুটো উত্তর পাশাপাশি
| তারিখ | ঘটনা | Revenue | A/R | Deferred | Advance | VAT | Cash/Bank |
|---|---|---|---|---|---|---|---|
| ০২ | ABC invoice | +৪,৩০,০০০ | +৪,৯৪,৫০০ | +৬৪,৫০০ | |||
| ০৮ | নগদ consulting | +২০,০০০ | +৩,০০০ | +২৩,০০০ | |||
| ১৫ | করিম contract | +১,৩৮,০০০ | +১,২০,০০০ | +১৮,০০০ | |||
| ২০ | সালমা advance | +৫০,০০০ | +৫০,০০০ | ||||
| ২৫ | ABC payment | −৪,৯৪,৫০০ | +৪,৯৪,৫০০ | ||||
| ২৮ | রহিম (নিট) | +৬,০০০ | +৬,৯০০ | +৯০০ | |||
| মোট | ৪,৫৬,০০০ | ১,৪৪,৯০০ | ১,২০,০০০ | ৫০,০০০ | ৮৬,৪০০ | ৫,৬৭,৫০০ |
সেপ্টেম্বরে আয় ৪,৫৬,০০০, আর বিক্রি থেকে নগদ ৫,৬৭,৫০০। দুটো সংখ্যা আলাদা, দুটোই ঠিক, আর দুটো আলাদা report-এ যাবে। কেউ যদি জিজ্ঞেস করেন “এ মাসে কত বিক্রি?” — পাল্টা প্রশ্ন: আয় জানতে চান, না নগদ?
Sales Register
Invoice-ভিত্তিক দিনের খাতা — Cash Book-এর বিক্রির সংস্করণ:
SALES REGISTER — সেপ্টেম্বর ২০২৫
তারিখ Invoice গ্রাহক Net VAT Total Status
───── ─────── ───── ─── ─── ───── ──────
02-09 SV-09-0001 ABC Ltd 4,30,000 64,500 4,94,500 paid
08-09 CI-09-0002 (নগদ) 20,000 3,000 23,000 paid
15-09 SV-09-0003 করিম ট্রেডার্স 1,20,000 18,000 1,38,000 issued
28-09 SV-09-0006 রহিম 60,000 9,000 69,000 cancelled
28-09 SV-09-0008 রহিম 6,000 900 6,900 issued
──────── ─────── ────────
(cancelled বাদে) 5,76,000 86,400 6,62,400লক্ষ করুন register-এর Net ৫,৭৬,০০০ কিন্তু Revenue ৪,৫৬,০০০ — পার্থক্য ঠিক ১,২০,০০০, করিমের deferred। Sales register বিক্রির document গোনে; Income Statement আয় গোনে। দুটো মেলানোর সূত্র:
register net − deferred অংশ + এ মাসে recognized deferred == revenue
5,76,000 − 1,20,000 + 0 == 4,56,000 ✓৫. Implementation — Software ও Database
Invoice-এর schema
sales_invoices
id BIGINT PK
company_id BIGINT FK
invoice_no VARCHAR(40) NULL -- issue-র সময় বসে; draft-এ NULL
customer_id BIGINT FK
invoice_date DATE
due_date DATE
currency CHAR(3)
kind VARCHAR(10) -- credit | cash
cash_bank_account_id BIGINT FK NULL -- kind = cash হলে কোথায় টাকা
subtotal DECIMAL(18,4) -- SUM(line_net)
tax_total DECIMAL(18,4) -- SUM(line_tax)
grand_total DECIMAL(18,4) -- subtotal + tax_total
status VARCHAR(20) -- draft | issued | partially_paid | paid | cancelled
journal_entry_id BIGINT FK NULL
cancelled_by_entry_id BIGINT FK NULL
cancel_reason TEXT NULL
created_by / created_at, issued_by / issued_at
UNIQUE (company_id, invoice_no) -- NULL একাধিক থাকতে পারে
INDEX (company_id, customer_id, status)
INDEX (company_id, invoice_date)sales_invoice_lines
id BIGINT PK
invoice_id BIGINT FK
line_no SMALLINT
item_id BIGINT FK NULL -- পণ্য/সেবা master
description TEXT
quantity DECIMAL(18,4)
unit_price DECIMAL(18,4)
discount_pct DECIMAL(5,2) DEFAULT 0
line_net DECIMAL(18,4) -- qty × price × (1 − discount)
revenue_account_id BIGINT FK -- item থেকে copy, invoice-এ স্থির
tax_code_id BIGINT FK NULL
tax_amount DECIMAL(18,4) -- line_net × rate, rounded
service_from DATE NULL -- থাকলে এবং > invoice month → deferred
service_to DATE NULL
CHECK (quantity > 0)
CHECK (line_net >= 0)tax_codes
id BIGINT PK
company_id BIGINT FK
code VARCHAR(20) -- 'VAT15', 'VAT0', 'EXEMPT'
rate DECIMAL(5,2) -- 15.00
output_account_id BIGINT FK -- 2140
input_account_id BIGINT FK -- 1160 (অধ্যায় ১৫)
is_active BOOLEANতিনটি সিদ্ধান্ত লক্ষ করুন:
১. revenue_account_id line-এ copy হয়ে থাকে, item master থেকে reference নয়। কারণ item-এর account পরে বদলালে পুরনো invoice-এর হিসাব বদলানো চলবে না। Document তৈরির মুহূর্তের সত্য document-এই থাকবে।
২. যোগফল সংরক্ষিত, কিন্তু যাচাইও হয়। subtotal, tax_total, grand_total header-এ থাকে (report দ্রুত হয়), কিন্তু issue-র মুহূর্তে line থেকে আবার হিসাব করে মেলানো হয়। অমিল মানে bug, আর সেটা post হওয়ার আগেই ধরা পড়ুক।
৩. সব অঙ্ক DECIMAL। 4,00,000 × 0.95 × 0.15 float-এ করলে ৫৭,০০০.০০০০০০০০১ আসে — আর অধ্যায় ১০-এর “পার্থক্য পয়সায়” সমস্যাটা এখান থেকেই জন্মায়।
Rounding — একবার ঠিক করুন
পদ্ধতি ক: line ধরে পদ্ধতি খ: মোটের উপর
প্রতিটি line_tax = round(line_net × rate) tax_total = round(subtotal × rate)
tax_total = SUM(line_tax)
line 1: 3,80,000 × 15% = 57,000 4,30,000 × 15% = 64,500
line 2: 50,000 × 15% = 7,500
total: 64,500এখানে দুটো সমান, কিন্তু ৩৩৩.৩৩-এর মতো দাম থাকলে ১ টাকা এদিক-ওদিক হবে। যেটাই নিন, invoice, register, VAT report — সবখানে একই। আমরা পদ্ধতি ক ধরব, কারণ line-এ tax থাকলে line-ভিত্তিক VAT report সরাসরি হয়।
Gapless নম্বর — lock সহ
document_sequences
company_id BIGINT
doc_type VARCHAR(10) -- 'SV', 'CI', 'CN' ...
fiscal_year SMALLINT
next_no INT
PK (company_id, doc_type, fiscal_year)nextInvoiceNo(company, type, year):
-- একই transaction-এ, issue-র সাথে
row = SELECT next_no FROM document_sequences
WHERE ... FOR UPDATE
no = row.next_no
UPDATE document_sequences SET next_no = no + 1 WHERE ...
return format(type, year, no) -- SV-09-0001FOR UPDATE ছাড়া দুজন একসাথে issue করলে একই নম্বর পাবেন — UNIQUE একজনকে ব্যর্থ করবে, কিন্তু তখন তার invoice-টা আধাআধি হয়ে থাকবে। আর নম্বর নেওয়া আর invoice issue করা একই database transaction-এ — নইলে নম্বর নেওয়ার পরে issue ব্যর্থ হলে ফাঁক তৈরি হবে।
Database-এর SEQUENCE ব্যবহার করবেন না — সেটা rollback-এ ফাঁক রাখে, সেটাই তার নকশা।
Posting rule
issueInvoice(inv):
-- একটাই transaction
যাচাই:
inv.status == 'draft'
অন্তত একটা line
recompute(lines) == inv.subtotal / tax_total / grand_total
প্রতিটি line: revenue_account_id সক্রিয়, পাতা, REVENUE প্রকার
customer সক্রিয়
inv.invoice_no = nextInvoiceNo(...)
entry = JournalEntry(
voucher_type = inv.kind == 'cash' ? 'RV' : 'SV',
posting_date = inv.invoice_date,
source_type = 'sales_invoice', source_id = inv.id,
narration = "Invoice {no} — {customer}")
-- debit পাশ: কে দেবে
যদি inv.kind == 'cash':
entry.line(inv.cash_bank_account.gl_account_id, debit = grand_total)
নইলে:
entry.line(AR_CONTROL, debit = grand_total,
party = ('customer', inv.customer_id))
-- credit পাশ: revenue বা deferred, line ধরে account অনুযায়ী যোগ
প্রতিটি line l:
acct = isDeferred(l, inv.invoice_date) ? DEFERRED_REVENUE
: l.revenue_account_id
credits[acct] += l.line_net
-- credit পাশ: tax, code অনুযায়ী যোগ
প্রতিটি line l যার tax_code আছে:
credits[l.tax_code.output_account_id] += l.tax_amount
প্রতিটি (acct, amt) in credits: entry.line(acct, credit = amt)
post(entry) -- অধ্যায় ৮
inv.journal_entry_id = entry.id
inv.status = 'issued'Account অনুযায়ী যোগ করে line বানানো হচ্ছে — দশটা line-এর সবগুলো 4110-এ গেলে entry-তে একটাই 4110 line। GL পরিষ্কার থাকে; line-ধরে বিস্তারিত invoice-এ আছে, দরকার হলে source_id দিয়ে যাওয়া যায়।
isDeferred(l, date) — service_from আছে এবং invoice-এর মাসের পরে শুরু, বা service_to invoice-এর মাস ছাড়িয়ে যায়। মাসে-মাসে recognize করার scheduler অধ্যায় ১৮-এ।
বাতিল
cancelInvoice(inv, reason, by):
যাচাই:
inv.status == 'issued' -- টাকা এলে আর নয় → credit note
inv.journal_entry.period খোলা -- বন্ধ হলে → credit note
কোনো receipt allocated নেই (অধ্যায় ১৪)
rev = reverse(inv.journal_entry, reason) -- অধ্যায় ৪৩
inv.cancelled_by_entry_id = rev.id
inv.cancel_reason = reason
inv.status = 'cancelled'
-- invoice_no থাকে; register-এ cancelled হিসেবে দেখাবেশর্ত তিনটি কড়া, আর ইচ্ছাকৃত। এর বাইরে সব ক্ষেত্রে credit note — কারণ credit note গ্রাহকের কাছেও যায়, VAT return-এও যায়; reversal শুধু আপনার খাতায়।
Report
Sales register — sales_invoices থেকে সরাসরি, status <> 'draft'।
VAT output report — দুই উৎস থেকে, আর দুটো মিলতে হবে:
-- উৎস ১: invoice line থেকে
SELECT t.code, SUM(l.line_net) AS taxable, SUM(l.tax_amount) AS tax
FROM sales_invoice_lines l
JOIN sales_invoices i ON i.id = l.invoice_id
JOIN tax_codes t ON t.id = l.tax_code_id
WHERE i.company_id = :c AND i.status IN ('issued','partially_paid','paid')
AND i.invoice_date BETWEEN :from AND :to
GROUP BY t.code;
-- উৎস ২: GL থেকে
SELECT SUM(credit - debit)
FROM posted_lines
WHERE account_id = 2140 AND posting_date BETWEEN :from AND :to
AND journal_entry_id IN (source_type = 'sales_invoice' বা তার reversal);দুটো সমান না হলে কোথাও একটা invoice post হয়নি, বা কেউ 2140-এ হাতে JV দিয়েছে। এটা subledger-বনাম-GL reconciliation-এর আরেকটা রূপ (অধ্যায় ৪৪), আর রাতের যাচাইয়ে থাকা উচিত:
১৬. SUM(issued invoice grand_total) − SUM(cancelled reversal)
== 1130-এ source_type='sales_invoice' line-এর যোগফল
১৭. invoice line VAT == 2140-এ sales_invoice-সূত্রের credit
১৮. status = 'issued' কিন্তু journal_entry_id IS NULL → ০ সারিTest হিসেবে
test "invoice issue-তে সঠিক account, সঠিক অঙ্ক":
inv = draft(customer = ABC,
line(4110, 4,00,000, discount 5%, VAT15),
line(4120, 50,000, VAT15))
before = balances()
issue(inv)
after = balances()
assert after[1130] − before[1130] == +4,94,500 (party ABC)
assert after[4110] − before[4110] == −3,80,000
assert after[4120] − before[4120] == −50,000
assert after[2140] − before[2140] == −64,500
assert inv.invoice_no == 'SV-09-0001'
assert inv.status == 'issued'
test "receipt আয় বদলায় না":
issue(inv) -- revenue = 4,30,000
receive(inv, 4,94,500)
assert balance(4110) + balance(4120) অপরিবর্তিত
test "deferred line revenue-তে যায় না":
inv = draft(line(4120, 1,20,000, service Oct–Sep, VAT15))
issue(inv)
assert Δ 4120 == 0
assert Δ 2180 == −1,20,000
test "issued invoice বদলানো যায় না":
issue(inv)
assert rejects inv.lines[0].unit_price = 1
test "gapless: দুটো concurrent issue-এ পরপর নম্বর, ফাঁক নেই":
parallel: issue(a), issue(b)
assert {a.no, b.no} == {'SV-09-0001', 'SV-09-0002'}
test "যোগফল অমিল হলে issue হয় না":
inv.grand_total = inv.grand_total + 1 -- হাতে বিকৃত
assert rejects issue(inv)৬. Financial Statement Impact
INCOME STATEMENT (সেপ্টেম্বর)
4110 Software Development Income 3,80,000
4120 Maintenance Income 50,000
4130 Consulting Income 26,000
────────
Revenue 4,56,000
BALANCE SHEET (৩০ সেপ্টেম্বর, এই মাসের নড়াচড়া)
1130 Accounts Receivable +1,44,900 (করিম 1,38,000 + রহিম 6,900)
2140 VAT Payable +86,400
2160 Customer Advance +50,000
2180 Deferred Revenue +1,20,000
CASH FLOW (operating)
গ্রাহক থেকে প্রাপ্তি 5,67,500তিনটি report, তিনটি আলাদা সংখ্যা, একই মাস — আর তিনটিই ঠিক।
একটা invoice-এর তিন report-এ ছাপ:
invoice issue-র দিন Income Statement ✓ Balance Sheet ✓ (A/R, VAT) Cash Flow ✗
টাকা পাওয়ার দিন Income Statement ✗ Balance Sheet ✓ (A/R↓ Bank↑) Cash Flow ✓Cash Flow-এ invoice-এর দিনে কিছুই নেই — এটাই Part 2-র exit criterion-এর মূল কথা।
৭. Common Developer Mistakes
| ভুল | কী ঘটে | সঠিক পথ |
|---|---|---|
| Receipt-এ revenue post | আয় দুবার, বা invoice-এর মাসে শূন্য | আয় শুধু issue-তে; receipt শুধু A/R |
sales table-এ paid_at column | বিক্রি আর receipt এক document | আলাদা invoice, আলাদা receipt |
| VAT সহ অঙ্ক revenue-তে | আয় ১৫% বেশি, VAT দেনা নেই | revenue net, VAT 2140-এ |
rate = 0.15 কোডে | হার বদলালে deploy | tax_codes table |
| Float-এ totals | পয়সার অমিল, Trial Balance বেঁকে | DECIMAL সর্বত্র |
| Rounding দুই জায়গায় দুই রকম | invoice আর VAT report ১ টাকা আলাদা | একটা পদ্ধতি, সবখানে |
| Trade discount আলাদা account-এ | আয় ফোলানো, “discount expense” অর্থহীন | দাম কমে, শেষ |
| Draft-এ invoice নম্বর | মুছলে ফাঁক | issue-র মুহূর্তে, lock সহ |
DB SEQUENCE নম্বরের জন্য | rollback-এ ফাঁক | document_sequences + FOR UPDATE |
| Issued invoice edit করা | গ্রাহকের কপি ও খাতা আলাদা | অপরিবর্তনীয়; credit note |
| Cancelled নম্বর পুনর্ব্যবহার | দুটো আলাদা invoice এক নম্বরে | নম্বর থাকে, status cancelled |
revenue_account_id item থেকে join | item বদলালে পুরনো invoice বদলায় | line-এ copy |
| বহু-মাসের সেবা সরাসরি revenue-তে | এক মাসে ১২ মাসের আয় | deferred, মাসে মাসে recognize |
| Advance-কে revenue | কাজ শুরুর আগেই আয় | 2160, invoice-এ সমন্বয় |
| Register আর GL না মেলানো | post না হওয়া invoice মাসের পর মাস | রাতের যাচাই ১৬–১৮ |
প্রথম দুটো একই ভুলের দুই চেহারা, আর এটাই developer-দের সবচেয়ে সাধারণ accounting ভুল: বিক্রি আর টাকা পাওয়াকে এক ঘটনা ভাবা। যে system-এ orders.status = 'paid' দেখে revenue report বানানো হয়, সেখানে বাকিতে বিক্রি কখনো আয়ে আসে না, আর advance আসে কাজ শুরুর আগেই।
৮. Exercises
সেট ক — entry লিখুন
প্রতিটির জন্য entry, এবং দুটো প্রশ্নের উত্তর — আয় হলো? টাকা এল?
১। নগদে ৮০,০০০ টাকার consulting, VAT ১৫%।
২। করিম ট্রেডার্সকে ২,০০,০০০ টাকার development কাজের invoice,
১০% trade discount, VAT ১৫%।
৩। ২ নম্বরের টাকা ২০ দিন পরে ব্যাংকে এল।
৪। গ্রাহক নতুন প্রকল্পের জন্য ১,০০,০০০ অগ্রিম দিল।
৫। ছয় মাসের hosting contract, ১ নভেম্বর থেকে, ৬০,০০০ + VAT,
invoice অক্টোবরে।
৬। ৫ নম্বরের নভেম্বর মাসের recognition entry।
৭। একটা invoice-এ তিন line: development ১,০০,০০০ (VAT15),
training ৩০,০০০ (VAT15), export service ৫০,০০০ (VAT0)।
৮। ৭ নম্বরের invoice একই দিনে, টাকা আসার আগে, ভুল ধরা পড়ল।
বাতিলের entry।সেট খ — কোনটা ভুল
৯। Dr Bank 1,15,000 / Cr Sales 1,15,000 — গ্রাহক invoice-এর টাকা দিল
১০। Dr A/R 1,00,000 / Cr Sales 1,00,000 — invoice ১,০০,০০০ + VAT ১৫,০০০
১১। Dr A/R 1,80,000 / Cr Sales 2,00,000 / Dr Discount Expense 20,000
— ১০% trade discount
১২। ১২ মাসের contract, invoice-এ Cr 4120 Maintenance 1,20,000
১৩। Draft invoice-এ নম্বর SV-09-0004 বসল; পরে draft মুছে ফেলা হলো
১৪। Issued invoice-এ গ্রাহক "ঠিকানা ভুল" বললেন; developer UPDATE
দিয়ে ঠিকানা বদলে দিলেন
১৫। Revenue report: SELECT SUM(total) FROM orders WHERE status = 'paid'
১৬। tax_amount = line_net * 0.15 — Python float-এসেট গ — হিসাব
১৭। Section ৪-এর সেপ্টেম্বরে যদি ABC Ltd-এর টাকা ২৫-০৯-এর বদলে
০৫-১০-এ আসত — সেপ্টেম্বরের Revenue, A/R, Cash কী হতো?
অক্টোবরের?
১৮। Sales register net ৮,০০,০০০। এর মধ্যে ২,৪০,০০০ একটা ১২-মাসের
contract (এ মাস থেকে শুরু)। আগের মাসের একটা deferred contract
থেকে এ মাসে ১৫,০০০ recognize হয়েছে। এ মাসের revenue কত?
১৯। একটা invoice-এ দশটা line, প্রতিটি ৩৩৩.৩৩ টাকা, VAT ১৫%।
পদ্ধতি ক (line ধরে) আর পদ্ধতি খ (মোটের উপর) — দুটোতে
tax_total কত? পার্থক্য কত? কোনটা ব্যবহার করবেন, কেন?
২০। VAT output report বলছে ৮৬,৪০০, কিন্তু 2140-এ sales_invoice-সূত্রের
credit ৭৭,৪০০। পার্থক্য ৯,০০০। কী হয়েছে থাকতে পারে?
(ইঙ্গিত: section ৪-এর রহিম)সেট ঘ — নকশা
২১। একটা e-commerce: order → shipped → delivered → paid (COD)।
revenue কোন ধাপে? entry কোন ধাপে? COD-তে "টাকা পাওয়া" আর
"delivery" একই দিন — তবু কি দুটো আলাদা document লাগবে?
২২। একটা subscription service: মাসিক ৯৯৯ টাকা, card থেকে
স্বয়ংক্রিয় কাটে, invoice কেউ চায় না। invoice document কি
লাগবে? না লাগলে source document কী?
২৩। Gapless নম্বরে বছর বদলের দিন কী হয়? fiscal_year কে ঠিক করে —
invoice_date, নাকি issue-র আজকের তারিখ? back-dated invoice
(গত বছরের তারিখে, এ বছরে issue) কোন sequence পাবে?
২৪। Multi-currency invoice (অধ্যায় ৫৪-এর আগাম): USD-এ invoice,
BDT-এ খাতা। line_net কোন currency-তে রাখবেন? দুটোই?
revenue কোন rate-এ?উত্তর আছে Workbook-এর Answer Key, অধ্যায় ১৩-এ।
৯. Developer Challenge
একটি SalesInvoiceService নকশা করুন — draft থেকে issued, cancelled, আর report পর্যন্ত।
যা যা নকশা করবেন:
১.
sales_invoices,sales_invoice_lines,tax_codes,document_sequences— সম্পূর্ণ schema, constraint সহ। “issued invoice অপরিবর্তনীয়” — এটা database-এ কীভাবে প্রয়োগ করবেন (trigger? row-level permission? শুধু application?) আর প্রতিটির দুর্বলতা কী?২. Totals-এর যুক্তি — line_net, tax_amount, subtotal, tax_total, grand_total —
DECIMAL-এ, rounding-এর একটা পদ্ধতি বেছে, আর issue-র মুহূর্তে পুনর্গণনা করে মেলানো। rounding-এর সিদ্ধান্ত কোথায় লেখা থাকবে যাতে VAT report একই পদ্ধতি ব্যবহার করে?৩.
issueInvoice()— নম্বর নেওয়া, journal entry তৈরি, post, status — একটাই transaction-এ। ব্যর্থ হলে কোনটা rollback হবে? নম্বর কি ফিরে যাবে? (হ্যাঁ — কীভাবে নিশ্চিত করবেন?)৪. Posting rule — line-ধরে account নির্ধারণ (revenue / deferred), account-ধরে যোগ, tax code-ধরে যোগ, cash হলে Cash/Bank নইলে A/R + party। এটা এমনভাবে লিখুন যেন অধ্যায় ১৫-এর purchase invoice একই কাঠামোয় শুধু দিক উল্টে চলে।
৫.
cancelInvoice()— তিনটি শর্ত, reversal, status। শর্ত না মিললে ব্যবহারকারীকে কী বলবেন, আর credit note-এর দিকে কীভাবে পাঠাবেন (অধ্যায় ১৯-এর আগাম)?৬. Sales register, revenue-by-account, VAT output report — তিনটি query, আর VAT report-এর দুই উৎস (invoice line বনাম GL) মেলানোর রাতের যাচাই।
৭. Item master-এ
revenue_account_id— কে বসাবেন, কে বদলাতে পারবেন, বদলালে কী হবে (পুরনো invoice অপরিবর্তিত — কেন, কীভাবে)? এটা অধ্যায় ৩৯-এর account mapping-এর প্রথম রূপ।৮. ছয়টি test (section ৫) — প্রতিটির জন্য কোন account-ভিত্তিক assertion লিখবেন, অধ্যায় ১০-এর “Trial Balance যা ধরে না” মাথায় রেখে।
৩ আর ৪ নম্বরটাই আসল পরীক্ষা। Gapless নম্বর আর atomic issue — এটা একটা transaction-boundary সমস্যা যা প্রতিটি ERP-তে অন্তত একবার ভুল হয়। আর posting rule-টা এমনভাবে লেখা যাতে purchase, credit note, debit note — সব একই ছাঁচে চলে — সেটাই অধ্যায় ৩৮-এর Posting Rule Engine-এর বীজ।
১০. Summary Card
দুটো প্রশ্ন
আয় কখন? delivery / invoice-এ, একবার → Income Statement
টাকা কখন? receipt-এ → Cash Flow
মাঝখানে A/REntry
নগদ বিক্রি Dr Cash/Bank (মোট) Cr Revenue (net) Cr VAT Payable
বাকিতে বিক্রি Dr A/R [গ্রাহক] (মোট) Cr Revenue (net) Cr VAT Payable
টাকা এল Dr Bank Cr A/R [গ্রাহক] ← Revenue নয়
ভবিষ্যৎ সেবা Dr A/R Cr Deferred Revenue Cr VAT
অগ্রিম Dr Bank Cr Customer Advanceচার account
টাকা? invoice? আয়?
Sales — হ্যাঁ হ্যাঁ
A/R না হ্যাঁ হ্যাঁ
Deferred Revenue — হ্যাঁ না
Customer Advance হ্যাঁ না নাVAT ও Discount
Revenue net of VAT, সবসময় VAT → 2140 (liability)
হার table-এ, rounding একটাই
Trade discount → দাম কমে, account নেই
Settlement disc. → receipt-এর ঘটনা (অধ্যায় ১৪)Invoice
draft → issued (নম্বর, entry, অপরিবর্তনীয়) → paid
└→ cancelled (reversal: একই period, টাকা আসেনি)
নইলে credit note (অধ্যায় ১৯)
নম্বর: issue-তে, gapless, FOR UPDATE, পুনর্ব্যবহার নয়Developer checklist
□ invoice আর receipt আলাদা document, আলাদা entry
□ revenue_account_id line-এ copy, item master থেকে
□ tax_codes table, কোডে হার নয়
□ DECIMAL সর্বত্র, rounding একটাই পদ্ধতি
□ issue-তে line থেকে totals পুনর্গণনা == header
□ document_sequences + FOR UPDATE, issue-র transaction-এ
□ DB SEQUENCE নয়
□ issued = অপরিবর্তনীয়; সংশোধন নতুন document-এ
□ cancelled নম্বর থাকে
□ service_from/to → deferred, revenue নয়
□ advance 2160-এ, revenue নয়
□ posting rule: account-ধরে যোগ, tax-ধরে যোগ
□ রাতে: register == GL (1130), invoice VAT == GL (2140), issued-but-unposted == 0
□ test: receipt-এ revenue অপরিবর্তিতপরবর্তী অধ্যায়
অধ্যায় ১৪ — Accounts Receivable: Invoice issue হলো, A/R-এ ৪,৯৪,৫০০ বসল, তারপর টাকা এল। কিন্তু টাকা যদি আংশিক আসে? একসাথে তিনটা invoice-এর টাকা এলে কোনটার বিপরীতে কত? তাড়াতাড়ি দিলে ২% ছাড়? ৯০ দিনেও না এলে? পরের অধ্যায়ে receipt allocation, aging, settlement discount, আর গ্রাহকের statement — অর্থাৎ invoice আর টাকার মাঝের পুরো সময়টা।