تقريب العملات في تطبيقات المالية: خزن الأموال بأمان
قد يسبب تقريب العملات في تطبيقات المالية أخطاء بنس واحد. تعلّم تخزين السنتات كأعداد صحيحة، قواعد تقريب الضرائب، وعرض متسق على الويب والهواتف.

لماذا تحدث أخطاء بنس واحد
خطأ البنس الواحد هو نوع من الأخطاء يلاحظه المستخدمون فورًا. يظهر مجموع سلة التسوق $19.99 في قائمة المنتجات، لكنه يصبح $20.00 عند الخروج. يصل استرداد بقيمة $14.38 كـ $14.37. يظهر سطر الفاتورة "الضريبة: $1.45"، ومع ذلك يبدو أن الإجمالي الكلي أضيف بضريبة بطريقـة مختلفة.
تأتي هذه المشاكل عادةً من فروق تقريب صغيرة تتراكم. المال ليس مجرد "رقم"؛ له قواعد: كم عدد المنازل العشرية التي تستخدمها العملة، متى تقرب، وهل تقرب لكل بند أم على الإجمالي النهائي. إذا اتُخذ قرار مختلف في مكان واحد داخل التطبيق، يمكن أن يظهر أو يختفي سنت واحد.
كذلك تميل هذه الأخطاء للظهور أحيانًا فقط، مما يجعل تصحيحها مؤلمًا. نفس المدخلات قد تنتج سنتات مختلفة اعتمادًا على إعدادات الجهاز أو اللوكل، ترتيب العمليات، أو كيف تُحوّل القيم بين الأنواع.
المثيرات الشائعة تشمل الحساب باستخدام float وتقريب "في النهاية" (لكن "النهاية" ليست نفسها في كل مكان)، تطبيق الضريبة لكل عنصر في شاشة وأخرى على المجموع الجزئي في شاشة مختلفة، خلط عملات أو أسعار صرف وتقريب في خطوات غير متسقة، أو تنسيق القيم للعرض ثم إعادة تحليلها كأرقام عن غير قصد.
الضرر يكون أشد حيث الثقة هشة والمبالغ خاضعة للتدقيق: إجماليات الخروج، الاستردادات، الفواتير، الاشتراكات، الإكراميات، المدفوعات، وتقارير المصروفات. اختلاف سنت واحد قد يسبب فشل المدفوعات، صعوبات في التسوية، وتذاكر دعم تقول "تطبيقكم يسرق مني".
الهدف بسيط: نفس المدخلات يجب أن تعطـي نفس السنتات في كل مكان. نفس العناصر، نفس الضريبة، نفس الخصومات، نفس قاعدة التقريب — بغض النظر عن الشاشة أو الجهاز أو اللغة أو التصدير.
مثال: إذا كان هناك عنصران بسعر $9.99 لكل منهما وبضريبة 7.25%، قرر ما إذا كنت تقرب الضريبة لكل بند أم على المجموع الفرعي، ثم طبق ذلك في الـ backend وواجهة الويب والتطبيق المحمول. الاتساق يمنع لحظة "لماذا يختلف هنا؟".
لماذا الـ floats محفوفة بالمخاطر بالنسبة للمال
معظم لغات البرمجة تخزّن قيم float و double في ثنائي. العديد من الأسعار العشرية لا يمكن تمثيلها بدقة في الثنائي، لذا الرقم الذي تعتقد أنك خزّنته غالبًا ما يكون أقل أو أكثر بقليل.
المثال الكلاسيكي هو 0.1 + 0.2. في الكثير من الأنظمة يصبح 0.30000000000000004. هذا يبدو غير ضار، لكن منطق المال عادةً سلسلة: أسعار البنود، الخصومات، الضريبة، الرسوم، ثم التقريب النهائي. الأخطاء الصغيرة قد تقلب قرار التقريب وتخلق فرقًا في سنت واحد.
الأعراض التي يلاحظها الناس عندما يخطئ تقريب المال:
- قيم مثل 9.989999 أو 19.9000001 تظهر في السجلات أو استجابات API.
- الانجراف في الإجماليات بعد إضافة عدة عناصر، حتى عندما يبدو كل عنصر سليمًا.
- لا يتطابق مجموع الاسترداد مع الشحنة الأصلية بفارق $0.01.
- نفس مجموع السلة يختلف بين الويب والهاتف والـ backend.
التنسيق غالبًا ما يخفي المشكلة. إن طبعت 9.989999 إلى منزلتين تظهر 9.99، فيبدو كل شيء صحيحًا. يظهر الخطأ لاحقًا عند جمع قيم كثيرة أو مقارنة إجماليات أو تقريب بعد الضريبة. لذلك ترسل الفرق في كثير من الأحيان إلى الإنتاج وتُكتَشَف فقط خلال التسوية مع مزودي الدفع أو صادرات المحاسبة.
قاعدة بسيطة: لا تخزّن أو تجمع المال كقيمة فاصلة. تعامل مع المال كعدد صحيح يمثل الوحدة الصغرى للعملة (مثل السنتات)، أو استخدم نوع عشري يضمن حسابًا عشريًا دقيقًا.
إذا كنت تبني backend أو تطبيق ويب أو تطبيق محمول (بما في ذلك منصات no-code مثل AppMaster)، طبق نفس المبدأ في كل مكان: خزّن قيمًا دقيقة، احسب على قيم دقيقة، ونسّق للعرض فقط في النهاية.
اختر نموذج مال يتناسب مع العملات الحقيقية
تبدأ معظم أخطاء المال قبل أي حساب: نموذج البيانات لا يتطابق مع كيفية عمل العملة فعليًا. صحّح النموذج من البداية وسيتحول التقريب إلى مسألة قواعد وليست تخمينًا.
الافتراضي الأكثر أمانًا هو تخزين المال كعدد صحيح بوحدة العملة الصغرى. بالنسبة لـ USD هذا يعني السنتات؛ بالنسبة لـ EUR سنتات اليورو. قاعدة البيانات والكود تتعامل مع صحيح دقيق، وتضيف الفواصل فقط عند التنسيق للبشر.
ليست كل العملات لها منزلتان عشريتان، لذا يجب أن يكون نموذجك واعيًا بالعملة. لـ JPY لا توجد منازل عشرية (أصغر وحدة هي الين). لـ BHD تكون شائعة 3 منازل عشرية (1 دينار = 1000 فلس). إذا قمت بتثبيت "منزلتين عشريتين في كل مكان" ستحمّل العميل أو تخرجه عن طريق الصدفة.
سجل عملي للمال عادةً يحتاج:
amount_minor(عدد صحيح، مثل 1999 مقابل $19.99)currency_code(نص مثل USD، EUR، JPY)- اختياريًا
minor_unitأوscale(0، 2، 3) إذا كان نظامك لا يستطيع البحث عنه reliably
خزن رمز العملة مع كل مبلغ، حتى داخل نفس الجدول. يمنع الأخطاء عند إضافة تسعير متعدد العملات أو استردادات أو تقارير لاحقًا.
كما قرّر أين يُسمح بالتقريب وأين يُمنع. سياسة عملية جيدة: لا تقرب داخل المجاميع الداخلية أو الحسابات العامة أو التحويلات الجارية؛ قرّب فقط عند حدود معرفة محددة (مثل خطوة الضريبة، خطوة الخصم، أو سطر الفاتورة النهائي)؛ وسجل دائمًا وضع التقريب المستخدم (half up، half even، round down) حتى تكون النتائج قابلة للتكرار.
خطوة بخطوة: تنفيذ المال كوحدة صغرى صحيحة
إذا أردت مفاجآت أقل، اختر شكلًا داخليًا واحدًا للمال ولا تكسره: خزّن المبالغ كأعداد صحيحة في الوحدة الصغرى للعملة (غالبًا السنتات).
هذا يعني أن $10.99 تصبح 1099 مع العملة USD. للعملات بلا وحدة صغرى مثل JPY، يبقى 1,500 ين 1500.
مسار تنفيذ بسيط يتدرج مع نمو التطبيق:
- قاعدة البيانات: خزّن
amount_minorكعدد صحيح 64-بت زائد رمز العملة (مثلUSD،EUR،JPY). سمِّ العمود بوضوح حتى لا يخطئ أحد ويفترض أنه عشري. - عقد الـ API: أرسل وتلقَّ
{ amount_minor: 1099, currency: "USD" }. تجنّب السلاسل المنسّقة مثل "$10.99" وتجنّب الفواصل العشرية في JSON. - إدخال الواجهة: عامل ما يكتبه المستخدم كنص، ليس رقمًا. طَبّعه (احذف المسافات، اقبل فاصل عشري واحد)، ثم حوّله باستخدام عدد منازل العملة الصغرى.
- كل الحسابات بالأعداد الصحيحة: المجاميع، مجموع البنود، الخصومات، الرسوم، والضرائب جميعها يجب أن تعمل على أعداد صحيحة فقط. عرف قواعد مثل "خصم نسبة يحسب ثم يُقرب للوحدة الصغرى" وطبقها دائمًا بنفس الطريقة.
- التنسيق فقط في النهاية: عند العرض، حوّل
amount_minorإلى سلسلة عرض باستخدام قواعد اللوكل والعملـة. لا تُحلل أبدًا مخرجاتك المنسّقة لإرجاع حسابات.
مثال عملي للـ parsing: بالنسبة لـ USD تعامل مع "12.3" كـ "12.30" قبل التحويل إلى 1230. بالنسبة لـ JPY ارفض الكسور مقدمًا.
قواعد تقريب الضريبة والخصم والرسوم
معظم منازعات البنس الواحد ليست أخطاء حسابية. إنها أخطاء سياسة. يمكن لنظامين أن يكونا "صحيحين" ويختلفا إن قربا في أوقات مختلفة.
اكتب سياسات التقريب واستخدمها في كل مكان: الحسابات، الإيصالات، الصادرات، والاستردادات. الخيارات الشائعة تشمل التقريب half-up (0.5 إلى الأعلى) وhalf-even (0.5 إلى أقرب رقم زوجي). بعض الرسوم تتطلب دائمًا التقريب للأعلى (ceiling) حتى لا تقلل المحصلة.
الإجماليات عادةً تتغير تبعًا لقرارات مثل: هل تقرب لكل بند أم لكل فاتورة، هل تخلط القواعد (مثلاً ضريبة لكل بند ورسوم على مستوى الفاتورة)، وهل الأسعار شاملة الضريبة (تسترجع الصافي والضريبة) أم حصرية الضريبة (تحسب الضريبة من الصافي).
الخصومات تضيف شوكة أخرى في الطريق. "خصم 10%" قبل الضريبة يقلل القاعدة الخاضعة للضريبة، بينما خصم بعد الضريبة يقلل ما يدفعه العميل لكنه قد لا يغيّر الضريبة المبلغ عنها بحسب الولاية أو العقد.
مثال صغير يوضح لماذا القواعد الصارمة مهمة. عنصران بسعر $9.99، ضريبة 7.5%. إذا قربت الضريبة لكل سطر، ضريبة كل سطر تكون $0.75 (9.99 x 0.075 = 0.74925). تصبح ضريبة المجموع $1.50. إذا ضريبة على إجمالي الفاتورة، الضريبة أيضًا هنا ستكون $1.50، لكن بتغيير طفيف في الأسعار سترى فرقًا سنتًا واحدًا.
اكتب القاعدة بلغة بسيطة حتى يستطيع الدعم والمالية شرحها. ثم أعد استخدام نفس الدالة للضريبة والرسوم والخصومات والاستردادات.
تحويل العملات دون انجراف في الإجماليات
الرياضيات متعددة العملات هي المكان الذي يمكن أن تغير فيه اختيارات التقريب الصغيرة الإجماليات ببطء. الهدف واضح: حوّل مرة، قرب عمدًا، واحفظ الحقائق الأصلية للرجوع إليها لاحقًا.
خزن أسعار الصرف بدقة صريحة. نمط شائع هو عدد صحيح مُدرّج، مثل "rate_micro" حيث يُخزن 1.234567 كـ 1234567 بمقياس 1,000,000. خيار آخر هو نوع عشري ثابت، لكن اكتب المقياس في الحقول حتى لا يُخمن.
اختر عملة أساسية للتقارير والمحاسبة (غالبًا عملة شركتك). حوّل المبالغ الواردة إلى العملة الأساسية للدفاتر والتحليلات، لكن احتفظ بالمبلغ الأصلي والعملـة بجانبه. بهذه الطريقة يمكنك تفسير كل رقم لاحقًا.
قواعد تمنع الانجراف:
- حوّل في اتجاه واحد فقط للمحاسبة (من أجنبي إلى أساسي)، وتجنب التحويل ذهابًا وإيابًا.
- قرر توقيت التقريب: قرب لكل بند عندما يجب إظهار مجموع البنود، أو قرب في النهاية عندما تعرض فقط الإجمالي العام.
- استخدم وضع تقريب واحد باستمرار ووثقه.
- احتفظ بالمبلغ الأصلي، العملة، والمعدل المستخدم للمعاملة.
مثال: يدفع زبون 19.99 EUR، وتخزّنها كـ 1999 وحدات صغرى مع currency=EUR. كذلك تخزن المعدل المستخدم عند الدفع (مثلاً EUR إلى USD بوحدات ميكرو). يسجل دفتر الأستاذ المبلغ المحوّل بالـ USD (مقربًا بقواعدك)، لكن الاستردادات تستخدم المبلغ الأصلي بالـ EUR المخزن، وليس إعادة تحويل من USD. هذا يمنع تذاكر "لماذا استلمت 19.98 EUR؟".
التنسيق والعرض عبر الأجهزة
الخطوة الأخيرة هي الشاشة. القيمة قد تكون صحيحة في التخزين ومع ذلك تبدو خاطئة إذا تغيّر التنسيق بين الويب والمحمول.
لوكلات مختلفة تتوقع علامات ترقيم ومكان رمز مختلف. على سبيل المثال، كثير من المستخدمين في الولايات المتحدة يقرؤون $1,234.50، بينما في كثير من أوروبا يتوقعون 1.234,50 € (نفس القيمة، فواصل مختلفة ومكان رمز مختلف). إذا ثبّتت التنسيق، ستربك الناس وتزيد عمل الدعم.
التزم بقاعدة واحدة في كل مكان: نسّق عند الحافة، لا في الجوهر. مصدر الحقيقة يجب أن يكون (currency code, minor units integer). حوّل إلى سلسلة للعرض فقط. لا تُحلل سلاسل منسّقة مرة أخرى إلى حساب، هناك يختبئ التقريب والقص والاختلافات الفرعية.
للمبالغ السالبة مثل الاستردادات، اختر أسلوبًا ثابتًا واستخدمه في كل مكان. بعض الأنظمة تُظهر -$12.34، وأخرى تعرض ($12.34). كلاهما مقبول. التبديل بينهما عبر الشاشات يبدو كخطأ.
عقد بسيط عبر الأجهزة يعمل جيدًا:
- احمل العملة كرمز ISO (مثل USD، EUR)، وليس رمزًا فقط.
- نسّق باستخدام لوكل الجهاز افتراضيًا، لكن ضع خيار تغييره داخل التطبيق.
- أظهر رمز العملة بجانب المبلغ في شاشات متعددة العملات (مثل 12.34 USD).
- عامل تنسيق الإدخال بشكل منفصل عن تنسيق العرض.
- قرب مرة واحدة، استنادًا إلى قواعد المال، قبل التنسيق.
مثال: يرى الزبون استردادًا 10,00 EUR على المحمول، ثم يفتح نفس الطلب على سطح المكتب ويرى -€10. إذا أظهرت أيضًا الكود (10,00 EUR) وحافظت على نمط السالب، فلن يتساءل إذا ما تغيّر.
مثال: سلة، ضريبة، واسترداد بدون مفاجآت
سلة بسيطة:
- العنصر A: $4.99 (499 سنت)
- العنصر B: $2.50 (250 سنت)
- العنصر C: $1.20 (120 سنت)
المجموع الجزئي = 869 سنت ($8.69). طبق خصم 10% أولًا: 869 x 10% = 86.9 سنت، قرّب إلى 87 سنت. المجموع الجزئي بعد الخصم = 782 سنت ($7.82). الآن طبق ضريبة 8.875%.
هنا حيث يمكن لقواعد التقريب أن تغير البنس النهائي.
إذا حسبت الضريبة على إجمالي الفاتورة: 782 x 8.875% = 69.4025 سنت، قرّب إلى 69 سنت.
إذا حسبت الضريبة لكل سطر (بعد الخصم) وقرّبت كل سطر:
- العنصر A: ضريبة $4.49 = 39.84875 سنت، قرّب إلى 40
- العنصر B: ضريبة $2.25 = 19.96875 سنت، قرّب إلى 20
- العنصر C: ضريبة $1.08 = 9.585 سنت، قرّب إلى 10
إجمالي ضريبة البنود = 70 سنت. نفس السلة، نفس النسبة، قاعدة صحيحة مختلفة، فرق سنت واحد.
أضف رسوم شحن بعد الضريبة، لنقل 399 سنت ($3.99). يصبح الإجمالي $12.50 (ضريبة على مستوى الفاتورة) أو $12.51 (ضريبة على مستوى البنود). اختر قاعدة واحدة، وثّقها، وطبقها باستمرار.
الآن استرد العنصر B فقط. استرد سعره بعد الخصم (225 سنت) زائد الضريبة الخاصة به. مع ضريبة على مستوى البنود يكون ذلك 225 + 20 = 245 سنت ($2.45). تظل الإجماليات المتبقية متسقة تمامًا.
لتفسير أي فرق لاحقًا، سجّل هذه القيم لكل شحنة واسترداد:
- صافي السطر بالوحدات الصغرى، ضريبة السطر بالوحدات الصغرى، ووضع التقريب
- خصم الفاتورة بالوحدات الصغرى وكيف تم توزيعه
- معدل الضريبة والقاعدة الخاضعة بالوحدات الصغرى المستخدمة
- شحن/رسوم بالوحدات الصغرى وهل هي خاضعة للضريبة
- الإجمالي النهائي بالوحدات الصغرى ومبالغ الاسترداد بالوحدات الصغرى
كيفية اختبار حسابات المال
معظم أخطاء المال ليست "أخطاء رياضية" بل أخطاء تقريب وترتيب وتنسيق تظهر لحالات سلة أو تواريخ محددة. الاختبارات الجيدة تجعل تلك الحالات مملة.
ابدأ باختبارات ذهبية: مدخلات ثابتة مع مخرجات متوقعة دقيقة بوحدات صغرى (مثل السنتات). اجعل assertions صارمة. إذا كان عنصر 199 سنت والضريبة 15 سنتًا، يجب أن يتحقق الاختبار من القيم الصحيحة، ليس من سلاسل العرض.
يمكن لمجموعة صغيرة من الحالات الذهبية تغطية الكثير:
- بند واحد بالضريبة ثم الخصم ثم الرسوم (تحقق من كل تقريب وسيط)
- العديد من البنود حيث تُقرّب الضريبة لكل بند مقابل على المجموع الجزئي (تحقق من قاعدتك المختارة)
- استردادات واستردادات جزئية (تحقق من الإشارات واتجاه التقريب)
- تحويلات ذهابًا وإيابًا (A إلى B إلى A) مع سياسة محددة لمكان التقريب
- قيم حافة (بنود بسنت واحد، كميات كبيرة، إجماليات ضخمة)
ثم أضف اختبارات قائمة على الخاصية (أو اختبارات عشوائية بسيطة) لالتقاط المفاجآت. بدل رقم متوقع واحد، أكد ثوابت: الإجماليات تساوي مجموع البنود، لا تظهر وحدات فرعية بعد الآن، و"المجموع = subtotal + tax + fees - discounts" دائمًا صحيح.
الاختبار عبر المنصات مهم لأن النتائج قد تنحرف بين الـ backend والـ clients. إذا كان لديك backend بـ Go وواجهة ويب بـ Vue وتطبيقات بـ Kotlin/SwiftUI، شغّل نفس متجهات الاختبار في كل طبقة وقارن المخرجات كأعداد صحيحة، وليس سلاسل UI.
أخيرًا، اختبر حالات زمنية. خزن معدل الضريبة المستخدم في الفاتورة وتحقق أن الفواتير القديمة تُعيد حسابها لنفس النتيجة حتى بعد تغير المعدلات. هنا يولد معظم أخطاء "كان يتطابق سابقًا".
الأخطاء الشائعة التي تجنبها
معظم أخطاء البنس الواحد ليست أخطاء برمجية، بل أخطاء سياسة: الكود يقوم تمامًا بما طُلِب منه، لكنه ليس ما تتوقعه المالية.
مخاطر جديرة بالحراسة:
- التقريب مبكرًا جدًا: إذا تقرب كل بند ثم تقرب المجموع الجزئي ثم تقرب الضريبة، قد تنجرف الإجماليات. قرّر قاعدة (مثلاً: الضريبة لكل بند مقابل على إجمالي الفاتورة) وقرب فقط حيث تسمح سياستك.
- خلط العملات في مجموع واحد: جمع USD وEUR في حقل "إجمالي" يبدو غير ضار حتى تأتي الاستردادات أو التقارير أو التسوية. احتفظ بالمبالغ موسومة بالعملة، وحوّل باستخدام معدل متفق عليه قبل أي مجموع متعدد العملات.
- تحليل إدخال المستخدم بشكل خاطئ: يكتب المستخدم "1,000.50" أو "1 000,50" أو "10.0". إذا افترض محللك تنسيقًا واحدًا، قد تُحمل 100050 بدل 1000.50، أو تُفقد الأصفار اللاحقة. طَبّع المدخل، تحقق، وخزن بوحدات صغرى.
- استخدام سلاسل منسّقة في APIs أو قواعد البيانات: "$1,234.56" للعرض فقط. إذا قبل الـ API ذلك، قد يحلله نظام آخر بشكل مختلف. مرّر أعدادًا صحيحة (الوحدات الصغرى) زائد رمز العملة، ودع كل عميل ينسّق محليًا.
- عدم إصدار قواعد الضرائب أو جداول المعدلات: معدلات الضرائب تتغير، والإعفاءات تتغير، وقواعد التقريب تتغير. إذا كتبت فوق المعدل القديم، تصبح الفواتير القديمة مستحيلة الإعادة بدقة. خزّن إصدارًا أو تاريخًا فعالًا مع كل حساب.
فحص واقعي سريع: checkout أنشئت يوم الإثنين بمعدل الضريبة من الشهر الماضي؛ استُرد المستخدم يوم الجمعة بعد أن تغيّر المعدل. إذا لم تخزن نسخة قاعدة الضريبة الأصلية وسياسة التقريب الأصلية، فلن يتطابق الاسترداد مع الإيصال الأصلي.
قائمة تحقق سريعة وخطوات تالية
إذا أردت مفاجآت أقل، عامل المال كنظام صغير بقواعد ومدخلات ومخرجات واضحة. معظم أخطاء البنس الواحد تبقى لأنها لا توجد سياسة مكتوبة توضح أين يسمح بالتقريب.
قائمة التحقق قبل الإطلاق:
- خزن المبالغ بالوحدات الصغرى (مثل السنتات) في كل مكان: قاعدة البيانات، منطق الأعمال، وAPIs.
- قم بكل الحسابات كأعداد صحيحة، وحوّل إلى صيغ العرض فقط في النهاية.
- اختر نقطة تقريب واحدة لكل حساب (ضريبة، خصم، رسوم، FX) وطبقها من مصدر واحد.
- نسق باستخدام قواعد العملة الصحيحة (منازل عشرية، فواصل، القيم السالبة) بثبات على الويب والمحمول.
- أضف اختبارات لحالات الحافة: 0.01، الكسور المتكررة في التحويل، الاستردادات، الالتقاطات الجزئية، وسلال كبيرة.
اكتب سياسة تقريب واحدة لكل نوع حساب. على سبيل المثال: "الخصم يقرب لكل بند إلى أقرب سنت؛ الضريبة تقرب على إجمالي الفاتورة؛ الاستردادات تعيد نفس مسار التقريب الأصلي." ضع هذه السياسات بجانب الكود وفي مستندات الفريق حتى لا تنحرف.
أضف سجلات خفيفة لكل خطوة مالية مهمة. التقط القيم المدخلة، اسم السياسة المختارة، والمخرجات بوحدة صغرى. عندما يبلغ زبون "تم تحميلي سنتًا إضافيًا"، تريد سطرًا واحدًا يفسر السبب.
خطط لتدقيق صغير قبل تغيير المنطق في الإنتاج. أعد حساب الإجماليات على عينة من الطلبات التاريخية، ثم قارن النتائج القديمة والجديدة وعدّ حالات الاختلاف. راجع بعض الاختلافات يدويًا لتتأكد أنها تتطابق مع سياستك الجديدة.
إذا أردت بناء هذا النوع من التدفق الشامل دون إعادة كتابة نفس القواعد ثلاث مرات، فـ AppMaster (appmaster.io) مصمم لتطبيقات كاملة بمنطق مشترك. يمكنك نمذجة المبالغ كوحدات صغرى صحيحة في PostgreSQL عبر Data Designer، تنفيذ خطوات التقريب والضرائب مرة واحدة في Business Process، ثم إعادة استخدام نفس المنطق عبر واجهات الويب والهواتف.
الأسئلة الشائعة
تحدث عادةً عندما تقوم أجزاء مختلفة من التطبيق بالتقريب في أوقات أو بطرق مختلفة. إذا كانت قائمة المنتجات تقرب خطوة واحدة وصفحة الدفع تقرب بطريقة أخرى، فيمكن أن يؤدي نفس السلة إلى حصول اختلاف مشروع في السنتات.
لأن معظم float لا يمكنها تمثيل أسعار عشرية شائعة بدقة في الثنائي، تتراكم فروق صغيرة مخفية. تلك الفروق الطفيفة قد تقلب قرار التقريب لاحقًا وتسبب فرقًا في سنت واحد.
خزن المال كعدد صحيح في الوحدة الصغرى للعملة، مثل السنتات للـ USD (1999 مقابل $19.99)، مع رمز العملة. أجرِ الحسابات على الأعداد الصحيحة وحوّل إلى سلسلة عشرية فقط عند العرض للمستخدمين.
التقييس على خانتين عشريتين يكسر عملات مثل JPY (0 منازل عشرية) أو BHD (3 منازل). خزن دائمًا رمز العملة مع المبلغ وطبّق المقياس الصحيح للوحدة الصغرى عند تحليل الإدخال وتنسيق الإخراج.
اختر قاعدة واضحة وطبقها في كل مكان، مثل تقريب الضريبة لكل سطر أو تقريب الضريبة على إجمالي الفاتورة. الأهم هو الاتساق بين backend والويب والهواتف والتقارير والاستردادات مع نفس وضع التقريب كل مرة.
قرر الترتيب مقدمًا واعتبره سياسة، ليس تفصيلاً تقنيًا. الافتراضي الشائع هو تطبيق الخصم أولًا (لتقليل القاعدة الخاضعة للضريبة) ثم الضريبة، لكن يجب أن تتبع ما تتطلبه أعمالك والاختصاص القضائي وتطبقه بنفس الطريقة عبر الشاشات والخدمات.
حوّل مرة واحدة باستخدام معدل مخزن بدقة واضحة، قرّب عمدًا عند خطوة محددة، وخزن المبلغ والعملـة الأصلية للاستردادات. تجنّب التحويل ذهابًا وإيابًا لأن التكرار يسبب انحراف النتائج.
لا تُحلل سلاسل العرض المنسّقة إلى أرقام لأن فواصل المحلّات والتقريب قد تغير القيمة. مرّر دائمًا قيمًا هيكلية مثل (amount_minor, currency_code) وقُم بالتنسيق فقط عند واجهة المستخدم حسب قواعد اللوكل.
اختبر بحالات "ذهبـية" ثابتة لها مخرجات متوقعة دقيقة بوحدات صغرى (سنتات). ثم أضف تحققًا من الثوابت مثل: الإجمالي يساوي مجموع البنود، ولا توجد وحدات فرعية بعدد صحيح، و"الإجمالي = subtotal + tax + fees - discounts" دائمًا صحيح.
ركّز حسابات المال في مكان واحد وأعد استخدامها في كل العملاء حتى تعطي نفس المدخلات نفس السنتات. في AppMaster، نهج عملي هو نمذجة amount_minor كعدد صحيح في PostgreSQL ووضع منطق التقريب والضرائب في Business Process واحد تستخدمه الويب والهواتف.


