добавление отчетов

This commit is contained in:
Sergey Yarkov 2026-03-11 16:28:02 +03:00
parent 433a412985
commit 9342a9cf5e
8 changed files with 90 additions and 26 deletions

View File

@ -1,15 +1,6 @@
import { BadRequestError } from "#root/http-server/index.js"; import { BadRequestError } from "#root/http-server/index.js";
import yup from "yup"; import { reportsService } from "#root/services/reports.service.js";
import { reportsSchema } from "#schemas/report.schema.js";
var reportItemSchema = yup.object({
date: yup.date().required(),
equipment: yup.string().nullable().required(),
reason_call: yup.string().required(),
job_description: yup.string().required(),
root_cause: yup.string().required(),
applicant: yup.number().required(),
executor_ids: yup.array(yup.number()).required()
});
/** /**
* URL: /api/reports_sync * URL: /api/reports_sync
@ -19,13 +10,10 @@ var reportItemSchema = yup.object({
* @type {import("#root/http-server/types/http-server.js").HttpRouteHandler} * @type {import("#root/http-server/types/http-server.js").HttpRouteHandler}
*/ */
export default async ({ res, data }) => { export default async ({ res, data }) => {
const inputSchema = yup.object({ reports: yup.array(reportItemSchema).required() }).required(); const { reports } = await reportsSchema.validate(data).catch((err) => {
await inputSchema.validate(data).catch((err) => {
throw new BadRequestError(err.message); throw new BadRequestError(err.message);
}); });
// TODO ... await reportsService.syncReportsWithDatabase(reports);
res.sendJson({ data: { message: "OK" } });
res.sendJson({ data });
}; };

View File

@ -3,11 +3,7 @@ import { createRequest } from "./request.js";
import { createResponse } from "./response.js"; import { createResponse } from "./response.js";
import { createRouter } from "./route.js"; import { createRouter } from "./route.js";
/** /** @import { HttpServerOptions, HttpServer, HttpContext } from "./types/http-server.js" */
* @typedef {import('./types/http-server.js').HttpServer} HttpServer
* @typedef {import('./types/http-server.js').HttpServerOptions} HttpServerOptions
* @typedef {import('./types/http-server.js').HttpContext} HttpContext
*/
/** /**
* @param {HttpServerOptions} options * @param {HttpServerOptions} options

View File

@ -1,6 +1,9 @@
/** @import { IncomingMessage } from "node:http" */
/** @import { HttpRequest } from "./types/http-server.js" */
/** /**
* @param {import('node:http').IncomingMessage} req * @param {IncomingMessage} req
* @returns {import('./types/http-server.js').HttpRequest} * @returns {HttpRequest}
*/ */
export function createRequest(req) { export function createRequest(req) {
return { return {

View File

@ -10,7 +10,8 @@
"paths": { "paths": {
"#root/*": ["./*"], "#root/*": ["./*"],
"#handlers/*": ["./handlers/*"], "#handlers/*": ["./handlers/*"],
"#services/*": ["./services/*"] "#services/*": ["./services/*"],
"#schemas/*": ["./schemas/*"]
} }
}, },
"exclude": ["./http-server/types/*.d.ts"] "exclude": ["./http-server/types/*.d.ts"]

View File

@ -24,7 +24,8 @@
"imports": { "imports": {
"#root/*": "./*", "#root/*": "./*",
"#handlers/*": "./handlers/*", "#handlers/*": "./handlers/*",
"#services/*": "./services/*" "#services/*": "./services/*",
"#schemas/*": "./schemas/*"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^10.0.1", "@eslint/js": "^10.0.1",

1
schemas/index.js Normal file
View File

@ -0,0 +1 @@
export * from "./report.schema.js";

26
schemas/report.schema.js Normal file
View File

@ -0,0 +1,26 @@
import y from "yup";
export const reportItemSchema = y.object({
date: y.string(),
equipment: y
.object({
id: y.number(),
name: y.string(),
location: y
.object({
id: y.string(),
name: y.string(),
base_location_name: y.string(),
base_location: y.string()
})
.nullable()
})
.nullable(),
reason_call: y.string(),
job_description: y.string(),
root_cause: y.string(),
applicant: y.object({ id: y.number(), name: y.string() }).nullable(),
executors: y.array(y.object({ id: y.number(), fullname: y.string() })).required()
});
export const reportsSchema = y.object({ reports: y.array(reportItemSchema).required() }).required();

View File

@ -1,6 +1,10 @@
import xlsx from "xlsx"; import xlsx from "xlsx";
import pLimit from "p-limit"; import pLimit from "p-limit";
import db from "#root/db.js"; import db from "#root/db.js";
import mssql from "mssql";
/** @import { reportsSchema } from "#schemas/report.schema.js" */
/** @import { InferType } from "yup" */
const sheetName = "Отчеты"; const sheetName = "Отчеты";
@ -163,6 +167,50 @@ export const reportsService = {
}) })
) )
}; };
},
/**
* @param {InferType<typeof reportsSchema>['reports']} reports
*/
async syncReportsWithDatabase(reports) {
const trx = new mssql.Transaction(db);
const table = new mssql.Table("dbo.gpp_report_api_report");
table.create = false;
table.columns.add("date", mssql.Date, { nullable: false });
table.columns.add("reason_call", mssql.NVarChar(mssql.MAX), { nullable: false });
table.columns.add("job_description", mssql.NVarChar(mssql.MAX), { nullable: false });
table.columns.add("root_cause", mssql.NVarChar(mssql.MAX), { nullable: true });
table.columns.add("applicant_id", mssql.BigInt, { nullable: true });
table.columns.add("equipment_id", mssql.BigInt, { nullable: true });
try {
const addReportsRequest = new mssql.Request(trx);
for (const r of reports) {
let date = new Date(r.date || "2026");
if (!(date instanceof Date && !Number.isNaN(date.valueOf()))) date = new Date("2026");
table.rows.add(
date,
r.reason_call || " ",
r.job_description || " ",
r.root_cause || " ",
r.applicant?.id || null,
r.equipment?.id || null
);
}
await trx.begin();
await addReportsRequest.bulk(table);
await trx.commit();
} catch (error) {
console.error(error);
await trx.rollback();
throw error;
}
} }
}; };