৩১ জুল, ২০২৫·8 মিনিট পড়তে

ট্যাক্স ও ইনভয়েসের জন্য বহুমুদ্রা মূল্য নির্ধারণ ডেটা মডেল

একটি বহুমুদ্রা মূল্য নির্ধারণ ডেটা মডেল শিখুন যা বিনিময় হার, রাউন্ডিং, কর এবং লোকালাইজড ইনভয়েস প্রদর্শন হ্যান্ডেল করে — আশ্চর্যের কোনো জায়গা না রেখে।

ট্যাক্স ও ইনভয়েসের জন্য বহুমুদ্রা মূল্য নির্ধারণ ডেটা মডেল

সাধারণত বহুমুদ্রা ইনভয়েসে কী ভুল হয়

বহুমুদ্রা ইনভয়েস সাধারণত বিরক্তিকর ও ব্যয়বহুলভাবে ব্যর্থ হয়। UI-তে সংখ্যাগুলো ঠিক দেখায়, তারপর কেউ PDF এক্সপোর্ট করে, অ্যাকাউন্টিং সেটা ইম্পোর্ট করে, এবং টোটালগুলো লাইন আইটেমের সাথে মেলেনা।

মূল কারণ সহজ: অর্থগত গণনা শুধু এক্সচেঞ্জ রেটে গুণ করা নয়। কর, রাউন্ডিং, এবং রেট ধরার ঠিক সময়—এসব ফলকে প্রভাবিত করে। যদি আপনার প্রাইসিং ডেটা মডেল এই সিদ্ধান্তগুলিকে স্পষ্ট করে না রাখে, তাহলে সিস্টেমের বিভিন্ন অংশ "সহায়কভাবে" পুনরায় গণনা করে ভিন্ন ফল দেবে।

তিনটি ভিউই সম্মত থাকতে হবে, যদিও তারা ভিন্ন মুদ্রা দেখায়:

  • গ্রাহকের ভিউ: গ্রাহক মুদ্রায় স্পষ্ট মূল্য, এবং এমন মোট যে সবগুলো যোগ করলে মিলে।
  • অ্যাকাউন্টিং ভিউ: রিপোর্টিং ও রিকনসিলিয়েশনের জন্য ধারাবাহিক বেস পরিমাণ।
  • অডিট ভিউ: কাগজের ট্রেইল যা দেখায় কোন রেট ও রাউন্ডিং নিয়ম ইনভয়েস তৈরি করেছে।

ম্যাচ না হওয়া সাধারণত বিভিন্ন জায়গায় নেওয়া ছোট সিদ্ধান্ত থেকে আসে। একজন দল প্রতি লাইন আইটেমে রাউন্ড করে; অন্যজন কেবল মোটে রাউন্ড করে। এক পেজ বর্তমান রেট ব্যবহার করে; অন্যটি ইনভয়েস-তারিখ রেট ব্যবহার করে। কিছু ট্যাক্স ছাড়ের আগে প্রযোজ্য, অন্যগুলো পরে। কিছু ট্যাক্স মূল্যর মধ্যে অন্তর্ভুক্ত; অন্যগুলো উপরে যোগ করা হয়।

একটি বাস্তব উদাহরণ: আপনি EUR-এ 19.99 দাম বিক্রি করেন, ইনভয়েস করেন GBP-এ, এবং রিপোর্ট করেন USD-এ। যদি আপনি প্রতি লাইনে রূপান্তর করে 2 দশমিক পর্যন্ত রাউন্ড করেন, তাহলে ট্যাক্সের মোট আলাদা হতে পারে যতক্ষণ না আপনি প্রথমে যোগ করে একবার রূপান্তর করেন। দুইটি পদ্ধতিই যুক্তিযুক্ত হতে পারে, কিন্তু আপনার নিয়ম হতে হবে একটাই।

লক্ষ্য হল পূর্বানুমেয় গণনা এবং স্পষ্টভাবে সংরক্ষিত মান। প্রতিটি ইনভয়েসে অনুমান ছাড়াই উত্তর থাকা উচিত: কি পরিমাণ এন্ট্রি করা হয়েছিল, কোন মুদ্রায় এন্ট্রি করা হয়েছিল, কোন রেট ব্যবহার করা হয়েছে (এবং কখন), কী রাউন্ড করা হয়েছে (এবং কিভাবে), এবং কোন ট্যাক্স নিয়ম প্রয়োগ করা হয়েছে। এই স্বচ্ছতা UI, PDF, এক্সপোর্ট ও অডিট জুড়ে মোটগুলোকে স্থিতিশীল রাখে।

স্কিমা ড্র করার আগে যে শব্দগুলোতে সম্মত হওয়া দরকার

টেবিল ড্র করার আগে, নিশ্চিত করুন সবাই একই শব্দগুলো ব্যবহার করে। বেশিরভাগ বহুমুদ্রা বাগ প্রযুক্তিগত নয়, তারা "আমরা ভিন্নভাবে বোঝেছি" প্রকারের বাগ। একটি পরিষ্কার স্কিমা শুরু হয় এমন ডেফিনিশন থেকে যা প্রডাক্ট, ফাইনান্স এবং ইঞ্জিনিয়ারিং সবাই গ্রহণ করে।

ডাটাবেজে প্রভাব ফেলে এমন মুদ্রা শব্দগুলো

