diff --git a/.changeset/short-deers-shave.md b/.changeset/short-deers-shave.md new file mode 100644 index 0000000000..ded32cb18f --- /dev/null +++ b/.changeset/short-deers-shave.md @@ -0,0 +1,11 @@ +--- +"@scow/mis-server": patch +"@scow/mis-web": patch +--- + +增加配置消费记录精度,默认精度为 2 位小数; +增加最小作业消费金额的功能,默认最小作业消费金额为 0.01; +账户、租户的余额展示精度与消费记录精度一致; +充值金额展示的小数位与消费记录的精度保持一致; +充值时数值输入框精度与消费记录的精度保持一致。 + diff --git a/.changeset/yellow-sloths-compare.md b/.changeset/yellow-sloths-compare.md new file mode 100644 index 0000000000..a99aa5ab25 --- /dev/null +++ b/.changeset/yellow-sloths-compare.md @@ -0,0 +1,11 @@ +--- +"@scow/config": patch +--- + +增加配置消费记录精度、最小消费金额的功能,默认精度为 2 位小数,默认最小消费金额为 0.01。 +### 注意:此更新必定影响作业计费结果(除非您以前所有计费项价格皆为0)如果您不想更改之前的版本中的计费逻辑,需要增加配置如下: + +```yaml title="config/mis.yaml" +jobChargeDecimalPrecision: 3 +jobMinCharge : 0 +``` \ No newline at end of file diff --git a/apps/mis-server/config/mis.yaml b/apps/mis-server/config/mis.yaml index 57bcb626e3..8e77d882d7 100644 --- a/apps/mis-server/config/mis.yaml +++ b/apps/mis-server/config/mis.yaml @@ -7,5 +7,3 @@ db: periodicSyncUserAccountBlockStatus: enabled: false - - diff --git a/apps/mis-server/src/bl/jobPrice.ts b/apps/mis-server/src/bl/jobPrice.ts index 4b2eaee34c..e44fc86906 100644 --- a/apps/mis-server/src/bl/jobPrice.ts +++ b/apps/mis-server/src/bl/jobPrice.ts @@ -107,9 +107,18 @@ export async function calculateJobPrice( amount = amount.multipliedBy(time); - amount = amount.decimalPlaces(3, Decimal.ROUND_DOWN); + amount = amount.decimalPlaces(misConfig.jobChargeDecimalPrecision, Decimal.ROUND_DOWN); + + // 如果单价大于0,且运行时间大于0,若结果算下来金额小于默认最低消费金额,按最低消费金额计算价格 + if (priceItem.price.gt(0) && time.gt(0)) { + if (priceItem.price.multipliedBy(amount).gt(new Decimal(misConfig.jobMinCharge))) { + return priceItem.price.multipliedBy(amount) + .decimalPlaces(misConfig.jobChargeDecimalPrecision, Decimal.ROUND_HALF_CEIL); + } + return new Decimal(misConfig.jobMinCharge); + } - return priceItem.price.multipliedBy(amount).decimalPlaces(3, Decimal.ROUND_HALF_CEIL); + return new Decimal(0); } const accountBase = getPriceItem(path, info.tenant); const tenantBase = getPriceItem(path); diff --git a/apps/mis-server/tests/job/billingItems.test.ts b/apps/mis-server/tests/job/billingItems.test.ts index 54ab65d81e..700425c1eb 100644 --- a/apps/mis-server/tests/job/billingItems.test.ts +++ b/apps/mis-server/tests/job/billingItems.test.ts @@ -10,6 +10,8 @@ * See the Mulan PSL v2 for more details. */ +import { after, before } from "node:test"; + import { asyncClientCall } from "@ddadaal/tsgrpc-client"; import { Server } from "@ddadaal/tsgrpc-server"; import { ChannelCredentials } from "@grpc/grpc-js"; @@ -19,6 +21,7 @@ import { Decimal, decimalToMoney, numberToMoney } from "@scow/lib-decimal"; import { AddBillingItemRequest, JobBillingItem, JobServiceClient } from "@scow/protos/build/server/job"; import { createServer } from "src/app"; import { createPriceMap } from "src/bl/PriceMap"; +import { misConfig } from "src/config/mis"; import { AmountStrategy, JobPriceItem } from "src/entities/JobPriceItem"; import { Tenant } from "src/entities/Tenant"; import { createPriceItems } from "src/tasks/createBillingItems"; @@ -236,15 +239,11 @@ it("adds billing item to another tenant", async () => { expect(reply.historyItems.length).toBe(0); }); -it("calculates price", async () => { - +const calculatePrice = async (testData: typeof import("./testData.json")) => { const priceMap = await createPriceMap(orm.em.fork(), server.ext.clusters, server.logger); - - // obtain test data by running the following data in db - const testData = (await import("./testData.json")).default; - const wrongPrices = [] as { + jobId: number, tenantPrice: { expected: number; actual: number | undefined }; accountPrice: { expected: number; actual: number | undefined } }[]; @@ -266,14 +265,35 @@ it("calculates price", async () => { }); if (price.tenant?.price.toNumber() !== t.tenantPrice || price.account?.price.toNumber() !== t.accountPrice) { wrongPrices.push({ + jobId: t.jobId, tenantPrice: { expected: t.tenantPrice, actual: price.tenant?.price.toNumber() }, accountPrice: { expected: t.accountPrice, actual: price.account?.price.toNumber() }, }); } }; + console.log(wrongPrices); + expect(wrongPrices).toBeArrayOfSize(0); +}; + +it("calculates job price in precision 3 and min charge 0", async () => { + + const beforeJobChargeDecimalPrecision = misConfig.jobChargeDecimalPrecision; + const beforeJobMinCharge = misConfig.jobMinCharge; + + misConfig.jobChargeDecimalPrecision = 3; + misConfig.jobMinCharge = 0; + + await calculatePrice((await import("./testData-precision3.json")).default).finally(() => { + + misConfig.jobChargeDecimalPrecision = beforeJobChargeDecimalPrecision; + misConfig.jobMinCharge = beforeJobMinCharge; + }); +}); +it.only("calculates job prices", async () => { + await calculatePrice((await import("./testData.json")).default); }); it("gets missing price items in platform scope", async () => { diff --git a/apps/mis-server/tests/job/testData-precision3.json b/apps/mis-server/tests/job/testData-precision3.json new file mode 100644 index 0000000000..5465966b9b --- /dev/null +++ b/apps/mis-server/tests/job/testData-precision3.json @@ -0,0 +1,938 @@ +[ + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 374400, + "cluster": "hpc00", + "memAllocMb": 374400, + "elapsedSeconds": 8465, + "cpusAlloc": 96, + "partition": "C032M0128G", + "account": "hpcc", + "user": "c", + "endTime": "2022-01-13T03:19:51.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 0, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "tenant": "another", + "name": "test", + "accountPrice": 18.059, + "tenantPrice": 9.029, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 374400, + "cluster": "hpc00", + "memAllocMb": 374400, + "elapsedSeconds": 9456, + "cpusAlloc": 96, + "partition": "C032M0128G", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:19:52.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 1, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "tenant": "default", + "name": "test", + "accountPrice": 10.086, + "tenantPrice": 10.086, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "cryoem", + "memReqMb": 1872000, + "cluster": "hpc00", + "memAllocMb": 1872000, + "elapsedSeconds": 46884, + "cpusAlloc": 480, + "partition": "C032M0128G", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:19:53.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 2, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "tenant": "default", + "name": "test", + "accountPrice": 250.048, + "tenantPrice": 250.048, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "cryoem", + "memReqMb": 1872000, + "cluster": "hpc00", + "memAllocMb": 1872000, + "elapsedSeconds": 51057, + "cpusAlloc": 480, + "partition": "C032M0128G", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:19:54.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 3, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 272.304, + "tenantPrice": 272.304, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "cryoem", + "memReqMb": 1872000, + "cluster": "hpc00", + "memAllocMb": 1872000, + "elapsedSeconds": 56285, + "cpusAlloc": 480, + "partition": "C032M0128G", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:19:55.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 4, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 300.187, + "tenantPrice": 300.187, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 124800, + "cluster": "hpc00", + "memAllocMb": 124800, + "elapsedSeconds": 116224, + "cpusAlloc": 32, + "partition": "C032M0128G", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:19:56.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 5, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 41.324, + "tenantPrice": 41.324, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 124800, + "cluster": "hpc00", + "memAllocMb": 124800, + "elapsedSeconds": 15413, + "cpusAlloc": 32, + "partition": "C032M0128G", + "account": "hpcc", + "user": "c", + "endTime": "2022-01-13T03:19:57.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 6, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "another", + "accountPrice": 10.96, + "tenantPrice": 5.48, + "nodeList": "" + }, + { + "gpusAlloc": 16, + "qos": "cryoem", + "memReqMb": 1008000, + "cluster": "hpc00", + "memAllocMb": 1008000, + "elapsedSeconds": 64874, + "cpusAlloc": 112, + "partition": "life", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:19:58.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 7, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "cryoem", + "memReqMb": 3744000, + "cluster": "hpc00", + "memAllocMb": 3744000, + "elapsedSeconds": 5679, + "cpusAlloc": 960, + "partition": "C032M0128G", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:19:59.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 8, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 60.576, + "tenantPrice": 60.576, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 124800, + "cluster": "hpc00", + "memAllocMb": 124800, + "elapsedSeconds": 1, + "cpusAlloc": 32, + "partition": "C032M0128G", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:00.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 9, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 124800, + "cluster": "hpc00", + "memAllocMb": 124800, + "elapsedSeconds": 137, + "cpusAlloc": 32, + "partition": "C032M0128G", + "account": "hpcc", + "user": "c", + "endTime": "2022-01-13T03:20:01.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 10, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "another", + "accountPrice": 0.097, + "tenantPrice": 0.049, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 124800, + "cluster": "hpc00", + "memAllocMb": 124800, + "elapsedSeconds": 561, + "cpusAlloc": 32, + "partition": "C032M0128G", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:02.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 11, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0.199, + "tenantPrice": 0.199, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 124800, + "cluster": "hpc00", + "memAllocMb": 124800, + "elapsedSeconds": 13540, + "cpusAlloc": 32, + "partition": "C032M0128G", + "account": "hpcc", + "user": "c", + "endTime": "2022-01-13T03:20:03.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 12, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "another", + "accountPrice": 9.628, + "tenantPrice": 4.814, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 3900, + "cluster": "hpc00", + "memAllocMb": 3900, + "elapsedSeconds": 21, + "cpusAlloc": 1, + "partition": "C032M0128G", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:04.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 13, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 3900, + "cluster": "hpc00", + "memAllocMb": 3900, + "elapsedSeconds": 21, + "cpusAlloc": 1, + "partition": "C032M0128G", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:20:05.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 14, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "another", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 3900, + "cluster": "hpc00", + "memAllocMb": 3900, + "elapsedSeconds": 21, + "cpusAlloc": 1, + "partition": "C032M0128G", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:06.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 15, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 3900, + "cluster": "hpc00", + "memAllocMb": 3900, + "elapsedSeconds": 21, + "cpusAlloc": 1, + "partition": "C032M0128G", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:20:07.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 16, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "another", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 3900, + "cluster": "hpc00", + "memAllocMb": 3900, + "elapsedSeconds": 23, + "cpusAlloc": 1, + "partition": "C032M0128G", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:08.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 17, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 3900, + "cluster": "hpc00", + "memAllocMb": 3900, + "elapsedSeconds": 24, + "cpusAlloc": 1, + "partition": "C032M0128G", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:20:09.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 18, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "another", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "low", + "memReqMb": 3900, + "cluster": "hpc00", + "memAllocMb": 3900, + "elapsedSeconds": 26, + "cpusAlloc": 1, + "partition": "C032M0128G", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:10.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 19, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 8041, + "cluster": "hpc01", + "memAllocMb": 8041, + "elapsedSeconds": 212, + "cpusAlloc": 1, + "partition": "gpu", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:20:11.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 20, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 8041, + "cluster": "hpc01", + "memAllocMb": 8041, + "elapsedSeconds": 0, + "cpusAlloc": 1, + "partition": "gpu", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:12.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 21, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 8041, + "cluster": "hpc01", + "memAllocMb": 8041, + "elapsedSeconds": 0, + "cpusAlloc": 1, + "partition": "gpu", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:20:13.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 22, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 8041, + "cluster": "hpc01", + "memAllocMb": 8041, + "elapsedSeconds": 177, + "cpusAlloc": 1, + "partition": "gpu", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:14.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 23, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 8041, + "cluster": "hpc01", + "memAllocMb": 8041, + "elapsedSeconds": 47, + "cpusAlloc": 1, + "partition": "gpu", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:20:15.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 24, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 2250, + "cluster": "hpc01", + "memAllocMb": 2250, + "elapsedSeconds": 7094, + "cpusAlloc": 1, + "partition": "compute", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:16.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 25, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0.118, + "tenantPrice": 0.118, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 2250, + "cluster": "hpc01", + "memAllocMb": 2250, + "elapsedSeconds": 11507, + "cpusAlloc": 1, + "partition": "compute", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:20:17.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 26, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0.192, + "tenantPrice": 0.192, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 2250, + "cluster": "hpc01", + "memAllocMb": 2250, + "elapsedSeconds": 1321, + "cpusAlloc": 1, + "partition": "compute", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:18.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 27, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0.022, + "tenantPrice": 0.022, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 504000, + "cluster": "hpc01", + "memAllocMb": 504000, + "elapsedSeconds": 2, + "cpusAlloc": 224, + "partition": "compute", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:20:19.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 28, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0.007, + "tenantPrice": 0.007, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 504000, + "cluster": "hpc01", + "memAllocMb": 504000, + "elapsedSeconds": 2, + "cpusAlloc": 224, + "partition": "compute", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:20.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 29, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0.007, + "tenantPrice": 0.007, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 2250, + "cluster": "hpc01", + "memAllocMb": 2250, + "elapsedSeconds": 1, + "cpusAlloc": 1, + "partition": "compute", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:20:21.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 30, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 2250, + "cluster": "hpc01", + "memAllocMb": 2250, + "elapsedSeconds": 0, + "cpusAlloc": 1, + "partition": "compute", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:22.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 31, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 2250, + "cluster": "hpc01", + "memAllocMb": 2250, + "elapsedSeconds": 0, + "cpusAlloc": 1, + "partition": "compute", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:20:23.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 32, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 2250, + "cluster": "hpc01", + "memAllocMb": 2250, + "elapsedSeconds": 19, + "cpusAlloc": 1, + "partition": "compute", + "account": "hpcb", + "user": "b", + "endTime": "2022-01-13T03:20:24.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 33, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 2250, + "cluster": "hpc01", + "memAllocMb": 2250, + "elapsedSeconds": 0, + "cpusAlloc": 1, + "partition": "compute", + "account": "hpca", + "user": "a", + "endTime": "2022-01-13T03:20:25.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 34, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + }, + { + "gpusAlloc": 0, + "qos": "normal", + "memReqMb": 2250, + "cluster": "hpc01", + "memAllocMb": 2250, + "elapsedSeconds": 0, + "cpusAlloc": 1, + "partition": "compute", + "account": "hpca", + "user": "not-exist-user", + "endTime": "2022-01-13T03:20:26.715Z", + "submitTime": "2022-01-13T03:19:50.715Z", + "startTime": "2022-01-13T03:19:50.715Z", + "jobId": 35, + "timeWait": 0, + "timeLimitMinutes": 0, + "nodesAlloc": 0, + "nodesReq": 0, + "cpusReq": 0, + "name": "test", + "tenant": "default", + "accountPrice": 0, + "tenantPrice": 0, + "nodeList": "" + } +] diff --git a/apps/mis-server/tests/job/testData.json b/apps/mis-server/tests/job/testData.json index 5465966b9b..d597cfc2ef 100644 --- a/apps/mis-server/tests/job/testData.json +++ b/apps/mis-server/tests/job/testData.json @@ -21,8 +21,8 @@ "cpusReq": 0, "tenant": "another", "name": "test", - "accountPrice": 18.059, - "tenantPrice": 9.029, + "accountPrice": 18.06, + "tenantPrice": 9.03, "nodeList": "" }, { @@ -47,8 +47,8 @@ "cpusReq": 0, "tenant": "default", "name": "test", - "accountPrice": 10.086, - "tenantPrice": 10.086, + "accountPrice": 10.09, + "tenantPrice": 10.09, "nodeList": "" }, { @@ -73,8 +73,8 @@ "cpusReq": 0, "tenant": "default", "name": "test", - "accountPrice": 250.048, - "tenantPrice": 250.048, + "accountPrice": 250.05, + "tenantPrice": 250.05, "nodeList": "" }, { @@ -99,8 +99,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 272.304, - "tenantPrice": 272.304, + "accountPrice": 272.3, + "tenantPrice": 272.3, "nodeList": "" }, { @@ -125,8 +125,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 300.187, - "tenantPrice": 300.187, + "accountPrice": 300.19, + "tenantPrice": 300.19, "nodeList": "" }, { @@ -151,8 +151,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 41.324, - "tenantPrice": 41.324, + "accountPrice": 41.32, + "tenantPrice": 41.32, "nodeList": "" }, { @@ -229,8 +229,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 60.576, - "tenantPrice": 60.576, + "accountPrice": 60.58, + "tenantPrice": 60.58, "nodeList": "" }, { @@ -255,8 +255,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -281,8 +281,8 @@ "cpusReq": 0, "name": "test", "tenant": "another", - "accountPrice": 0.097, - "tenantPrice": 0.049, + "accountPrice": 0.1, + "tenantPrice": 0.05, "nodeList": "" }, { @@ -307,8 +307,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0.199, - "tenantPrice": 0.199, + "accountPrice": 0.2, + "tenantPrice": 0.2, "nodeList": "" }, { @@ -333,8 +333,8 @@ "cpusReq": 0, "name": "test", "tenant": "another", - "accountPrice": 9.628, - "tenantPrice": 4.814, + "accountPrice": 9.63, + "tenantPrice": 4.81, "nodeList": "" }, { @@ -359,8 +359,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -385,8 +385,8 @@ "cpusReq": 0, "name": "test", "tenant": "another", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -411,8 +411,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -437,8 +437,8 @@ "cpusReq": 0, "name": "test", "tenant": "another", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -463,8 +463,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -489,8 +489,8 @@ "cpusReq": 0, "name": "test", "tenant": "another", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -515,8 +515,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -541,8 +541,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -619,8 +619,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -645,8 +645,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -671,8 +671,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0.118, - "tenantPrice": 0.118, + "accountPrice": 0.12, + "tenantPrice": 0.12, "nodeList": "" }, { @@ -697,8 +697,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0.192, - "tenantPrice": 0.192, + "accountPrice": 0.19, + "tenantPrice": 0.19, "nodeList": "" }, { @@ -723,8 +723,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0.022, - "tenantPrice": 0.022, + "accountPrice": 0.02, + "tenantPrice": 0.02, "nodeList": "" }, { @@ -749,8 +749,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0.007, - "tenantPrice": 0.007, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -775,8 +775,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0.007, - "tenantPrice": 0.007, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -801,8 +801,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { @@ -879,8 +879,8 @@ "cpusReq": 0, "name": "test", "tenant": "default", - "accountPrice": 0, - "tenantPrice": 0, + "accountPrice": 0.01, + "tenantPrice": 0.01, "nodeList": "" }, { diff --git a/apps/mis-web/config.js b/apps/mis-web/config.js index 9e4ae1dd8e..4cdc020934 100644 --- a/apps/mis-web/config.js +++ b/apps/mis-web/config.js @@ -190,6 +190,9 @@ const buildRuntimeConfig = async (phase, basePath) => { JOB_CHARGE_METADATA: misConfig.jobChargeMetadata, + JOB_CHARGE_DECIMAL_PRECISION: misConfig.jobChargeDecimalPrecision, + JOB_MIN_CHARGE: misConfig.jobMinCharge, + }; if (!building) { diff --git a/apps/mis-web/src/pageComponents/accounts/SetBlockThresholdAmountModal.tsx b/apps/mis-web/src/pageComponents/accounts/SetBlockThresholdAmountModal.tsx index a83117f429..fe5edead8e 100644 --- a/apps/mis-web/src/pageComponents/accounts/SetBlockThresholdAmountModal.tsx +++ b/apps/mis-web/src/pageComponents/accounts/SetBlockThresholdAmountModal.tsx @@ -17,6 +17,7 @@ import { useState } from "react"; import { api } from "src/apis"; import { ModalLink } from "src/components/ModalLink"; import { prefix, useI18nTranslateToString } from "src/i18n"; +import { publicConfig } from "src/utils/config"; import { moneyToString } from "src/utils/money"; interface Props { @@ -119,7 +120,10 @@ export const SetBlockThresholdAmountModal: React.FC = ({ - + diff --git a/apps/mis-web/src/pageComponents/admin/DataBarChart.tsx b/apps/mis-web/src/pageComponents/admin/DataBarChart.tsx index a0415f7670..0fd5ea75c8 100644 --- a/apps/mis-web/src/pageComponents/admin/DataBarChart.tsx +++ b/apps/mis-web/src/pageComponents/admin/DataBarChart.tsx @@ -15,6 +15,7 @@ import React from "react"; import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts"; import { Formatter } from "recharts/types/component/DefaultTooltipContent"; +import { moneyNumberToString } from "src/utils/money"; import { styled } from "styled-components"; interface Props { @@ -58,7 +59,7 @@ export const DataBarChart: React.FC = ({ toolTipFormatter = (value) => value, }) => { const tickFormatter = (value: number) => { - const roundedValue = Number.isInteger(value) ? value : parseFloat(value.toFixed(2)); + const roundedValue = Number.isInteger(value) ? value : parseFloat(moneyNumberToString(value)); return roundedValue.toString(); }; diff --git a/apps/mis-web/src/pageComponents/admin/TenantChargeForm.tsx b/apps/mis-web/src/pageComponents/admin/TenantChargeForm.tsx index 0badb38df8..81ffc0fea5 100644 --- a/apps/mis-web/src/pageComponents/admin/TenantChargeForm.tsx +++ b/apps/mis-web/src/pageComponents/admin/TenantChargeForm.tsx @@ -118,7 +118,11 @@ export const TenantChargeForm: React.FC = () => { /> - + = ({ accountNames, searchType }) => { - {data ? data.total.toFixed(2) : 0} + {data ? moneyNumberToString(data.total) : 0} @@ -262,7 +263,12 @@ export const PaymentTable: React.FC = ({ accountNames, searchType }) => { : undefined } formatDateTime(v)} /> - v.toFixed(2)} /> + moneyNumberToString(v) } + /> ; } @@ -73,10 +73,9 @@ export const AccountInfoSection: React.FC = ({ info }) => { const isBlocked = accountBlocked || userStatus === UserStatus.BLOCKED; const [ textColor, Icon, opacity] = isBlocked ? statusTexts.blocked : statusTexts.normal; const availableLimit = jobChargeLimit && usedJobCharge - ? (moneyToNumber(jobChargeLimit) - moneyToNumber(usedJobCharge)).toFixed(2) - : undefined; + ? moneyNumberToString(moneyToNumber(jobChargeLimit) - moneyToNumber(usedJobCharge)) : undefined; const whitelistCharge = isInWhitelist ? "不限" : undefined; - const normalCharge = (balance - blockThresholdAmount).toFixed(2); + const normalCharge = moneyNumberToString(balance - blockThresholdAmount); const showAvailableBalance = availableLimit ?? whitelistCharge ?? normalCharge; return ( diff --git a/apps/mis-web/src/pageComponents/finance/ChargeForm.tsx b/apps/mis-web/src/pageComponents/finance/ChargeForm.tsx index cbad1554f0..75c2b06569 100644 --- a/apps/mis-web/src/pageComponents/finance/ChargeForm.tsx +++ b/apps/mis-web/src/pageComponents/finance/ChargeForm.tsx @@ -112,7 +112,11 @@ export const ChargeForm: React.FC = () => { - + = ({ - {totalResultData?.totalAmount?.toFixed(2) ?? 0} + {totalResultData?.totalAmount ? moneyNumberToString(totalResultData.totalAmount) : 0} @@ -330,7 +331,7 @@ export const ChargeTable: React.FC = ({ dataIndex="amount" title={t(p("amount"))} - render={(v) => v.toFixed(2)} + render={(v) => moneyNumberToString(v)} sorter={true} /> diff --git a/apps/mis-web/src/pageComponents/job/EditableJobBillingTable.tsx b/apps/mis-web/src/pageComponents/job/EditableJobBillingTable.tsx index 406766a6e9..142f24a15d 100644 --- a/apps/mis-web/src/pageComponents/job/EditableJobBillingTable.tsx +++ b/apps/mis-web/src/pageComponents/job/EditableJobBillingTable.tsx @@ -22,6 +22,7 @@ import { CommonModalProps, ModalLink } from "src/components/ModalLink"; import { prefix, useI18n, useI18nTranslateToString } from "src/i18n"; import { AmountStrategy } from "src/models/job"; import { ClusterInfoStore } from "src/stores/ClusterInfoStore"; +import { publicConfig } from "src/utils/config"; const p = prefix("pageComp.job.editableJobBillingTable."); const pCommon = prefix("common."); @@ -80,7 +81,11 @@ const EditPriceModal: React.FC ({ label: x, value: x }))} /> - + diff --git a/apps/mis-web/src/pageComponents/job/ManageJobBillingTable.tsx b/apps/mis-web/src/pageComponents/job/ManageJobBillingTable.tsx index bad69ab120..59ec06e20e 100644 --- a/apps/mis-web/src/pageComponents/job/ManageJobBillingTable.tsx +++ b/apps/mis-web/src/pageComponents/job/ManageJobBillingTable.tsx @@ -283,7 +283,11 @@ const EditPriceModal: React.FC - + diff --git a/apps/mis-web/src/pageComponents/tenant/AccountWhitelistTable.tsx b/apps/mis-web/src/pageComponents/tenant/AccountWhitelistTable.tsx index 873353099f..e5e698152e 100644 --- a/apps/mis-web/src/pageComponents/tenant/AccountWhitelistTable.tsx +++ b/apps/mis-web/src/pageComponents/tenant/AccountWhitelistTable.tsx @@ -26,7 +26,7 @@ import { prefix, useI18nTranslateToString } from "src/i18n"; import { Money } from "src/models/UserSchemaModel"; import type { GetWhitelistedAccountsSchema } from "src/pages/api/tenant/accountWhitelist/getWhitelistedAccounts"; -import { moneyToString } from "src/utils/money"; +import { moneyNumberToString, moneyToString } from "src/utils/money"; interface Props { data: Static | undefined; @@ -134,7 +134,8 @@ export const AccountWhitelistTable: React.FC = ({ <> - {t(p("debtSum"))}:{getTotalDebtAmount(data).toFixed(2)} {t(pCommon("unit"))} + {t(p("debtSum"))}:{ + moneyNumberToString(getTotalDebtAmount(data))} {t(pCommon("unit"))} diff --git a/apps/mis-web/src/pageComponents/tenant/ChangeDefaultAccountBlockThresholdModal.tsx b/apps/mis-web/src/pageComponents/tenant/ChangeDefaultAccountBlockThresholdModal.tsx index fb1ee20e60..d2c29b2202 100644 --- a/apps/mis-web/src/pageComponents/tenant/ChangeDefaultAccountBlockThresholdModal.tsx +++ b/apps/mis-web/src/pageComponents/tenant/ChangeDefaultAccountBlockThresholdModal.tsx @@ -16,6 +16,7 @@ import { useState } from "react"; import { api } from "src/apis"; import { ModalLink } from "src/components/ModalLink"; import { prefix, useI18nTranslateToString } from "src/i18n"; +import { publicConfig } from "src/utils/config"; import { moneyToString } from "src/utils/money"; interface Props { @@ -77,7 +78,10 @@ export const ChangeDefaultAccountBlockThresholdModal: React.FC = ({ {tenantName} - + diff --git a/apps/mis-web/src/pageComponents/users/JobChargeLimitModal.tsx b/apps/mis-web/src/pageComponents/users/JobChargeLimitModal.tsx index 6e7d87635b..6ac3f114d3 100644 --- a/apps/mis-web/src/pageComponents/users/JobChargeLimitModal.tsx +++ b/apps/mis-web/src/pageComponents/users/JobChargeLimitModal.tsx @@ -20,6 +20,7 @@ import { api } from "src/apis"; import { ModalLink } from "src/components/ModalLink"; import { prefix, useI18n, useI18nTranslateToString } from "src/i18n"; import { UserStatus } from "src/models/User"; +import { publicConfig } from "src/utils/config"; import { moneyToString } from "src/utils/money"; interface Props { @@ -133,7 +134,11 @@ export const JobChargeLimitModal: React.FC = ({ compareUsedChargeRule(_, value, currentUsed ? moneyToNumber(currentUsed) : undefined, languageId) }, ]} > - + diff --git a/apps/mis-web/src/pages/accounts/[accountName]/info.tsx b/apps/mis-web/src/pages/accounts/[accountName]/info.tsx index 563e3a9ecc..fc25e44050 100644 --- a/apps/mis-web/src/pages/accounts/[accountName]/info.tsx +++ b/apps/mis-web/src/pages/accounts/[accountName]/info.tsx @@ -25,6 +25,7 @@ import { checkQueryAccountNameIsAdmin } from "src/pageComponents/accounts/checkQueryAccountNameIsAdmin"; import { getAccounts } from "src/pages/api/tenant/getAccounts"; import { Head } from "src/utils/head"; +import { moneyNumberToString } from "src/utils/money"; type Props = SSRProps<{ accountName: string; @@ -69,10 +70,10 @@ export const AccountInfoPage: NextPage = requireAuth( - {balance.toFixed(2)} {t("common.unit")} + {moneyNumberToString(balance)} {t("common.unit")} - {blockThresholdAmount.toFixed(2)} {t("common.unit")} + {moneyNumberToString(blockThresholdAmount)} {t("common.unit")} diff --git a/apps/mis-web/src/pages/admin/statistic.tsx b/apps/mis-web/src/pages/admin/statistic.tsx index 707af6b742..8722239833 100644 --- a/apps/mis-web/src/pages/admin/statistic.tsx +++ b/apps/mis-web/src/pages/admin/statistic.tsx @@ -28,8 +28,10 @@ import { PlatformRole, SearchType } from "src/models/User"; import { DataBarChart } from "src/pageComponents/admin/DataBarChart"; import { DataLineChart } from "src/pageComponents/admin/DataLineChart"; import { StatisticCard } from "src/pageComponents/admin/StatisticCard"; +import { publicConfig } from "src/utils/config"; import { dateMessageToDayjs } from "src/utils/date"; import { Head } from "src/utils/head"; +import { moneyNumberToString } from "src/utils/money"; import { styled } from "styled-components"; const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; @@ -244,7 +246,7 @@ export const PlatformStatisticsPage: NextPage = requireAuth( return topChargeAccount?.results.map((r) => ({ x: r.userName, - y: moneyToNumber(r.chargedAmount).toFixed(2), + y: moneyNumberToString(moneyToNumber(r.chargedAmount)), })) || []; }, [query, topChargeAccount]); @@ -252,7 +254,7 @@ export const PlatformStatisticsPage: NextPage = requireAuth( return topPayAccount?.results.map((r) => ({ x: r.userName, - y: moneyToNumber(r.payAmount).toFixed(2), + y: moneyNumberToString(moneyToNumber(r.payAmount)), })) || []; }, [query, topPayAccount]); @@ -383,7 +385,7 @@ export const PlatformStatisticsPage: NextPage = requireAuth( loading={totalChargeAmountLoading || dailyChargeLoading} icon={MoneyCollectOutlined} iconColor="#feca57" - precision={2} + precision={publicConfig.JOB_CHARGE_DECIMAL_PRECISION} /> @@ -447,7 +449,7 @@ export const PlatformStatisticsPage: NextPage = requireAuth( ({ x: d.date.format("YYYY-MM-DD"), - y: Number(d.count.toFixed(2)), + y: Number(moneyNumberToString(d.count)), }))} title={t(p("chargeAmount"))} isLoading={dailyChargeLoading} @@ -469,7 +471,7 @@ export const PlatformStatisticsPage: NextPage = requireAuth( ({ x: d.date.format("YYYY-MM-DD"), - y: Number(d.count.toFixed(2)), + y: Number(moneyNumberToString(d.count)), }))} title={t(p("payAmount"))} toolTipFormatter={amountToolTipFormatter} diff --git a/apps/mis-web/src/pages/tenant/info.tsx b/apps/mis-web/src/pages/tenant/info.tsx index 34885a1b06..658b556944 100644 --- a/apps/mis-web/src/pages/tenant/info.tsx +++ b/apps/mis-web/src/pages/tenant/info.tsx @@ -12,7 +12,7 @@ import { asyncClientCall } from "@ddadaal/tsgrpc-client"; import { status } from "@grpc/grpc-js"; -import { moneyToNumber, numberToMoney } from "@scow/lib-decimal"; +import { numberToMoney } from "@scow/lib-decimal"; import type { GetTenantInfoResponse } from "@scow/protos/build/server/tenant"; import { TenantServiceClient } from "@scow/protos/build/server/tenant"; import { Descriptions, Space, Tag } from "antd"; @@ -31,6 +31,7 @@ import { import { ensureNotUndefined } from "src/utils/checkNull"; import { getClient } from "src/utils/client"; import { Head } from "src/utils/head"; +import { moneyToString } from "src/utils/money"; import { handlegRPCError } from "src/utils/server"; type Info = GetTenantInfoResponse & { tenantName: string }; @@ -87,12 +88,12 @@ export const TenantInfoPage: NextPage = requireAuth((u) => u.tenantRoles. {userCount} - {moneyToNumber(balance).toFixed(2)} {t("common.unit")} + {moneyToString(balance)} {t("common.unit")} - {moneyToNumber(defaultAccountBlockThreshold).toFixed(2)} {t("common.unit")} + {moneyToString(defaultAccountBlockThreshold)} {t("common.unit")} = (baseConfigPath, logge checkUiExtensionConfig(config.uiExtension); } + if (config.jobChargeDecimalPrecision && config.jobMinCharge && + (1 / Math.pow(10, config.jobChargeDecimalPrecision) > config.jobMinCharge)) { + throw new Error("The config jobMinCharge needs to match the config jobChargeDecimalPrecision"); + } + + if (![0,1,2,3,4].includes(config.jobChargeDecimalPrecision)) { + throw new Error("The config jobChargeDecimalPrecision must be one of the values 0, 1, 2, 3 or 4"); + } + return config; }; diff --git a/turbo.json b/turbo.json index fad557bdec..ed0e4d015f 100644 --- a/turbo.json +++ b/turbo.json @@ -1,5 +1,6 @@ { "$schema": "https://turbo.build/schema.json", + "globalEnv": ["HTTPS_PROXY"], "tasks": { "dev": { "persistent": true,