Merge branch 'tariff' into 'dev'
feat: tariff See merge request pena-services/hub_admin_backend_service!3
This commit is contained in:
commit
bda96dbd14
@ -1,6 +1,7 @@
|
|||||||
import { setAccountRoutes } from "@/routes/account.routes";
|
import { setAccountRoutes } from "@/routes/account.routes";
|
||||||
import { setPrivilegeRoutes } from "@/routes/privilege.routes";
|
import { setPrivilegeRoutes } from "@/routes/privilege.routes";
|
||||||
import { setRoleRoutes } from "@/routes/role.routes";
|
import { setRoleRoutes } from "@/routes/role.routes";
|
||||||
|
import { setTariffRoutes } from "@/routes/tariff.routes";
|
||||||
|
|
||||||
import type { FastifyInstance } from "fastify";
|
import type { FastifyInstance } from "fastify";
|
||||||
|
|
||||||
@ -8,4 +9,5 @@ export const combineRoutes = (server: FastifyInstance): void => {
|
|||||||
server.register(setRoleRoutes, { prefix: "/role" });
|
server.register(setRoleRoutes, { prefix: "/role" });
|
||||||
server.register(setAccountRoutes, { prefix: "/account" });
|
server.register(setAccountRoutes, { prefix: "/account" });
|
||||||
server.register(setPrivilegeRoutes, { prefix: "/privilege" });
|
server.register(setPrivilegeRoutes, { prefix: "/privilege" });
|
||||||
|
server.register(setTariffRoutes, { prefix: "/tariff" });
|
||||||
};
|
};
|
||||||
|
22
src/handlers/tariff/helpers.ts
Normal file
22
src/handlers/tariff/helpers.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { validateEmptyFields } from "@/utils/validate-empty-fields";
|
||||||
|
|
||||||
|
import type { TariffMessage } from "@/types/messages/tariff-message.type";
|
||||||
|
import type { ObjectWithRequiredFields } from "@/types/object-with-required-fields";
|
||||||
|
|
||||||
|
export const validateTariff = (tariff: TariffMessage): [ObjectWithRequiredFields<TariffMessage>, Error | null] => {
|
||||||
|
const [validatedTariff, errorEmpty] = validateEmptyFields(
|
||||||
|
tariff,
|
||||||
|
["isCustom", "name", "price", "privilegies"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
if (errorEmpty) {
|
||||||
|
return [validatedTariff, errorEmpty];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(Number(validatedTariff.price))) {
|
||||||
|
return [validatedTariff, new Error("invalid 'price' value")];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [validatedTariff, null];
|
||||||
|
};
|
125
src/handlers/tariff/index.ts
Normal file
125
src/handlers/tariff/index.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
|
import { TariffModel } from "@/models/tariff.model";
|
||||||
|
import { PrivilegeModel } from "@/models/privilege.model";
|
||||||
|
|
||||||
|
import { validateEmptyFields } from "@/utils/validate-empty-fields";
|
||||||
|
import { validateTariff } from "./helpers";
|
||||||
|
|
||||||
|
import type { FastifyReply } from "fastify";
|
||||||
|
|
||||||
|
import type { Privilege } from "@/types/models/privilege.type";
|
||||||
|
import type { CreateTariffRequest, GetTariffRequest, ReplaceTariffRequest } from "./types";
|
||||||
|
|
||||||
|
export const getTariffs = async () => TariffModel.find({}).lean();
|
||||||
|
|
||||||
|
export const getTariff = async (request: GetTariffRequest, reply: FastifyReply) => {
|
||||||
|
const [requestParams, error] = validateEmptyFields(request.params || {}, ["id"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(requestParams.id)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tariff = await TariffModel.findById(requestParams.id).lean();
|
||||||
|
|
||||||
|
if (!tariff) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("tariff not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return tariff;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createTariff = async (request: CreateTariffRequest, reply: FastifyReply) => {
|
||||||
|
const [requestBody, error] = validateTariff(request.body || {});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const privilege of requestBody.privilegies) {
|
||||||
|
const findedPrivilege = await PrivilegeModel.findOne({ privilegeId: privilege.privilegeId }).lean();
|
||||||
|
|
||||||
|
if (!findedPrivilege) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error(`privilege with id ${privilege.privilegeId} not found`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const privilegiesMap = requestBody.privilegies.reduce<Record<string, Privilege[]>>((accamulator, privilege) => {
|
||||||
|
if (!accamulator[privilege.privilegeId]) {
|
||||||
|
accamulator[privilege.privilegeId] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
accamulator[privilege.privilegeId].push(privilege);
|
||||||
|
|
||||||
|
return accamulator;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const newTariff = new TariffModel({
|
||||||
|
name: requestBody.name,
|
||||||
|
price: requestBody.price,
|
||||||
|
isCustom: requestBody.isCustom,
|
||||||
|
privilegies: privilegiesMap,
|
||||||
|
});
|
||||||
|
|
||||||
|
await newTariff.save();
|
||||||
|
|
||||||
|
return newTariff;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replaceTariff = async (request: ReplaceTariffRequest, reply: FastifyReply) => {
|
||||||
|
const [requestBody, error] = validateTariff(request.body || {});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(request.params?.id || "")) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tariff = await TariffModel.findById(request.params?.id);
|
||||||
|
|
||||||
|
if (!tariff) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("tariff not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const privilege of requestBody.privilegies) {
|
||||||
|
const findedPrivilege = await PrivilegeModel.findOne({ privilegeId: privilege.privilegeId }).lean();
|
||||||
|
|
||||||
|
if (!findedPrivilege) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error(`privilege with id ${privilege.privilegeId} not found`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const privilegiesMap = requestBody.privilegies.reduce<Record<string, Privilege[]>>((accamulator, privilege) => {
|
||||||
|
if (!accamulator[privilege.privilegeId]) {
|
||||||
|
accamulator[privilege.privilegeId] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
accamulator[privilege.privilegeId].push(privilege);
|
||||||
|
|
||||||
|
return accamulator;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
await tariff.replaceOne({
|
||||||
|
name: requestBody.name,
|
||||||
|
price: requestBody.price,
|
||||||
|
isCustom: requestBody.isCustom,
|
||||||
|
privilegies: privilegiesMap,
|
||||||
|
});
|
||||||
|
|
||||||
|
return tariff;
|
||||||
|
};
|
11
src/handlers/tariff/types.ts
Normal file
11
src/handlers/tariff/types.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import type { FastifyRequest } from "fastify";
|
||||||
|
import type { CreateTariffRoute, ReplaceTariffRoute } from "@/types/routes/tariff-routes.type";
|
||||||
|
|
||||||
|
export type GetTariffRequest = FastifyRequest<{
|
||||||
|
Params?: {
|
||||||
|
id?: string;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type CreateTariffRequest = FastifyRequest<CreateTariffRoute>;
|
||||||
|
export type ReplaceTariffRequest = FastifyRequest<ReplaceTariffRoute>;
|
@ -1,6 +1,6 @@
|
|||||||
import { Schema, model, SchemaDefinition } from "mongoose";
|
import { Schema, model, SchemaDefinition } from "mongoose";
|
||||||
|
|
||||||
import { eloquentModelSchema } from "./eloquent-model.schema";
|
import { EloquentSchema } from "./eloquent-model.schema";
|
||||||
|
|
||||||
import type { Account } from "@/types/models/account.type";
|
import type { Account } from "@/types/models/account.type";
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ const schema: SchemaDefinition<Account> = {
|
|||||||
type: String,
|
type: String,
|
||||||
default: "user",
|
default: "user",
|
||||||
},
|
},
|
||||||
...eloquentModelSchema,
|
...EloquentSchema,
|
||||||
};
|
};
|
||||||
|
|
||||||
const schemaSettings = {
|
const schemaSettings = {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import type { SchemaDefinition } from "mongoose";
|
import { Schema, SchemaDefinition } from "mongoose";
|
||||||
|
|
||||||
import type { EloquentModel } from "@/types/models/eloquent-model.type";
|
import type { EloquentModel } from "@/types/models/eloquent-model.type";
|
||||||
|
|
||||||
export const eloquentModelSchema: SchemaDefinition<EloquentModel> = {
|
export const schema: SchemaDefinition<EloquentModel> = {
|
||||||
createdAt: {
|
createdAt: {
|
||||||
type: Date,
|
type: Date,
|
||||||
required: true,
|
required: true,
|
||||||
@ -22,3 +23,10 @@ export const eloquentModelSchema: SchemaDefinition<EloquentModel> = {
|
|||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const schemaSettings = {
|
||||||
|
versionKey: false,
|
||||||
|
collection: "privilegies",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EloquentSchema = new Schema<EloquentModel>(schema, schemaSettings);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Schema, model, SchemaDefinition } from "mongoose";
|
import { Schema, model, SchemaDefinition } from "mongoose";
|
||||||
|
|
||||||
import { eloquentModelSchema } from "./eloquent-model.schema";
|
import { EloquentSchema } from "./eloquent-model.schema";
|
||||||
|
|
||||||
import type { Privilege } from "@/types/models/privilege.type";
|
import type { Privilege } from "@/types/models/privilege.type";
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ const schema: SchemaDefinition<Privilege> = {
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
...eloquentModelSchema,
|
...EloquentSchema,
|
||||||
};
|
};
|
||||||
|
|
||||||
const schemaSettings = {
|
const schemaSettings = {
|
||||||
@ -45,6 +45,6 @@ const schemaSettings = {
|
|||||||
collection: "privilegies",
|
collection: "privilegies",
|
||||||
};
|
};
|
||||||
|
|
||||||
const PrivilegeSchema = new Schema<Privilege>(schema, schemaSettings);
|
export const PrivilegeSchema = new Schema<Privilege>(schema, schemaSettings);
|
||||||
|
|
||||||
export const PrivilegeModel = model("Privilege", PrivilegeSchema);
|
export const PrivilegeModel = model("Privilege", PrivilegeSchema);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Schema, model, SchemaDefinition } from "mongoose";
|
import { Schema, model, SchemaDefinition } from "mongoose";
|
||||||
|
|
||||||
import { eloquentModelSchema } from "./eloquent-model.schema";
|
import { EloquentSchema } from "./eloquent-model.schema";
|
||||||
|
|
||||||
import type { Role } from "@/types/models/role.type";
|
import type { Role } from "@/types/models/role.type";
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ const schema: SchemaDefinition<Role> = {
|
|||||||
of: Boolean,
|
of: Boolean,
|
||||||
default: {},
|
default: {},
|
||||||
},
|
},
|
||||||
...eloquentModelSchema,
|
...EloquentSchema,
|
||||||
};
|
};
|
||||||
|
|
||||||
const schemaSettings = {
|
const schemaSettings = {
|
||||||
|
36
src/models/tariff.model.ts
Normal file
36
src/models/tariff.model.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Schema, model, SchemaDefinition } from "mongoose";
|
||||||
|
|
||||||
|
import { EloquentSchema } from "./eloquent-model.schema";
|
||||||
|
import { PrivilegeSchema } from "./privilege.model";
|
||||||
|
|
||||||
|
import type { Tariff } from "@/types/models/tariff.type";
|
||||||
|
|
||||||
|
const schema: SchemaDefinition<Tariff> = {
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
price: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
isCustom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
privilegies: {
|
||||||
|
type: Map,
|
||||||
|
of: PrivilegeSchema,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
...EloquentSchema,
|
||||||
|
};
|
||||||
|
|
||||||
|
const schemaSettings = {
|
||||||
|
versionKey: false,
|
||||||
|
collection: "tariffs",
|
||||||
|
};
|
||||||
|
|
||||||
|
const TariffSchema = new Schema<Tariff>(schema, schemaSettings);
|
||||||
|
|
||||||
|
export const TariffModel = model("Tariff", TariffSchema);
|
@ -1,5 +1,5 @@
|
|||||||
import { createAccount, getAccount } from "@/handlers/account";
|
import { createAccount, getAccount } from "@/handlers/account";
|
||||||
import { verifyUser } from "@/handlers/account/middleware";
|
import { verifyUser } from "@/handlers/auth/middleware";
|
||||||
|
|
||||||
import type { FastifyInstance, FastifyPluginOptions } from "fastify";
|
import type { FastifyInstance, FastifyPluginOptions } from "fastify";
|
||||||
import type { GetAccountRoute, CreateAccountRoute } from "@/types/routes/account-routes.type";
|
import type { GetAccountRoute, CreateAccountRoute } from "@/types/routes/account-routes.type";
|
||||||
|
14
src/routes/tariff.routes.ts
Normal file
14
src/routes/tariff.routes.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { createTariff, replaceTariff, getTariff, getTariffs } from "@/handlers/tariff";
|
||||||
|
import { verifyUser } from "@/handlers/auth/middleware";
|
||||||
|
|
||||||
|
import type { FastifyInstance, FastifyPluginOptions } from "fastify";
|
||||||
|
import type { CreateTariffRoute, ReplaceTariffRoute } from "@/types/routes/tariff-routes.type";
|
||||||
|
|
||||||
|
export const setTariffRoutes = <T = FastifyPluginOptions>(server: FastifyInstance, opts: T, done: () => void): void => {
|
||||||
|
server.get("/:id", getTariff);
|
||||||
|
server.get("/", getTariffs);
|
||||||
|
server.post<CreateTariffRoute>("/", { preHandler: [verifyUser] }, createTariff);
|
||||||
|
server.put<ReplaceTariffRoute>("/", { preHandler: [verifyUser] }, replaceTariff);
|
||||||
|
|
||||||
|
done();
|
||||||
|
};
|
154
src/swagger.json
154
src/swagger.json
@ -1,154 +0,0 @@
|
|||||||
{
|
|
||||||
"openapi": "3.0.3",
|
|
||||||
"info": {
|
|
||||||
"title": "PenaHub Server",
|
|
||||||
"version": "1.0.11",
|
|
||||||
"license": {
|
|
||||||
"name": "Apache 2.0",
|
|
||||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"externalDocs": {
|
|
||||||
"description": "Find out more about Swagger",
|
|
||||||
"url": "http://swagger.io"
|
|
||||||
},
|
|
||||||
"servers": [
|
|
||||||
{
|
|
||||||
"url": "http://84.201.155.77:8080"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"paths": {
|
|
||||||
"/": {
|
|
||||||
"get": {
|
|
||||||
"tags": [
|
|
||||||
"/"
|
|
||||||
],
|
|
||||||
"summary": "Список пользователей",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Successful"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/auth": {
|
|
||||||
"get": {
|
|
||||||
"tags": [
|
|
||||||
"auth"
|
|
||||||
],
|
|
||||||
"summary": "Страница регистрации",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Successful"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/auth": {
|
|
||||||
"post": {
|
|
||||||
"tags": [
|
|
||||||
"auth"
|
|
||||||
],
|
|
||||||
"summary": "Регистрация нового пользователя",
|
|
||||||
"requestBody": {
|
|
||||||
"content": {
|
|
||||||
"application/urlencoded": {
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"login": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "valera24"
|
|
||||||
},
|
|
||||||
"email": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "valera24@mail.com"
|
|
||||||
},
|
|
||||||
"phoneNumber": {
|
|
||||||
"type": "string",
|
|
||||||
"example": 79993337733
|
|
||||||
},
|
|
||||||
"password": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "secret"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Successful"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/login": {
|
|
||||||
"get": {
|
|
||||||
"tags": [
|
|
||||||
"login"
|
|
||||||
],
|
|
||||||
"summary": "Страница авторизации",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "return",
|
|
||||||
"in": "query",
|
|
||||||
"description": "URL на который будет перенаправлен пользователь после авторизации",
|
|
||||||
"required": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Successful"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/login": {
|
|
||||||
"post": {
|
|
||||||
"tags": [
|
|
||||||
"login"
|
|
||||||
],
|
|
||||||
"summary": "Авторизация пользователя",
|
|
||||||
"requestBody": {
|
|
||||||
"content": {
|
|
||||||
"application/urlencoded": {
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"email": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "valera24@mail.com"
|
|
||||||
},
|
|
||||||
"password": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "secret"
|
|
||||||
},
|
|
||||||
"goto": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "http://penahub.quiz/signedup"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Successful (Если не передан goto)"
|
|
||||||
},
|
|
||||||
"304": {
|
|
||||||
"description": "Successful (Если передан goto)"
|
|
||||||
},
|
|
||||||
"401": {
|
|
||||||
"description": "password incorrect"
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "User not found"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
10
src/types/messages/tariff-message.type.ts
Normal file
10
src/types/messages/tariff-message.type.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import type { EloquentModel } from "../models/eloquent-model.type";
|
||||||
|
import type { Privilege } from "../models/privilege.type";
|
||||||
|
import type { Tariff } from "../models/tariff.type";
|
||||||
|
import type { ObjectWithPossibleFields } from "../object-with-possible-fields";
|
||||||
|
|
||||||
|
export type TariffMessage = ObjectWithPossibleFields<
|
||||||
|
Omit<Tariff, keyof EloquentModel | "privilegies"> & {
|
||||||
|
privilegies: Privilege[];
|
||||||
|
}
|
||||||
|
>;
|
9
src/types/models/tariff.type.ts
Normal file
9
src/types/models/tariff.type.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import type { Privilege } from "./privilege.type";
|
||||||
|
import type { EloquentModel } from "./eloquent-model.type";
|
||||||
|
|
||||||
|
export type Tariff = EloquentModel & {
|
||||||
|
name: string;
|
||||||
|
price: number;
|
||||||
|
isCustom: boolean;
|
||||||
|
privilegies: Record<string, Privilege>;
|
||||||
|
};
|
3
src/types/object-with-possible-fields.ts
Normal file
3
src/types/object-with-possible-fields.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export type ObjectWithPossibleFields<KeyValue extends Record<string, unknown>> = {
|
||||||
|
[Key in keyof KeyValue]?: KeyValue[Key];
|
||||||
|
};
|
11
src/types/routes/tariff-routes.type.ts
Normal file
11
src/types/routes/tariff-routes.type.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import type { RequestGenericInterface } from "fastify";
|
||||||
|
import type { TariffMessage } from "../messages/tariff-message.type";
|
||||||
|
|
||||||
|
export type CreateTariffRoute = RequestGenericInterface & {
|
||||||
|
Body?: TariffMessage;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ReplaceTariffRoute = RequestGenericInterface & {
|
||||||
|
Body?: TariffMessage;
|
||||||
|
Params?: { id?: string };
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user