প্রতি মনিট প্রবাহের জন্য তিনটি মুদ্রায় সম্মত হন:

  • Transactional currency: গ্রাহক যা দেখে এবং সম্মত হয় (প্রাইস লিস্ট, কার্ট, ইনভয়েস ডিসপ্লে)।
  • Settlement currency: আপনি যে মুদ্রায় প্রকৃত পে পান (পেমেন্ট প্রোভাইডার বা ব্যাংক যা সেটল করে)।
  • Reporting currency: ড্যাশবোর্ড ও অ্যাকাউন্টিং সারাংশে ব্যবহৃত মুদ্রা।

এছাড়াও minor units সংজ্ঞায়িত করুন। USD-এ 2 (সেন্ট), JPY-তে 0, KWD-তে 3। এটা গুরুত্বপূর্ণ কারণ "12.34" ফ্লোটিং পয়েন্ট হিসেবে রাখলে ড্রিফট হবে, কিন্তু ছোট ইউনিটে (যেমন 1234 সেন্ট) পূর্ণসংখ্যা রাখলে এক্স্যাক্ট থাকে এবং রাউন্ডিং পূর্বানুমেয় হয়।

ট্যাক্স সম্পর্কিত শব্দ যা মোটকে বদলে দেয়

ট্যাক্সেও সমান স্তরের সম্মতি দরকার। সিদ্ধান্ত নিন মূল্যগুলো tax-inclusive (প্রদর্শিত মূল্যই কর অন্তর্ভুক্ত) নাকি tax-exclusive (কর উপরে যোগ) হবে। এছাড়া নির্ধারণ করুন ট্যাক্স প্রতি লাইন আইটেমে গণনা হবে নাকি প্রতি ইনভয়েসে (প্রথমে যোগ করে পরে ট্যাক্স)। এই পছন্দগুলো রাউন্ডিংকে প্রভাবিত করে এবং চূড়ান্ত প্রদেয় পরিমাণ কয়েকটি minor unit দ্বারা বদলে দিতে পারে।

শেষে, স্থির করুন কী সংরক্ষণ করতে হবে বনাম কী পুনরায় গণনা করা যাবে:

  • যা আইনি ও আর্থিকভাবে গুরুত্বপূর্ণ তা সংরক্ষণ করুন: সম্মত দাম, প্রয়োগকৃত ট্যাক্স রেট, চূড়ান্ত রাউন্ড করা মোট, এবং ব্যবহৃত মুদ্রা।
  • কী নিরাপদে পুনরায় গণনা করা যাবে তা ডেরাইভ করুন: ফরম্যাট করা স্ট্রিং, ডিসপ্লে-অনলি রূপান্তর, এবং বেশিরভাগ মধ্যবর্তী গণনা।

মূল অর্থ ক্ষেত্র: কী সংরক্ষণ করবেন এবং কীভাবে

শুরু করুন কোন সংখ্যাগুলোই এমন ফ্যাক্ট যা আপনি সংরক্ষণ করবেন এবং কোনগুলো ফলাফল যা পুনরায় গণনা করা যাবে। এদের মিশ্রণ হলেই ইনভয়েসে এক স্ক্রিনে এক মোট দেখা যায় এবং এক্সপোর্টে অন্য মোট।

অর্থকে ছোট ইউনিটে পূর্ণসংখ্যা হিসেবে সংরক্ষণ করুন (যেমন সেন্ট) এবং সর্বদা মুদ্রা কোড পাশেই রাখুন। মুদ্রা ছাড়া একটি পরিমাণ অসম্পূর্ণ ডেটা। পূর্ণসংখ্যা ছোট ফ্লোটিং ত্রুটিগুলো এড়ায় যা বহু লাইনের যোগফলে দেখা যায়।

একটি বাস্তব পরামর্শ হলো কাঁচা ইনপুট এবং ক্যালকুলেটেড আউটপুট দুইটিই রাখা। ইনপুটগুলো ব্যাখ্যা করে ব্যবহারকারী কি দিল। আউটপুটগুলো ব্যাখ্যা করে আপনি কি বিল করেছেন। কেউ মাস পরে অভিযোগ করলে আপনাকে দুটোই লাগবে।

ইনভয়েস লাইনের জন্য একটি পরিষ্কার, স্থায়ী ফিল্ড সেট দেখতে পারে:

  • unit_price_minor + unit_currency
  • quantity (প্রয়োজনে uom)
  • line_subtotal_minor (ট্যাক্স/ডিসকাউন্টের আগে)
  • line_discount_minor
  • line_tax_minor (অথবা ট্যাক্স টাইপ অনুযায়ী বিভক্ত)
  • line_total_minor (লাইনের চূড়ান্ত পরিমাণ)

রাউন্ডিং কেবল UI-এর বিবরণ নয়। গণনার জন্য ব্যবহৃত রাউন্ডিং পদ্ধতি ও প্রিসিশন পERSIST করুন, বিশেষত যদি আপনি বিভিন্ন minor units (JPY বনাম USD) বা ক্যাশ রাউন্ডিং নিয়ম সমর্থন করেন। একটি ছোট calculation context রেকর্ড calc_precision, rounding_mode, এবং রাউন্ডিং প্রতি লাইন হয় নাকি কেবল ইনভয়েস মোটে—এসব ক্যাপচার করতে পারে।

ডিসপ্লে ফরম্যাটিং স্টোরড ভ্যালুগুলো থেকে আলাদা রাখুন। সংরক্ষিত মানগুলো সাধারণ নম্বর এবং কোড হওয়া উচিত; ফরম্যাটিং (মুদ্রা প্রতীক, সেপারেটর, লোকালাইজড নম্বর ফরম্যাট) প্রেজেন্টেশন লেয়ারের কাজ। উদাহরণস্বরূপ, 12345 + EUR সংরক্ষণ করুন, আর UI ঠিক করবে এটা "€123.45" না কি "123,45 €" দেখাবে।

