If you're running a subscription business across Malaysia, Singapore, and Indonesia, you're managing three tax systems, three currencies, and a proration logic that breaks silently. A customer upgrades mid-month, and a 2% rounding error appears in their invoice. Multiply that across 100 subscribers and you're reconciling ₹8,000 in phantom line items every quarter. This playbook walks through a three-currency recurring billing setup that nails proration, tax handling, and GL posting without the drift. Why standard recurring billing fails across three zones Most billing systems treat proration as a simple ratio: days-used / days-in-cycle × plan-price. That works in one currency and one tax rate. The moment you cross zones, three problems stack: Tax is calculated before or after proration? If a customer in Malaysia (GST 6%) upgrades on day 15 of a 30-day cycle, is the prorated amount ₹100 pre-tax (then tax added), or ₹106 inclusive? Your GL won't reconcile if Finance assumes one and the billing system assumes the other. Rounding compounds monthly. A ₹499 annual plan prorated to 17 days is ₹231.37. Invoice shows ₹231. Next month, that 0.37 paise doesn't vanish—it sits in a suspense account, and by Q3 you're carrying ₹2,400 in unreconciled micro-transactions. Currency conversion happens at three points. Customer in Singapore on a USD-listed plan: conversion at invoice generation, at tax calculation, or at settlement? Different times = different rates = GL mismatches. Most platforms (including some billing-focused tools) hide these decisions in a settings tab. Orin forces you to name them explicitly in billing configuration and then enforces them at invoice generation and GL posting . The proration formula that prevents rounding drift Here's the formula that works across all three zones: Prorated Amount (pre-tax) = (Plan Price × Days Used) / Days in Cycle, rounded to the nearest paisa/sen (2 decimals). Tax = Prorated Amount × Tax Rate (rounded separately). GL posting = Prorated Amount + Tax. The key: proration happens first, tax is applied to the prorated amount, and rounding happens at both steps independently. This means: A ₹5,000 MYR plan for 15 of 30 days = ₹2,500 pre-tax. GST at 6% = ₹150 tax (₹2,500 × 0.06). Invoice total = ₹2,650. GL posts: Revenue ₹2,500, Tax Payable ₹150. No suspense account, no drift. When a customer switches from a ₹5,000 annual to a ₹8,000 annual plan on day 15 of a 30-day cycle: Credit the original plan for unused days: (₹5,000 × 15) / 30 = ₹2,500 (already invoiced—reverse this). Charge the new plan for the full cycle: ₹8,000 (next billing date). Pro-rata difference for remainder of current cycle: (₹8,000 × 15) / 30 = ₹4,000. Final invoice: –₹2,500 (reversal) + ₹4,000 (pro-rata new plan) = ₹1,500 due today. Tax is applied to each component separately, not to the net. This keeps GL split by transaction type, not buried in one lump line item. Currency, tax rate, and GL GL account mapping Before you set up invoicing , build a matrix in a spreadsheet (or a config document in your accounting system): Zone Currency Tax Code Tax Rate GL Revenue Account GL Tax Payable Account Conversion Rule Malaysia MYR GST 6% 4100-MYR-Subscription 2200-MYR-GST-Payable Invoice generation (spot rate) Singapore SGD GST 9% 4100-SGD-Subscription 2200-SGD-GST-Payable Invoice generation (spot rate) Indonesia IDR PPN 11% 4100-IDR-Subscription 2200-IDR-PPN-Payable Invoice generation (spot rate) Observations: Each zone gets its own GL accounts by currency. This makes reconciliation trivial: ID code 4100-MYR-Subscription's balance should equal your MYR revenue journal from your billing system. Convert at invoice generation time, not at payment settlement. This locks the rate and prevents a second variance when the customer pays. If a customer pays in a different currency (e.g., a Singapore customer pays in USD), handle the FX gain/loss separately in a realized/unrealized FX account (4500-series) rather than burying it in revenue. Setting up the GL reconciliation loop Every Friday (or end of week), run this check: Export all invoices generated this week from your billing system, grouped by (zone, currency, tax code). Sum by currency and tax code. Example: MYR-GST invoices = ₹87,342 revenue + ₹5,240 tax. Pull the same week's GL posting report from your accounting system, filtered to revenue and payable accounts. Reconcile line-by-line. If the sums don't match, the difference is either a rounding error, a failed invoice post, or a timing gap (invoice generated but not posted yet). If a discrepancy is under ₹50 or equivalent, create a rounding adjustment entry. If it's over, investigate the invoice. This is why bundled platforms matter: when invoicing and accounting share the same data layer, the reconciliation happens automatically. Separate systems mean you're babysitting an API sync and debugging CSV imports. Handling mid-cycle plan changes without GL chaos A customer upgrades or downgrades. Your billing system must p