बहु-मुद्रा सदस्यता चालान: व्यावहारिक राउंडिंग और न्यूनतम-टेबल तरीके ताकि वेब, मोबाइल और लेखा एक्सपोर्ट में टोटल्स संगत रहें।

एक आम सिरदर्द: वेब चेकआउट एक कुल दिखाता है, मोबाइल ऐप थोड़ा अलग दिखाता है, और लेखा एक्सपोर्ट तीसरी संख्या पर आ जाता है। हर सिस्टम "यथोचित" गणना कर रहा होता है, लेकिन एक ही तरह नहीं।
सदस्यताएँ इस समस्या को बढ़ाती हैं क्योंकि आप गणना बार-बार दोहरा रहे हैं। छोटे अंतर नवीकरणों में, मिड-साइकल अपग्रेड पर प्रोरैशन, क्रेडिट और रिफंड, असफल भुगतान के बाद रिट्राय शुल्क, और प्लान की शुरुआत या अंत में आंशिक अवधि के कारण संयोजित होकर बड़ा प्रभाव दिखाते हैं।
यह ड्रिफ्ट अक्सर छोटे चुनावों से शुरू होती है जो तब तक अदृश्य रहती हैं जब तक कि वे समस्या ना बन जाएं: कब राउंड करना है (प्रति लाइन या अंत में), कौन सा टैक्स बेस उपयोग करना है (नेट बनाम ग्रॉस), कैसे 0 या 3 दशमलव वाली मुद्राएँ संभालनी हैं, और कौन-सी FX दर लागू होती है (कौन सा टाइमस्टैम्प, कौन सा स्रोत, कितनी प्रिसिजन)। यदि वेब प्रत्येक लाइन को 2 दशमलव पर राउंड करता है और मोबाइल केवल फाइनल टोटल को राउंड करता है, तो एक ही इनपुट के साथ भी 0.01 का अंतर आ सकता है।
लक्ष्य नीरस पर महत्वपूर्ण है: एक ही इनवॉइस हर जगह, हर बार एक जैसे टोटल दे। इससे ग्राहक शांत रहते हैं, सपोर्ट टिकट कम होते हैं, और ऑडिट में टिकता है।
"संगत" का मतलब है कि किसी दिए गए इनवॉइस ID और वर्ज़न के लिए:
उदाहरण: एक ग्राहक EUR 19.99 से EUR 29.99 पर मिड-मंथ अपग्रेड करता है, प्रोरैटेड चार्ज मिलता है, फिर डाउनटाइम के लिए एक छोटा क्रेडिट मिलता है। यदि एक सिस्टम प्रत्येक प्रोरैटेड लाइन को राउंड करता है और दूसरा केवल फाइनल टोटल को राउंड करता है, तो एक्सपोर्टेड इनवॉइस उस चीज़ से असहमति कर सकता है जो ग्राहक ने देखा, भले ही हर संख्या "काफी पास" दिखती हो।
FX दरों या टैक्स राउंडिंग नियमों पर चर्चा करने से पहले मूल बातें लॉक करें। यदि ये अस्पष्ट हैं, तो आपकी इनवॉइस वेब ऐप, मोबाइल ऐप और लेखा एक्सपोर्ट में भिन्न होंगी।
हर इनवॉइस लाइन और इनवॉइस टोटल को स्पष्ट रूप से तीन राशियाँ धारण करनी चाहिए: नेट (टैक्स से पहले), टैक्स, और ग्रॉस (नेट + टैक्स)। एक को स्टोरेज और गणना के स्रोत के रूप में चुनें, फिर बाकी को हर जगह एक ही तरीके से व्युत्पन्न करें। कई टीमें नेट और टैक्स स्टोर करती हैं, फिर ग्रॉस को net + tax से निकालती हैं क्योंकि यह ऑडिट और रिफंड आसान बनाता है।
किसी भी संख्या के साथ यह स्पष्ट बताएं कि वह किस मुद्रा में है। टीमें अक्सर तीन अलग विचार मिश्रित कर देती हैं:
ये समान हो सकते हैं, लेकिन जरूरी नहीं। यदि आपका इनवॉइस EUR में है पर कार्ड USD में सेटल होता है, तब भी इनवॉइस को EUR में संगत रहना चाहिए भले ही बैंक जमा अलग हो।
अगला, पैसे को माइनर यूनिट्स में इंटीजर के रूप में मानें (उदाहरण के लिए सेंट्स)। 9.99 को फ्लोटिंग नंबर के रूप में स्टोर करना सामान्यतः बाद में 9.989999 जैसी समस्याएँ पैदा करता है, खासकर जब आप टैक्स, डिस्काउंट, प्रोरैशन, या कई आइटम जोड़ते हैं। 9.99 को 999 (सेंट) के रूप में स्टोर करें और केवल डिस्प्ले के लिए फॉर्मैट करें।
अंत में, अपना प्राइसिंग टैक्स मोड तय करें:
एक ठोस चेक: 10.00 (टैक्स-इनक्लूसिव, 20% VAT) दिखाए जाने पर वेब और मोबाइल पर वही स्टोर किया हुआ ग्रॉस माइनर यूनिट होना चाहिए, और फिर नेट और टैक्स एक साझा नियम से निकाले जाएँ।
FX अंतर अक्सर टैक्स और राउंडिंग से पहले शुरू होते हैं। दो सिस्टम दोनों ही "सही" हो सकते हैं और फिर भी असहमत रह सकते हैं क्योंकि उन्होंने अलग स्रोत, अलग टाइमस्टैम्प, या अलग प्रिसिजन इस्तेमाल की।
रेट प्रोवाइडर शायद ही कभी बिल्कुल मेल खाते हैं। कुछ मध्य-बाज़ार (mid-market) रेट देते हैं, कुछ में स्प्रेड शामिल होता है। कुछ हर मिनट अपडेट करते हैं, कुछ घंटे या दिन में। एक ही प्रोवाइडर के साथ भी, एक सिस्टम दर को 4 दशमलव पर राउंड कर सकता है जबकि दूसरा 8+ दशमलव रखेगा, जो सब्सक्रिप्शन राशियों और टैक्स को गुणा करते समय टोटल बदल देता है।
सबसे महत्वपूर्ण निर्णय यह है कि आपकी रेट टाइमस्टैम्प का क्या मतलब है। यदि आप EUR में चार्ज करते हैं पर ग्राहक USD में भुगतान करता है, क्या आप FX रेट को इनवॉइस जारी होने पर लॉक करते हैं, या भुगतान कैप्चर होने पर? दोनों सामान्य हैं, लेकिन इन्हें वेब, मोबाइल और लेखा एक्सपोर्ट में मिलाना मिसमैच की गारंटी है।
एक बार नियम चुन लें, उपयोग की गई सटीक दर इनवॉइस पर स्टोर करें। बाद में "वर्तमान" दरों से पुनःगणना न करें, भले ही आप ऐतिहासिक दर देख सकें। प्रोवाइडर सुधार, टाइमज़ोन अंतर, और छोटी प्रिसिजन डिफरेंसेस पुराने इनवॉइस को एक्सपोर्ट के दौरान भटका देंगी या PDF फिर से जनरेट करने पर।
एक साधारण उदाहरण: आप 23:59 पर इनवॉइस जारी करते हैं, पर भुगतान 00:02 पर सफल होता है। ये टाइमस्टैम्प अक्सर अलग प्रोवाइडर "दिनों" पर पड़ते हैं, इसलिए दैनिक रेट टेबल अलग संख्या दे सकती है।
इन FX विवरणों को निर्णय कर दस्तावेज़ करें:
विशेष मामले पहले से संभालें: शून्य-दशमलव मुद्राएँ (जैसे JPY), बहुत उच्च प्रिसिजन रेट्स, और रिफंड। रिफंड आमतौर पर मूल इनवॉइस की स्टोर की हुई FX रेट को पुनः उपयोग करना चाहिए। अन्यथा रिफंड राशि ग्राहक की अपेक्षा और आपके लेखांकन एक्सपोर्ट में अंतर पैदा कर सकती है।
यदि आप चाहते हैं कि इनवॉइस वेब, मोबाइल और लेखा एक्सपोर्ट में मेल खाएँ, तो आपका डेटा मॉडल सिर्फ इनपुट नहीं बल्कि परिणाम स्टोर करना चाहिए। लक्ष्य सरल है: एक ही इनवॉइस हर जगह एक जैसे माइनर यूनिट्स रेंडर करे, यहाँ तक कि महीनों बाद भी।
कई मामलों में कुछ ही एंटिटीज़ पर्याप्त होती हैं:
मुख्य नियम: मनी फील्ड्स माइनर यूनिट्स में इंटीजर होने चाहिए। यूनिट प्राइस और कम्प्यूटेड लाइन टोटल दोनों स्टोर करें। इससे बाद में अलग राउंडिंग नियम या अलग FX स्रोत से पुनर्गणना होने से रोका जा सकता है।
FX को इनवॉइस पर कैप्चर किया जाना चाहिए, न कि अनुमानित किया जाना चाहिए। भले ही आप एक साझा FX टेबल स्टोर करें, इनवॉइस को वह सटीक fx_rate_value चाहिए जो फाइनलाइज़ेशन के समय इस्तेमाल हुई थी (और कहां से आई), ताकि एक्सपोर्ट्स वही संख्याएँ पुनरुत्पादित कर सकें।
एक अलग tax breakdown तालिका केवल तब चाहिए जब एक इनवॉइस में कई टैक्स दरें या जुरिस्डिक्शन्स एक साथ हो (उदाहरण: मिश्रित आइटम, EU VAT + स्थानीय लेवी, या एक इनवॉइस के भीतर पते के आधार पर टैक्स बदलना)। तब प्रत्येक टैक्स दर के लिए एक रो स्टोर करें जिसमें taxable_base_minor और tax_amount_minor हो।
अंततः, एक फाइनलाइज़्ड इनवॉइस को अपरिवर्तनीय मानें। फाइनल किए जाने के पल पर कम्प्यूटेड वैल्यूज़ का स्नैपशॉट सेव करें और बाद में सब्सक्रिप्शन से टोटल्स फिर से गणना न करें। यही एक निर्णय अधिकांश "सेंट्स क्यों बदल गए?" बग्स खत्म कर देता है।
राउंडिंग गणित का एक साधारण हिस्सा नहीं है; यह एक प्रोडक्ट नियम है। यदि आपका वेब ऐप एक तरह से राउंड करता है, मोबाइल दूसरे तरीके से, और लेखा एक्सपोर्ट तीसरे, तो आप अलग टोटल के साथ समाप्त होंगे भले ही इनपुट एक जैसे हों।
तीन सामान्य रणनीतियाँ हैं, और ये तय करती हैं कि आप माइनर यूनिट्स को कहाँ "लॉक इन" करते हैं:
सब्सक्रिप्शन्स के लिए एक अच्छा डिफ़ॉल्ट प्रति लाइन राउंड है। यह ग्राहकों के लिए अनुमानित है (हर लाइन सही दिखती है), ऑडिट के लिए आसान है (आप हर लाइन टोटल समझा सकते हैं), और नवीकरणों में स्थिर रहती है। प्रति यूनिट राउंड मात्रा बदलने पर या UI में यूनिट प्राइस दिखाते समय ड्रिफ्ट कर सकती है। केवल इनवॉइस टोटल पर राउंड करने से अक्सर "यह लाइन क्यों नहीं मिलती?" जैसे सपोर्ट टिकट आते हैं क्योंकि दिखाई देने वाले लाइन सम्स और डिस्प्ले टोटल मेल नहीं खाते।
क्लासिक पेननी समस्या तब दिखती है जब आपकी कई छोटी आइटम्स या अंशात्मक टैक्स होते हैं। उदाहरण: 20 लाइनों में प्रत्येक 0.004 राउंडिंग शेष दे सकता है। प्रति लाइन राउंड करने पर यह 0.08 अंतर बन सकता है बनाम केवल अंत में राउंड करने पर। FX कन्वर्ज़न्स के साथ, ये छोटे शेष अक्सर होते हैं और समय के साथ एक्सपोर्ट्स और रेवेन्यू रिपोर्ट्स में जमा हो जाते हैं।
जो भी चुनें, उसे निर्णायक बनाएं। एक ही इनपुट हर जगह एक ही आउटपुट दे:
यदि आप वेब और मोबाइल दोनों बिलिंग फ्लो बनाते हैं, तो राउंडिंग नियम को UI व्यवहार के रूप में नहीं बल्कि टेस्टेबल स्पेसिफिकेशन के रूप में लिखें।
वेब, मोबाइल और लेखा एक्सपोर्ट में एक ही संख्याएँ रखने के लिए, गणना को एक रेसिपी की तरह लें। प्रमुख विचार: अधिक प्रिसिजन के साथ गणना करें, लेकिन इनवॉइस करंसी में केवल इंटीजर स्टोर और जोड़ें।
प्रत्येक लाइन आइटम नेट अमाउंट के साथ शुरू करें उच्च प्रिसिजन में। क्वांटिटी गुणा करते समय, डिस्काउंट लागू करते समय, और (अगर आवश्यक हो) करंसी कनवर्ट करते समय अतिरिक्त दशमलव रखें। फिर अपने चुने हुए नियम से इनवॉइस करंसी माइनर यूनिट्स में एक बार राउंड करें। उस इंटीजर को लाइन नेट के रूप में स्टोर करें।
स्टोर किए गए लाइन नेट से टैक्स कम्प्यूट करें (या अगर आपके नियम अनुमति दें तो टैक्स ग्रुप सबटोटल से)। वही राउंडिंग नियम लागू करें और टैक्स को माइनर यूनिट्स में इंटीजर के रूप में स्टोर करें। यही वह जगह है जहाँ सिस्टम अक्सर भिन्न होते हैं: एक तरफ राउंड करने से पहले टैक्स लगता है, दूसरी तरफ बाद में।
प्रत्येक लाइन ग्रॉस को (स्टोर किया हुआ नेट + स्टोर किया हुआ टैक्स) के रूप में कम्प्यूट करें। इनवॉइस टोटल्स स्टोर किए गए माइनर्स का योग हों। डिस्प्ले के लिए फ्लोटिंग-पॉइंट से टोटल्स फिर से गणना न करें। डिस्प्ले और एक्सपोर्ट्स स्टोर किए गए इंटीजर पढ़ें और उन्हें फॉर्मैट करें।
यदि आपके स्थानीय नियम इनवॉइस-स्तर टैक्स टोटल्स की मांग करते हैं, तो आपको शेष आवंटित करना पड़ सकता है। उदाहरण: तीन लाइनों का टैक्स प्रत्येक 0.01 हो सकता है जो कुल 0.03 बनता है, पर इनवॉइस-स्तर राउंडिंग कहती है 0.02। एक निर्णायक टाई-ब्रेकर चुनें (उदाहरण: सबसे बड़े टैक्सेबल लाइन से 1 माइनर यूनिट जोड़ें या घटाएँ, फिर लाइन id के अनुसार स्थिर सॉर्ट)। समायोजन को प्रभावित लाइनों पर एक छोटा टैक्स करेक्शन के रूप में स्टोर करें ताकि हर सिस्टम इसे पुनरुत्पादित कर सके।
इनवॉइस को लॉक करें। अंतिम राउंडिंग और किसी भी शेष आवंटन के बाद, इनवॉइस को अपरिवर्तनीय मानें। अगर बाद में सब्सक्रिप्शन प्राइस बदलता है, नया इनवॉइस या क्रेडिट नोट बनाएं, पर पुराने नंबर कभी न बदलें।
एक ठोस चेक: यदि EUR 9.99 प्लान पर 19% VAT है, आपका स्टोर किया हुआ नेट 999 सेंट, टैक्स 190 सेंट, ग्रॉस 1189 सेंट हो सकता है। हर क्लाइंट को उन स्टोर किए हुए इंटीजर से 11.89 EUR रेंडर करना चाहिए, न कि VAT को ऑन-द-फ्लाई फिर से गणना करके।
टैक्स राउंडिंग वह जगह है जहाँ सही गणित मिसमैच इनवॉइस में बदल जाता है। मुख्य मुद्दा सरल है: पहले राउंड करने से अंतिम योग बदल जाता है।
यदि आप प्रत्येक लाइन आइटम (या प्रति क्वांटिटी) पर टैक्स राउंड करते हैं, फिर जोड़ते हैं, तो आप एक अलग कुल पा सकते हैं बनाम यदि आप इनवॉइस पर बिना राउंड किए टैक्स जोड़कर अंत में राउंड करें। कई लाइनों के साथ यह अंतर बड़ा हो जाता है, खासकर जब माइनर यूनिट्स और FX कन्वर्ज़न्स पहले से ही छोटे भिन्न दे रहे हों।
एक ठोस उदाहरण (2 दशमलव): दो लाइनों में टैक्सेबल अमाउंट 0.05 है और टैक्स 10% है। प्रति लाइन अनराउंडेड टैक्स 0.005 है। यदि आप प्रति लाइन राउंड करें तो हर एक 0.01 होगा, कुल टैक्स 0.02 होगा। यदि आप इनवॉइस स्तर पर राउंड करें तो कुल टैक्सेबल 0.10 होगा, टैक्स 0.01 होगा। दोनों वाजिब हैं, पर वे असहमत हैं।
जब आपको प्रति-लाइन टैक्स दिखाना ही है पर इनवॉइस टोटल भी बिल्कुल मैच करना है, तो राउंडिंग शेष को निर्णायक रूप से आवंटित करें:
जब लेखांकन लाइनों को समूहित करता है (उत्पाद, टैक्स दर, या जुरिस्डिक्शन के अनुसार), तो एक्सपोर्ट्स फिर भी भटका सकते हैं। ताकि एक्सपोर्टेड टोटल्स इनवॉइस टोटल्स से मेल खाएँ, आवश्यक समूहों के भीतर पहले शेष आवंटित करें, फिर सत्यापित करें कि समूह टोटल्स इनवॉइस टैक्स और ग्रॉस तक रोल-अप करते हैं।
यदि लेखांकन दर या जुरिस्डिक्शन के अनुसार टैक्स स्प्लिट चाहता है पर UI एक टैक्स संख्या दिखाती है, तब भी ब्रेकडाउन स्टोर करें (प्रति दर या जुरिस्डिक्शन टोटल्स प्लस एक ऑडिट-फ्रेंडली आवंटन नियम)। UI एक ही कुल दिखा सकती है, जबकि एक्सपोर्ट्स विवरण के साथ भेजें बिना इनवॉइस ग्रैंड टोटल बदले।
ज्यादातर इनवॉइस मिसमैच कॉर्नर्स में होते हैं। नियमों को पहले से तय कर दें और वे आश्चर्य नहीं रहेंगे।
शून्य-दशमलव मुद्राओं को विशेष ध्यान चाहिए। JPY और KRW में माइनर यूनिट्स नहीं होते, इसलिए कोई भी स्टेप जो "सेंट" मानकर चलता है चुपचाप अंतर पैदा करेगा। तय करें कि आप किस स्टेप पर राउंड करेंगे और सभी क्लाइंट उसी मुद्रा सेटिंग्स का उपयोग करें।
क्रॉस-बॉर्डर VAT या GST ग्राहक के स्थान और आप जिन साक्ष्यों को स्वीकार करते हैं (बिलिंग पता, IP, टैक्स ID) पर टैक्स दर बदल सकती है। मुश्किल हिस्सा दर नहीं बल्कि उसे कब लॉक करना है। किसी समय बिंदु (चेकआउट, इनवॉइस जारी होने की तारीख, या सेवा अवधि की शुरुआत) को चुनें और उस पर टिके रहें।
प्रोरेशन वह जगह है जहाँ दशमलव गुणा होते हैं। मिड-साइकिल अपग्रेड दिनों की तरह 9.3333... प्रति दिन जैसी राशियाँ बना सकता है। तय करें कि आप पहले नेट अमाउंट प्रोरैट करेंगे, ग्रॉस अमाउंट प्रोरैट करेंगे, या सेवा अवधि पहले गणना करेंगे — क्रम बदलने से अंतिम माइनर यूनिट बदल जाएगी।
इन नियमों को लिखें ताकि समय के साथ वे न बदलें:
रिफंड अंतिम जाल है। यदि मूल इनवॉइस में 0.01 शेष किसी लाइन को आवंटित किया गया था, तो आपका रिफंड उसी सटीक आवंटन को उलटना चाहिए। अन्यथा ग्राहक एक कुल देखेगा और आपके लेज़र एक्सपोर्ट अलग।
ज्यादातर इनवॉइस मिसमैच "कठोर गणित" से नहीं आते। वे छोटे, असंगत चुनावों से आते हैं जो स्टैक्स के विभिन्न हिस्सों में किए गए।
एक बड़ी गलती पैसे को फ्लोटिंग-पॉइंट के रूप में स्टोर करना है। 19.99 जैसा मान कई सिस्टम में ठीक से प्रतिनिधित्व नहीं होता, इसलिए जोड़ते समय छोटे त्रुटियाँ बनती हैं। राशि को माइनर यूनिट्स में इंटीजर के रूप में स्टोर करें, साथ में करंसी कोड और माइनर यूनिट स्केल स्टोर करें।
एक और आम समस्या एक्सपोर्ट के समय FX को फिर से गणना करना है। ग्राहक ने एक विशिष्ट दर पर भुगतान किया था। यदि आपका लेखांकन एक्सपोर्ट "आज की" दर खींचता है, तो आप भिन्न टोटल प्राप्त कर सकते हैं भले ही हर स्टेप सही हो। इनवॉइस को स्नैपशॉट मानें: FX दर, कनवर्ट की गई राशियाँ, और राउंडिंग परिणाम स्टोर करें।
राउंडिंग अंतर तब भी दिखते हैं जब UI और बैकएंड अलग स्टेज पर राउंड करते हैं। उदाहरण: बैकएंड प्रति लाइन टैक्स राउंड करता है जबकि वेब UI केवल इनवॉइस टोटल राउंड करता है। दोनों उचित दिख सकते हैं, पर मेल नहीं खाँते।
पांच सामान्य अपराधी अधिकांश गैप्स समझाते हैं:
एक त्वरित यथार्थ जाँच: मोबाइल ऐप तीन आइटम EUR 9.99 पर 20% टैक्स दिखाता है। यदि ऐप टैक्स को अंत में राउंड करता है पर बैकएंड प्रति लाइन राउंड करता है, तो आप EUR 0.01 से हट सकते हैं। वही सेंट रिकंसिलिएशन तोड़ने और सपोर्ट टिकट ट्रिगर करने के लिए काफी है।
सबसे सरल फिक्स नीरस पर प्रभावी है: बैकएंड पर एक बार गणना करें, पूरा इनवॉइस स्नैपशॉट स्टोर करें, और वेब/मोबाइल उन्हीं स्टोर की हुई संख्याओं को ठीक वैसे ही दिखाएँ।
जब आपकी वेब ऐप, मोबाइल ऐप और लेखा एक्सपोर्ट के बीच संख्याएँ अलग हों, तो आमतौर पर यह गणित की समस्या नहीं होती। यह स्टोरेज और राउंडिंग की समस्या होती है।
नीति यह है कि क्लाइंट्स वही दिखाएँ जो इनवॉइस स्टोर करता है, न कि फिर से गणना करें। आपका बैकएंड एकल सिंगल सोर्स ऑफ ट्रुथ होना चाहिए, और हर चैनल वही सेव की हुई वैल्यूज़ पढ़े।
रिफंड्स और क्रेडिट नोट्स को मूल इनवॉइस के राउंडिंग परिणामों को प्रतिबिंबित करना चाहिए। यदि मूल इनवॉइस ने प्रति-लाइन टैक्स राउंड किया था, तो रिफंड भी वही तरीका उपयोग करके होना चाहिए और वही करंसी प्रिसिजन व स्टोर की हुई FX दर इस्तेमाल करनी चाहिए। अन्यथा छोटे शेष समय के साथ दिखाई देंगे और जमा हो सकते हैं।
इसे लागू करने का व्यावहारिक तरीका यह है कि प्रत्येक इनवॉइस के साथ एक स्पष्ट कैलकुलेशन स्नैपशॉट स्टोर करें: करंसी, माइनर यूनिट प्रिसिजन, राउंडिंग मोड, FX रेट और टाइमस्टैम्प, और फाइनल लाइन माइनर्स।
यहाँ एक इनवॉइस है जो हर जगह संगत रहता है।
मान लें इनवॉइस EUR में जारी हुआ (2 दशमलव), VAT 20% है, और ग्राहक से USD में चार्ज लिया गया। बैकएंड एक FX स्नैपशॉट स्टोर करता है: 1 EUR = 1.0857 USD।
| आइटम | नेट (EUR) |
|---|---|
| Pro plan (monthly) | 19.99 |
| Extra seats | 10.00 |
| Discount (10% of 29.99, rounded) | -3.00 |
नेट टोटल (EUR) = 26.99
VAT 20% (EUR) = 5.40 (क्योंकि 26.99 x 0.20 = 5.398, जिसे 5.40 पर राउंड किया गया)
ग्रॉस टोटल (EUR) = 32.39
अब बैकएंड स्टोर किए गए EUR टोटल से चार्ज करंसी में वैल्यूज़ व्युत्पन्न करता है और स्टोर किए गए FX स्नैपशॉट का उपयोग करता है:
यदि आप प्रति-लाइन भी USD वैल्यूज़ स्टोर करते हैं, तो अक्सर प्रति-लाइन कन्वर्ट करके राउंड करने और उन्हें जोड़ने पर 0.01 का अंतर मिलेगा। यही वह जगह है जहाँ इनवॉइस आमतौर पर ड्रिफ्ट होते हैं।
इसे निर्णायक बनाइए: प्रत्येक लाइन को कन्वर्ट और राउंड करें, फिर किसी भी बची हुई सेंट्स (सकारात्मक या नकारात्मक) को फ़िक्स्ड ऑर्डर (उदाहरण: line_id आरोही) में बाँट दें जब तक कि प्रति-लाइन सम कुल फिक्स्ड ग्रॉस USD टोटल के बराबर न हो जाए।
वेब और मोबाइल को बैकएंड-स्टोर किए गए लाइन टोटल्स, टैक्स टोटल्स, FX रेट, और ग्रॉस दिखाना चाहिए — न कि उन्हें फिर से गणना करना चाहिए। लेखा एक्सपोर्ट को वही स्टोर की हुई संख्याएँ और FX स्नैपशॉट (रेट, टाइमस्टैम्प या स्रोत) भेजनी चाहिए ताकि लेज़र वही दिखे जो ग्राहक ने देखा।
एक व्यावहारिक अगला कदम यह है कि गणना को एक साझा सर्विस के रूप में इम्प्लीमेंट करें जो एक ही इनवॉइस स्नैपशॉट आउटपुट करे (लाइन्स, टैक्स, टोटल्स, FX, राउंडिंग समायोजन) और हर चैनल वहीं से रेंडर करे। यदि आप Koder.ai (koder.ai) पर ये फ्लो बना रहे हैं, तो यह स्नैपशॉट मॉडल मदद करता है ताकि वेब, मोबाइल, और एक्सपोर्ट्स एक जैसी सेव की हुई वैल्यूज़ पढ़ें।
क्योंकि हर सिस्टम थोड़े अलग चुनाव करता है — कब राउंड करना है, क्या राउंड करना है (नेट बनाम ग्रॉस), और टैक्स व FX के लिए कितनी प्रिसिजन रखें। ये छोटे अंतर प्ररेशन, क्रेडिट और रिट्राइ में बार-बार होने पर 0.01–0.02 के गैप बन जाते हैं।
माइनर यूनिट्स (जैसे सेंट) में पूर्णांकों के रूप में राशि स्टोर करें और केवल डिसप्ले के लिए फॉर्मैट करें। फ्लोटिंग-पॉइंट मान कई दशमलव ठीक से नहीं दर्शाते, जिससे जोड़ते समय छोटे त्रुटियाँ आ जाती हैं।
एक को स्रोत-तथ्य (source of truth) के रूप में चुनें और बाकी सभी उसी तरह उत्पन्न करें। सामान्यतः नेट और टैक्स को माइनर यूनिट्स में स्टोर करना अच्छा होता है, और ग्रॉस = नेट + टैक्स की तरह निकाला जाता है, क्योंकि इससे रिफंड और ऑडिट आसान होते हैं।
इनवॉइस करंसी वही है जिसमें इनवॉइस कानूनी रूप से व्यक्त होता है और जिससे आप मिलान करते हैं। डिस्प्ले करंसी UI में दिखाने के लिए है, और सेटल्मेंट करंसी वह है जिसमें पेमेंट प्रोवाइडर जमा करता है; ये अलग हो सकते हैं बशर्ते इनवॉइस करंसी की गणना लगातार हो।
एक्सपोर्ट या PDF फिर से जनरेट करते समय दरों को फिर से नहीं लाएँ। इनवॉइस पर प्रयुक्त सटीक FX दर (मान, प्रिसिजन, प्रोवाइडर और प्रभावी समय) स्टोर करें और हमेशा वही वापिस इस्तेमाल करें ताकि पुराने इनवॉइस महीनों बाद भी समान संख्याएँ दें।
एक नियम चुने और सब जगह लागू करें: या तो “रेट इनवॉइस जारी होने पर लॉक करें” या “रेट भुगतान कैप्चर पर लॉक करें”। सिस्टम्स में टाइमस्टैम्प्स मिक्स करने से खासकर मिडनाइट या टाइमज़ोन के आसपास असंगतियाँ आती हैं।
सदस्यता इनवॉइस के लिए डिफ़ॉल्ट के रूप में प्रति लाइन राउंडिंग सुरक्षित रहता है: हर लाइन पर राउंड करें और स्टोर किए गए लाइन माइनर्स का योग इनवॉइस टोटल बनता है। यह ग्राहकों के लिए समझने में आसान है और रिकन्सीलिएशन में मदद करता है।
स्पष्ट रूप से चुनें कि आप प्रति-लाइन टैक्स राउंडिंग करेंगे या इनवॉइस-स्तर पर; फिर एक निश्चत तरीका अपनाएँ। यदि आपको इनवॉइस-स्तर लक्ष्य से मेल करना है तो राउंडिंग शेष को एक निश्चित क्रम में बाटें और परिणामस्वरूप प्रति-लाइन टैक्स माइनर स्टोर करें ताकि सभी सिस्टम एक जैसा दिखाएँ।
प्रोरेशन बार-बार दशांश पैदा करता है (जैसे प्रति दिन 9.3333...). इसलिए पहले ऑपरेशन का क्रम तय करें: उदाहरण के लिए पहले नेट को प्रोरैट करें, फिर टैक्स कैलकुलेट करें, राउंड उसी स्टेप पर करें, और फाइनल लाइन माइनर स्टोर करें। इससे अपग्रेड/डग्रेड/रिफंड्स मूल गणना को दर्शाएंगे।
सबसे सरल आर्किटेक्चर: बैकएंड एक फाइनलाइज़्ड इनवॉइस स्नैपशॉट बनाये (लाइनें, टैक्स, टोटल्स, करंसी नियम, FX स्नैपशॉट, राउंडिंग मोड) और इसे फाइनल मानें। वेब, मोबाइल, PDF और एक्सपोर्ट्स वही स्टोर की हुई इंटीजर वैल्यूज रेंडर करें, न कि खुद से गणना करें। Koder.ai पर बिलिंग फ्लो बनाते वक्त यह पैटर्न मददगार है।