Skip to content

Conversation

@yalaska04
Copy link
Contributor

This PR introduces initial support for Malaysia (MY) into the GOBL system, implementing the Sales and Service Tax (SST) structure. The contribution includes a new regime definition, validation logic, tax category definitions, and tests.

Implemented Features:

  1. New Malaysian Regime

    • Registered MY regime using TaxScheme: "st" (Sales Tax system)
    • Configured metadata (currency, timezone, tags, etc.)
  2. Tax Categories for SST

    • Defined two custom categories:
      • sales-tax with 5% and 10% rates
      • service-tax with 6% and 8% rates (including March 2024 update)
    • Included metadata such as official source URLs and date of applicability
  3. Invoice Validation (invoice.go)

    • Ensures supplier and customer have a valid tax_id
    • Enforces a minimum of one invoice line
  4. Tax Identity Validation (tax_identity.go)

    • Supports 12-digit registration numbers and SST-style alphanumeric formats
    • Normalizes values (e.g., removes spaces, uppercases SST IDs)
    • Includes unit tests for normalization and validation logic
  5. Testing

    • invoice_test.go validates:
      • A correct Malaysian invoice
      • Missing or invalid tax IDs
    • tax_identity_test.go verifies:
      • Normalization of SST and registration numbers
      • Acceptance and rejection of known-valid/invalid formats

Notes:

  • identities[] field (e.g., for SST numbers) is supported structurally but not yet validated.
  • Includes a disclaimer in the README clarifying that this is a technical exercise for demonstration purposes only and not production-certified.

Copy link
Collaborator

@samlown samlown left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good start. The original contributing comment checklist should be maintained as that lists useful steps which have been skipped here. Its important that the tests and linters pass, also so that we can confirm test coverage.

More attention needs to be take when comparing against existing examples. The tax category definitions for example are not aligned with any of the existing tax regimes.


## Disclaimer

> This implementation of the Malaysian tax regime (`MY`) for GOBL has been developed as part of a technical exercise and is intended for **demonstration and testing purposes only**. While every effort has been made to align with publicly available SST regulations and business practices in Malaysia, this module is **not certified for production use** and may not cover all legal, fiscal, or e-invoicing requirements.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is necessary.

)
}

func validateCustomer(val any) error {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method looks identical to the validateSupplier. Are both methods required?

require.NoError(t, inv.Calculate())
err := inv.Validate()
assert.ErrorContains(t, err, "supplier: (tax_id: cannot be blank.)")
})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No test appears to be present for requiring the customer.

Comment on lines +48 to +49
validation.Required,
tax.RequireIdentityCode,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this is a requirement? How are simplified invoices issued in Malasia when there is no customer?

return &tax.RegimeDef{
Country: "MY",
Currency: currency.MYR,
TaxScheme: tax.CategoryST, // tax/constants.go. Malaysia uses SST — a form of ST in GOBL terms.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to add a tax.CategorySST to represent this unique type in Malaysia.

},
},
{
Key: "standard-10",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably just standard.

},
},
{
Key: "standard-8",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming this category is merged into a single SST, this key could perhaps be standard+services.

},
Rates: []*tax.RateDef{
{
Key: "standard-6",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this should be reduced+services.

taxCodeMYNumeric = regexp.MustCompile(`^\d{12}$`)

// Alphanumeric SST/Service Tax IDs — e.g., SST1234567890 or W10-12345678-123
taxCodeSST = regexp.MustCompile(`^SST\d{10,12}$`)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd ditch the SST part and just focus on the numbers. This could be normalized out. I think it'd also be important to detail why there are different formats, even if just in the comments.

}
str := strings.ToUpper(strings.TrimSpace(code.String()))

if taxCodeMYNumeric.MatchString(str) || taxCodeSST.MatchString(str) || taxCodeWStyle.MatchString(str) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally there should only be one primary tax code format to use. I'd expect SST to be the primary code to use in international transactions. But if there is a source of information where this logic was determined, it'd be useful to mention here.

@samlown samlown added the needs changes The PR/Issue is put on hold as it needs further changes before it can be merged. label Jul 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs changes The PR/Issue is put on hold as it needs further changes before it can be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants