done
This commit is contained in:
parent
6dafe854b6
commit
ec7b733ff6
|
@ -130,3 +130,6 @@ dist
|
|||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
build/
|
||||
.env
|
||||
service-account-file.json
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
FROM node:22-bullseye
|
||||
|
||||
WORKDIR /opt/app
|
||||
|
||||
COPY package.json package-lock.json .env src eslint.config.mjs tsconfig.json db_schema.sql .
|
||||
COPY src ./src
|
||||
|
||||
RUN npm i
|
||||
|
||||
CMD ["npm", "run", "start"]
|
|
@ -0,0 +1,8 @@
|
|||
CREATE TABLE IF NOT EXISTS warehouses (
|
||||
name VARCHAR(64) PRIMARY KEY,
|
||||
box_delivery_and_storage_expr INTEGER,
|
||||
box_delivery_base INTEGER,
|
||||
box_delivery_liter INTEGER,
|
||||
box_storage_base REAL,
|
||||
box_storage_liter REAL
|
||||
);
|
|
@ -0,0 +1,22 @@
|
|||
services:
|
||||
database:
|
||||
image: 'postgres:15'
|
||||
env_file: .env
|
||||
ports:
|
||||
- 5432:5432
|
||||
volumes:
|
||||
- ./data/db:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_USER: ${DB_USER}
|
||||
POSTGRES_PASSWORD: ${DB_PASS}
|
||||
POSTGRES_DB: ${DB_NAME}
|
||||
healthcheck:
|
||||
test: pg_isready -U $${DB_USER} -d $${DB_NAME}
|
||||
api_script:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
env_file: .env
|
||||
depends_on:
|
||||
- database
|
||||
restart: on-failure
|
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
|
@ -5,7 +5,8 @@
|
|||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev":"nodemon src/index.js"
|
||||
"start": "npx tsx --env-file=.env --watch src/index.ts",
|
||||
"build": "npx rsc src/index.ts"
|
||||
},
|
||||
"imports": {
|
||||
"#*": [
|
||||
|
@ -18,9 +19,13 @@
|
|||
"axios": "^1.6.2",
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2",
|
||||
"googleapis": "^144.0.0",
|
||||
"knex": "^3.0.1",
|
||||
"log4js": "^6.9.1",
|
||||
"pg": "^8.11.3",
|
||||
"pg": "^8.13.1",
|
||||
"tsc": "^2.0.4",
|
||||
"tsx": "^4.19.2",
|
||||
"typescript": "^5.7.3",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -38,7 +43,6 @@
|
|||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"jest": "^29.7.0",
|
||||
"nodemon": "^3.1.9",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-jsdoc": "^1.3.0",
|
||||
"prettier-plugin-sql": "^0.18.1"
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_USER=api_user
|
||||
DB_NAME=api_db
|
||||
DB_PASS=S0M3S7R0NGPA$$W0RD
|
||||
#in seconds
|
||||
TIME_BETWEEN_REQUESTS=10
|
||||
WB_TOKEN=TOKEN_HERE
|
||||
SPREADSHEETS_NAME=stocks_coefs
|
||||
#in format id1:id2:id3:.....
|
||||
SPREADSHEETS_IDS=
|
|
@ -0,0 +1,165 @@
|
|||
import axios from 'axios';
|
||||
import knex from 'knex';
|
||||
import fs from 'fs';
|
||||
import { google } from 'googleapis';
|
||||
/**
|
||||
* @type Warehouse
|
||||
* Type contains information about a warehouse.
|
||||
* I dunno what other things aside from name means,
|
||||
* anyways it works and I don't think I need to know :P
|
||||
*/
|
||||
type Warehouse = {
|
||||
name: string,
|
||||
box_delivery_and_storage_expr: Number,
|
||||
box_delivery_base: Number,
|
||||
box_delivery_liter: Number,
|
||||
box_storage_base: Number,
|
||||
box_storage_liter: Number
|
||||
};
|
||||
|
||||
const dbClient = knex({
|
||||
client: "pg",
|
||||
connection: {
|
||||
host: process.env.DB_HOST,
|
||||
port: Number.parseInt(process.env.DB_PORT!),
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASS,
|
||||
database: process.env.DB_NAME
|
||||
}
|
||||
})
|
||||
/**
|
||||
* This function executes file ./db_schema.psql that contains the DB schema in format "create if not exists"
|
||||
*/
|
||||
const initDb = async () => {
|
||||
console.log("Starting database initialization.");
|
||||
const initializeQuery = fs.readFileSync('./db_schema.sql').toString();
|
||||
|
||||
await dbClient.raw(initializeQuery);
|
||||
console.log("Database initialization ended.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This function makes request to the WB API
|
||||
* and puts the data to the DB.
|
||||
*/
|
||||
const request = async () => {
|
||||
console.log("starting request")
|
||||
const data = {
|
||||
response: {
|
||||
data: {
|
||||
dtNextBox: "2024-02-01",
|
||||
dtTillMax: "2024-03-31",
|
||||
warehouseList: [
|
||||
{
|
||||
boxDeliveryAndStorageExpr: "160",
|
||||
boxDeliveryBase: "48",
|
||||
boxDeliveryLiter: "11,2",
|
||||
boxStorageBase: "0,1",
|
||||
boxStorageLiter: "0,1",
|
||||
warehouseName: "Коледино"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
const data = await axios.get(`https://common-api.wildberries.ru/api/v1/tariffs/box`, {
|
||||
params: {
|
||||
date: new Date().toISOString().split('T')[0]
|
||||
},
|
||||
headers: {
|
||||
"Authorization": `Bearer ${process.env.WB_TOKEN}`
|
||||
}
|
||||
});
|
||||
*/
|
||||
const warehouses: Warehouse[] = []
|
||||
data.response.data.warehouseList.forEach(warehouse => {
|
||||
const warehoseData: Warehouse = {
|
||||
name: warehouse.warehouseName,
|
||||
box_delivery_and_storage_expr: Number.parseInt(warehouse.boxDeliveryAndStorageExpr),
|
||||
box_delivery_base: Number.parseInt(warehouse.boxDeliveryBase),
|
||||
box_delivery_liter: Number.parseInt(warehouse.boxDeliveryLiter),
|
||||
box_storage_base: Number.parseFloat(warehouse.boxStorageBase.replace(",", ".")),
|
||||
box_storage_liter: Number.parseFloat(warehouse.boxStorageLiter.replace(",", "."))
|
||||
};
|
||||
warehouses.push(warehoseData);
|
||||
dbClient("warehouses")
|
||||
.insert(warehoseData)
|
||||
.onConflict("name")
|
||||
.merge()
|
||||
.catch(e => console.log(e));
|
||||
});
|
||||
return warehouses;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function handles data export to the google sheets.
|
||||
*/
|
||||
const exportData = async (warehouses: Warehouse[]) => {
|
||||
const auth = new google.auth.GoogleAuth({
|
||||
keyFile: "./service-account-file.json",
|
||||
scopes: ["https://www.googleapis.com/auth/spreadsheets"]
|
||||
});
|
||||
|
||||
const sheets = google.sheets({
|
||||
version: "v4",
|
||||
auth
|
||||
});
|
||||
|
||||
const spreadsheetsIds = process.env.SPREADSHEETS_IDS?.split(':')
|
||||
|
||||
warehouses.forEach( async (warehouse, index) => {
|
||||
|
||||
const headerValues = [
|
||||
['Склад', 'box delivery and storage expr', 'box delivery base', 'box delivery liter', 'box storage_base', 'box storage liter']
|
||||
];
|
||||
|
||||
spreadsheetsIds?.forEach(async spreadsheetId => {
|
||||
// sheets.spreadsheets.values.clear();
|
||||
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
// Print header.
|
||||
await sheets.spreadsheets.values.update({
|
||||
spreadsheetId,
|
||||
range: `${process.env.SPREADSHEETS_NAME}!${alphabet[0]}1:${alphabet[headerValues[0].length-1]}1`,
|
||||
valueInputOption: "RAW",
|
||||
resource: {
|
||||
values: headerValues
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const values = [
|
||||
[warehouse.name, warehouse.box_delivery_and_storage_expr, warehouse.box_delivery_base, warehouse.box_delivery_liter, warehouse.box_storage_base, warehouse.box_storage_liter]
|
||||
];
|
||||
|
||||
|
||||
const reponse = await sheets.spreadsheets.values.update({
|
||||
spreadsheetId,
|
||||
range: `${process.env.SPREADSHEETS_NAME}!${alphabet[index]}${index+2}:${alphabet[index+values[index].length]}${index+2}`,
|
||||
valueInputOption: "RAW",
|
||||
resource: {
|
||||
values
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function call DB initialization and sets timeout (whit it reads from .env file) for the request() function
|
||||
*/
|
||||
const start = async () => {
|
||||
await initDb();
|
||||
|
||||
const warehouses = await request();
|
||||
exportData(warehouses);
|
||||
|
||||
setInterval(async () => {
|
||||
const warehouses = await request();
|
||||
exportData(warehouses);
|
||||
}, Number.parseInt(process.env.TIME_BETWEEN_REQUESTS!) * 1000);
|
||||
}
|
||||
|
||||
await start();
|
|
@ -10,8 +10,9 @@
|
|||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"noEmit": true,
|
||||
"skipLibCheck": true
|
||||
"noEmit": false,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "./build"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "src/**/*.test.*", "src/**/*.spec.*"]
|
||||
|
|
Loading…
Reference in New Issue