এক্সচেঞ্জ রেট: টেবিল, টাইমস্ট্যাম্প এবং অডিট ট্রেইল

এক্সচেঞ্জ রেটকে সময়-ভিত্তিক ডেটা এবং একটি স্পষ্ট সোর্স হিসেবে বিবেচনা করুন। "আজকের রেট" পরে নিরাপদে পুনরায় গণনা করা যায় না।

একটি ব্যবহারিক এক্সচেঞ্জ রেট টেবিল সাধারণত অন্তর্ভুক্ত করে:

  • base_currency (রূপান্তর করা, যেমন USD)
  • quote_currency (রূপান্তর গন্তব্য, যেমন EUR)
  • rate (প্রতি 1 base-এ quote, উচ্চ-প্রিসিশন দশমিক হিসেবে সংরক্ষণ)
  • effective_at (রেট যে সময় থেকে বৈধ তার টাইমস্ট্যাম্প)
  • source (প্রোভাইডার) এবং source_ref (তাদের ID বা একটি পলোড হ্যাশ)

অডিটে এই সোর্স তথ্য গুরুত্বপূর্ণ। যদি গ্রাহক অমিলের অভিযোগ করেন, আপনি ঠিক বলতে পারবেন সংখ্যাটি কোথা থেকে এসেছে।

পরবর্তী ধাপে, কোন রেট একটি ইনভয়েস ব্যবহার করবে—একটা নিয়ম বেছে নিন এবং সেটায় দৃঢ় থাকুন। সাধারণ অপশনগুলো হল অর্ডার টাইম, শিপমেন্ট টাইম, বা ইনভয়েস টাইমের রেট। সেরা পছন্দ আপনার ব্যবসার উপর নির্ভর করে; গুরুত্বপূর্ণ অংশ হল ধারাবাহিকতা ও ডকুমেন্টেশন।

আপনি যে নিয়মই বেছে নেন, ইনভয়েসে ব্যবহার করা নির্দিষ্ট রেট সংরক্ষণ করুন (প্রায়ই প্রতিটি ইনভয়েস লাইনেরও)। পরে আবার খুঁজে দেখার উপর নির্ভর করবেন না। fx_rate, fx_rate_effective_at, এবং fx_rate_source মত ফিল্ড ইনভয়েসে যোগ করুন যেন ইনভয়েস পুরোপুরি পুনরুত্পাদন করা যায়।

মিসিং রেটের জন্য (উদাহরণ: উইকেন্ড, ছুটি, প্রোভাইডার আউটেজ), ফলব্যাক আচরণ স্পষ্ট রাখুন। সাধারণ পন্থা হল: পূর্ববর্তী সর্বশেষ রেট ব্যবহার করা, ইনভয়েস ব্লক করা যতক্ষণ না রেট আসে, বা ম্যানুয়াল রেট অনুমোদন সহ অনুমোদন রাখা।

উদাহরণ: একটি অর্ডার শনিবার করা হলো, সোমদিবসে শিপ করা হলো, এবং সোমদিবসই ইনভয়েস করা হলো। যদি আপনার নিয়ম ইনভয়েস-টাইম হয় কিন্তু আপনার প্রোভাইডার উইকেন্ড রেট প্রকাশ না করে, আপনি শুক্রবারের শেষ রেট ব্যবহার করতে পারেন এবং effective_at = Friday 23:59source_ref রেকর্ড করবেন ট্রেসেবিলিটির জন্য।

মুদ্রা রূপান্তর ও রাউন্ডিং নিয়ম যা স্থিতিশীল থাকে

আপনার ডিপ্লয়মেন্ট পথ বেছে নিন
ক্লাউডে ডিপ্লয় করুন অথবা ফুল কন্ট্রোলের জন্য সোর্স কোড এক্সপোর্ট করুন।
AppMaster চেষ্টা করুন

রাউন্ডিং সমস্যা সাধারণত বড় বাগের মতো দেখায় না। তারা 1-পয়সার গ্যাপ হিসেবে দেখা দেয় ইনভয়েস মোট ও লাইনের যোগফলের মধ্যে, অথবা ছোট ট্যাক্স পার্থক্য হিসেবে যা আপনি দেখান এবং পেমেন্ট প্রোভাইডার আশা করে—এরকম হলে সমাধান জটিল হয়। ভাল মডেল রাউন্ডিংকে এমন একটি নিয়ম বানায় যা আপনি ব্যাখ্যা করতে পারেন, না যে পরে প্যাচ করতে হয়।

ঠিক নির্ধারণ করুন কোথায় রাউন্ডিং হবে

রাউন্ডিং করার পয়েন্টগুলো বেছে নিন, এবং বাকি সবকিছু উচ্চ প্রিসিশনে রাখুন। সাধারণ রাউন্ডিং পয়েন্টগুলো:

  • লাইন এক্সটেনশন (quantity x unit price, ডিসকাউন্টের পরে)
  • প্রতিটি ট্যাক্সের পরিমাণ (লাইন-ভিত্তিক বা ইনভয়েস-ভিত্তিক)
  • চূড়ান্ত ইনভয়েস মোট

যদি আপনি এই পয়েন্টগুলি সংজ্ঞায়িত না করেন, সিস্টেমের বিভিন্ন অংশ যখন সুবিধাজনক তখন রাউন্ড করবে এবং মোটগুলো ড্রিফট করবে।

একটি রাউন্ডিং মোড ব্যবহার করুন, ট্যাক্স নিয়মের জন্য স্পষ্ট ব্যতিক্রম রাখুন

