地区
This commit is contained in:
parent
f6822d2411
commit
ea78619f5f
@ -20,7 +20,7 @@ import {
|
||||
listFinanceWithdrawalApplications,
|
||||
refreshFinanceGoogleRechargePaid,
|
||||
rejectFinanceApplication,
|
||||
rejectFinanceWithdrawalApplication
|
||||
rejectFinanceWithdrawalApplication,
|
||||
} from "./api.js";
|
||||
import { FinanceApplicationForm } from "./components/FinanceApplicationForm.jsx";
|
||||
import { FinanceApplicationList } from "./components/FinanceApplicationList.jsx";
|
||||
@ -36,7 +36,7 @@ import {
|
||||
EMPTY_RECHARGE_OVERVIEW,
|
||||
EMPTY_RECHARGE_SUMMARY,
|
||||
buildApplicationPayload,
|
||||
validateApplicationPayload
|
||||
validateApplicationPayload,
|
||||
} from "./format.js";
|
||||
import { downloadCsv } from "@/shared/api/download";
|
||||
import { TimeRangeFilter } from "@/shared/ui/TimeRangeFilter.jsx";
|
||||
@ -62,7 +62,7 @@ function timePresets() {
|
||||
{ key: "7d", label: "近7天", range: { endMs: todayStart + DAY_MS, startMs: todayStart - 6 * DAY_MS } },
|
||||
{ key: "30d", label: "近30天", range: { endMs: todayStart + DAY_MS, startMs: todayStart - 29 * DAY_MS } },
|
||||
{ key: "month", label: "本月", range: { endMs: todayStart + DAY_MS, startMs: monthStart } },
|
||||
{ key: "all", label: "不限", range: { endMs: "", startMs: "" } }
|
||||
{ key: "all", label: "不限", range: { endMs: "", startMs: "" } },
|
||||
];
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ function reconMonthMeta(offset) {
|
||||
endMs,
|
||||
isCurrent: offset === 0,
|
||||
label: `${startDate.getUTCFullYear()}年${startDate.getUTCMonth() + 1}月`,
|
||||
startMs
|
||||
startMs,
|
||||
};
|
||||
}
|
||||
|
||||
@ -85,17 +85,45 @@ export function FinanceApp() {
|
||||
const { showToast } = useToast();
|
||||
const [sessionState, setSessionState] = useState({ error: "", loading: true, session: null });
|
||||
const [optionsState, setOptionsState] = useState({ data: emptyOptions, error: "", loading: false });
|
||||
const [rechargeDetailsState, setRechargeDetailsState] = useState({ data: { items: [], page: 1, pageSize, total: 0 }, error: "", loading: false });
|
||||
const [rechargeSummaryState, setRechargeSummaryState] = useState({ merged: EMPTY_RECHARGE_SUMMARY, loading: false, perApp: [], prev: null });
|
||||
const [rechargeOverviewState, setRechargeOverviewState] = useState({ data: EMPTY_RECHARGE_OVERVIEW, loading: false });
|
||||
const [rechargeRegionsState, setRechargeRegionsState] = useState({ appCode: "", items: [], loading: false });
|
||||
const [rechargeDetailsState, setRechargeDetailsState] = useState({
|
||||
data: { items: [], page: 1, pageSize, total: 0 },
|
||||
error: "",
|
||||
loading: false,
|
||||
});
|
||||
const [rechargeSummaryState, setRechargeSummaryState] = useState({
|
||||
merged: EMPTY_RECHARGE_SUMMARY,
|
||||
loading: false,
|
||||
perApp: [],
|
||||
prev: null,
|
||||
});
|
||||
const [rechargeOverviewState, setRechargeOverviewState] = useState({
|
||||
data: EMPTY_RECHARGE_OVERVIEW,
|
||||
loading: false,
|
||||
});
|
||||
const [rechargeRegionsState, setRechargeRegionsState] = useState({ byApp: {}, loading: false });
|
||||
const [rechargeAppsState, setRechargeAppsState] = useState({ items: [], loaded: false });
|
||||
const [googlePaidRefreshing, setGooglePaidRefreshing] = useState(false);
|
||||
const [reconMonthOffset, setReconMonthOffset] = useState(0);
|
||||
const [reconState, setReconState] = useState({ loading: false, overview: EMPTY_RECHARGE_OVERVIEW, summary: EMPTY_RECHARGE_SUMMARY });
|
||||
const [myApplicationsState, setMyApplicationsState] = useState({ data: { items: [], page: 1, pageSize, total: 0 }, error: "", loading: false });
|
||||
const [applicationsState, setApplicationsState] = useState({ data: { items: [], page: 1, pageSize, total: 0 }, error: "", loading: false });
|
||||
const [withdrawalsState, setWithdrawalsState] = useState({ data: { items: [], page: 1, pageSize, total: 0 }, error: "", loading: false });
|
||||
const [reconState, setReconState] = useState({
|
||||
loading: false,
|
||||
overview: EMPTY_RECHARGE_OVERVIEW,
|
||||
summary: EMPTY_RECHARGE_SUMMARY,
|
||||
});
|
||||
const [myApplicationsState, setMyApplicationsState] = useState({
|
||||
data: { items: [], page: 1, pageSize, total: 0 },
|
||||
error: "",
|
||||
loading: false,
|
||||
});
|
||||
const [applicationsState, setApplicationsState] = useState({
|
||||
data: { items: [], page: 1, pageSize, total: 0 },
|
||||
error: "",
|
||||
loading: false,
|
||||
});
|
||||
const [withdrawalsState, setWithdrawalsState] = useState({
|
||||
data: { items: [], page: 1, pageSize, total: 0 },
|
||||
error: "",
|
||||
loading: false,
|
||||
});
|
||||
const [activeView, setActiveView] = useState("create");
|
||||
const [rechargeDetailFilters, setRechargeDetailFilters] = useState(() => ({
|
||||
appCode: "",
|
||||
@ -105,7 +133,7 @@ export function FinanceApp() {
|
||||
paidState: "",
|
||||
rechargeType: "",
|
||||
regionId: "",
|
||||
timeRange: timePresets().find((preset) => preset.key === "30d").range
|
||||
timeRange: timePresets().find((preset) => preset.key === "30d").range,
|
||||
}));
|
||||
const [rechargeExporting, setRechargeExporting] = useState(false);
|
||||
const [myFilters, setMyFilters] = useState({ appCode: "", keyword: "", operation: "", page: 1, status: "" });
|
||||
@ -134,7 +162,7 @@ export function FinanceApp() {
|
||||
? "applications"
|
||||
: session.canCreateApplication
|
||||
? "create"
|
||||
: "withdrawals"
|
||||
: "withdrawals",
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
@ -161,18 +189,18 @@ export function FinanceApp() {
|
||||
region_id: rechargeDetailFilters.appCode ? rechargeDetailFilters.regionId : "",
|
||||
start_at_ms: rechargeDetailFilters.timeRange.startMs,
|
||||
stat_tz: "Asia/Shanghai",
|
||||
status: "succeeded"
|
||||
status: "succeeded",
|
||||
}),
|
||||
[rechargeDetailFilters]
|
||||
[rechargeDetailFilters],
|
||||
);
|
||||
const rechargeDetailQuery = useMemo(
|
||||
() => ({
|
||||
...rechargeBaseQuery,
|
||||
page: rechargeDetailFilters.page,
|
||||
page_size: pageSize,
|
||||
paid_state: rechargeDetailFilters.paidState
|
||||
paid_state: rechargeDetailFilters.paidState,
|
||||
}),
|
||||
[rechargeBaseQuery, rechargeDetailFilters.page, rechargeDetailFilters.paidState]
|
||||
[rechargeBaseQuery, rechargeDetailFilters.page, rechargeDetailFilters.paidState],
|
||||
);
|
||||
const myApplicationQuery = useMemo(
|
||||
() => ({
|
||||
@ -181,9 +209,9 @@ export function FinanceApp() {
|
||||
operation: myFilters.operation,
|
||||
page: myFilters.page,
|
||||
page_size: pageSize,
|
||||
status: myFilters.status
|
||||
status: myFilters.status,
|
||||
}),
|
||||
[myFilters]
|
||||
[myFilters],
|
||||
);
|
||||
const applicationQuery = useMemo(
|
||||
() => ({
|
||||
@ -192,18 +220,18 @@ export function FinanceApp() {
|
||||
operation: filters.operation,
|
||||
page: filters.page,
|
||||
page_size: pageSize,
|
||||
status: filters.status
|
||||
status: filters.status,
|
||||
}),
|
||||
[filters]
|
||||
[filters],
|
||||
);
|
||||
const withdrawalQuery = useMemo(
|
||||
() => ({
|
||||
app_code: withdrawalFilters.appCode,
|
||||
keyword: withdrawalFilters.keyword,
|
||||
page: withdrawalFilters.page,
|
||||
page_size: pageSize
|
||||
page_size: pageSize,
|
||||
}),
|
||||
[withdrawalFilters]
|
||||
[withdrawalFilters],
|
||||
);
|
||||
|
||||
const loadOptions = useCallback(async () => {
|
||||
@ -228,14 +256,21 @@ export function FinanceApp() {
|
||||
const data = await listMyFinanceApplications(myApplicationQuery);
|
||||
setMyApplicationsState({ data, error: "", loading: false });
|
||||
} catch (err) {
|
||||
setMyApplicationsState((current) => ({ ...current, error: err.message || "加载我的申请列表失败", loading: false }));
|
||||
setMyApplicationsState((current) => ({
|
||||
...current,
|
||||
error: err.message || "加载我的申请列表失败",
|
||||
loading: false,
|
||||
}));
|
||||
}
|
||||
}, [myApplicationQuery, session?.canCreateApplication]);
|
||||
|
||||
// 充值详情的 App 目录来自 recharge-apps(含 Yumi/Aslan 等 legacy 外部账单源);接口未就绪时回退到财务通用 App 列表。
|
||||
const rechargeApps = useMemo(
|
||||
() => (rechargeAppsState.loaded && rechargeAppsState.items.length ? rechargeAppsState.items : optionsState.data.apps),
|
||||
[optionsState.data.apps, rechargeAppsState]
|
||||
() =>
|
||||
rechargeAppsState.loaded && rechargeAppsState.items.length
|
||||
? rechargeAppsState.items
|
||||
: optionsState.data.apps,
|
||||
[optionsState.data.apps, rechargeAppsState],
|
||||
);
|
||||
|
||||
const loadRechargeApps = useCallback(async () => {
|
||||
@ -259,7 +294,11 @@ export function FinanceApp() {
|
||||
const data = await listFinanceRechargeDetails(rechargeDetailQuery, rechargeApps);
|
||||
setRechargeDetailsState({ data, error: "", loading: false });
|
||||
} catch (err) {
|
||||
setRechargeDetailsState((current) => ({ ...current, error: err.message || "加载充值流水失败", loading: false }));
|
||||
setRechargeDetailsState((current) => ({
|
||||
...current,
|
||||
error: err.message || "加载充值流水失败",
|
||||
loading: false,
|
||||
}));
|
||||
}
|
||||
}, [canViewFinance, rechargeApps, rechargeDetailQuery]);
|
||||
|
||||
@ -307,13 +346,13 @@ export function FinanceApp() {
|
||||
end_at_ms: month.endMs,
|
||||
keyword: "",
|
||||
recharge_type: "",
|
||||
start_at_ms: month.startMs
|
||||
start_at_ms: month.startMs,
|
||||
};
|
||||
setReconState((current) => ({ ...current, loading: true }));
|
||||
try {
|
||||
const [{ merged }, overview] = await Promise.all([
|
||||
fetchFinanceRechargeSummaries(query, rechargeApps),
|
||||
fetchFinanceRechargeOverview(query, rechargeApps)
|
||||
fetchFinanceRechargeOverview(query, rechargeApps),
|
||||
]);
|
||||
setReconState({ loading: false, overview, summary: merged });
|
||||
} catch {
|
||||
@ -322,19 +361,27 @@ export function FinanceApp() {
|
||||
}, [activeView, canViewFinance, rechargeApps, rechargeBaseQuery, reconMonthOffset]);
|
||||
|
||||
const rechargeAppCode = rechargeDetailFilters.appCode;
|
||||
// 一次拉齐所有 App 的区域目录:区域筛选下拉用当前 App 的,流水区域列在“全部 App”下要跨 App 显示名称。
|
||||
const loadRechargeRegions = useCallback(async () => {
|
||||
if (!canViewFinance || !rechargeAppCode) {
|
||||
setRechargeRegionsState({ appCode: "", items: [], loading: false });
|
||||
if (!canViewFinance || !rechargeApps.length) {
|
||||
return;
|
||||
}
|
||||
setRechargeRegionsState((current) => ({ ...current, appCode: rechargeAppCode, loading: true }));
|
||||
setRechargeRegionsState((current) => ({ ...current, loading: true }));
|
||||
try {
|
||||
const items = await listFinanceRechargeRegions(rechargeAppCode);
|
||||
setRechargeRegionsState({ appCode: rechargeAppCode, items, loading: false });
|
||||
const entries = await Promise.all(
|
||||
rechargeApps.map(async (app) => {
|
||||
try {
|
||||
return [app.appCode, await listFinanceRechargeRegions(app.appCode)];
|
||||
} catch {
|
||||
setRechargeRegionsState({ appCode: rechargeAppCode, items: [], loading: false });
|
||||
return [app.appCode, []];
|
||||
}
|
||||
}, [canViewFinance, rechargeAppCode]);
|
||||
}),
|
||||
);
|
||||
setRechargeRegionsState({ byApp: Object.fromEntries(entries), loading: false });
|
||||
} catch {
|
||||
setRechargeRegionsState((current) => ({ ...current, loading: false }));
|
||||
}
|
||||
}, [canViewFinance, rechargeApps]);
|
||||
|
||||
const refreshGooglePaid = useCallback(
|
||||
async (transactionIds) => {
|
||||
@ -347,8 +394,10 @@ export function FinanceApp() {
|
||||
const failed = results.filter((item) => item.error).length;
|
||||
const succeeded = results.length - failed;
|
||||
showToast(
|
||||
failed ? `谷歌实付同步完成:成功 ${succeeded} 笔,失败 ${failed} 笔` : `谷歌实付同步完成:${succeeded} 笔`,
|
||||
failed ? "warning" : "success"
|
||||
failed
|
||||
? `谷歌实付同步完成:成功 ${succeeded} 笔,失败 ${failed} 笔`
|
||||
: `谷歌实付同步完成:${succeeded} 笔`,
|
||||
failed ? "warning" : "success",
|
||||
);
|
||||
await Promise.all([loadRechargeDetails(), loadRechargeOverview()]);
|
||||
} catch (err) {
|
||||
@ -357,7 +406,7 @@ export function FinanceApp() {
|
||||
setGooglePaidRefreshing(false);
|
||||
}
|
||||
},
|
||||
[googlePaidRefreshing, loadRechargeDetails, loadRechargeOverview, rechargeAppCode, showToast]
|
||||
[googlePaidRefreshing, loadRechargeDetails, loadRechargeOverview, rechargeAppCode, showToast],
|
||||
);
|
||||
|
||||
const exportRechargeBills = useCallback(async () => {
|
||||
@ -371,7 +420,7 @@ export function FinanceApp() {
|
||||
.replaceAll(/[: ]/g, "-");
|
||||
await downloadCsv(
|
||||
() => exportFinanceRechargeBills(rechargeAppCode, rechargeDetailQuery),
|
||||
`充值明细-${rechargeAppCode}-${timestamp}.csv`
|
||||
`充值明细-${rechargeAppCode}-${timestamp}.csv`,
|
||||
);
|
||||
showToast("充值明细已导出", "success");
|
||||
} catch (err) {
|
||||
@ -390,7 +439,11 @@ export function FinanceApp() {
|
||||
const data = await listFinanceApplications(applicationQuery);
|
||||
setApplicationsState({ data, error: "", loading: false });
|
||||
} catch (err) {
|
||||
setApplicationsState((current) => ({ ...current, error: err.message || "加载申请列表失败", loading: false }));
|
||||
setApplicationsState((current) => ({
|
||||
...current,
|
||||
error: err.message || "加载申请列表失败",
|
||||
loading: false,
|
||||
}));
|
||||
}
|
||||
}, [applicationQuery, session?.canAuditApplication]);
|
||||
|
||||
@ -403,7 +456,11 @@ export function FinanceApp() {
|
||||
const data = await listFinanceWithdrawalApplications(withdrawalQuery);
|
||||
setWithdrawalsState({ data, error: "", loading: false });
|
||||
} catch (err) {
|
||||
setWithdrawalsState((current) => ({ ...current, error: err.message || "加载提现申请列表失败", loading: false }));
|
||||
setWithdrawalsState((current) => ({
|
||||
...current,
|
||||
error: err.message || "加载提现申请列表失败",
|
||||
loading: false,
|
||||
}));
|
||||
}
|
||||
}, [session?.canViewWithdrawalApplications, withdrawalQuery]);
|
||||
|
||||
@ -449,7 +506,7 @@ export function FinanceApp() {
|
||||
|
||||
const operationOptions = useMemo(
|
||||
() => filterOperationsByPermissions(optionsState.data.operations, session?.permissions || []),
|
||||
[optionsState.data.operations, session?.permissions]
|
||||
[optionsState.data.operations, session?.permissions],
|
||||
);
|
||||
|
||||
const submitApplication = async (event) => {
|
||||
@ -471,7 +528,10 @@ export function FinanceApp() {
|
||||
const result = await createFinanceApplication(cleanPayload(payload));
|
||||
setForm({ ...DEFAULT_APPLICATION_FORM, appCode: payload.appCode });
|
||||
setCreateDialogOpen(false);
|
||||
showToast(result?.dingTalkNotified === false ? "申请已提交,钉钉通知未确认" : "申请已提交并通知财务", "success");
|
||||
showToast(
|
||||
result?.dingTalkNotified === false ? "申请已提交,钉钉通知未确认" : "申请已提交并通知财务",
|
||||
"success",
|
||||
);
|
||||
await loadMyApplications();
|
||||
if (session.canAuditApplication) {
|
||||
await loadApplications();
|
||||
@ -507,7 +567,8 @@ export function FinanceApp() {
|
||||
}
|
||||
setWithdrawalAuditLoading(true);
|
||||
try {
|
||||
const submitter = decision === "approved" ? approveFinanceWithdrawalApplication : rejectFinanceWithdrawalApplication;
|
||||
const submitter =
|
||||
decision === "approved" ? approveFinanceWithdrawalApplication : rejectFinanceWithdrawalApplication;
|
||||
await submitter(withdrawalAuditTarget.id, cleanPayload({ auditImageUrl, auditRemark: remark }));
|
||||
showToast(decision === "approved" ? "提现申请已通过" : "提现申请已拒绝", "success");
|
||||
setWithdrawalAuditTarget(null);
|
||||
@ -558,7 +619,7 @@ export function FinanceApp() {
|
||||
const activePreset = presets.find(
|
||||
(preset) =>
|
||||
String(preset.range.startMs || "") === String(rechargeDetailFilters.timeRange.startMs || "") &&
|
||||
String(preset.range.endMs || "") === String(rechargeDetailFilters.timeRange.endMs || "")
|
||||
String(preset.range.endMs || "") === String(rechargeDetailFilters.timeRange.endMs || ""),
|
||||
);
|
||||
const isFinanceView = FINANCE_VIEWS.has(activeView);
|
||||
const financeToolbar =
|
||||
@ -584,13 +645,15 @@ export function FinanceApp() {
|
||||
<div className="finance-seg" role="group" aria-label="计价单位">
|
||||
{[
|
||||
["usd", "USD"],
|
||||
["coin", "金币"]
|
||||
["coin", "金币"],
|
||||
].map(([value, label]) => (
|
||||
<button
|
||||
className={rechargeDetailFilters.currency === value ? "is-on" : ""}
|
||||
key={value}
|
||||
type="button"
|
||||
onClick={() => updateRechargeDetailFilters({ currency: value, page: rechargeDetailFilters.page })}
|
||||
onClick={() =>
|
||||
updateRechargeDetailFilters({ currency: value, page: rechargeDetailFilters.page })
|
||||
}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
@ -603,7 +666,9 @@ export function FinanceApp() {
|
||||
isFinanceView && session.canViewAppRechargeDetails ? (
|
||||
<div className="finance-appbar">
|
||||
<button
|
||||
className={["finance-appchip", rechargeDetailFilters.appCode === "" ? "is-on" : ""].filter(Boolean).join(" ")}
|
||||
className={["finance-appchip", rechargeDetailFilters.appCode === "" ? "is-on" : ""]
|
||||
.filter(Boolean)
|
||||
.join(" ")}
|
||||
type="button"
|
||||
onClick={() => updateRechargeDetailFilters({ appCode: "", regionId: "" })}
|
||||
>
|
||||
@ -611,7 +676,9 @@ export function FinanceApp() {
|
||||
</button>
|
||||
{rechargeApps.map((app) => (
|
||||
<button
|
||||
className={["finance-appchip", rechargeDetailFilters.appCode === app.appCode ? "is-on" : ""].filter(Boolean).join(" ")}
|
||||
className={["finance-appchip", rechargeDetailFilters.appCode === app.appCode ? "is-on" : ""]
|
||||
.filter(Boolean)
|
||||
.join(" ")}
|
||||
key={app.appCode}
|
||||
type="button"
|
||||
onClick={() => updateRechargeDetailFilters({ appCode: app.appCode, regionId: "" })}
|
||||
@ -629,7 +696,13 @@ export function FinanceApp() {
|
||||
canCreate={session.canCreateApplication}
|
||||
canViewRechargeDetails={session.canViewAppRechargeDetails}
|
||||
canViewWithdrawals={session.canViewWithdrawalApplications}
|
||||
loading={optionsState.loading || rechargeDetailsState.loading || myApplicationsState.loading || applicationsState.loading || withdrawalsState.loading}
|
||||
loading={
|
||||
optionsState.loading ||
|
||||
rechargeDetailsState.loading ||
|
||||
myApplicationsState.loading ||
|
||||
applicationsState.loading ||
|
||||
withdrawalsState.loading
|
||||
}
|
||||
session={session}
|
||||
subtitle={isFinanceView ? "中国时区 · 数据实时" : ""}
|
||||
toolbar={financeToolbar}
|
||||
@ -675,7 +748,8 @@ export function FinanceApp() {
|
||||
filters={rechargeDetailFilters}
|
||||
googlePaidRefreshing={googlePaidRefreshing}
|
||||
loading={rechargeDetailsState.loading}
|
||||
regions={rechargeRegionsState.items}
|
||||
regions={rechargeRegionsState.byApp[rechargeAppCode] || []}
|
||||
regionsByApp={rechargeRegionsState.byApp}
|
||||
summary={rechargeSummaryState.merged}
|
||||
onExport={exportRechargeBills}
|
||||
onFiltersChange={updateRechargeDetailFilters}
|
||||
|
||||
@ -37,6 +37,7 @@ export function FinanceRechargeDetailList({
|
||||
onRefreshGooglePaid,
|
||||
onReload,
|
||||
regions,
|
||||
regionsByApp,
|
||||
summary,
|
||||
}) {
|
||||
const [expandedId, setExpandedId] = useState("");
|
||||
@ -231,7 +232,7 @@ export function FinanceRechargeDetailList({
|
||||
</AmountText>
|
||||
</td>
|
||||
<td className="r num">{taxDeductionText(item)}</td>
|
||||
<td>{regionText(item, regionNames)}</td>
|
||||
<td>{regionText(item, regionsByApp, apps, !filters.appCode)}</td>
|
||||
</tr>
|
||||
{expanded ? (
|
||||
<tr className="finance-detailrow">
|
||||
@ -445,12 +446,15 @@ function appName(appCode, apps) {
|
||||
return (apps || []).find((app) => app.appCode === appCode)?.appName || appCode || "-";
|
||||
}
|
||||
|
||||
function regionText(item, regionNames) {
|
||||
// regionText 解析区域列:全部 App 视图下带上 App 前缀(如 “Lalu-南亚区”),单 App 视图只显示区域名。
|
||||
function regionText(item, regionsByApp, apps, withAppPrefix) {
|
||||
const regionId = item.targetRegionId || item.sellerRegionId;
|
||||
if (!regionId) {
|
||||
return "—";
|
||||
}
|
||||
return regionNames.get(String(regionId)) || `区域 ${regionId}`;
|
||||
const appRegions = (regionsByApp || {})[item.appCode] || [];
|
||||
const name = appRegions.find((region) => String(region.regionId) === String(regionId))?.name || `区域 ${regionId}`;
|
||||
return withAppPrefix ? `${appName(item.appCode, apps)}-${name}` : name;
|
||||
}
|
||||
|
||||
function secondaryOrderNo(item) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user