price.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. // 商品价格计算相关
  2. import { times, plus, minus, divide } from 'number-precision'
  3. // 价格格式化
  4. export function formatPrice(value, needSymbol = true) {
  5. // 不能在最后一步显示之前格式化999 111, 否则可能出现单价1买999个得到999价格被格式化成poa的情况
  6. if (value === 0) {
  7. return needSymbol ? '£0.00' : '0.00'
  8. } else {
  9. return needSymbol ? `£${value}` : `${value}`
  10. }
  11. }
  12. // 简单的乘法换算
  13. function multiply(value, ratio = 100) {
  14. return parseFloat((value * ratio).toPrecision(12))
  15. }
  16. // 小数处理, 四舍五入, 为toFixed做准备
  17. export function round(number, ratio = 100) {
  18. return Math.round(multiply(number, ratio)) / ratio
  19. }
  20. /**
  21. * 将字符串简单转换成数字, 并可数倍转换. 注意, 这个适用于整数倍(商品件数), 非整数的不能用这个处理小数.
  22. * @param {*} value 目标值
  23. * @param {*} ratio 倍数, 默认1
  24. * @returns number | origin, 转换后的数字, 无法转成数字的返回原值
  25. */
  26. export function transformNumber(value, ratio = 1) {
  27. const v = Number(value)
  28. if (Number.isNaN(v)) {
  29. return value
  30. } else {
  31. // 保留两位小数
  32. return divide(Math.trunc(times(times(v, ratio), 100)), 100)
  33. }
  34. }
  35. // unit 单个商品的, 没有乘数量. 因为含有111 999 这些极端值, 没有格式化输出之前直接乘回出问题的.
  36. export const getUnit = function (buyNum, index, attributeList, basePriceList) {
  37. // 算出购买数量位于 价格阶梯的 哪个区间
  38. const candidate = Object.entries(attributeList).filter(
  39. item => buyNum >= item[1]
  40. )
  41. let key = 'website_qty1'
  42. if (candidate.length) {
  43. key = candidate.pop()[0]
  44. }
  45. return transformNumber(basePriceList[index][key], buyNum)
  46. }
  47. // 打印和附加价格 的steup之和. 商品基础价格现在没有setup了.
  48. export const getSetup = function (buyNum, form, additionList) {
  49. const sum = Object.entries(form).reduce((total, current) => {
  50. let s = 0
  51. // 打印服务表单的数据跟附加服务表单的数据结构不一致, 以数字id字符串键名的是打印服务的数据
  52. if (/\d+/.test(current[0]) && current[1].enable) {
  53. const temp = current[1].colorForm.filter(
  54. i => i.id === current[1].printService
  55. )
  56. let colorNumber = 1
  57. if (temp.length) {
  58. colorNumber = temp[0].colorNumber
  59. }
  60. const decoration = current[1].decorationList.filter(
  61. i => i.id === current[1].printService
  62. )
  63. let setup = 0
  64. if (decoration.length) {
  65. setup = plus(
  66. Number(decoration[0].website_setup),
  67. times(Number(decoration[0].supplier_setup), colorNumber - 1)
  68. )
  69. }
  70. s = plus(s, setup)
  71. } else if (current[1].length) {
  72. // 附加服务的表单数据, 有值说明该项有选中了附加服务
  73. const addition = additionList[current[0]].filter(addition =>
  74. current[1].includes(addition.id)
  75. )
  76. if (addition.length) {
  77. const temp = addition.reduce((t, c) => {
  78. let value = Number(c.website_setup)
  79. if ([5, 6].includes(c.website_setup_id)) {
  80. // 5是poa, 6是waived. 这种情况一般setup是留空的, 不留空大概是异常数据, 重置0保险一点.
  81. value = 0
  82. }
  83. return plus(t, Number.isNaN(value) ? 0 : value)
  84. }, 0)
  85. s = plus(s, temp)
  86. }
  87. }
  88. total = plus(total, s)
  89. return total
  90. }, 0)
  91. return transformNumber(sum)
  92. }
  93. // 打印价格的 阶梯基础价*购买数量.
  94. export const getPrint = function (buyNum, form, attributeList) {
  95. // 算出购买数量位于 价格阶梯的 哪个区间
  96. const candidate = Object.entries(attributeList).filter(
  97. item => buyNum >= item[1]
  98. )
  99. const key = `website_qty${candidate.length}`
  100. const key2 = `supplier_qty${candidate.length}`
  101. // 如果其中一项为POA, 则‘和’都是POA
  102. const result = Object.entries(form).reduce((total, current) => {
  103. if (total === 'POA') {
  104. return total
  105. }
  106. let sum = 0
  107. if (/\d+/.test(current[0]) && current[1].enable) {
  108. const temp = current[1].colorForm.filter(
  109. i => i.id === current[1].printService
  110. )
  111. let colorNumber = 1
  112. if (temp.length) {
  113. colorNumber = temp[0].colorNumber
  114. }
  115. const decoration = current[1].decorationList.filter(
  116. i => i.id === current[1].printService
  117. )
  118. // 打印价格的基础价. 其中数字111(代表'-') 和999(代表'POA')
  119. const p1 = transformNumber(decoration[0][key])
  120. if (p1 === 999 || p1 === 111 || typeof p1 !== 'number') {
  121. return 'POA'
  122. }
  123. // 打印价格的附加价
  124. const p2 = transformNumber(decoration[0][key2])
  125. if (p2 === 999 || p2 === 111 || typeof p2 !== 'number') {
  126. return 'POA'
  127. }
  128. let price = 0
  129. if (decoration.length) {
  130. price = plus(p1, times(p2, colorNumber - 1))
  131. }
  132. sum = plus(sum, price)
  133. }
  134. total = plus(total, sum)
  135. return total
  136. }, 0)
  137. return transformNumber(result, buyNum)
  138. }
  139. // 附加服务除了packing之外的总价
  140. export const getAddon = function (buyNum, form, attributeList, additionList) {
  141. // 算出购买数量位于 价格阶梯的 哪个区间
  142. const candidate = Object.entries(attributeList).filter(
  143. item => buyNum >= item[1]
  144. )
  145. const key = `website_qty${candidate.length}`
  146. const result = Object.entries(form).reduce((total, current) => {
  147. if (total === 'POA') {
  148. return total
  149. }
  150. let sum = 0
  151. if (!/\d+/.test(current[0]) && current[0] !== 'packaging') {
  152. sum = additionList[current[0]]
  153. .filter(item => current[1].includes(item.id))
  154. .reduce((t, c) => {
  155. if (t === 'POA') {
  156. return t
  157. }
  158. let temp = transformNumber(c[key])
  159. if (temp === 999 || temp === 111 || typeof temp !== 'number') {
  160. temp = 0
  161. return 'POA'
  162. }
  163. t = plus(t, temp)
  164. return t
  165. }, 0)
  166. }
  167. return plus(total, sum)
  168. }, 0)
  169. return transformNumber(result, buyNum)
  170. }
  171. // 附加服务中 packing 的价格
  172. export const getPackaging = function (
  173. buyNum,
  174. form,
  175. attributeList,
  176. additionList
  177. ) {
  178. // 算出购买数量位于 价格阶梯的 哪个区间
  179. const candidate = Object.entries(attributeList).filter(
  180. item => buyNum >= item[1]
  181. )
  182. const key = `website_qty${candidate.length}`
  183. const result = Object.entries(form).reduce((total, current) => {
  184. if (total === 'POA') {
  185. return total
  186. }
  187. let sum = 0
  188. if (!/\d+/.test(current[0]) && current[0] === 'packaging') {
  189. sum = additionList[current[0]]
  190. .filter(item => current[1].includes(item.id))
  191. .reduce((t, c) => {
  192. if (t === 'POA') {
  193. return t
  194. }
  195. let temp = transformNumber(c[key])
  196. if (temp === 999 || temp === 111 || typeof temp !== 'number') {
  197. temp = 0
  198. return 'POA'
  199. }
  200. t = plus(t, temp)
  201. return t
  202. }, 0)
  203. }
  204. return plus(total, sum)
  205. }, 0)
  206. return transformNumber(result, buyNum)
  207. }
  208. // 运费计算. 从product页面抄过来的逻辑. +号是隐式类型转换
  209. export const getFright = function (buyNum, config, freight, weight, ratio = 1) {
  210. // 单独批次数量的总重
  211. const totalWeight = Math.ceil(times(+weight.unit_w_local, buyNum))
  212. const expressFactor = plus(
  213. 1,
  214. divide(plus(+config.express_freight, +config.fuel), 100)
  215. )
  216. const AAEFactor = plus(
  217. 1,
  218. divide(plus(+config.bag_freight, +config.fuel), 100)
  219. )
  220. let frightCost = 0
  221. if (freight.type === 1) {
  222. if (totalWeight > 20) {
  223. const a1 = minus(totalWeight, 20)
  224. const a2 = times(a1, +freight.basic)
  225. const a3 = plus(+freight.pickup, a2)
  226. frightCost = times(a3, expressFactor)
  227. } else {
  228. frightCost = times(+freight.pickup, expressFactor)
  229. }
  230. } else if (freight.type === 2) {
  231. const a1 = times(totalWeight, +freight.basic)
  232. const a2 = plus(+freight.pickup, a1)
  233. frightCost = times(a2, AAEFactor)
  234. } else {
  235. frightCost = 0
  236. }
  237. return transformNumber(frightCost, ratio)
  238. }