একটি রাউন্ডিং মোড বেছে নিন (half-up বা bankers) এবং ধারাবাহিকভাবে প্রয়োগ করুন। গ্রাহকদের বোঝাতে half-up সহজ। Bankers rounding বড় ভলিউমে বায়াস কমাতে সাহায্য করে। যেটাই ব্যবহার করুন, আপনার API, UI, এক্সপোর্ট এবং অ্যাকাউন্টিং রিপোর্টগুলো একই মোড ব্যবহার করবে।

রূপান্তরের সময় অতিরিক্ত প্রিসিশন রাখুন এবং মধ্যবর্তী ধাপগুলোতে রাউন্ডিং কম করে রাখুন (উদাহরণ: FX রেট অনেক দশমিক দিয়ে সংরক্ষণ করুন), তারপর কেবল আপনার নির্ধারিত রাউন্ডিং পয়েন্টে রাউন্ড করুন।

ডিসকাউন্টের ক্ষেত্রেও একটি একক নিয়ম দরকার: ডিসকাউন্ট ট্যাক্সের আগে প্রয়োগ করা হবে (কুপনের ক্ষেত্রে সাধারণ) নাকি ট্যাক্সের পরে (কিছু ফি-তে প্রয়োজন হতে পারে)। এটা লিখে রাখুন এবং একবার কোডে এনকোড করুন।

কিছু অঞ্চলে ট্যাক্স লাইনে প্রতিটি আইটেমে রাউন্ড করা আবশ্যক, অন্যত্র ইনভয়েস মোটে রাউন্ড করা লাগতে পারে। কোডবেস জুড়ে এক-অফ কেস হার্ডকোড করার চেয়ে, একটি rounding policy সেটিং (দেশ/রাজ্য/ট্যাক্স রেজিম অনুযায়ী) সংরক্ষণ করুন এবং গণনা সেই নীতিকে অনুসরণ করুক।

একটি সহজ চেক: যদি আপনি একই ইনভয়েসটি কাল পুনর্গঠন করেন একই সংরক্ষিত রেট ও পলিসি ব্যবহার করে, আপনি প্রত্যেক সেন্টে একই ফল পাবেন।

ট্যাক্স ফিল্ড: VAT, sales tax এবং বহু ট্যাক্সের প্যাটার্ন

একটি অডিট ট্রেইল স্ক্রিন যোগ করুন
একটি অডিট ভিউ বানান যা সংরক্ষিত পরিমাণ এবং নীতিমালা ব্যবহার করে মোটগুলো ব্যাখ্যা করে।
AppMaster চেষ্টা করুন

ট্যাক্স দ্রুত জটিল হয়ে যায় কারণ এগুলো ক্রেতার অবস্থান, আপনি কী বিক্রি করছেন, এবং মূল্য net না gross প্রদর্শিত হচ্ছে—এসবের উপর নির্ভর করে। একটি পরিষ্কার মডেল ট্যাক্সকে ইম্প্লিসিট না রেখে স্পষ্ট রাখে।

ট্যাক্সের বেস অনিশ্চিত করবেন না। সংরক্ষণ করুন মূল্যটি net (ট্যাক্স আলাদাভাবে যোগ করা হবে) নাকি gross (ট্যাক্স অন্তর্ভুক্ত) — এবং তারপর আপনি প্রয়োগ করা রেট এবং গণনা করা ট্যাক্স পরিমাণও স্ন্যাপশট হিসেবে সংরক্ষণ করুন, যাতে পরে নিয়ম বদলালে ইতিহাস বদলায় না।

প্রতি ইনভয়েস লাইনে ন্যূনতম সেট যা বছর পরে স্পষ্ট থাকবে:

  • tax_basis (NET বা GROSS)
  • tax_rate (দশমিক, উদাহরণ 0.20)
  • taxable_amount_minor (আপনি যে বেসে ট্যাক্স করেছেন)
  • tax_amount_minor
  • tax_method (PER_LINE বা ON_SUBTOTAL)

একাধিক ট্যাক্স প্রযোজ্য হলে (উদাহরণ: VAT প্লাস সিটি সারচার্জ), একটি পৃথক ব্রেকডাউন টেবিল রাখুন যেমন InvoiceLineTax যেখানে প্রতিটি প্রয়োগকৃত ট্যাক্সের জন্য একটি সারি থাকবে। প্রতিটি সারিতে থাকা উচিত tax_code, tax_rate, taxable_amount_minor, tax_amount_minor, মুদ্রা, এবং গণনা সময় ব্যবহৃত জুরিসডিকশনের হিন্ট (দেশ, অঞ্চল, পোস্টাল কোড যেখানে প্রাসঙ্গিক)।

ইনভয়েস বা ইনভয়েস লাইনে প্রয়োগকৃত নিয়মগুলোর স্ন্যাপশট রাখুন, যেমন rule_version বা সিদ্ধান্ত-ইনপুটের JSON ব্লব (গ্রাহকের ট্যাক্স স্ট্যাটাস, reverse charge, exemption)। যদি ভবিষ্যতে VAT নিয়ম বদলে যায়, পুরনো ইনভয়েসগুলো তখনও আপনার আসলে যা চার্জ করেছিলেন তা মেলে।

উদাহরণ: একটি SaaS সাবস্ক্রিপশন জার্মানিতে বিক্রি হলে 19% VAT NET লাইনের মূল্যে প্রযোজ্য হতে পারে, প্লাস 1% লোকাল ট্যাক্স। লাইনের টোটালগুলো বিল করা হিসেবে সংরক্ষণ করুন এবং প্রতিটি ট্যাক্সের জন্য একটি ব্রেকডাউন সারি রাখুন প্রদর্শন ও অডিটের জন্য।

