From 7e1192f2efc41e4f49aec89945a7fbf5b8705081 Mon Sep 17 00:00:00 2001 From: R524809 Date: Thu, 27 Aug 2026 10:35:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BB=B7=E6=A0=BC=E8=AF=95=E7=AE=97?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/v2.1/trial-page.md | 17 ++- studio/src/pages/product/PriceInfoPanel.tsx | 28 ++-- studio/src/pages/trial/TrialExportPanel.tsx | 12 +- studio/src/pages/trial/TrialPricingPanel.tsx | 147 ++++++++++--------- studio/src/pricing/pricing.ts | 21 +-- 5 files changed, 120 insertions(+), 105 deletions(-) diff --git a/docs/v2.1/trial-page.md b/docs/v2.1/trial-page.md index 4fd88b3..4b64e34 100644 --- a/docs/v2.1/trial-page.md +++ b/docs/v2.1/trial-page.md @@ -55,9 +55,12 @@ ## 4. 02 价格试算(公式从 web/js/app.js 移植,单位口径不变) 输入参数(存 `product.pricing` JSON):`purchasePrice` 进货价¥(默认30)、`profitRate` 净利率%(默认100)、 -`tdPrice` 贴单费¥(默认3)、`logisticsLevel` low/high/high2(默认 low)、`discountReserve` 预留折扣%(默认50,≤95)、 +`tdPrice` 贴单费¥(默认3)、`logisticsLevel` low/high/high2(默认 low)、`lineMultiplier` 划线价倍数%(默认100,0-500)、 `fxRate` 汇率(`product.fx_rate` 快照,无则 `GET /api/fx` 拉取)。重量/尺寸取自 01 区块。 +> 划线价口径(v2.1 调整):原 v1 的「预留折扣空间」(划线价 = 销售价 ÷ (1-折扣%))在 >95% 区间发散且 ≥100% 无解, +> 改为「划线价倍数」:`划线价 = 销售价 × (1 + 倍数%)`。倍数 100% → 划线价 = 2× 销售价;50% → 1.5×。线性、全程可算。 + **物流费**(`baseLogisticsFee` 已在 `studio/src/pricing/pricing.ts`): | 等级 | 条件 | 公式 | 规则文案 | @@ -81,8 +84,8 @@ 平台佣金 = 销售价 × 12%(low)/ 18%(其余) ← 展示用 平台总抽成 = 销售价 × (1 - 净得率) = 15.5% / 21.5% ← 含佣金及约3.5%其它费 完全成本 = 进货价 + 物流费 + 平台总抽成 -预留后¥ = 销售价 / (1 - 预留折扣%);差额 = 预留后 - 销售价 -销售价₽ = 销售价¥ × 汇率;预留₽ = 预留后¥ × 汇率 +预留后¥ = 销售价 × (1 + 划线价倍数%)(即划线价);差额 = 划线价 - 销售价 +销售价₽ = 销售价¥ × 汇率;划线₽ = 划线价¥ × 汇率 ``` **校验**(v2.1 新增移植到 `pricing.ts`:`validateDimensions` / `validateLogisticsLevelCny` / `validatePriceRange`,注意等级/区间建议用的销售价单位是 **CNY**,与 v1 一致): @@ -99,14 +102,14 @@ // product.pricing(PriceInfoPanel 字段的超集,向后兼容) { "purchasePrice": 30, "profitRate": 100, "logisticsLevel": "low", "tdPrice": 3, - "discountReserve": 50, "fxRate": 11.5, "weightG": 600, "dims": { "l": 20, "w": 15, "h": 10 }, + "lineMultiplier": 100, "fxRate": 11.5, "weightG": 600, "dims": { "l": 20, "w": 15, "h": 10 }, "logisticsFee": 22.12, "receivedPrice": 60, "profitPrice": 30, "commission": 11.63, "fullCommission": 15.02, "totalCost": 67.14, - "sellingPriceCny": 77.51, "reservedPriceCny": 155.02, - "sellingPriceRub": 891.4, "reservedPriceRub": 1782.7, + "sellingPriceCny": 77.51, "linePriceCny": 155.02, + "sellingPriceRub": 891.4, "linePriceRub": 1782.7, "calculatedAt": "2026-08-26T12:00:00Z" } -// 同时回填:price=销售价CNY,old_price=预留后CNY,currency_code=CNY,fx_rate=汇率 +// 同时回填:price=销售价CNY,old_price=划线价CNY,currency_code=CNY,fx_rate=汇率 ``` ## 5. 03 俄文文案 diff --git a/studio/src/pages/product/PriceInfoPanel.tsx b/studio/src/pages/product/PriceInfoPanel.tsx index bc31c5f..5189dcf 100644 --- a/studio/src/pages/product/PriceInfoPanel.tsx +++ b/studio/src/pages/product/PriceInfoPanel.tsx @@ -33,16 +33,16 @@ function dimsCm(product: ProductDetail): { l: number; w: number; h: number } { } /** - * 售价信息:售价/划线价(CNY)+ 定价参数(进货价/净利率/物流等级/汇率/预留折扣)。 + * 售价信息:售价/划线价(CNY)+ 定价参数(进货价/净利率/物流等级/汇率/划线价倍数)。 * 重量、尺寸直接读「主要信息」的包装字段,不重复填写。 - * 任一定价参数变化即重算并回填售价(= 销售价)与划线价(= 预留折扣前价格)。 + * 任一定价参数变化即重算并回填售价(= 销售价)与划线价(= 销售价 × (1 + 倍数%))。 */ export default function PriceInfoPanel({ product, onSave }: Props) { const pricing = (product.pricing ?? {}) as PricingPayload; const [purchasePrice, setPurchasePrice] = useState(pricing.purchasePrice ?? 30); const [profitRate, setProfitRate] = useState(pricing.profitRate ?? 100); const [level, setLevel] = useState((pricing.logisticsLevel as LogisticsLevel) ?? 'low'); - const [reserve, setReserve] = useState(pricing.discountReserve ?? 50); + const [multiplier, setMultiplier] = useState(pricing.lineMultiplier ?? 100); const [fxRate, setFxRate] = useState(product.fx_rate ?? pricing.fxRate ?? 0); // 币种固定人民币:历史数据(默认 RUB)打开编辑页时纠正一次 @@ -67,7 +67,7 @@ export default function PriceInfoPanel({ product, onSave }: Props) { const tdPrice = pricing.tdPrice ?? 3; /** 用当前参数(可被 patch 覆盖)实时计算,不落库 */ - const compute = (patch: Partial<{ purchasePrice: number; profitRate: number; level: LogisticsLevel; reserve: number; fxRate: number }> = {}) => + const compute = (patch: Partial<{ purchasePrice: number; profitRate: number; level: LogisticsLevel; multiplier: number; fxRate: number }> = {}) => calculatePricing({ purchasePrice: patch.purchasePrice ?? purchasePrice, profitRate: patch.profitRate ?? profitRate, @@ -75,17 +75,17 @@ export default function PriceInfoPanel({ product, onSave }: Props) { weightG: weightGrams(product), dims: dimsCm(product), tdPrice, - discountReserve: patch.reserve ?? reserve, + lineMultiplier: patch.multiplier ?? multiplier, fxRate: patch.fxRate ?? fxRate, }); /** 重算并落库:定价参数 + 售价/划线价一并保存 */ - const recalc = (patch: Partial<{ purchasePrice: number; profitRate: number; level: LogisticsLevel; reserve: number; fxRate: number }> = {}) => { + const recalc = (patch: Partial<{ purchasePrice: number; profitRate: number; level: LogisticsLevel; multiplier: number; fxRate: number }> = {}) => { const p = { purchasePrice: patch.purchasePrice ?? purchasePrice, profitRate: patch.profitRate ?? profitRate, level: patch.level ?? level, - reserve: patch.reserve ?? reserve, + multiplier: patch.multiplier ?? multiplier, fxRate: patch.fxRate ?? fxRate, }; const r = compute(patch); @@ -98,7 +98,7 @@ export default function PriceInfoPanel({ product, onSave }: Props) { weightG: weightGrams(product), dims: dimsCm(product), tdPrice, - discountReserve: p.reserve, + lineMultiplier: p.multiplier, fxRate: p.fxRate, logisticsFee: r.logisticsFee, fullCommission: r.fullCommission, @@ -109,7 +109,7 @@ export default function PriceInfoPanel({ product, onSave }: Props) { }, fx_rate: p.fxRate, price: r.sellingPriceCny, - old_price: r.reservedPriceCny, + old_price: r.linePriceCny, currency_code: 'CNY', }); }; @@ -189,15 +189,15 @@ export default function PriceInfoPanel({ product, onSave }: Props) { /> - 预留折扣 % + 划线价倍数 % { - setReserve(v ?? 0); - recalc({ reserve: v ?? 0 }); + setMultiplier(v ?? 0); + recalc({ multiplier: v ?? 0 }); }} /> diff --git a/studio/src/pages/trial/TrialExportPanel.tsx b/studio/src/pages/trial/TrialExportPanel.tsx index db94625..3afccb8 100644 --- a/studio/src/pages/trial/TrialExportPanel.tsx +++ b/studio/src/pages/trial/TrialExportPanel.tsx @@ -1,6 +1,6 @@ /** * 05 入库与导出(docs/v2.1/trial-page.md §7): - * 入库即各区块自动落库;此处提供 本商品CSV / 批量CSV(16 列,对齐 v1 web)与 组合码(SKU 预留₽价)。 + * 入库即各区块自动落库;此处提供 本商品CSV / 批量CSV(16 列,对齐 v1 web)与 组合码(SKU 划线₽价)。 * Phase A 由前端拼装(逐个拉详情),Phase D 可换 GET /api/export/trial-csv。 */ import { useState } from 'react'; @@ -50,11 +50,11 @@ function buildRow(p: ProductDetail): Array { ]; } -/** 组合码一行:`货号 预留₽价(两位)`,无预留价回退销售价₽ */ +/** 组合码一行:`货号 划线₽价(两位)`,无划线价回退销售价₽ */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function comboCode(p: ProductDetail): string { const pr = (p.pricing ?? {}) as Record; - const rub = pr.reservedPriceRub ?? pr.sellingPriceRub; + const rub = pr.linePriceRub ?? pr.reservedPriceRub ?? pr.sellingPriceRub; if (!p.offer_id || rub == null) return ''; return `${p.offer_id} ${Number(rub).toFixed(2)}`; } @@ -127,7 +127,7 @@ export default function TrialExportPanel({ product }: Props) { const copyCurrentCombo = async () => { const code = comboCode(product); if (!code) { - message.warning('缺少货号或计价结果(卢布预留价)'); + message.warning('缺少货号或计价结果(卢布划线价)'); return; } const ok = await copyText(code); @@ -141,7 +141,7 @@ export default function TrialExportPanel({ product }: Props) { const list = await fetchAllPricedProducts(); const lines = list.map(comboCode).filter(Boolean); if (lines.length === 0) { - message.warning('没有可用的组合码(需要货号 + 卢布预留价)'); + message.warning('没有可用的组合码(需要货号 + 卢布划线价)'); return; } setComboText(lines.join('\n')); @@ -188,7 +188,7 @@ export default function TrialExportPanel({ product }: Props) { - 组合码格式:`货号 预留₽价`(无预留价回退销售价₽),用于 Ozon 后台批量改价; + 组合码格式:`货号 划线₽价`(无划线价回退销售价₽),用于 Ozon 后台批量改价; CSV 为 16 列(对齐 v1 工具台),UTF-8 BOM 编码可直接用 Excel 打开。 diff --git a/studio/src/pages/trial/TrialPricingPanel.tsx b/studio/src/pages/trial/TrialPricingPanel.tsx index fa830fd..00fdc5d 100644 --- a/studio/src/pages/trial/TrialPricingPanel.tsx +++ b/studio/src/pages/trial/TrialPricingPanel.tsx @@ -1,9 +1,10 @@ import { useEffect, useState, type CSSProperties } from 'react'; -import { Alert, Button, Card, Col, InputNumber, Radio, Row, Space, Typography, message } from 'antd'; -import { ReloadOutlined } from '@ant-design/icons'; +import { Alert, Button, Card, Col, InputNumber, message, Radio, Row, Space, Typography } from 'antd'; +import { CopyOutlined, ReloadOutlined } from '@ant-design/icons'; import { ProductDetail } from '@/services/product'; import { getFxRate } from '@/services/fx'; import { apiErrorMessage } from '@/services/api'; +import { copyText } from '@/utils/file'; import { calculatePricing, logisticsFeeRule, @@ -28,7 +29,7 @@ interface Props { type PricingPayload = Record; // eslint-disable-next-line @typescript-eslint/no-explicit-any -type PricingState = Partial<{ purchasePrice: number; profitRate: number; tdPrice: number; level: LogisticsLevel; reserve: number; fxRate: number }>; +type PricingState = Partial<{ purchasePrice: number; profitRate: number; tdPrice: number; level: LogisticsLevel; multiplier: number; fxRate: number }>; function weightGrams(product: ProductDetail): number { const w = product.weight ?? 0; @@ -55,22 +56,24 @@ function Metric({ label, value, rule, color }: { label: string; value: string; r ); } -/** 销售价格四宫格:人民币/卢布 × 销售价/划线价,价格居中,划线价带删除线 */ +/** 销售价格四宫格:人民币/卢布 × 销售价/划线价,价格居中,划线价带删除线;人民币销售价可一键复制 */ function SalePriceGrid({ cnySelling, + cnySellingNumber, cnyLine, rubSelling, rubLine, - reserve, + multiplier, fxRate, cnyGap, rubGap, }: { cnySelling: string; + cnySellingNumber?: string; cnyLine: string; rubSelling: string; rubLine: string; - reserve: number; + multiplier: number; fxRate: number; cnyGap: number | null; rubGap: number | null; @@ -88,11 +91,37 @@ function SalePriceGrid({ lineHeight: '30px', }; const noteStyle: CSSProperties = { fontSize: 11, color: 'rgba(0,0,0,0.35)' }; + const multiple = (1 + multiplier / 100).toFixed(2); + + const copyCnySelling = async () => { + if (!cnySellingNumber) return; + const ok = await copyText(cnySellingNumber); + ok ? message.success(`已复制:${cnySellingNumber}`) : message.error('复制失败'); + }; + return (
-
人民币-销售价格
+
+ 人民币-销售价格 + {cnySellingNumber && ( + + )} +
{cnySelling}
销售价(现价)
@@ -107,14 +136,16 @@ function SalePriceGrid({
人民币-划线价
{cnyLine}
- 预留 {reserve}% 后{cnyGap != null ? ` · 差额 ¥ ${cnyGap.toFixed(2)}` : ''} + 销售价 × {multiple} + {cnyGap != null ? ` · 差额 ¥ ${cnyGap.toFixed(2)}` : ''}
卢布-划线价
{rubLine}
- 预留 {reserve}% 后{rubGap != null ? ` · 差额 ₽ ${rubGap.toFixed(0)}` : ''} + 销售价 × {multiple} + {rubGap != null ? ` · 差额 ₽ ${rubGap.toFixed(0)}` : ''}
@@ -125,9 +156,10 @@ function SalePriceGrid({ /** * 02 价格试算:公式与告警完整移植 v1 web/js/app.js(trial-page.md §4)。 * 布局:左侧操作项(进货价→物流等级),右侧展示项(物流费→销售价)。 + * 划线价为「倍数」口径:划线价 = 销售价 × (1 + 倍数%),0-500% 线性可算(v2.1 调整)。 * 颜色对齐 v1:完全成本/平台总抽成红色,人民币/卢布销售价绿色。 * 参数变化即重算并落库(pricing JSON + price/old_price/fx_rate); - * 尺寸不合规时不落计价结果;预留折扣空间 ≥100% 时划线价无法计算(显示 --,只落销售价)。 + * 尺寸不合规时不落计价结果。 */ export default function TrialPricingPanel({ product, onSave }: Props) { const pricing = (product.pricing ?? {}) as PricingPayload; @@ -135,7 +167,7 @@ export default function TrialPricingPanel({ product, onSave }: Props) { const [profitRate, setProfitRate] = useState(pricing.profitRate ?? 100); const [tdPrice, setTdPrice] = useState(pricing.tdPrice ?? 3); const [level, setLevel] = useState((pricing.logisticsLevel as LogisticsLevel) ?? 'low'); - const [reserve, setReserve] = useState(pricing.discountReserve ?? 50); + const [multiplier, setMultiplier] = useState(pricing.lineMultiplier ?? 100); const [fxRate, setFxRate] = useState(product.fx_rate ?? pricing.fxRate ?? 0); const [fxSource, setFxSource] = useState(''); @@ -178,7 +210,7 @@ export default function TrialPricingPanel({ product, onSave }: Props) { weightG: weightGrams(product), dims: dimsCm(product), tdPrice: patch.tdPrice ?? tdPrice, - discountReserve: patch.reserve ?? reserve, + lineMultiplier: patch.multiplier ?? multiplier, fxRate: patch.fxRate ?? fxRate, }); @@ -189,7 +221,7 @@ export default function TrialPricingPanel({ product, onSave }: Props) { profitRate: patch.profitRate ?? profitRate, tdPrice: patch.tdPrice ?? tdPrice, level: patch.level ?? level, - reserve: patch.reserve ?? reserve, + multiplier: patch.multiplier ?? multiplier, fxRate: patch.fxRate ?? fxRate, }; const dims = dimsCm(product); @@ -201,40 +233,9 @@ export default function TrialPricingPanel({ product, onSave }: Props) { weightG: weightGrams(product), dims, tdPrice: p.tdPrice, - discountReserve: p.reserve, + lineMultiplier: p.multiplier, fxRate: p.fxRate, }); - // 预留折扣空间 ≥100% 时划线价无数学意义(除数 ≤0):只保存销售价,并清空划线价字段 - const lineValid = p.reserve < 100; - const lineFields = r && lineValid - ? { - logisticsFee: r.logisticsFee, - receivedPrice: r.receivedPrice, - profitPrice: r.profitPrice, - commission: r.commission, - fullCommission: r.fullCommission, - totalCost: r.totalCost, - sellingPriceCny: r.sellingPriceCny, - reservedPriceCny: r.reservedPriceCny, - sellingPriceRub: r.sellingPriceRub, - reservedPriceRub: r.reservedPriceRub, - calculatedAt: new Date().toISOString(), - } - : r - ? { - logisticsFee: r.logisticsFee, - receivedPrice: r.receivedPrice, - profitPrice: r.profitPrice, - commission: r.commission, - fullCommission: r.fullCommission, - totalCost: r.totalCost, - sellingPriceCny: r.sellingPriceCny, - sellingPriceRub: r.sellingPriceRub, - reservedPriceCny: null, - reservedPriceRub: null, - calculatedAt: new Date().toISOString(), - } - : {}; onSave({ pricing: { ...pricing, @@ -242,18 +243,28 @@ export default function TrialPricingPanel({ product, onSave }: Props) { profitRate: p.profitRate, tdPrice: p.tdPrice, logisticsLevel: p.level, - discountReserve: p.reserve, + lineMultiplier: p.multiplier, fxRate: p.fxRate, weightG: weightGrams(product), dims, - ...lineFields, + ...(r + ? { + logisticsFee: r.logisticsFee, + receivedPrice: r.receivedPrice, + profitPrice: r.profitPrice, + commission: r.commission, + fullCommission: r.fullCommission, + totalCost: r.totalCost, + sellingPriceCny: r.sellingPriceCny, + linePriceCny: r.linePriceCny, + sellingPriceRub: r.sellingPriceRub, + linePriceRub: r.linePriceRub, + calculatedAt: new Date().toISOString(), + } + : {}), }, fx_rate: p.fxRate, - ...(r && lineValid - ? { price: r.sellingPriceCny, old_price: r.reservedPriceCny } - : r - ? { price: r.sellingPriceCny, old_price: null } - : {}), + ...(r ? { price: r.sellingPriceCny, old_price: r.linePriceCny } : {}), currency_code: 'CNY', }); }; @@ -262,8 +273,7 @@ export default function TrialPricingPanel({ product, onSave }: Props) { const preview = fxRate && !dimError ? compute() : null; const levelHint = preview ? validateLogisticsLevelCny(preview.sellingPriceCny, level) : ''; const rangeHint = preview ? validatePriceRange(preview.sellingPriceCny) : ''; - const lineValid = reserve < 100; - const discountGap = preview && lineValid ? preview.reservedPriceCny - preview.sellingPriceCny : 0; + const discountGap = preview ? preview.linePriceCny - preview.sellingPriceCny : 0; const num = (v: number | undefined | null, digits = 2) => (v == null ? '--' : v.toFixed(digits)); @@ -314,17 +324,17 @@ export default function TrialPricingPanel({ product, onSave }: Props) { /> - 预留折扣空间 % + 划线价倍数 % { const n = v ?? 0; - setReserve(n); - recalc({ reserve: n }); + setMultiplier(n); + recalc({ multiplier: n }); }} /> @@ -384,19 +394,19 @@ export default function TrialPricingPanel({ product, onSave }: Props) { {dimError && } - 参数变化自动计价并入库;尺寸不合规时不落计价结果。重量/尺寸在「商品信息」区块维护。 + 划线价 = 销售价 × (1 + 倍数%);参数变化自动计价并入库;尺寸不合规时不落计价结果。重量/尺寸在「商品信息」区块维护。 - - {/* ── 右:展示项(物流费 → 销售价) ── */} - {(levelHint || rangeHint) && ( -
+
{levelHint && } {rangeHint && }
)} + + {/* ── 右:展示项(物流费 → 销售价) ── */} + {/* 第一行:物流费 / 平台佣金 / 提现费及其他 */} @@ -445,13 +455,14 @@ export default function TrialPricingPanel({ product, onSave }: Props) { {/* 第三、四行:人民币/卢布 销售价 + 划线价 四宫格 */} diff --git a/studio/src/pricing/pricing.ts b/studio/src/pricing/pricing.ts index ffe6063..a1b6189 100644 --- a/studio/src/pricing/pricing.ts +++ b/studio/src/pricing/pricing.ts @@ -1,7 +1,8 @@ /** * 计价纯函数 —— 从 v1 web/js/app.js 抄录(只抄不改,见 docs/v2/migration.md §3)。 - * 输入:进货价/净利率/物流等级/重量/尺寸/贴单费/预留折扣/汇率 - * 输出:物流费/佣金/完全成本/销售价(¥/₽)/预留折扣价 + * v2.1 调整:划线价改为「倍数」口径(划线价 = 销售价 × (1 + 倍数%)),替代 v1 的 ÷(1-预留折扣)。 + * 输入:进货价/净利率/物流等级/重量/尺寸/贴单费/划线价倍数/汇率 + * 输出:物流费/佣金/完全成本/销售价(¥/₽)/划线价(¥/₽) */ export type LogisticsLevel = 'low' | 'high' | 'high2'; @@ -13,7 +14,7 @@ export interface PricingInput { weightG: number; // 重量 g dims: { l: number; w: number; h: number }; // cm tdPrice: number; // 贴单费用 ¥ - discountReserve: number; // 预留折扣 % + lineMultiplier: number; // 划线价倍数 %(划线价 = 销售价 × (1 + 倍数/100)) fxRate: number; // 汇率 CNY→RUB } @@ -27,8 +28,8 @@ export interface PricingResult { commission: number; // 展示用平台佣金 totalCost: number; // 完全成本 sellingPriceRub: number; // 销售价 ₽ - reservedPriceCny: number;// 预留折扣后 ¥ - reservedPriceRub: number;// 预留折扣后 ₽ + linePriceCny: number; // 划线价 ¥(销售价 × (1 + 倍数)) + linePriceRub: number; // 划线价 ₽ } /** 物流费(不含贴单费) */ @@ -44,7 +45,7 @@ export function baseLogisticsFee(weightG: number, level: LogisticsLevel): number } export function calculatePricing(input: PricingInput): PricingResult { - const { purchasePrice, profitRate, logisticsLevel, weightG, tdPrice, discountReserve, fxRate } = input; + const { purchasePrice, profitRate, logisticsLevel, weightG, tdPrice, lineMultiplier, fxRate } = input; const logisticsFee = baseLogisticsFee(weightG, logisticsLevel) + tdPrice; const profitDecimal = profitRate / 100; @@ -57,8 +58,8 @@ export function calculatePricing(input: PricingInput): PricingResult { const totalCost = purchasePrice + logisticsFee + fullCommission; const sellingPriceRub = sellingPriceCny * fxRate; - const reservedPriceCny = sellingPriceCny / (1 - discountReserve / 100); - const reservedPriceRub = reservedPriceCny * fxRate; + const linePriceCny = sellingPriceCny * (1 + lineMultiplier / 100); + const linePriceRub = linePriceCny * fxRate; return { logisticsFee, @@ -70,8 +71,8 @@ export function calculatePricing(input: PricingInput): PricingResult { commission, totalCost, sellingPriceRub, - reservedPriceCny, - reservedPriceRub, + linePriceCny, + linePriceRub, }; }