Kotchasan Framework Documentation
Currency Class - Currency and Number Management
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\CurrencyOverview
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): stringParameters:
$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): stringParameters:
$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): floatParameters:
$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) ÷ 100VAT 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
): stringParameters:
$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
Related Classes
Summary
Currency class has 4 main methods:
- bahtThai() - Convert number to Thai text
- bahtEng() - Convert number to English text
- calcVat() - Calculate VAT (supports both exclusive/inclusive)
- format() - Format number with decimals and separators
Perfect for:
- Receipt/invoice systems
- Payroll systems
- Accounting systems
- POS systems
- Financial documents