টেবিল ডিজাইন ধাপে ধাপে কীভাবে করবেন

এটি মেধাবী গণিতের চেয়ে বেশি সঠিক সময়ে সঠিক ফ্যাক্টগুলো ফ্রিজ করা সম্পর্কিত। লক্ষ্য হলো একটি ইনভয়েস মাস পরে খুললে একই সংখ্যাগুলো দেখায়।

শুরুতে সিদ্ধান্ত নিন প্রোডাক্ট মূল্যের জন্য ট্রুথ কোথায় আছে। অনেক দল একটি বেস-কারেন্সি মূল্য প্রতি প্রোডাক্ট রাখে এবং বাজার অনুসারে ওভাররাইড যোগ করে (উদাহরণ: USD এবং EUR এর আলাদা দাম)। যাইই হোক, স্কিমায় এটা স্পষ্ট রাখুন যাতে আপনি "ক্যাটালগ মূল্য" এবং "রূপান্তরিত মূল্য" মিশ্রিত না করেন।

একটি সহজ সিকোয়েন্স যা টেবিলগুলো বোধগম্য রাখে:

  • Products and pricing: product_id, price_amount_minor, price_currency, effective_from (মূল্য সময়ে সময়ে বদলে গেলে)।
  • Order and invoice headers: document_currency, customer_locale, billing_country, এবং টাইমস্ট্যাম্প (issued_at, tax_point_at)।
  • Line items: unit_price_amount_minor, quantity, discount_amount_minor, tax_amount_minor, line_total_amount_minor, এবং প্রতিটি সংরক্ষিত অর্থ ক্ষেত্রের জন্য মুদ্রা।
  • Exchange rate snapshot: ব্যবহার হওয়া নির্দিষ্ট রেট (rate_value, rate_provider, rate_timestamp) যা অর্ডার বা ইনভয়েস থেকে রেফার করা হবে।
  • Tax breakdown records: প্রতি ট্যাক্স একটি সারি (tax_type, rate_percent, taxable_base_minor, tax_amount_minor) প্লাস একটি calculation_method ফ্ল্যাগ।

পরে থেকে পুনরায় গণনার উপর নির্ভর করবেন না। যখন ইনভয়েস তৈরি করবেন, চূড়ান্ত ইউনিট মূল্য, ডিসকাউন্ট, এবং টোটালগুলো ইনভয়েস লাইনে কপি করুন—even যদি সেগুলো অর্ডার থেকে আসে।

ট্রেসেবিলিটির জন্য ইনভয়েসে একটি calculation_version (বা calc_hash) এবং একটি ছোট calculation_log টেবিল যোগ করুন যা রেকর্ড করে কে রিক্যালকুলেশন ট্রিগার করেছে এবং কেন (উদাহরণ: "ইস্যু করার আগে রেট আপডেট করা হলো")।

লোকালাইজড ইনভয়েস প্রদর্শন সংখ্যাগুলো ভাঙা ছাড়াই

FX ও ট্যাক্স সেটিংস ম্যানেজ করুন
রেট, ট্যাক্স নীতি এবং অনুমোদনের জন্য অ্যাডমিন স্ক্রিন তৈরি করুন যা ইনভয়েসকে স্থিতিশীল রাখে।
এখন শুরু করুন

লোকালাইজেশন ইনভয়েসের কিভাবে দেখায় সেটা বদলানো উচিত, মানে কি তা নয়। সব গণনা সংরক্ষিত সংখ্যাগত মান (ছোট ইউনিট বা ফিক্সড-প্রিসিশন দশমিক) ব্যবহার করে করুন, তারপর রেন্ডারিংয়ের সময় লোকাল ফরম্যাটিং প্রয়োগ করুন।

ইনভয়েস প্রেজেন্টেশন সেটিংগুলো ইনভয়েসেই রাখুন, কেবল গ্রাহকের প্রোফাইলে না। গ্রাহকরা দেশ, বিলিং কনট্যাক্ট ও পছন্দ বদলে ফেলেন; একটি ইনভয়েস একটি আইনি স্ন্যাপশট। invoice_language, invoice_locale, এবং ফরম্যাটিং ফ্ল্যাগ (উদাহরণ: trailing zeros দেখাবেন কি না) ডকুমেন্টের সাথে সংরক্ষণ করুন যাতে ছয় মাস পরে পুনরায় প্রিন্ট করলে মূল অনুলিপির মতোই হয়।

মুদ্রা চিহ্ন প্রদর্শনের বিষয়। কিছু লোকেলে প্রতীক সংখ্যার আগে, কিছুতে পরে থাকে; কিছুতে স্পেস লাগে, কিছুতে লাগে না। প্রতীক স্থাপন, স্পেসিং, দশমিক সেপারেটর, এবং হাজার বিভাজন রেন্ডার সময় ইনভয়েস লোকেল ও মুদ্রার উপর ভিত্তি করে হ্যান্ডেল করুন। স্টোরড মানে প্রতীক বেক করবেন না, এবং ফরম্যাট করা স্ট্রিংগুলো নম্বারে পার্স করবেন না।

যদি আপনাকে রিপোর্টিং-এ একটি দ্বিতীয় মুদ্রা দেখাতে হয় (প্রায়শই হোম মুদ্রা যেমন USD বা EUR), সেটি স্পষ্টভাবে সেকেন্ডারি টোটাল হিসেবে দেখান, রিপ্লেসমেন্ট নয়। ডকুমেন্ট কারেন্সি আইনি সোর্স অফ ট্রুথ থাকে।

