Kotchasan Framework Documentation

Kotchasan Framework Documentation

Currency Class - Currency and Number Management

EN 03 Feb 2026 14:03

Currency Class - Currency and Number Management

The Currency class provides utilities for converting numbers to Thai and English text, calculating VAT amounts, and formatting financial numbers.

Namespace

Kotchasan\Currency

Overview

Currency class provides:

  • Convert numbers to Thai text (baht/satang)
  • Convert numbers to English text (baht/satang)
  • Calculate VAT for both exclusive and inclusive amounts
  • Format numbers with decimal places and thousands separators

API Reference

bahtThai()

Convert number to Thai text (baht)

public static function bahtThai($thb): string

Parameters:

  • $thb - Amount (float, int, or string)

Returns: Thai text representation, e.g. "หนึ่งร้อยบาทถ้วน", "สองพันบาทห้าสิบสตางค์"

Example:

use Kotchasan\Currency;

// Basic numbers
echo Currency::bahtThai(13);
// "สิบสามบาทถ้วน"

echo Currency::bahtThai(101.55);
// "หนึ่งร้อยเอ็ดบาทห้าสิบห้าสตางค์"

echo Currency::bahtThai(1234.56);
// "หนึ่งพันสองร้อยสามสิบสี่บาทห้าสิบหกสตางค์"

// Large numbers
echo Currency::bahtThai(1000000);
// "หนึ่งล้านบาทถ้วน"

echo Currency::bahtThai(10000000050.25);
// "หนึ่งหมื่นล้านห้าสิบบาทยี่สิบห้าสตางค์"

// Negative amounts
echo Currency::bahtThai(-1000000050);
// "ลบหนึ่งพันล้านห้าสิบบาทถ้วน"

// Receipt example
class Receipt
{
    public function generate($total)
    {
        echo "Total: " . number_format($total, 2) . " Baht\n";
        echo "(" . Currency::bahtThai($total) . ")\n";
    }
}

$receipt = new Receipt();
$receipt->generate(1500.75);
// Total: 1,500.75 Baht
// (หนึ่งพันห้าร้อยบาทเจ็ดสิบห้าสตางค์)

// Payment voucher
function createPaymentVoucher($amount, $payee)
{
    $text = "Pay to: {$payee}\n";
    $text .= "Amount: " . Currency::bahtThai($amount) . "\n";
    $text .= "(" . number_format($amount, 2) . " THB)";
    return $text;
}

echo createPaymentVoucher(25000, "ABC Company Ltd.");

bahtEng()

Convert number to English text (baht)

public static function bahtEng($thb): string

Parameters:

  • $thb - Amount (float, int, or string)

Returns: English text representation, e.g. "one hundred baht", "two thousand baht and fifty satang"

Example:

use Kotchasan\Currency;

// Basic numbers
echo Currency::bahtEng(13);
// "thirteen baht"

echo Currency::bahtEng(101.55);
// "one hundred one baht and fifty-five satang"

echo Currency::bahtEng(1234.56);
// "one thousand two hundred thirty-four baht and fifty-six satang"

// Large numbers
echo Currency::bahtEng(1000000);
// "one million baht"

// Negative amounts
echo Currency::bahtEng(-500);
// "negative five hundred baht"

// Bank check example
class BankCheck
{
    public function create($amount, $payee, $date)
    {
        $check = "Pay to: {$payee}\n";
        $check .= "Amount: " . number_format($amount, 2) . " THB\n";
        $check .= "Amount in words: " . Currency::bahtEng($amount) . "\n";
        $check .= "Date: {$date}\n";
        return $check;
    }
}

$check = new BankCheck();
echo $check->create(15750.50, "John Smith", "2024-01-15");
// Pay to: John Smith
// Amount: 15,750.50 THB
// Amount in words: fifteen thousand seven hundred fifty baht and fifty satang
// Date: 2024-01-15

// International invoice
function createInternationalInvoice($items, $customer)
{
    $total = array_sum(array_column($items, 'amount'));

    $invoice = "INVOICE\n";
    $invoice .= "Customer: {$customer}\n\n";

    foreach ($items as $item) {
        $invoice .= "- {$item['desc']}: " . number_format($item['amount'], 2) . " THB\n";
    }

    $invoice .= "\nTotal: " . number_format($total, 2) . " THB\n";
    $invoice .= "(" . Currency::bahtEng($total) . ")";

    return $invoice;
}

calcVat()

Calculate VAT amount from a given amount

public static function calcVat(float $amount, float $vat, bool $vat_ex = true): float

Parameters:

  • $amount - Amount
  • $vat - VAT rate (percentage), e.g. 7
  • $vat_ex - true = VAT exclusive, false = VAT inclusive

Returns: VAT amount

VAT Exclusive (amount excludes VAT):

VAT = (amount × vat) ÷ 100

VAT Inclusive (amount includes VAT):

VAT = amount - (amount × 100 ÷ (100 + vat))

Example:

use Kotchasan\Currency;

// 7% VAT from VAT-exclusive amount
$vat = Currency::calcVat(1000, 7, true);
echo $vat; // 70

$grandTotal = 1000 + $vat; // 1070

// Extract VAT from VAT-inclusive amount
$vat = Currency::calcVat(1070, 7, false);
echo number_format($vat, 2); // 70.00

$netAmount = 1070 - $vat; // 1000

// Invoice calculator
class InvoiceCalculator
{
    private $vatRate;

    public function __construct($vatRate = 7)
    {
        $this->vatRate = $vatRate;
    }

    public function calculate($items)
    {
        $subtotal = 0;
        foreach ($items as $item) {
            $subtotal += $item['price'] * $item['qty'];
        }

        $vat = Currency::calcVat($subtotal, $this->vatRate, true);
        $total = $subtotal + $vat;

        return [
            'subtotal' => $subtotal,
            'vat' => $vat,
            'total' => $total
        ];
    }

    public function reverseCalculate($totalWithVat)
    {
        $vat = Currency::calcVat($totalWithVat, $this->vatRate, false);
        $subtotal = $totalWithVat - $vat;

        return [
            'subtotal' => $subtotal,
            'vat' => $vat,
            'total' => $totalWithVat
        ];
    }
}

$calc = new InvoiceCalculator(7);

// Calculate from VAT-exclusive amount
$items = [
    ['name' => 'Product A', 'price' => 500, 'qty' => 2],
    ['name' => 'Product B', 'price' => 300, 'qty' => 1]
];

$result = $calc->calculate($items);
echo \"Subtotal: \" . number_format($result['subtotal'], 2) . \" THB\\n\";
echo \"VAT 7%: \" . number_format($result['vat'], 2) . \" THB\\n\";
echo \"Total: \" . number_format($result['total'], 2) . \" THB\\n\";
// Subtotal: 1,300.00 THB
// VAT 7%: 91.00 THB
// Total: 1,391.00 THB

// Reverse calculate VAT from total
$reverse = $calc->reverseCalculate(1391);
echo \"Before VAT: \" . number_format($reverse['subtotal'], 2) . \" THB\\n\";
echo \"VAT: \" . number_format($reverse['vat'], 2) . \" THB\\n\";
// Before VAT: 1,300.00 THB
// VAT: 91.00 THB

// POS System
class POSSystem
{
    public function processTransaction($items, $discount = 0, $vatRate = 7)
    {
        // Calculate subtotal
        $subtotal = 0;
        foreach ($items as $item) {
            $subtotal += $item['price'] * $item['qty'];
        }

        // Apply discount
        $discountAmount = ($subtotal * $discount) / 100;
        $afterDiscount = $subtotal - $discountAmount;

        // Calculate VAT
        $vat = Currency::calcVat($afterDiscount, $vatRate, true);
        $total = $afterDiscount + $vat;

        return [
            'subtotal' => $subtotal,
            'discount_percent' => $discount,
            'discount_amount' => $discountAmount,
            'after_discount' => $afterDiscount,
            'vat' => $vat,
            'total' => $total,
            'total_thai' => Currency::bahtThai($total)
        ];
    }
}

$pos = new POSSystem();
$transaction = $pos->processTransaction([
    ['name' => 'Product 1', 'price' => 1000, 'qty' => 2],
    ['name' => 'Product 2', 'price' => 500, 'qty' => 1]
], 10, 7); // 10% discount, 7% VAT

echo \"Subtotal: \" . number_format($transaction['subtotal'], 2) . \" THB\\n\";
echo \"Discount 10%: \" . number_format($transaction['discount_amount'], 2) . \" THB\\n\";
echo \"After discount: \" . number_format($transaction['after_discount'], 2) . \" THB\\n\";
echo \"VAT 7%: \" . number_format($transaction['vat'], 2) . \" THB\\n\";
echo \"Total: \" . number_format($transaction['total'], 2) . \" THB\\n\";
echo \"(\" . $transaction['total_thai'] . \")\\n\";

format()

Format number with decimal places and thousands separator

public static function format(
    float $amount,
    int $digit = 2,
    string $thousands_sep = ',',
    bool $round = true
): string

Parameters:

  • $amount - Number to format
  • $digit - Decimal places (default: 2)
  • thousands_sep - Thousands separator (default: ',')
  • $round - Round number (default: true)

