fix remove auto logic, fix space on url
This commit is contained in:
parent
324cb52741
commit
a811a77165
|
|
@ -1,3 +1,9 @@
|
|||
[safe]
|
||||
directory = /home/Log_service/
|
||||
directory = /home/Log_service/
|
||||
directory = /home/Log_service/
|
||||
directory = /home/Log_service/
|
||||
directory = /home/Log_service/
|
||||
directory = /home/Log_service/
|
||||
directory = /home/Log_service/
|
||||
directory = /home/Log_service/
|
||||
|
|
|
|||
|
|
@ -21,17 +21,17 @@ export default class ErpsController {
|
|||
try {
|
||||
const listLog: string[] = [];
|
||||
const response = await axios.get(BASE_URL);
|
||||
const responseAUTO = await axios.get(BASE_URL_AUTO);
|
||||
// const responseAUTO = await axios.get(BASE_URL_AUTO);
|
||||
console.log("check!!!!!!!!!!!!!!!!!!!!!")
|
||||
|
||||
let data1 = response.data
|
||||
.split("\n")
|
||||
.filter((i) => i.search("<a href") !== -1 && i.search(".log") !== -1);
|
||||
let data2 = responseAUTO.data
|
||||
.split("\n")
|
||||
.filter((i) => i.search("<a href") !== -1 && i.search(".log") !== -1);
|
||||
// let data2 = responseAUTO.data
|
||||
// .split("\n")
|
||||
// .filter((i) => i.search("<a href") !== -1 && i.search(".log") !== -1);
|
||||
|
||||
const arrayLine = data1.concat(data2);
|
||||
const arrayLine = data1;
|
||||
|
||||
// const arrayLineAUTO = data
|
||||
// .split("\n")
|
||||
|
|
@ -47,18 +47,12 @@ export default class ErpsController {
|
|||
parseInt(temp?.split("-")[0]) <= to
|
||||
) {
|
||||
listLog.push(
|
||||
(u
|
||||
.slice(u.search("<a ") + 9, u.search("</a>"))
|
||||
.split(">")[1]
|
||||
.includes("AUTO")
|
||||
? BASE_URL_AUTO
|
||||
: BASE_URL + "/") +
|
||||
(BASE_URL + "/") +
|
||||
u.slice(u.search("<a ") + 9, u.search("</a>")).split(">")[1] +
|
||||
" "
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return listLog;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
|
@ -139,6 +133,21 @@ export default class ErpsController {
|
|||
}
|
||||
}
|
||||
|
||||
// Vendor Serial (SN)
|
||||
if (cleanedLine.includes("Vendor Serial (SN)")) {
|
||||
const PCB_SN = extractSN(cleanedLine.split(":")[1]);
|
||||
if (PCB_SN) {
|
||||
results.push({
|
||||
PID: "",
|
||||
VID: "",
|
||||
SN: PCB_SN.trim(),
|
||||
line: [index + 1],
|
||||
fileName: fName,
|
||||
warehouse: getWarehouse(fName),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (cleanedLine.includes("System serial num")) {
|
||||
const PCB_SN = extractSN(cleanedLine.split(":")[1]);
|
||||
if (PCB_SN) {
|
||||
|
|
@ -192,7 +201,7 @@ export default class ErpsController {
|
|||
return [];
|
||||
}
|
||||
const fileContents = await Promise.all(
|
||||
urls.map((u) => fetchWithRetry(u?.split(" ")[0]))
|
||||
urls.map((u) => fetchWithRetry(u?.split(".log")[0]+".log"))
|
||||
);
|
||||
|
||||
let report: any = [];
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ const BASE_URL = Env.get("BASE_URL_LOG");
|
|||
export default class LogsController {
|
||||
public async showLog({ request, response }: HttpContextContract) {
|
||||
try {
|
||||
const fileName = request.params().name;
|
||||
const fileName = decodeURIComponent(request.params().name);
|
||||
console.log(fileName);
|
||||
const fileDetect = await LogDetectFile.findBy("file_name", fileName);
|
||||
|
||||
if (!fileDetect) {
|
||||
|
|
@ -27,9 +28,7 @@ export default class LogsController {
|
|||
(a: number, b: number) => a - b
|
||||
);
|
||||
|
||||
const logUrl = fileName.includes("AUTO")
|
||||
? `${BASE_URL}/AUTOlog/${fileName}`
|
||||
: `${BASE_URL}/${fileName}`;
|
||||
const logUrl = `${BASE_URL}/${fileName}`;
|
||||
|
||||
const content = await axios.get(logUrl);
|
||||
const allKeyValues = await KeyValue.all();
|
||||
|
|
|
|||
|
|
@ -1,208 +1,264 @@
|
|||
import Env from "@ioc:Adonis/Core/Env";
|
||||
// const axios = require("axios");
|
||||
// import fs from "fs";
|
||||
|
||||
import axios from "axios";
|
||||
import { addLogFunction } from "./addLogFunction";
|
||||
import moment from "moment";
|
||||
|
||||
export const checkIndexSN = async (content, beginLine, nameF) => {
|
||||
type OutputItem = {
|
||||
PID: string;
|
||||
VID: string;
|
||||
SN: string;
|
||||
line: number[];
|
||||
fileName: string;
|
||||
warehouse: "US" | "AU";
|
||||
};
|
||||
|
||||
export const checkIndexSN = async (
|
||||
content: string[],
|
||||
beginLine: number,
|
||||
nameF: string
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const arrayLine = content;
|
||||
const output: OutputItem[] = [];
|
||||
|
||||
let output = [];
|
||||
if (arrayLine !== undefined) {
|
||||
for (let i = 0; i < arrayLine.length; i++) {
|
||||
let SN = arrayLine[i]
|
||||
?.split("SN:")[1]
|
||||
?.trim()
|
||||
.replace(/[!@#$%^&*()_+{}\[\]:;<>,.?~\\/]/g, "");
|
||||
if (
|
||||
arrayLine[i].search("PID:") !== -1 &&
|
||||
arrayLine[i].search("SN:") !== -1 &&
|
||||
arrayLine[i].search("%") === -1 &&
|
||||
SN !== "" &&
|
||||
SN !== "N/A" &&
|
||||
SN.length > 4 &&
|
||||
i >= beginLine
|
||||
) {
|
||||
if (output.some((u) => u.SN === SN)) {
|
||||
output.map((u, index) => {
|
||||
if (u.SN === SN) {
|
||||
output[index].PID =
|
||||
arrayLine[i]?.split("VID:")[0] !== undefined
|
||||
? arrayLine[i]
|
||||
?.split("VID:")[0]
|
||||
?.slice(arrayLine[i]?.split("VID:")[0]?.search("PID"))
|
||||
?.split(":")[1]
|
||||
?.split(",")[0]
|
||||
?.trim()
|
||||
: "";
|
||||
(output[index].VID =
|
||||
arrayLine[i]?.split("SN:")[0] !== undefined
|
||||
? arrayLine[i]
|
||||
?.split("SN:")[0]
|
||||
?.split("VID:")[1]
|
||||
?.split(",")[0]
|
||||
?.trim()
|
||||
: ""),
|
||||
(output[index].line = output[index].line.concat([i + 1]));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
output.push({
|
||||
PID:
|
||||
arrayLine[i]?.split("VID:")[0] !== undefined
|
||||
? arrayLine[i]
|
||||
?.split("VID:")[0]
|
||||
?.slice(arrayLine[i]?.split("VID:")[0]?.search("PID"))
|
||||
?.split(":")[1]
|
||||
?.split(",")[0]
|
||||
?.trim()
|
||||
: "",
|
||||
VID:
|
||||
arrayLine[i]?.split("SN:")[0] !== undefined
|
||||
? arrayLine[i]
|
||||
?.split("SN:")[0]
|
||||
?.split("VID:")[1]
|
||||
?.split(",")[0]
|
||||
?.trim()
|
||||
: "",
|
||||
SN:
|
||||
arrayLine[i].split("SN:")[1] !== undefined
|
||||
? SN.search(" ") !== -1
|
||||
? SN?.split(" ")[0]
|
||||
: SN
|
||||
: "",
|
||||
line: [i + 1],
|
||||
fileName: nameF,
|
||||
warehouse:
|
||||
(nameF.search("-US") !== -1 ||
|
||||
nameF.search(".US") !== -1 ||
|
||||
nameF.search("US-") !== -1) &&
|
||||
nameF.search("AUS") === -1
|
||||
? "US"
|
||||
: "AU",
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!arrayLine) return;
|
||||
|
||||
if (arrayLine[i].search("Serial Number") !== -1 && i >= beginLine) {
|
||||
let PCB_SN = arrayLine[i]
|
||||
?.split("Serial Number")[1]
|
||||
.split(":")[1]
|
||||
?.replace("\r", "")
|
||||
.trim()
|
||||
.replace(/[!@#$%^&*()_+{}\[\]:;<>,.?~\\/]/g, "");
|
||||
if (
|
||||
//Neu SN da nam trong output
|
||||
output.some((u) => u.SN === PCB_SN)
|
||||
) {
|
||||
output.map((u, index) => {
|
||||
if (u.SN === PCB_SN) {
|
||||
output[index].line = output[index].line.concat([i + 1]);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// if (
|
||||
// /^[A-Z0-9-]{5,}$/.test(
|
||||
// PCB_SN
|
||||
// )
|
||||
// ) {
|
||||
for (let i = 0; i < arrayLine.length; i++) {
|
||||
const line = arrayLine[i];
|
||||
const SN = line
|
||||
?.split("SN:")[1]
|
||||
?.trim()
|
||||
.replace(/[!@#$%^&*()_+{}\[\]:;<>,.?~\\/]/g, "");
|
||||
|
||||
output.push({
|
||||
PID: "",
|
||||
VID: "",
|
||||
SN: PCB_SN?.search(" ") !== -1 ? PCB_SN?.split(" ")[0] : PCB_SN,
|
||||
line: [i + 1],
|
||||
fileName: nameF,
|
||||
warehouse:
|
||||
(nameF.search("-US") !== -1 ||
|
||||
nameF.search(".US") !== -1 ||
|
||||
nameF.search("US-") !== -1) &&
|
||||
nameF.search("AUS") === -1
|
||||
? "US"
|
||||
: "AU",
|
||||
});
|
||||
// }
|
||||
}
|
||||
}
|
||||
// Pattern: PID + SN
|
||||
if (
|
||||
line.includes("PID:") &&
|
||||
line.includes("SN:") &&
|
||||
!line.includes("%") &&
|
||||
SN &&
|
||||
SN !== "N/A" &&
|
||||
SN.length > 4 &&
|
||||
i >= beginLine
|
||||
) {
|
||||
const existingIndex = output.findIndex((u) => u.SN === SN);
|
||||
const PID = line?.split("VID:")[0]
|
||||
?.slice(line?.split("VID:")[0]?.search("PID"))
|
||||
?.split(":")[1]
|
||||
?.split(",")[0]
|
||||
?.trim() ?? "";
|
||||
|
||||
if (
|
||||
arrayLine[i].search("Processor board ID") !== -1 &&
|
||||
i >= beginLine
|
||||
) {
|
||||
let PBID = arrayLine[i]
|
||||
?.split(" ")
|
||||
[arrayLine[i]?.split(" ").length - 1]?.replace("\r", "")
|
||||
.trim()
|
||||
.replace(/[!@#$%^&*()_+{}\[\]:;<>,.?~\\/]/g, "");
|
||||
if (
|
||||
//Neu SN da nam trong output
|
||||
output.some((u) => u.SN === PBID)
|
||||
) {
|
||||
output.map((u, index) => {
|
||||
if (u.SN === PBID) {
|
||||
output[index].line = output[index].line.concat([i + 1]);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (PBID?.length >= 8) {
|
||||
output.push({
|
||||
PID: "",
|
||||
VID: "",
|
||||
SN: PBID?.search(" ") !== -1 ? PBID?.split(" ")[0] : PBID,
|
||||
line: [i + 1],
|
||||
fileName: nameF,
|
||||
warehouse:
|
||||
(nameF.search("-US") !== -1 ||
|
||||
nameF.search(".US") !== -1 ||
|
||||
nameF.search("US-") !== -1) &&
|
||||
nameF.search("AUS") === -1
|
||||
? "US"
|
||||
: "AU",
|
||||
});
|
||||
}
|
||||
}
|
||||
const VID = line?.split("SN:")[0]
|
||||
?.split("VID:")[1]
|
||||
?.split(",")[0]
|
||||
?.trim() ?? "";
|
||||
|
||||
if (existingIndex !== -1) {
|
||||
output[existingIndex].PID = PID;
|
||||
output[existingIndex].VID = VID;
|
||||
output[existingIndex].line.push(i + 1);
|
||||
} else {
|
||||
output.push({
|
||||
PID,
|
||||
VID,
|
||||
SN: SN.includes(" ") ? SN.split(" ")[0] : SN,
|
||||
line: [i + 1],
|
||||
fileName: nameF,
|
||||
warehouse:
|
||||
(nameF.includes("-US") ||
|
||||
nameF.includes(".US") ||
|
||||
nameF.includes("US-")) &&
|
||||
!nameF.includes("AUS")
|
||||
? "US"
|
||||
: "AU",
|
||||
});
|
||||
}
|
||||
}
|
||||
// console.log(nameF+" output\n", output);
|
||||
let pattern = /[\x00-\x20\x7F]/g;
|
||||
if (output.filter((i) => i.PID !== "" && i.PID.match(pattern)==null).length > 0) {
|
||||
let token =
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2FwaS5uc3d0ZWFtLm5ldC9hcGkvbG9naW4iLCJpYXQiOjE2OTg0NTg5MTAsImV4cCI6MTcyOTk5NDkxMCwibmJmIjoxNjk4NDU4OTEwLCJqdGkiOiJobGxQYWVZQzBmd2xlamZtIiwic3ViIjoxLCJwcnYiOiJjOGVlMWZjODllNzc1ZWM0YzczODY2N2U1YmUxN2E1OTBiNmQ0MGZjIn0.miEyaJEQmovST6Bu43USWAz5xND-9C49uB_3WEudqEs";
|
||||
|
||||
let token_int =
|
||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2ludC5pcHN1cHBseS5jb20uYXUvYXBpL2xvZ2luIiwiaWF0IjoxNjg5ODYyNjAxLCJleHAiOjE3MjEzOTg2MDEsIm5iZiI6MTY4OTg2MjYwMSwianRpIjoiUElZVjNBM3ZPQVlMQ081SyIsInN1YiI6MSwicHJ2IjoiYzhlZTFmYzg5ZTc3NWVjNGM3Mzg2NjdlNWJlMTdhNTkwYjZkNDBmYyJ9.UcybIKMBjTAY9i0PfIDQMtqHyN72Ul0jC03ZDGLGpMI";
|
||||
// Pattern: "Serial Number"
|
||||
if (line.includes("Serial Number") && i >= beginLine) {
|
||||
const rawSN = line.split("Serial Number")[1]?.split(":")[1]
|
||||
?.replace("\r", "")
|
||||
?.trim()
|
||||
?.replace(/[!@#$%^&*()_+{}\[\]:;<>,.?~\\/]/g, "");
|
||||
|
||||
let data = {
|
||||
data: output.filter((i) => i.PID !== "" && i.PID.match(pattern)===null),
|
||||
urlAPI: "/api/test-log-serial-number/save-data",
|
||||
};
|
||||
if (!rawSN) continue;
|
||||
|
||||
const response = await axios.post(
|
||||
"https://api.nswteam.net/api/transferPostData",
|
||||
const SN = rawSN.includes(" ") ? rawSN.split(" ")[0] : rawSN;
|
||||
|
||||
const existing = output.find((u) => u.SN === SN);
|
||||
if (existing) {
|
||||
existing.line.push(i + 1);
|
||||
} else {
|
||||
output.push({
|
||||
PID: "",
|
||||
VID: "",
|
||||
SN,
|
||||
line: [i + 1],
|
||||
fileName: nameF,
|
||||
warehouse:
|
||||
(nameF.includes("-US") ||
|
||||
nameF.includes(".US") ||
|
||||
nameF.includes("US-")) &&
|
||||
!nameF.includes("AUS")
|
||||
? "US"
|
||||
: "AU",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//Vendor Serial (SN)
|
||||
if (line.includes("Vendor Serial (SN)") && i >= beginLine) {
|
||||
const rawSN = line.split("Vendor Serial (SN)")[1]?.split(":")[1]
|
||||
?.replace("\r", "")
|
||||
?.trim()
|
||||
?.replace(/[!@#$%^&*()_+{}\[\]:;<>,.?~\\/]/g, "");
|
||||
|
||||
if (!rawSN) continue;
|
||||
|
||||
const SN = rawSN.includes(" ") ? rawSN.split(" ")[0] : rawSN;
|
||||
|
||||
const existing = output.find((u) => u.SN === SN);
|
||||
if (existing) {
|
||||
existing.line.push(i + 1);
|
||||
} else {
|
||||
output.push({
|
||||
PID: "",
|
||||
VID: "",
|
||||
SN,
|
||||
line: [i + 1],
|
||||
fileName: nameF,
|
||||
warehouse:
|
||||
(nameF.includes("-US") ||
|
||||
nameF.includes(".US") ||
|
||||
nameF.includes("US-")) &&
|
||||
!nameF.includes("AUS")
|
||||
? "US"
|
||||
: "AU",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//System serial num
|
||||
if (line.includes("System serial num") && i >= beginLine) {
|
||||
const rawSN = line.split("System serial num")[1]?.split(":")[1]
|
||||
?.replace("\r", "")
|
||||
?.trim()
|
||||
?.replace(/[!@#$%^&*()_+{}\[\]:;<>,.?~\\/]/g, "");
|
||||
|
||||
if (!rawSN) continue;
|
||||
|
||||
const SN = rawSN.includes(" ") ? rawSN.split(" ")[0] : rawSN;
|
||||
|
||||
const existing = output.find((u) => u.SN === SN);
|
||||
if (existing) {
|
||||
existing.line.push(i + 1);
|
||||
} else {
|
||||
output.push({
|
||||
PID: "",
|
||||
VID: "",
|
||||
SN,
|
||||
line: [i + 1],
|
||||
fileName: nameF,
|
||||
warehouse:
|
||||
(nameF.includes("-US") ||
|
||||
nameF.includes(".US") ||
|
||||
nameF.includes("US-")) &&
|
||||
!nameF.includes("AUS")
|
||||
? "US"
|
||||
: "AU",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Pattern: "Processor board ID"
|
||||
if (line.includes("Processor board ID") && i >= beginLine) {
|
||||
const parts = line.split(" ");
|
||||
const PBID = parts[parts.length - 1]
|
||||
?.replace("\r", "")
|
||||
?.trim()
|
||||
?.replace(/[!@#$%^&*()_+{}\[\]:;<>,.?~\\/]/g, "");
|
||||
|
||||
if (!PBID || PBID.length < 8) continue;
|
||||
|
||||
const SN = PBID.includes(" ") ? PBID.split(" ")[0] : PBID;
|
||||
|
||||
const existing = output.find((u) => u.SN === SN);
|
||||
if (existing) {
|
||||
existing.line.push(i + 1);
|
||||
} else {
|
||||
output.push({
|
||||
PID: "",
|
||||
VID: "",
|
||||
SN,
|
||||
line: [i + 1],
|
||||
fileName: nameF,
|
||||
warehouse:
|
||||
(nameF.includes("-US") ||
|
||||
nameF.includes(".US") ||
|
||||
nameF.includes("US-")) &&
|
||||
!nameF.includes("AUS")
|
||||
? "US"
|
||||
: "AU",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const pattern = /[\x00-\x20\x7F]/g;
|
||||
const invalidPIDItems = output.filter(
|
||||
(i) => i.PID !== "" && !i.PID.match(pattern)
|
||||
);
|
||||
|
||||
if (invalidPIDItems.length > 0) {
|
||||
const tokenStage = Env.get("STAGE_TOKEN_REQUEST");
|
||||
const tokenProd = Env.get("INT_TOKEN_REQUEST");
|
||||
const data = {
|
||||
data: invalidPIDItems,
|
||||
urlAPI: "/api/test-log-serial-number/save-data",
|
||||
};
|
||||
|
||||
// Try stage first
|
||||
try {
|
||||
await axios.post(
|
||||
"https://stage.nswteam.net/api/transferPostData",
|
||||
data,
|
||||
{ headers: { Authorization: "Bearer " + token } }
|
||||
{
|
||||
headers: { Authorization: "Bearer " + tokenStage },
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("Error sending to stage.nswteam.net:", JSON.stringify(e));
|
||||
}
|
||||
|
||||
if (Env.get("RUN_ENV") === "prod") {
|
||||
// If prod, send to int.ipsupply.com.au too
|
||||
if (Env.get("RUN_ENV") === "prod") {
|
||||
try {
|
||||
const response_int = await axios.post(
|
||||
"https://int.ipsupply.com.au/api/transferPostData",
|
||||
data,
|
||||
{ headers: { Authorization: "Bearer " + token_int } }
|
||||
{
|
||||
headers: { Authorization: "Bearer " + tokenProd },
|
||||
}
|
||||
);
|
||||
|
||||
console.log(nameF + " response\n", response_int.data);
|
||||
const fileName =
|
||||
"./app/store/logsAPI/" +
|
||||
moment(Date.now()).format("DD_MM_YYYY").toString() +
|
||||
moment().format("DD_MM_YYYY") +
|
||||
".log";
|
||||
addLogFunction(fileName, "URL: https://int.ipsupply.com.au/api/transferPostData\n"+ JSON.stringify(response_int.data, null, 2), "Update SN index to int.ipsupply.com.au");
|
||||
|
||||
addLogFunction(
|
||||
fileName,
|
||||
"URL: https://int.ipsupply.com.au/api/transferPostData\n" +
|
||||
JSON.stringify(response_int.data, null, 2),
|
||||
"Update SN index to int.ipsupply.com.au"
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("Error sending to int.ipsupply.com.au:", JSON.stringify(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Can't connect to log server", error);
|
||||
console.error("Can't connect to log server:", JSON.stringify(error));
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ export const sendDeviceInfora = async () => {
|
|||
});
|
||||
const options = {
|
||||
from: "admin@apactech.io",
|
||||
to: "joseph@apactech.io, ips@ipsupply.com.au",
|
||||
to: "joseph@apactech.io",
|
||||
// to: "joseph@apactech.io",
|
||||
subject: "(AUTO-REPORT) SERIAL NUMBER",
|
||||
html:
|
||||
|
|
|
|||
|
|
@ -77,10 +77,9 @@ Route.post("/api/addValue", "ValuesController.create").middleware("writeLog");
|
|||
|
||||
Route.post("/api/backupProduct", async ({ request, response }) => {
|
||||
try {
|
||||
const date = moment(Date.now()).format("YYYYMMDD");
|
||||
const res = await axios.post(
|
||||
"https://logs.danielvu.com/api/getIndexSerialNumber",
|
||||
{ from: date, to: date },
|
||||
{ from: request.all().from, to: request.all().to },
|
||||
{
|
||||
headers: {
|
||||
Authorization: request.headers().authorization?.replace(/"/g, ""),
|
||||
|
|
@ -106,7 +105,9 @@ Route.post("/api/backupProduct", async ({ request, response }) => {
|
|||
"networkToolBot",
|
||||
"Log service",
|
||||
"Backup product " +
|
||||
date +
|
||||
request.all().from +
|
||||
" to " +
|
||||
request.all().to +
|
||||
" success with " +
|
||||
res.data.length +
|
||||
" products"
|
||||
|
|
|
|||
Loading…
Reference in New Issue