ইনভয়েস আউটপুটের জন্য একটি ব্যবহারিক সেটআপ:

  • লাইন আইটেম ও টোটালগুলো ডকুমেন্ট কারেন্সিতে দেখান, ইনভয়েস-লোকেল ফরম্যাটিং ব্যবহার করে।
  • বিকল্পভাবে সেকেন্ডারি রিপোর্টিং টোটাল দেখান, রেট সোর্স এবং টাইমস্ট্যাম্প লেবেল করে।
  • ট্যাক্স ব্রেকডাউন আলাদা লাইনে দেখান (taxable base, প্রতিটি ট্যাক্স, মোট ট্যাক্স), একক মিলিত পরিমাণ নয়।
  • PDF ও ইমেইল একই সংরক্ষিত টোটাল থেকে রেন্ডার করুন যাতে সংখ্যাগুলো ড্রিফট না করে।

উদাহরণ: একজন ফরাসি গ্রাহক CHF-এ বিল পায়। ইনভয়েস লোকেল কমা দশমিক ব্যবহার করে এবং মুদ্রা সংখ্যার পরে রাখে, কিন্তু গণনা এখনও সংরক্ষিত CHF পরিমাণ ও ট্যাক্স টোটাল ব্যবহার করে। ফরম্যাট বদলায়; সংখ্যাগুলো না।

সাধারণ ভুল এবং ফাঁদ যা এড়ানো উচিত

বহুমুদ্রা ইনভয়েস দ্রুত ভাঙার দ্রুততম উপায় হল অর্থকে সাধারণ একটি সংখ্যার মতো বিবেচনা করা। মূল্য, ট্যাক্স, এবং টোটালের জন্য ফ্লোটিং পয়েন্ট টাইপ ব্যবহার করলে ছোট ত্রুটি দেখা দেয় যা পরে "$0.01-ই অফ" সমস্যা তৈরি করে। পরিমাণগুলো ছোট ইউনিটে পূর্ণসংখ্যা হিসেবে রাখুন (সেন্ট) বা একটি স্পষ্ট স্কেলের সাথে ফিক্সড দশমিক টাইপ ব্যবহার করুন এবং জায়গায় ধারাবাহিকভাবে ব্যবহার করুন।

আরেক ক্লাসিক ফাঁদ হল ইতিহাস অনিচ্ছাকৃতভাবে বদলানো। যদি আপনি আজকের এক্সচেঞ্জ রেট দিয়ে একটি পুরনো ইনভয়েস পুনরায় গণনা করেন, বা আপডেট হওয়া ট্যাক্স নিয়ম দিয়ে, তাহলে আপনি আর গ্রাহক যে ডকুমেন্টটি দেখেছিলো এবং পরিশোধ করেছিল সেটার সাথে মিলবে না। ইনভয়েসগুলো অপরিবর্তনীয় হওয়া উচিত: ইস্যু হলে নির্দিষ্ট এক্সচেঞ্জ রেট, রাউন্ডিং নিয়ম, এবং ট্যাক্স পদ্ধতি সংরক্ষণ করুন, এবং সংরক্ষিত টোটাল পুনরায় গণনা করবেন না।

একটি লাইনে মুদ্রা মিশ্রিত করাও একটি চুপচাপ স্কিমা বাগ। যদি ইউনিট মূল্য EUR-এ, ডিসকাউন্ট USD-এ, এবং ট্যাক্স GBP-এ হয়, তাহলে পরে গণিত ব্যাখ্যা করা যাবে না। একটি ডকুমেন্ট কারেন্সি চয়ন করুন ডিসপ্লে ও সেটেলমেন্টের জন্য, এবং ভিতরে রিপোর্টিংর জন্য একটি বেস কারেন্সি (যদি প্রয়োজন) নির্বাচন করুন। প্রতিটি সংরক্ষিত পরিমাণের একটি স্পষ্ট মুদ্রা থাকা উচিত।

রাউন্ডিং ভুল প্রায়ই অনেক ধাপে রাউন্ডিং করার কারণে হয়। যদি আপনি ইউনিট প্রাইস-এ রাউন্ড করেন, তারপর লাইন টোটালে, তারপর প্রতিটি লাইনে ট্যাক্সে, তারপর সাবটোটালে আবার—তাহলে মোটগুলো লাইনের যোগফলের সাথে মিলে না।

সতর্কতার জন্য কিছু ফাঁদ:

  • অর্থ বা এক্সচেঞ্জ রেটের জন্য ফ্লোট ব্যবহার
  • পুরনো ইনভয়েসগুলোর জন্য রূপান্তর পুনরায় চালানো
  • একটি লাইনে একাধিক মুদ্রা থাকা অনুমতি দেওয়া
  • অনেক ধাপে রাউন্ডিং করা বদলে নির্ধারিত পয়েন্টে রাউন্ড করা
  • প্রতিটি ডকুমেন্টে রেট টাইমস্ট্যাম্প, রাউন্ডিং মোড এবং ট্যাক্স পদ্ধতি সংরক্ষণ না করা

উদাহরণ: আপনি CAD-এ ইনভয়েস তৈরি করেন, EUR-এ সেবা ব্যয় রূপান্তর করে, তারপর পরে আপনার রেট টেবিল আপডেট করা হলো। যদি আপনি কেবল EUR পরিমাণ সংরক্ষণ করে ডিসপ্লেতে রূপান্তর করে রাখেন, CAD টোটাল পরের সপ্তাহে বদলে যাবে। EUR পরিমাণ, প্রয়োগকৃত FX রেট (এবং সময়), এবং ইনভয়েসে ব্যবহৃত চূড়ান্ত CAD পরিমাণ সব সংরক্ষণ করুন।

চালু করার আগে দ্রুত চেকলিস্ট

বিলিং দ্রুত প্রটোটাইপ করুন
ওয়েব ও মোবাইল UI একই লজিক থেকে ঘুরিয়ে দ্রুত একটি অভ্যন্তরীণ বিলিং টুল তৈরি করুন।
প্রটোটাইপ তৈরি করুন

বহুমুদ্রা ইনভয়েসগুলো "সম্পন্ন" ঘোষণা করার আগে সামঞ্জস্যতার উপর একটি চূড়ান্ত পাস করুন। বেশিরভাগ বাগ সাধারণত জটিল নয়; এগুলো আপনার যা সংরক্ষণ করেন, আপনি কী দেখান, এবং আপনি কী যোগ করছেন—এসবের অমিল থেকে আসে।

রিলিজ গেট হিসেবে এটি ব্যবহার করুন:

  • প্রতিটি ইনভয়েস হেডারে ঠিক একটি ডকুমেন্ট কারেন্সি আছে, এবং ইনভয়েসে সংরক্ষিত প্রতিটি টোটাল সেই মুদ্রায়।
  • আপনি সংরক্ষণ করা প্রতিটি আর্থিক মান একটি পূর্ণসংখ্যা ছোট ইউনিটে, লাইনের টোটাল, ট্যাক্স পরিমাণ, ডিসকাউন্ট, এবং শিপিং সহ।
  • ইনভয়েসে প্রয়োগকৃত নির্দিষ্ট এক্সচেঞ্জ রেট সংরক্ষিত আছে (একটি নির্দিষ্ট দশমিক), প্লাস টাইমস্ট্যাম্প এবং রেট সোর্স।
  • রাউন্ডিং নিয়মগুলো নথিভুক্ত এবং এক শেয়ার্ড জায়গায় ইমপ্লিমেন্ট করা আছে।
  • একাধিক ট্যাক্স প্রযোজ্য হলে, আপনি প্রতিটি লাইনের জন্য ট্যাক্স ব্রেকডাউন সংরক্ষণ করেন (প্রয়োজনে প্রতিটি জুরিসডিকশনের জন্য), কেবল হেডারের একক ট্যাক্স টোটাল নয়।

স্কিমা ঠিক হলে, একজন অডিটারের দৃষ্টিকোণে গণনা যাচাই করুন। ইনভয়েস টোটালগুলো সংরক্ষিত লাইনের টোটাল ও সংরক্ষিত ট্যাক্স পরিমাণের যোগফল সমান হওয়া উচিত। দেখানো মান বা ফরম্যাট করা স্ট্রিং থেকে পুনরায় গণনা করবেন না।

একটি ব্যবহারিক টেস্ট: তিনটি লাইনের একটি ইনভয়েস নিন, একটি ডিসকাউন্ট প্রয়োগ করুন, এবং একটি লাইনে দুইটি ট্যাক্স যোগ করুন। তারপর একটি ভিন্ন লোকেলে প্রিন্ট করে নিশ্চিত করুন সংরক্ষিত সংখ্যাগুলো বদলায় না।

উদাহরণ কেস: এক অর্ডার, তিনটি মুদ্রা, এবং ট্যাক্স

রিলিজ গেট পাস করুন
আপনার চেকলিস্টকে ডাটাবেস ফিল্ড এবং ভ্যালিডেশন হিসেবে রূপান্তর করুন, হাতে-কলমে প্রতিটি স্ক্রিন না লিখেই।
নির্মাণ শুরু করুন

একজন US গ্রাহক USD-এ বিল পায়, আপনার EU সরবরাহকারী আপনাকে EUR-এ চার্জ করে, এবং আপনার ফাইন্যান্স দল GBP-এ রিপোর্ট করে। এখানে একটি মডেল শান্ত থাকতে পারে বা ছোট 1-পয়সার অমিলের স্তূপে পরিণত হতে পারে।

অর্ডার: একটি প্রোডাক্টের 3 ইউনিট।

  • গ্রাহকের দাম: $19.99 প্রতি ইউনিট (USD)
  • ডিসকাউন্ট: লাইনে 10%
  • US সেলস ট্যাক্স: 8.25% (ডিসকাউন্টের পরে ট্যাক্স)
  • সরবরাহকারীর খরচ: EUR 12.40 প্রতি ইউনিট (EUR)
  • রিপোর্টিং কারেন্সি: GBP

কি হয় এবং কখন আপনি রূপান্তর করবেন

একটি রূপান্তর মুহূর্ত বেছে নিন এবং সেটায় দৃঢ় থাকুন। বহু ইনভয়েসিং সিস্টেমে, ইনভয়েস ইস্যু করার সময় রূপান্তর করা নিরাপদ পছন্দ এবং পরে ব্যবহার করার জন্য নির্দিষ্ট রেট সংরক্ষণ করা হয়।

ইনভয়েস তৈরির সময়:

  1. USD লাইনের সাবটোটাল গণনা: 3 x 19.99 = 59.97 USD.
  2. ডিসকাউন্ট প্রয়োগ: 59.97 x 10% = 5.997, যা রাউন্ড করে 6.00 USD.
  3. লাইন নেট: 59.97 - 6.00 = 53.97 USD.
  4. ট্যাক্স: 53.97 x 8.25% = 4.452525, রাউন্ড করে 4.45 USD.
  5. মোট: 53.97 + 4.45 = 58.42 USD.