Returns: Formatted number string

Rounding Behavior:

  • $round = true: Round to specified decimal places
  • $round = false: Truncate extra decimals without rounding

Example:

use Kotchasan\Currency;

// Basic (2 decimals, rounded)
echo Currency::format(1000000.444);
// "1,000,000.44"

echo Currency::format(1000000.555);
// "1,000,000.56" (rounded up)

// 3 decimals, no rounding (truncate)
echo Currency::format(1000000.55455, 3, ',', false);
// "1,000,000.554"

// 3 decimals, rounded
echo Currency::format(1000000.55455, 3);
// "1,000,000.555"

// No separator
echo Currency::format(1234.56, 2, '');
// "1234.56"

// Dot separator
echo Currency::format(1234567.89, 2, '.');
// "1.234.567.89"

// Space separator
echo Currency::format(9999999.99, 2, ' ');
// "9 999 999.99"

// Financial report
class FinancialReport
{
    public function generate($data)
    {
        $report = "Financial Report\n";
        $report .= str_repeat("=", 50) . "\n\n";

        $totalIncome = 0;
        $totalExpense = 0;

        $report .= "Income:\n";
        foreach ($data['income'] as $item) {
            $totalIncome += $item['amount'];
            $report .= "  {$item['desc']}: " .
                      Currency::format($item['amount']) . " THB\n";
        }

        $report .= "\nExpenses:\n";
        foreach ($data['expenses'] as $item) {
            $totalExpense += $item['amount'];
            $report .= "  {$item['desc']}: " .
                      Currency::format($item['amount']) . " THB\n";
        }

        $netIncome = $totalIncome - $totalExpense;

        $report .= "\n" . str_repeat("-", 50) . "\n";
        $report .= "Total Income: " . Currency::format($totalIncome) . " THB\n";
        $report .= "Total Expense: " . Currency::format($totalExpense) . " THB\n";
        $report .= "Net Income: " . Currency::format($netIncome) . " THB\n";

        return $report;
    }
}

