fix(currency): update fields

This commit is contained in:
ghazall-ag
2025-12-30 22:23:55 +03:30
parent ecf6574e5d
commit 964965f0d1
4 changed files with 335 additions and 113 deletions

View File

@@ -22,7 +22,7 @@ const Sidebar = ({ isOpen, onToggle }) => {
{ name: 'Currency', href: '/currency', icon: DollarSign },
{ name: 'Location', href: '/location', icon: MapPin },
{ name: 'Issuer', href: '/issuer', icon: Building2 },
// { name: 'Settings', href: '/settings', icon: Settings },
{ name: 'Settings', href: '/settings', icon: Settings },
];
return (

View File

@@ -1,7 +1,7 @@
import React, { useEffect, useMemo, useState, useCallback } from 'react';
import DataTable from '../components/DataTable';
import { currencyAPI } from '../services/api';
import { Plus, Search, Power, Wrench, Settings, DollarSign, Shield } from 'lucide-react';
import { Plus, Search, Power, Wrench, Settings, DollarSign, Shield, AlertTriangle, CheckCircle2 } from 'lucide-react';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { getErrorMessage, getSuccessMessage } from '../utils/errorHandler';
@@ -49,12 +49,10 @@ const Currency = () => {
voucherLimits: { min: null, max: null },
});
const [feesForm, setFeesForm] = useState({
depositFee: { percent: 0, fixed: 0, minAmount: null, maxAmount: null },
cashOutFee: { percent: 0, fixed: 0, minAmount: null, maxAmount: null },
transferFee: { percent: 0, fixed: 0, minAmount: null, maxAmount: null },
exchangeFee: { percent: 0, fixed: 0, minAmount: null, maxAmount: null },
generateVoucherFee: { percent: 0, fixed: 0, minAmount: null, maxAmount: null },
expireVoucherSystemFee: { percent: 0, fixed: 0, minAmount: null, maxAmount: null },
depositLimits: { min: null, max: null },
cashOutLimits: { min: null, max: null },
transferLimits: { min: null, max: null },
voucherLimits: { min: null, max: null },
});
// دریافت ارزها
@@ -96,7 +94,7 @@ const Currency = () => {
}
// بررسی وجود ارز در لیست (برای جلوگیری از درخواست غیرضروری)
const exists = currencies.some(c => c.currencyCode?.code?.toUpperCase() === code);
const exists = currencies.some(c => c.currencyCode?.toUpperCase() === code);
if (exists) {
toast.error(`Currency ${code} already exists`);
return;
@@ -127,8 +125,12 @@ const Currency = () => {
// --- فعال/غیرفعال کردن Maintenance ---
const onEnableMaintenance = async (currencyCode, message = '') => {
if (!message || message.trim() === '') {
toast.error('Maintenance message is required');
return;
}
try {
const result = await currencyAPI.enableMaintenance(currencyCode, message || null);
const result = await currencyAPI.enableMaintenance(currencyCode, message);
await fetchCurrencies();
setMaintenanceModal(null);
setMaintenanceMessage('');
@@ -177,11 +179,25 @@ const Currency = () => {
// --- به‌روزرسانی Fees ---
const onUpdateFees = async (currencyCode, fees) => {
try {
const result = await currencyAPI.updateFees(currencyCode, fees);
// API PUT expects: depositFee, cashOutFee, transferFee, exchangeFee, generateVoucherByAgentFee, generateVoucherByUserFee, expireVoucherSystemFee
// But GET returns: depositLimits, cashOutLimits, transferLimits, voucherLimits
// Map our structure to API expected structure
const payload = {
depositFee: fees.depositLimits || { min: null, max: null },
cashOutFee: fees.cashOutLimits || { min: null, max: null },
transferFee: fees.transferLimits || { min: null, max: null },
exchangeFee: { min: null, max: null }, // Required by API
generateVoucherByAgentFee: fees.voucherLimits || { min: null, max: null }, // Map voucherLimits to generateVoucherByAgentFee
generateVoucherByUserFee: { min: null, max: null }, // Required by API
expireVoucherSystemFee: { min: null, max: null }, // Required by API
};
console.log('🔵 Currency - onUpdateFees payload:', payload);
const result = await currencyAPI.updateFees(currencyCode, payload);
await fetchCurrencies();
setFeesModal(null);
toast.success(getSuccessMessage(result) || 'Fees updated successfully');
} catch (err) {
console.error('🔴 Currency - onUpdateFees error:', err);
toast.error(getErrorMessage(err));
}
};
@@ -190,19 +206,11 @@ const Currency = () => {
const columns = useMemo(() => [
{
key: 'currencyCode',
header: 'Currency',
header: 'Currency Code',
render: (val) => (
<div>
<div className="font-semibold">{val?.code || '—'}</div>
<div className="text-xs text-gray-500">{val?.name || ''}</div>
</div>
<span className="font-semibold font-mono">{val || '—'}</span>
),
},
{
key: 'currencyCode',
header: 'Symbol',
render: (val) => <span className="font-mono">{val?.symbol || '—'}</span>,
},
{
key: 'isActive',
header: 'Active',
@@ -216,8 +224,18 @@ const Currency = () => {
key: 'isUnderMaintenance',
header: 'Maintenance',
render: (val, row) => (
<span className={`px-2 py-1 rounded text-xs ${val ? 'bg-yellow-100 text-yellow-800' : 'bg-gray-100 text-gray-800'}`}>
{val ? '⚠️ Yes' : '✓ No'}
<span className={`inline-flex items-center gap-1 px-2 py-1 rounded text-xs ${val ? 'bg-yellow-100 text-yellow-800' : 'bg-gray-100 text-gray-800'}`}>
{val ? (
<>
<AlertTriangle className="h-3 w-3" />
<span>Yes</span>
</>
) : (
<>
<CheckCircle2 className="h-3 w-3" />
<span>No</span>
</>
)}
</span>
),
},
@@ -234,7 +252,7 @@ const Currency = () => {
key: 'actions',
header: 'Actions',
render: (_val, row) => {
const code = row.currencyCode?.code;
const code = row.currencyCode;
if (!code) return '—';
return (
<div className="flex flex-wrap items-center gap-2">
@@ -290,16 +308,32 @@ const Currency = () => {
<Settings className="h-3 w-3 mr-1" /> Limits
</button>
<button
onClick={() => {
onClick={async () => {
setFeesModal(row);
setFeesForm(row.fees || {
depositFee: { percent: 0, fixed: 0, minAmount: null, maxAmount: null },
cashOutFee: { percent: 0, fixed: 0, minAmount: null, maxAmount: null },
transferFee: { percent: 0, fixed: 0, minAmount: null, maxAmount: null },
exchangeFee: { percent: 0, fixed: 0, minAmount: null, maxAmount: null },
generateVoucherFee: { percent: 0, fixed: 0, minAmount: null, maxAmount: null },
expireVoucherSystemFee: { percent: 0, fixed: 0, minAmount: null, maxAmount: null },
try {
// Fetch fees data from API
const feesData = await currencyAPI.getFees(row.currencyCode);
// API returns: depositLimits, cashOutLimits, transferLimits, voucherLimits
const allowedFields = ['depositLimits', 'cashOutLimits', 'transferLimits', 'voucherLimits'];
const filteredFees = allowedFields.reduce((acc, key) => {
if (feesData && feesData[key]) {
acc[key] = feesData[key];
} else {
acc[key] = { min: null, max: null };
}
return acc;
}, {});
setFeesForm(filteredFees);
} catch (err) {
console.error('Error fetching fees:', err);
// Fallback to default structure
setFeesForm({
depositLimits: { min: null, max: null },
cashOutLimits: { min: null, max: null },
transferLimits: { min: null, max: null },
voucherLimits: { min: null, max: null },
});
}
}}
className="inline-flex items-center px-2 py-1 text-xs rounded-md bg-indigo-100 text-indigo-700 hover:opacity-90"
title="Fees"
@@ -352,7 +386,7 @@ const Currency = () => {
// --- مودال Maintenance ---
const renderMaintenanceModal = () => {
if (!maintenanceModal) return null;
const code = maintenanceModal.currencyCode?.code;
const code = maintenanceModal.currencyCode;
return (
<>
@@ -367,19 +401,23 @@ const Currency = () => {
</h3>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium mb-2">Maintenance Message (optional)</label>
<label className="block text-sm font-medium mb-2">
Maintenance Message <span className="text-red-500">*</span>
</label>
<textarea
value={maintenanceMessage}
onChange={(e) => setMaintenanceMessage(e.target.value)}
className="w-full p-2 border rounded-lg"
rows={3}
placeholder="Enter maintenance message..."
placeholder="Enter maintenance message (required)..."
required
/>
</div>
<div className="flex gap-2">
<button
onClick={() => onEnableMaintenance(code, maintenanceMessage)}
className="flex-1 px-4 py-2 bg-yellow-500 text-white rounded-lg hover:opacity-90"
disabled={!maintenanceMessage || maintenanceMessage.trim() === ''}
className="flex-1 px-4 py-2 bg-yellow-500 text-white rounded-lg hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed"
>
Enable Maintenance
</button>
@@ -404,7 +442,7 @@ const Currency = () => {
// --- مودال Permissions ---
const renderPermissionsModal = () => {
if (!permissionsModal) return null;
const code = permissionsModal.currencyCode?.code;
const code = permissionsModal.currencyCode;
const handleSubmit = (e) => {
e.preventDefault();
@@ -443,7 +481,7 @@ const Currency = () => {
// --- مودال Limits ---
const renderLimitsModal = () => {
if (!limitsModal) return null;
const code = limitsModal.currencyCode?.code;
const code = limitsModal.currencyCode;
const handleSubmit = (e) => {
e.preventDefault();
@@ -508,19 +546,19 @@ const Currency = () => {
// --- مودال Fees ---
const renderFeesModal = () => {
if (!feesModal) return null;
const code = feesModal.currencyCode?.code;
const code = feesModal.currencyCode;
const handleSubmit = (e) => {
e.preventDefault();
onUpdateFees(code, feesForm);
};
const updateFee = (category, field, value) => {
const updateFee = (category, type, value) => {
setFeesForm({
...feesForm,
[category]: {
...feesForm[category],
[field]: value === '' ? null : parseFloat(value) || null,
[type]: value === '' ? null : parseFloat(value) || null,
},
});
};
@@ -529,60 +567,38 @@ const Currency = () => {
<>
<div className="fixed inset-0 bg-black bg-opacity-50 z-40" onClick={() => setFeesModal(null)} />
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
<div className="w-full max-w-3xl card p-6 relative bg-white rounded-2xl shadow-lg max-h-[90vh] overflow-y-auto">
<div className="w-full max-w-2xl card p-6 relative bg-white rounded-2xl shadow-lg max-h-[90vh] overflow-y-auto">
<h3 className="text-lg font-semibold text-gray-900 mb-4">Fees: {code}</h3>
<form onSubmit={handleSubmit} className="space-y-4">
{Object.keys(feesForm).map((category) => (
{Object.keys(feesForm).map((category) => {
return (
<div key={category} className="border rounded-lg p-3">
<h4 className="font-medium mb-2">{category.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase())}</h4>
<h4 className="font-medium mb-2">{category}</h4>
<div className="grid grid-cols-2 gap-2">
<div>
<label className="block text-xs text-gray-600 mb-1">Percent</label>
<label className="block text-xs text-gray-600 mb-1">Min</label>
<input
type="number"
step="0.01"
value={feesForm[category].percent ?? ''}
onChange={(e) => updateFee(category, 'percent', e.target.value)}
value={feesForm[category].min ?? ''}
onChange={(e) => updateFee(category, 'min', e.target.value)}
className="w-full p-2 border rounded"
placeholder="Percent"
placeholder="Min"
/>
</div>
<div>
<label className="block text-xs text-gray-600 mb-1">Fixed</label>
<label className="block text-xs text-gray-600 mb-1">Max</label>
<input
type="number"
step="0.01"
value={feesForm[category].fixed ?? ''}
onChange={(e) => updateFee(category, 'fixed', e.target.value)}
value={feesForm[category].max ?? ''}
onChange={(e) => updateFee(category, 'max', e.target.value)}
className="w-full p-2 border rounded"
placeholder="Fixed"
/>
</div>
<div>
<label className="block text-xs text-gray-600 mb-1">Min Amount</label>
<input
type="number"
step="0.01"
value={feesForm[category].minAmount ?? ''}
onChange={(e) => updateFee(category, 'minAmount', e.target.value)}
className="w-full p-2 border rounded"
placeholder="Min Amount"
/>
</div>
<div>
<label className="block text-xs text-gray-600 mb-1">Max Amount</label>
<input
type="number"
step="0.01"
value={feesForm[category].maxAmount ?? ''}
onChange={(e) => updateFee(category, 'maxAmount', e.target.value)}
className="w-full p-2 border rounded"
placeholder="Max Amount"
placeholder="Max"
/>
</div>
</div>
</div>
))}
);
})}
<div className="flex justify-end gap-x-2 mt-4">
<button type="button" onClick={() => setFeesModal(null)} className="px-4 py-2 border rounded-lg">Cancel</button>
<button type="submit" className="btn-primary px-4 py-2 rounded-lg">Save</button>
@@ -640,9 +656,8 @@ const Currency = () => {
data={currencies.filter(c => {
if (!filter) return true;
const search = filter.toLowerCase();
const code = c.currencyCode?.code?.toLowerCase() || '';
const name = c.currencyCode?.name?.toLowerCase() || '';
return code.includes(search) || name.includes(search);
const code = c.currencyCode?.toLowerCase() || '';
return code.includes(search);
})}
columns={columns}
searchable={false}

View File

@@ -6,52 +6,199 @@ import api from './apiClient';
export const currencyAPI = {
// GET /api/v1/Currency
async list() {
console.log('🔵 Currency API - list request');
const res = await api.get('/api/v1/Currency', { skipAuthRedirect: true });
return res?.data?.data || [];
console.log('🟢 Currency API - list response:', res?.data);
// Response structure: { data: [{ currencyCode, isActive, permissions, limits, fees, ... }, ...] }
return Array.isArray(res?.data?.data) ? res.data.data : (Array.isArray(res?.data) ? res.data : []);
},
// GET /api/v1/Currency/{currencyCode}
async getByCode(currencyCode) {
if (!currencyCode) {
throw new Error('Currency code is required');
}
const res = await api.get(`/api/v1/Currency/${encodeURIComponent(currencyCode)}`, {
skipAuthRedirect: true
});
return res?.data?.data || res?.data;
},
// POST /api/v1/Currency
async create(currencyCode) {
const payload = { currencyCode: String(currencyCode || '') };
if (!currencyCode) {
throw new Error('Currency code is required');
}
const payload = { currencyCode: String(currencyCode).trim() };
const res = await api.post('/api/v1/Currency', payload, { skipAuthRedirect: true });
return res?.data;
},
// PATCH /api/v1/Currency/{currencyCode}/ToggleActivation
async toggleActivation(currencyCode) {
if (!currencyCode) {
throw new Error('Currency code is required');
}
const res = await api.patch(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/ToggleActivation`, null, { skipAuthRedirect: true });
return res?.data;
},
// PATCH /api/v1/Currency/{currencyCode}/Maintenance/Enable
async enableMaintenance(currencyCode, maintenanceMessage = null) {
const payload = maintenanceMessage ? { maintenanceMessage } : {};
async enableMaintenance(currencyCode, maintenanceMessage) {
if (!currencyCode) {
throw new Error('Currency code is required');
}
if (!maintenanceMessage || String(maintenanceMessage).trim() === '') {
throw new Error('Maintenance message is required');
}
// API expects "Description" field (PascalCase)
const payload = { Description: String(maintenanceMessage).trim() };
console.log('🔵 Currency API - enableMaintenance request:', {
currencyCode,
payload
});
try {
const res = await api.patch(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Maintenance/Enable`, payload, { skipAuthRedirect: true });
console.log('🟢 Currency API - enableMaintenance response:', res?.data);
return res?.data;
} catch (error) {
console.error('🔴 Currency API - enableMaintenance error:', {
currencyCode,
payload,
status: error?.response?.status,
data: error?.response?.data,
error: error?.response?.data || error?.message
});
throw error;
}
},
// PATCH /api/v1/Currency/{currencyCode}/Maintenance/Disable
async disableMaintenance(currencyCode) {
if (!currencyCode) {
throw new Error('Currency code is required');
}
const res = await api.patch(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Maintenance/Disable`, null, { skipAuthRedirect: true });
return res?.data;
},
// GET /api/v1/Currency/{currencyCode}/Permissions
async getPermissions(currencyCode) {
if (!currencyCode) {
throw new Error('Currency code is required');
}
try {
const res = await api.get(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Permissions`, {
skipAuthRedirect: true
});
// Response structure: { statusCode, isSuccess, code, message, errors, data: {...} }
// Return the data field from the response
return res?.data?.data || null;
} catch (error) {
console.error('🔴 Currency API - getPermissions error:', {
currencyCode,
status: error?.response?.status,
data: error?.response?.data,
error: error?.response?.data || error?.message
});
throw error;
}
},
// PUT /api/v1/Currency/{currencyCode}/Permissions
async updatePermissions(currencyCode, permissions) {
if (!currencyCode) {
throw new Error('Currency code is required');
}
const res = await api.put(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Permissions`, permissions, { skipAuthRedirect: true });
return res?.data;
},
// GET /api/v1/Currency/{currencyCode}/Limits
async getLimits(currencyCode) {
if (!currencyCode) {
throw new Error('Currency code is required');
}
try {
const res = await api.get(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Limits`, {
skipAuthRedirect: true
});
// Response structure: { statusCode, isSuccess, code, message, errors, data: { depositLimits, cashOutLimits, transferLimits, voucherLimits } }
// Return the data field from the response
return res?.data?.data || null;
} catch (error) {
console.error('🔴 Currency API - getLimits error:', {
currencyCode,
status: error?.response?.status,
data: error?.response?.data,
error: error?.response?.data || error?.message
});
throw error;
}
},
// PUT /api/v1/Currency/{currencyCode}/Limits
async updateLimits(currencyCode, limits) {
if (!currencyCode) {
throw new Error('Currency code is required');
}
const res = await api.put(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Limits`, limits, { skipAuthRedirect: true });
return res?.data;
},
// GET /api/v1/Currency/{currencyCode}/Fees
async getFees(currencyCode) {
if (!currencyCode) {
throw new Error('Currency code is required');
}
try {
console.log('🔵 Currency API - getFees request:', { currencyCode });
const res = await api.get(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Fees`, {
skipAuthRedirect: true
});
console.log('🟢 Currency API - getFees response:', res?.data);
// Response structure: { statusCode, isSuccess, code, message, errors, data: { depositLimits, cashOutLimits, transferLimits, voucherLimits } }
// Return the data field from the response
return res?.data?.data || null;
} catch (error) {
console.error('🔴 Currency API - getFees error:', {
currencyCode,
status: error?.response?.status,
data: error?.response?.data,
error: error?.response?.data || error?.message
});
throw error;
}
},
// PUT /api/v1/Currency/{currencyCode}/Fees
async updateFees(currencyCode, fees) {
const res = await api.put(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Fees`, fees, { skipAuthRedirect: true });
if (!currencyCode) {
throw new Error('Currency code is required');
}
if (!fees) {
throw new Error('Fees data is required');
}
try {
console.log('🔵 Currency API - updateFees request:', {
currencyCode,
payload: fees
});
const res = await api.put(`/api/v1/Currency/${encodeURIComponent(currencyCode)}/Fees`, fees, {
skipAuthRedirect: true
});
console.log('🟢 Currency API - updateFees response:', res?.data);
return res?.data;
} catch (error) {
console.error('🔴 Currency API - updateFees error:', {
currencyCode,
payload: fees,
status: error?.response?.status,
data: error?.response?.data,
error: error?.response?.data || error?.message
});
throw error;
}
},
};

View File

@@ -376,6 +376,9 @@ export const issuerAPI = {
// GET /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement
async getTopUpAgentManagement(issuerId) {
if (!issuerId) {
throw new Error('Issuer ID is required');
}
try {
const res = await api.get(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement`, {
skipAuthRedirect: true
@@ -388,9 +391,15 @@ export const issuerAPI = {
},
// PUT /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement
async updateTopUpAgentManagement(issuerId, maxAgents) {
async updateTopUpAgentManagement(issuerId, settings) {
if (!issuerId) {
throw new Error('Issuer ID is required');
}
try {
const payload = { maxAgents: Number(maxAgents) || 0 };
// Support both old format (just maxAgents) and new format (settings object)
const payload = typeof settings === 'number'
? { maxAgents: Number(settings) || 0 }
: { maxAgents: Number(settings?.maxAgents) || 0, ...settings };
const res = await api.put(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement`, payload, {
skipAuthRedirect: true
});
@@ -403,11 +412,14 @@ export const issuerAPI = {
// GET /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency
async getTopUpAgentManagementCurrencies(issuerId) {
if (!issuerId) {
throw new Error('Issuer ID is required');
}
try {
const res = await api.get(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency`, {
skipAuthRedirect: true
});
return Array.isArray(res?.data?.data) ? res?.data?.data : [];
return Array.isArray(res?.data?.data) ? res?.data?.data : (Array.isArray(res?.data) ? res?.data : []);
} catch (error) {
console.error('🔴 TopUpAgentManagement Currencies GET error:', error);
throw error;
@@ -416,11 +428,17 @@ export const issuerAPI = {
// GET /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}
async getTopUpAgentManagementCurrency(issuerId, currencyCode) {
if (!issuerId) {
throw new Error('Issuer ID is required');
}
if (!currencyCode) {
throw new Error('Currency code is required');
}
try {
const res = await api.get(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}`, {
skipAuthRedirect: true
});
return res?.data?.data || null;
return res?.data?.data || res?.data || null;
} catch (error) {
console.error('🔴 TopUpAgentManagement Currency GET error:', error);
throw error;
@@ -428,27 +446,33 @@ export const issuerAPI = {
},
// POST /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}
async createTopUpAgentManagementCurrency(issuerId, currencyCode, currencyData) {
async createTopUpAgentManagementCurrency(issuerId, currencyCode, currencyData = {}) {
if (!issuerId) {
throw new Error('Issuer ID is required');
}
if (!currencyCode) {
throw new Error('Currency code is required');
}
try {
const payload = {
voucherGeneratingFee: {
percent: Number(currencyData.voucherGeneratingFee?.percent) || 0,
fixed: Number(currencyData.voucherGeneratingFee?.fixed) || 0,
minAmount: Number(currencyData.voucherGeneratingFee?.minAmount) || 0,
maxAmount: Number(currencyData.voucherGeneratingFee?.maxAmount) || 0
minAmount: currencyData.voucherGeneratingFee?.minAmount != null ? Number(currencyData.voucherGeneratingFee.minAmount) : null,
maxAmount: currencyData.voucherGeneratingFee?.maxAmount != null ? Number(currencyData.voucherGeneratingFee.maxAmount) : null
},
agentMarketingFee: {
percent: Number(currencyData.agentMarketingFee?.percent) || 0,
fixed: Number(currencyData.agentMarketingFee?.fixed) || 0,
minAmount: Number(currencyData.agentMarketingFee?.minAmount) || 0,
maxAmount: Number(currencyData.agentMarketingFee?.maxAmount) || 0
minAmount: currencyData.agentMarketingFee?.minAmount != null ? Number(currencyData.agentMarketingFee.minAmount) : null,
maxAmount: currencyData.agentMarketingFee?.maxAmount != null ? Number(currencyData.agentMarketingFee.maxAmount) : null
},
agentWalletMaxBalanceLimit: {
min: Number(currencyData.agentWalletMaxBalanceLimit?.min) || 0,
max: Number(currencyData.agentWalletMaxBalanceLimit?.max) || 0
min: currencyData.agentWalletMaxBalanceLimit?.min != null ? Number(currencyData.agentWalletMaxBalanceLimit.min) : null,
max: currencyData.agentWalletMaxBalanceLimit?.max != null ? Number(currencyData.agentWalletMaxBalanceLimit.max) : null
},
agentWalletDepositMonthlyLimit: {
amount: Number(currencyData.agentWalletDepositMonthlyLimit?.amount) || 0
amount: currencyData.agentWalletDepositMonthlyLimit?.amount != null ? Number(currencyData.agentWalletDepositMonthlyLimit.amount) : null
}
};
const res = await api.post(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}`, payload, {
@@ -463,26 +487,35 @@ export const issuerAPI = {
// PUT /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}
async updateTopUpAgentManagementCurrency(issuerId, currencyCode, currencyData) {
if (!issuerId) {
throw new Error('Issuer ID is required');
}
if (!currencyCode) {
throw new Error('Currency code is required');
}
if (!currencyData) {
throw new Error('Currency data is required');
}
try {
const payload = {
voucherGeneratingFee: {
percent: Number(currencyData.voucherGeneratingFee?.percent) || 0,
fixed: Number(currencyData.voucherGeneratingFee?.fixed) || 0,
minAmount: Number(currencyData.voucherGeneratingFee?.minAmount) || 0,
maxAmount: Number(currencyData.voucherGeneratingFee?.maxAmount) || 0
minAmount: currencyData.voucherGeneratingFee?.minAmount != null ? Number(currencyData.voucherGeneratingFee.minAmount) : null,
maxAmount: currencyData.voucherGeneratingFee?.maxAmount != null ? Number(currencyData.voucherGeneratingFee.maxAmount) : null
},
agentMarketingFee: {
percent: Number(currencyData.agentMarketingFee?.percent) || 0,
fixed: Number(currencyData.agentMarketingFee?.fixed) || 0,
minAmount: Number(currencyData.agentMarketingFee?.minAmount) || 0,
maxAmount: Number(currencyData.agentMarketingFee?.maxAmount) || 0
minAmount: currencyData.agentMarketingFee?.minAmount != null ? Number(currencyData.agentMarketingFee.minAmount) : null,
maxAmount: currencyData.agentMarketingFee?.maxAmount != null ? Number(currencyData.agentMarketingFee.maxAmount) : null
},
agentWalletMaxBalanceLimit: {
min: Number(currencyData.agentWalletMaxBalanceLimit?.min) || 0,
max: Number(currencyData.agentWalletMaxBalanceLimit?.max) || 0
min: currencyData.agentWalletMaxBalanceLimit?.min != null ? Number(currencyData.agentWalletMaxBalanceLimit.min) : null,
max: currencyData.agentWalletMaxBalanceLimit?.max != null ? Number(currencyData.agentWalletMaxBalanceLimit.max) : null
},
agentWalletDepositMonthlyLimit: {
amount: Number(currencyData.agentWalletDepositMonthlyLimit?.amount) || 0
amount: currencyData.agentWalletDepositMonthlyLimit?.amount != null ? Number(currencyData.agentWalletDepositMonthlyLimit.amount) : null
}
};
const res = await api.put(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}`, payload, {
@@ -497,6 +530,12 @@ export const issuerAPI = {
// DELETE /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}
async deleteTopUpAgentManagementCurrency(issuerId, currencyCode) {
if (!issuerId) {
throw new Error('Issuer ID is required');
}
if (!currencyCode) {
throw new Error('Currency code is required');
}
try {
const res = await api.delete(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}`, {
skipAuthRedirect: true
@@ -512,11 +551,17 @@ export const issuerAPI = {
// GET /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}/Wallet/Balance
async getTopUpAgentManagementWalletBalance(issuerId, currencyCode) {
if (!issuerId) {
throw new Error('Issuer ID is required');
}
if (!currencyCode) {
throw new Error('Currency code is required');
}
try {
const res = await api.get(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}/Wallet/Balance`, {
skipAuthRedirect: true
});
return res?.data?.data || null;
return res?.data?.data || res?.data || null;
} catch (error) {
console.error('🔴 TopUpAgentManagement Wallet Balance GET error:', error);
throw error;
@@ -525,6 +570,15 @@ export const issuerAPI = {
// POST /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}/Wallet/Deposit
async depositTopUpAgentManagementWallet(issuerId, currencyCode, amount) {
if (!issuerId) {
throw new Error('Issuer ID is required');
}
if (!currencyCode) {
throw new Error('Currency code is required');
}
if (amount == null || amount === '') {
throw new Error('Amount is required');
}
try {
const payload = { amount: Number(amount) || 0 };
const res = await api.post(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}/Wallet/Deposit`, payload, {
@@ -539,11 +593,17 @@ export const issuerAPI = {
// GET /api/v1/issuer/{issuerId}/Capability/TopUpAgentManagement/Currency/{currencyCode}/Wallet/Transactions
async getTopUpAgentManagementWalletTransactions(issuerId, currencyCode) {
if (!issuerId) {
throw new Error('Issuer ID is required');
}
if (!currencyCode) {
throw new Error('Currency code is required');
}
try {
const res = await api.get(`/api/v1/issuer/${encodeURIComponent(issuerId)}/Capability/TopUpAgentManagement/Currency/${encodeURIComponent(currencyCode)}/Wallet/Transactions`, {
skipAuthRedirect: true
});
return Array.isArray(res?.data?.data) ? res?.data?.data : [];
return Array.isArray(res?.data?.data) ? res?.data?.data : (Array.isArray(res?.data) ? res?.data : []);
} catch (error) {
console.error('🔴 TopUpAgentManagement Wallet Transactions GET error:', error);
throw error;