রাউন্ডিং কেবল নির্ধারিত পয়েন্টে ঘটে (ডিসকাউন্ট, প্রতিটি ট্যাক্স পরিমাণ, লাইন টোটাল)। সেই রাউন্ড করা ফলাফলগুলো সংরক্ষণ করুন, এবং সর্বদা সংরক্ষিত মানগুলো যোগ করুন। এতে ক্লাসিক সমস্যা এড়ায় যেখানে আপনার PDF-এ 58.42 দেখায় কিন্তু এক্সপোর্টে পুনরায় গণনা হয়ে 58.43 আসে।

ভবিষ্যতে একই ইনভয়েস পুনরুত্পাদন করতে কী সংরক্ষণ করবেন

ইনভয়েসে (এবং ইনভয়েস লাইনে) সংরক্ষণ করুন কারেন্সি কোড (USD), ছোট ইউনিটে পরিমাণ (সেন্ট), ট্যাক্স ব্রেকডাউন প্রতি ট্যাক্স টাইপ, এবং USD থেকে GBP-এ রিপোর্টিং করার জন্য ব্যবহৃত রেট রেকর্ড আইডি। সরবরাহকারীর খরচের জন্য EUR খরচ এবং সেটি GBP-এ রূপান্তরের রেট রেকর্ডও সংরক্ষণ করুন যদি আপনি কস্টও রূপান্তর করেন।

গ্রাহক একটি পরিষ্কার USD ইনভয়েস দেখবে (মূল্য, ডিসকাউন্ট, ট্যাক্স, মোট)। ফাইন্যান্স USD পরিমাণের পাশাপাশি ফ্রিজ করা GBP সমতুল্য ও নির্দিষ্ট রেট টাইমস্ট্যাম্প এক্সপোর্ট করবে, যাতে মাস শেষে সংখ্যাগুলো ম্যাচ করে এমনকি রেট পরের দিন বদলে গেলেও।

পরবর্তী ধাপ: ইমপ্লিমেন্ট, টেস্ট, এবং রক্ষণযোগ্য রাখা

আপনার মিনিমাম স্কিমা একটি ছোট কনট্র্যাক্ট হিসেবে লিখে রাখুন: কোন পরিমাণগুলো সংরক্ষণ করা হবে (অরিজিনাল, রূপান্তরিত, ট্যাক্স), প্রতিটি পরিমাণ কোন মুদ্রায়, কোন রাউন্ডিং নিয়ম প্রয়োগ হবে, এবং কোন টাইমস্ট্যাম্প এক্সচেঞ্জ রেট লক করবে—এগুলো নির্দিষ্ট ও মনোচোখে রাখুন।

UI স্ক্রীন বানানোর আগে টেস্ট লিখুন। কেবল স্বাভাবিক ইনভয়েস পরীক্ষা করবেন না। এমন এজ-কেস যোগ করুন যা রাউন্ডিং গোলমাল বের করে এবং সমষ্টি সমস্যা ফাঁস করে।

একটি স্টার্টার টেস্ট সেট:

  • খুবই ছোট ইউনিট মূল্য (যেমন 0.01) উচ্চ পরিমাণে গুণ করা
  • ডিসকাউন্ট যা রূপান্তরের পরে রিপিটিং দশমিক তৈরি করে
  • অর্ডার তারিখ ও ইনভয়েস তারিখের মধ্যে এক্সচেঞ্জ রেট পরিবর্তন
  • একই ইনভয়েস টাইপে মিক্সড ট্যাক্স নিয়ম (ট্যাক্স ইনক্লুডেড বনাম এক্সক্লুডেড)
  • রিফান্ড ও ক্রেডিট নোট যা মূল রাউন্ডিং মিলাতে হবে

সপোর্ট টিকিট ছোট রাখতে, একটি অডিট ভিউ যোগ করুন যা ইনভয়েসের প্রতিটি সংখ্যার ব্যাখ্যা দেয়: সংরক্ষিত পরিমাণ, মুদ্রা কোড, এক্সচেঞ্জ রেট ID ও টাইমস্ট্যাম্প, এবং ব্যবহৃত রাউন্ডিং পদ্ধতি। কেউ জিজ্ঞেস করলে "এটির মোট কিভাবে আলাদা?"—আপনি সংরক্ষিত ফ্যাক্ট থেকে উত্তর দিতে পারবেন।

যদি আপনি একটি অভ্যন্তরীণ বিলিং টুল বানাচ্ছেন, AppMaster (appmaster.io) মতো নো-কোড প্ল্যাটফর্ম আপনাকে এটি ধারাবাহিক রাখতেও সাহায্য করতে পারে—স্কিমাকে এক জায়গায় রাখা এবং ক্যালকুলেশন লজিককে এক পুনঃব্যবহারযোগ্য ওয়ার্কফ্লোতে রাখা যাতে ওয়েব এবং মোবাইল স্ক্রীন প্রত্যেকে আলাদা গণনা না করে।

শেষে, দায়িত্ব ভাগ করুন। নির্ধারণ করুন কে এক্সচেঞ্জ রেট আপডেট করে, কে ট্যাক্স নিয়ম আপডেট করে, এবং কে ইস্যু করা ইনভয়েসে প্রভাব ফেলে এমন পরিবর্তন অনুমোদন করে। স্থিরতা একটি প্রক্রিয়া, কেবলমাত্র একটি স্কিমা নয়।

শুরু করা সহজ
কিছু আশ্চর্যজনকতৈরি করুন

বিনামূল্যের পরিকল্পনা সহ অ্যাপমাস্টারের সাথে পরীক্ষা করুন।
আপনি যখন প্রস্তুত হবেন তখন আপনি সঠিক সদস্যতা বেছে নিতে পারেন৷

এবার শুরু করা যাক