// Price table
class PriceTable
{
    public function create($products)
    {
        $table = sprintf(\"%-30s %15s\\n\", \"Product\", \"Price\");
        $table .= str_repeat(\"-\", 50) . \"\\n\";

        foreach ($products as $product) {
            $price = Currency::format($product['price']);
            $table .= sprintf(\"%-30s %15s\\n\",
                            $product['name'],
                            $price . ' THB');
        }

        return $table;
    }
}

$priceTable = new PriceTable();
echo $priceTable->create([
    ['name' => 'Laptop', 'price' => 25000.50],
    ['name' => 'Mouse', 'price' => 350.75],
    ['name' => 'Keyboard', 'price' => 1200]
]);

// Multi-currency display
function formatPrice($amount, $currency = 'THB', $precision = 2)
{
    $formatted = Currency::format($amount, $precision);

    switch ($currency) {
        case 'USD':
            return '$' . $formatted;
        case 'EUR':
            return '€' . $formatted;
        case 'THB':
        default:
            return $formatted . ' THB';
    }
}

echo formatPrice(1500.75, 'USD'); // $1,500.75
echo formatPrice(1500.75, 'THB'); // 1,500.75 THB

// Special fuel price formatting (3 decimals)
$oilPrice = 35.754;
echo \"Fuel price: \" . Currency::format($oilPrice, 3) . \" THB/liter\";
// \"Fuel price: 35.754 THB/liter\"

Real-World Examples

1. Complete Receipt System

use Kotchasan\Currency;

class ReceiptSystem
{
    public function generate($items, $vatRate = 7)
    {
        $receipt = "RECEIPT\n";
        $receipt .= str_repeat("=", 60) . "\n\n";

        $subtotal = 0;
        $receipt .= sprintf("%-30s %8s %10s %12s\n",
                          "Item", "Qty", "Price", "Total");
        $receipt .= str_repeat("-", 60) . "\n";

        foreach ($items as $item) {
            $itemTotal = $item['price'] * $item['qty'];
            $subtotal += $itemTotal;

            $receipt .= sprintf("%-30s %8d %10s %12s\n",
                              $item['name'],
                              $item['qty'],
                              Currency::format($item['price']),
                              Currency::format($itemTotal));
        }

        $vat = Currency::calcVat($subtotal, $vatRate, true);
        $total = $subtotal + $vat;

        $receipt .= str_repeat("-", 60) . "\n";
        $receipt .= sprintf("%51s %12s\n", "Subtotal:",
                          Currency::format($subtotal) . " THB");
        $receipt .= sprintf("%51s %12s\n", "VAT {$vatRate}%:",
                          Currency::format($vat) . " THB");
        $receipt .= sprintf("%51s %12s\n", "Total:",
                          Currency::format($total) . " THB");
        $receipt .= "\n(" . Currency::bahtEng($total) . ")\n";

        return $receipt;
    }
}

2. Payroll System

class PayrollSystem
{
    public function generatePayslip($employee, $salary, $deductions = [])
    {
        $slip = \"PAYSLIP\\n\";
        $slip .= \"Name: {$employee['name']}\\n\";
        $slip .= \"Position: {$employee['position']}\\n\\n\";

        $slip .= \"Salary: \" . Currency::format($salary) . \" THB\\n\";

        if (!empty($deductions)) {
            $slip .= \"\\nDeductions:\\n\";
            $totalDeduction = 0;

            foreach ($deductions as $type => $amount) {
                $totalDeduction += $amount;
                $slip .= \"  {$type}: \" . Currency::format($amount) . \" THB\\n\";
            }

            $slip .= \"  Total deductions: \" . Currency::format($totalDeduction) . \" THB\\n\";

            $netSalary = $salary - $totalDeduction;
        } else {
            $netSalary = $salary;
        }

        $slip .= \"\\nNet salary: \" . Currency::format($netSalary) . \" THB\\n\";
        $slip .= \"(\" . Currency::bahtThai($netSalary) . \")\\n\";

        return $slip;
    }
}

$payroll = new PayrollSystem();
echo $payroll->generatePayslip(
    ['name' => 'John Doe', 'position' => 'Developer'],
    35000,
    ['Social Security' => 750, 'Tax' => 2500]
);

3. Tax Invoice System

class TaxInvoice
{
    public function create($invoiceData)
    {
        $doc = "TAX INVOICE\n";
        $doc .= "Invoice No.: {$invoiceData['number']}\n";
        $doc .= "Customer: {$invoiceData['customer']}\n";
        $doc .= "Date: {$invoiceData['date']}\n\n";

        $subtotal = 0;
        foreach ($invoiceData['items'] as $item) {
            $itemTotal = $item['price'] * $item['qty'];
            $subtotal += $itemTotal;
            $doc .= "- {$item['name']} x{$item['qty']} = " .
                   Currency::format($itemTotal) . " THB\n";
        }

        $vat = Currency::calcVat($subtotal, 7, true);
        $total = $subtotal + $vat;

        $doc .= "\nSubtotal: " . Currency::format($subtotal) . " THB\n";
        $doc .= "VAT 7%: " . Currency::format($vat) . " THB\n";
        $doc .= "Total: " . Currency::format($total) . " THB\n";
        $doc .= "(" . Currency::bahtEng($total) . ")\n";

        return $doc;
    }
}

Best Practices

1. Choose Language Based on Context

// ✅ Good - Thai for domestic documents
$receipt = "Amount: " . Currency::bahtThai($amount);

// ✅ Good - English for international documents
$check = "Amount in words: " . Currency::bahtEng($amount);

2. Specify VAT Exclusive/Inclusive Clearly

// ✅ Good - explicit
$vat = Currency::calcVat($price, 7, true);  // VAT exclusive
$vat = Currency::calcVat($price, 7, false); // VAT inclusive

// ❌ Bad - relies on default, may confuse
$vat = Currency::calcVat($price, 7);

3. Use format() for Display

// ✅ Good - readable with separator
echo Currency::format(1234567.89); // "1,234,567.89"

// ❌ Bad - hard to read
echo $amount; // "1234567.89"

4. Handle Decimals by Data Type

// ✅ Good - money uses 2 decimals
$price = Currency::format($amount, 2);

// ✅ Good - percentage uses 2-4 decimals
$percent = Currency::format($rate, 4);

// ✅ Good - fuel uses 3 decimals
$fuel = Currency::format($liters, 3);

Important Considerations

[!IMPORTANT]
Precision: When $round = false, format() truncates extra decimals without rounding

[!NOTE]
VAT Calculation: calcVat() uses precise formulas, returns float

[!WARNING]
Large Numbers: bahtThai() supports up to 1 trillion (1,000,000,000,000)

[!TIP]
String Input: All methods accept string input, suitable for form data

  • Number - Number formatting
  • Text - Text manipulation
  • Date - Date management

Summary

Currency class has 4 main methods:

  1. bahtThai() - Convert number to Thai text
  2. bahtEng() - Convert number to English text
  3. calcVat() - Calculate VAT (supports both exclusive/inclusive)
  4. format() - Format number with decimals and separators

Perfect for:

  • Receipt/invoice systems
  • Payroll systems
  • Accounting systems
  • POS systems
  • Financial documents