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

অধ্যায় ১৩ — 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_at column রেখে দুটোকে এক করে ফেলে, সে প্রথম দিন থেকেই 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,000

Credit পাশ অভিন্ন। শুধু 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 discountSettlement (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 ← LIABILITY

Advance আর 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

বিক্রি

ঘটনাDebitCredit
নগদ বিক্রিCash/Bank (মোট)Revenue (net), VAT Payable
বাকিতে বিক্রিA/R [গ্রাহক] (মোট)Revenue (net), VAT Payable
টাকা এল (পরে)BankA/R [গ্রাহক] — Revenue নয়
ভবিষ্যতের সেবার invoiceA/R [গ্রাহক]Deferred Revenue, VAT Payable
Deferred → আয় (মাসে মাসে)Deferred RevenueRevenue
অগ্রিম টাকা (invoice নেই)BankCustomer 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,000

Issued হয়ে গেছে — বদলানো যাবে না। একই দিনে, টাকা আসেনি, গ্রাহককে পাঠানোর আগেই ধরা পড়েছে — তাই 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 আলাদা।

মাসের হিসাব — দুটো উত্তর পাশাপাশি

তারিখঘটনাRevenueA/RDeferredAdvanceVATCash/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-0001

FOR 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 registersales_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 কোডেহার বদলালে deploytax_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 থেকে joinitem বদলালে পুরনো 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/R

Entry

নগদ বিক্রি 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 আর টাকার মাঝের পুরো সময়টা।