Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ringgit

Malaysian money, handled the way the rules say. Cash rounding to 5 sen per Bank Negara, SST by category, and amounts in words for cheques and invoices. Everything is Decimal; floats are refused at the door.

$ ringgit round 12.33
  RM12.33  ->  RM12.35   (rounding +RM0.02)

$ ringgit words 1234.50
  Ringgit Malaysia: Seribu Dua Ratus Tiga Puluh Empat Dan Lima Puluh Sen Sahaja

$ ringgit sst 33.33 fnb
  net    RM33.33
  sst    RM2.00
  gross  RM35.33
  cash   RM35.35
pip install ringgit

No dependencies. Python 3.10+.

Why

Three things go wrong in almost every Malaysian invoicing codebase:

  1. Money in floats. 0.1 + 0.2 is not 0.3, and a total that is off by a sen fails reconciliation. ringgit takes str, int or Decimal and raises TypeError on a float instead of rounding it quietly.
  2. The 5-sen rule done wrong. Since 1 April 2008 the total of a cash bill is rounded to the nearest 5 sen: 1 and 2 sen down, 3 and 4 up to 5, 6 and 7 down to 5, 8 and 9 up to 10. It applies to the cash total only, not to each line and not to card or transfer payments. People round every item, or round electronic payments, or use a generic "round to nearest 0.05" that behaves differently at the edges.
  3. "The SST rate." There is not one. Service tax is 8% standard and 6% for food and beverage, telecommunications, parking, logistics and, since 1 January 2026, industrial rental. Sales tax is 5% or 10% by tariff line, with exempt goods at 0%. A single constant is the wrong answer.

Use it

from ringgit import RM, round_cash, sst, to_words

total = RM("10.10") + RM("0.20") + "0.03"     # RM10.33
total.cash()                                    # RM10.35  — what the customer hands over
str(total)                                      # 'RM10.33'

round_cash("12.38")                             # Decimal('12.40')
sst("100", "service")                           # Decimal('8.00')
sst("100", "fnb")                               # Decimal('6.00')
sst("100", Decimal("0.07"))                     # an explicit rate, when you must

to_words("1500")                                # 'Ringgit Malaysia: Seribu Lima Ratus Sahaja'
to_words("1500", "en")                          # 'Ringgit Malaysia One Thousand Five Hundred Only'

The words follow cheque convention: Ringgit Malaysia: ... Sahaja, with se- before puluh, belas, ratus and ribu (sepuluh, sebelas, seratus, seribu) and satu before juta and bilion.

Sources

  • Rounding: Bank Negara Malaysia, Rounding Mechanism, effective 1 April 2008.
  • SST: Royal Malaysian Customs Department, MySST. Rates as of 1 January 2026.

47 tests, including the full sen-ending table for the rounding rule and the awkward Malay numerals (sebelas, seratus satu, satu juta).

Licence

MIT.

About

Malaysian money done right: BNM 5-sen cash rounding, SST rates, and ringgit-to-Malay-words for invoices and cheques. Decimal only, no floats.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages