PHP项目数字毛里求斯卢比与eMUR

wen PHP项目 1

本文目录导读:

PHP项目数字毛里求斯卢比与eMUR

  1. 核心假设与业务规则
  2. 数据模型设计(PHP + MySQL/SQL)
  3. PHP 金额处理类(面向对象)
  4. 汇率与转换服务
  5. 支付与转账逻辑(避免混用)
  6. 前端显示(HTML + Blade / Twig)
  7. 总结建议

这是一个非常具体的需求,PHP 项目中处理 数字毛里求斯卢比(MUR)eMUR(e-MUR,数字版本或电子版本的毛里求斯卢比)

由于毛里求斯银行(Bank of Mauritius)目前仍在推进其 CBDC(央行数字货币,即数字卢比)的试点与落地,市面上并没有一个“eMUR”的公开汇率或专用API,它通常被视为 MUR 的一种数字形式,在金融结算中通常与 MUR 等值。

在 PHP 项目中处理这两者,核心挑战在于数据建模汇率处理(通常是1:1固定或浮动) 以及前端展示

以下是针对该需求的完整解决方案:

核心假设与业务规则

  • 关系:1 eMUR = 1 MUR,数字卢比不是另一个币种,而是 MUR 的电子形式,通常结算价值相等。
  • 存管:同一个货币代码“MUR”下,需要区分是“传统账户余额”还是“eMUR 数字钱包余额”。
  • 前端显示:需要显示符号 Rs 或 ,同时标识出是电子货币(例如加上“e-”前缀或不同的颜色/图标)。

数据模型设计(PHP + MySQL/SQL)

在数据库层面,建议将 eMUR 视为 MUR 的一个子类型或来源字段。

方案 A:单表加类型字段(推荐最简化)

CREATE TABLE `wallets` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `user_id` INT NOT NULL,
    `currency_type` ENUM('MUR', 'eMUR') NOT NULL DEFAULT 'MUR',
    `balance` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
    `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY `user_currency` (`user_id`, `currency_type`)
);
  • 说明:同一个用户既有 MUR 余额,也有 eMUR 余额。
  • PHP 查询
// 获取用户所有余额
$query = "SELECT currency_type, balance FROM wallets WHERE user_id = ?";

方案 B:双币种合一表 + 卡片字段(基于 JSON 或两个字段)

CREATE TABLE `accounts` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `user_id` INT NOT NULL,
    `balance_mur` DECIMAL(15, 2) DEFAULT 0.00,
    `balance_emur` DECIMAL(15, 2) DEFAULT 0.00,
    `emur_to_mur_rate` DECIMAL(8, 4) DEFAULT 1.0000, -- 预留灵活性
    `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
  • 优势:便于在一个查询里获取所有余额,无需 JOIN。

PHP 金额处理类(面向对象)

<?php
class Money
{
    private string $amount; // 使用 string 避免浮点数精度问题
    private string $currency; // 'MUR' 或 'eMUR'
    public function __construct(string $amount, string $currency = 'MUR')
    {
        if (!in_array($currency, ['MUR', 'eMUR'])) {
            throw new InvalidArgumentException("Unsupported currency type: {$currency}");
        }
        $this->amount = $amount;
        $this->currency = $currency;
    }
    // 核心转换:eMUR 转 MUR
    public function toMur(): self
    {
        if ($this->currency === 'MUR') {
            return $this;
        }
        // 假设 1 eMUR = 1 MUR
        return new self($this->amount, 'MUR');
    }
    // 转换回 eMUR
    public function toEmur(): self
    {
        if ($this->currency === 'eMUR') {
            return $this;
        }
        return new self($this->amount, 'eMUR');
    }
    // 金额相加(自动处理类型)
    public function add(Money $other): self
    {
        // 先统一转为 MUR 相加
        $total = bcadd($this->toMur()->getAmount(), $other->toMur()->getAmount(), 2);
        // 结果货币类型按原对象
        return new self($total, $this->currency);
    }
    // 格式化显示(带符号)
    public function format(): string
    {
        $symbol = 'Rs ';
        if ($this->currency === 'eMUR') {
            $symbol = 'e' . $symbol; // 显示 eRs 100.00
        }
        return $symbol . number_format($this->amount, 2);
    }
    public function getAmount(): string
    {
        return $this->amount;
    }
    public function getCurrency(): string
    {
        return $this->currency;
    }
}
// 使用示例
$murMoney = new Money('500.00', 'MUR');
$emurMoney = new Money('150.75', 'eMUR');
echo $murMoney->format(); // Rs 500.00
echo $emurMoney->format(); // eRs 150.75
$total = $murMoney->add($emurMoney);
echo $total->format(); // Rs 650.75 (默认使用第一个对象的货币类型)

汇率与转换服务

如果未来 eMUR 与 MUR 不再 1:1,或者你正在开发一个交易系统。

<?php
class CurrencyConverter
{
    private array $rates;
    public function __construct()
    {
        // 从数据库或外部 API 加载汇率
        // 例: 1 eMUR = 1.0023 MUR (仅示例)
        $this->rates = [
            'MUR_to_eMUR' => 1.0000,
            'eMUR_to_MUR' => 1.0000, // 通常相等
        ];
    }
    public function convert(Money $money, string $targetCurrency): Money
    {
        if ($money->getCurrency() === $targetCurrency) {
            return $money;
        }
        $rateKey = $money->getCurrency() . '_to_' . $targetCurrency;
        if (!isset($this->rates[$rateKey])) {
            throw new Exception("Conversion rate not found");
        }
        $convertedAmount = bcmul($money->getAmount(), (string) $this->rates[$rateKey], 2);
        return new Money($convertedAmount, $targetCurrency);
    }
}
// 使用示例
$converter = new CurrencyConverter();
$emur = new Money('100', 'eMUR');
$mur = $converter->convert($emur, 'MUR');
echo $mur->format(); // Rs 100.00

支付与转账逻辑(避免混用)

在支付交易中,必须严格指定使用哪种余额(MUR 或 eMUR)。

<?php
function processPayment(int $userId, Money $paymentAmount, string $sourceType)
{
    // 1. 检查余额
    // 2. 如果是 eMUR 支付,只从 eMUR 余额扣减
    // 3. 如果是 MUR 支付,只从 MUR 余额扣减
    $db = getDbConnection();
    // 原子操作:从特定类型钱包扣减
    $sql = "UPDATE wallets 
            SET balance = balance - ? 
            WHERE user_id = ? 
              AND currency_type = ? 
              AND balance >= ?";
    $stmt = $db->prepare($sql);
    $stmt->execute([
        $paymentAmount->getAmount(),
        $userId,
        $paymentAmount->getCurrency(),
        $paymentAmount->getAmount()
    ]);
    if ($stmt->rowCount() === 0) {
        throw new Exception("Insufficient funds or wallet not found");
    }
}

前端显示(HTML + Blade / Twig)

如果你使用模板引擎:

// 在控制器中
$userWallet = [
    'mur_balance' => 1250.50,
    'emur_balance' => 300.00,
];

Blade 模板示例

<div class="wallet">
    <div class="balance-item">
        <span class="currency-label">MUR 余额</span>
        <span class="amount">Rs {{ number_format($userWallet['mur_balance'], 2) }}</span>
    </div>
    <div class="balance-item">
        <span class="currency-label e">eMUR 余额</span>
        <span class="amount e">eRs {{ number_format($userWallet['emur_balance'], 2) }}</span>
    </div>
</div>
<style>
    .currency-label.e { color: #1a73e8; }
    .amount.e { background: #e8f0fe; padding: 2px 8px; border-radius: 4px; }
</style>

总结建议

场景 推荐做法
简单钱包 使用 currency_type 字段区分 MUR / eMUR
Excel/报告导出 先转换为统一 MUR,再显示符号
与外部系统对接 一律传输 MUR 数值,在备注中注明 eMUR
API 设计 currency 字段传 MUReMURamount 只需数字
精度 使用 BCMathDecimal 类,避免 float

如果你需要对接毛里求斯银行实际发行的数字卢比 API(BOM数字卢比试点),目前的公开资料较少,通常需要企业身份申请接口,市面上的主流支付网关(如 MyT Pos、Jubilee)暂未公开支持直接扣减 eMUR。

建议:在 PHP 项目中将 eMUR 作为 MUR 的一个“标签”或“钱包类型”处理,保持金额逻辑一致,前端做差异化展示,这是目前成本最低、最稳定的实现方式。

抱歉,评论功能暂时关闭!