Files
FastGPT/packages/service/support/wallet/sub/utils.ts
Archer 0720bbe4da V4.9.7 feature (#4669)
* update doc

* feat: Add coupon redemption feature for team subscriptions (#4595)

* feat: Add coupon redemption feature for team subscriptions

- Introduced `TeamCouponSub` and `TeamCouponSchema` types
- Added `redeemCoupon` API endpoint
- Updated UI to include a modal for coupon redemption
- Added new icon and translations for "Redeem coupon"

* perf: remove field teamId

* perf: use dynamic import

* refactor: move to page component

* perf: coupon code

* perf: mcp server

* perf: test

* auto layout (#4634)

* fix 4.9.6 (#4631)

* fix debug quote list

* delete next text node match

* fix extract default boolean value

* export latest 100 chat items

* fix quote item ui

* doc

* fix doc

* feat: auto layout

* perf: auto layout

* fix: auto layout null

* add start node

---------

Co-authored-by: heheer <heheer@sealos.io>

* fix: share link (#4644)

* Add workflow run duration;Get audio duration (#4645)

* add duration

* get audio duration

* Custom config path (#4649)

* feat: 通过环境变量DATA_PATH获取配置文件目录 (#4622)

通过环境变量DATA_PATH获取配置文件目录,以应对不同的部署方式的多样化需求

* feat: custom configjson path

* doc

---------

Co-authored-by: John Chen <sss1991@163.com>

* 程序api调用场景下,如果大量调用带有图片或视频,产生的聊天记录会导致后台mongo数据库异常。这个修改给api客户端一个禁止生成聊天记录的选项,避免这个后果。 (#3964)

* update special chatId

* perf: vector db rename

* update operationLog (#4647)

* update operationLog

* combine operationLogMap

* solve operationI18nLogMap bug

* remoce log

* feat: Rerank usage (#4654)

* refresh concat when update (#4655)

* fix: refresh code

* perf: timer lock

* Fix operationLog (#4657)

* perf: http streamable mcp

* add alipay (#4630)

* perf: subplan ui

* perf: pay code

* hiden bank tip

* Fix: pay error (#4665)

* fix quote number (#4666)

* remove log

---------

Co-authored-by: a.e. <49438478+I-Info@users.noreply.github.com>
Co-authored-by: heheer <heheer@sealos.io>
Co-authored-by: John Chen <sss1991@163.com>
Co-authored-by: gaord <bengao168@msn.com>
Co-authored-by: gggaaallleee <91131304+gggaaallleee@users.noreply.github.com>
2025-04-26 16:17:21 +08:00

172 lines
5.0 KiB
TypeScript

import {
StandardSubLevelEnum,
SubModeEnum,
SubTypeEnum,
standardSubLevelMap
} from '@fastgpt/global/support/wallet/sub/constants';
import { MongoTeamSub } from './schema';
import { FeTeamPlanStatusType, TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type.d';
import { getVectorCountByTeamId } from '../../../common/vectorDB/controller';
import dayjs from 'dayjs';
import { ClientSession } from '../../../common/mongo';
import { addMonths } from 'date-fns';
import { readFromSecondary } from '../../../common/mongo/utils';
export const getStandardPlansConfig = () => {
return global?.subPlans?.standard;
};
export const getStandardPlanConfig = (level: `${StandardSubLevelEnum}`) => {
return global.subPlans?.standard?.[level];
};
export const sortStandPlans = (plans: TeamSubSchema[]) => {
return plans.sort(
(a, b) =>
standardSubLevelMap[b.currentSubLevel].weight - standardSubLevelMap[a.currentSubLevel].weight
);
};
export const getTeamStandPlan = async ({ teamId }: { teamId: string }) => {
const plans = await MongoTeamSub.find(
{
teamId,
type: SubTypeEnum.standard
},
undefined,
{
...readFromSecondary
}
);
sortStandPlans(plans);
const standardPlans = global.subPlans?.standard;
const standard = plans[0];
return {
[SubTypeEnum.standard]: standard,
standardConstants:
standard?.currentSubLevel && standardPlans
? standardPlans[standard.currentSubLevel]
: undefined
};
};
export const initTeamFreePlan = async ({
teamId,
session
}: {
teamId: string;
session?: ClientSession;
}) => {
const freePoints = global?.subPlans?.standard?.[StandardSubLevelEnum.free]?.totalPoints || 100;
const freePlan = await MongoTeamSub.findOne({
teamId,
type: SubTypeEnum.standard,
currentSubLevel: StandardSubLevelEnum.free
});
// Reset one month free plan
if (freePlan) {
freePlan.currentMode = SubModeEnum.month;
freePlan.nextMode = SubModeEnum.month;
freePlan.startTime = new Date();
freePlan.expiredTime = addMonths(new Date(), 1);
freePlan.currentSubLevel = StandardSubLevelEnum.free;
freePlan.nextSubLevel = StandardSubLevelEnum.free;
freePlan.totalPoints = freePoints;
freePlan.surplusPoints =
freePlan.surplusPoints && freePlan.surplusPoints < 0
? freePlan.surplusPoints + freePoints
: freePoints;
return freePlan.save({ session });
}
return MongoTeamSub.create(
[
{
teamId,
type: SubTypeEnum.standard,
currentMode: SubModeEnum.month,
nextMode: SubModeEnum.month,
startTime: new Date(),
expiredTime: addMonths(new Date(), 1),
currentSubLevel: StandardSubLevelEnum.free,
nextSubLevel: StandardSubLevelEnum.free,
totalPoints: freePoints,
surplusPoints: freePoints
}
],
{ session, ordered: true }
);
};
export const getTeamPlanStatus = async ({
teamId
}: {
teamId: string;
}): Promise<FeTeamPlanStatusType> => {
const standardPlans = global.subPlans?.standard;
/* Get all plans and datasetSize */
const [plans, usedDatasetSize] = await Promise.all([
MongoTeamSub.find({ teamId }).lean(),
getVectorCountByTeamId(teamId)
]);
/* Get all standardPlans and active standardPlan */
const teamStandardPlans = sortStandPlans(
plans.filter((plan) => plan.type === SubTypeEnum.standard)
);
const standardPlan = teamStandardPlans[0];
const extraDatasetSize = plans.filter((plan) => plan.type === SubTypeEnum.extraDatasetSize);
const extraPoints = plans.filter((plan) => plan.type === SubTypeEnum.extraPoints);
// Free user, first login after expiration. The free subscription plan will be reset
if (
(standardPlan &&
standardPlan.expiredTime &&
standardPlan.currentSubLevel === StandardSubLevelEnum.free &&
dayjs(standardPlan.expiredTime).isBefore(new Date())) ||
teamStandardPlans.length === 0
) {
console.log('Init free stand plan', { teamId });
await initTeamFreePlan({ teamId });
return getTeamPlanStatus({ teamId });
}
const totalPoints = standardPlans
? (standardPlan?.totalPoints || 0) +
extraPoints.reduce((acc, cur) => acc + (cur.totalPoints || 0), 0)
: Infinity;
const surplusPoints =
(standardPlan?.surplusPoints || 0) +
extraPoints.reduce((acc, cur) => acc + (cur.surplusPoints || 0), 0);
const standardMaxDatasetSize =
standardPlan?.currentSubLevel && standardPlans
? standardPlans[standardPlan.currentSubLevel]?.maxDatasetSize || Infinity
: Infinity;
const totalDatasetSize =
standardMaxDatasetSize +
extraDatasetSize.reduce((acc, cur) => acc + (cur.currentExtraDatasetSize || 0), 0);
return {
[SubTypeEnum.standard]: standardPlan,
standardConstants:
standardPlan?.currentSubLevel && standardPlans
? standardPlans[standardPlan.currentSubLevel]
: undefined,
totalPoints,
usedPoints: totalPoints - surplusPoints,
datasetMaxSize: totalDatasetSize,
usedDatasetSize
};
};