From 74d95e7cbb56cfdf4e2d89b315a09ffa67e1c6db Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 27 Sep 2024 16:27:41 -0400 Subject: [PATCH 01/79] feature/IO-2962-Task-Email-Footer-Timestamps - Localize Date in Task Email Footer Signed-off-by: Dave Richer --- server/email/tasksEmails.js | 22 +++++++++++++++------- server/graphql-client/queries.js | 2 ++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/server/email/tasksEmails.js b/server/email/tasksEmails.js index 1f508be31..a3a2e0392 100644 --- a/server/email/tasksEmails.js +++ b/server/email/tasksEmails.js @@ -10,7 +10,7 @@ const logger = require("../utils/logger"); const client = require("../graphql-client/graphql-client").client; const queries = require("../graphql-client/queries"); const generateEmailTemplate = require("./generateTemplate"); -const moment = require("moment"); +const moment = require("moment-timezone"); const { taskEmailQueue } = require("./tasksEmailsQueue"); const ses = new aws.SES({ @@ -108,12 +108,13 @@ const getEndpoints = (bodyshop) => : "https://romeonline.io" }); -const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, job, taskId) => { +const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, job, taskId, dateLine) => { const endPoints = getEndpoints(bodyshop); return { header: title, subHeader: `Body Shop: ${bodyshop.shopname} | Priority: ${formatPriority(priority)} ${formatDate(dueDate)}`, - body: `Reference: ${job.ro_number || "N/A"} | ${job.ownr_co_nm ? job.ownr_co_nm : `${job.ownr_fn || ""} ${job.ownr_ln || ""}`.trim()} | ${`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${job.v_model_desc || ""}`.trim()}
${description ? description.concat("
") : ""}View this task.` + body: `Reference: ${job.ro_number || "N/A"} | ${job.ownr_co_nm ? job.ownr_co_nm : `${job.ownr_fn || ""} ${job.ownr_ln || ""}`.trim()} | ${`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${job.v_model_desc || ""}`.trim()}
${description ? description.concat("
") : ""}View this task.`, + dateLine }; }; @@ -178,6 +179,8 @@ const taskAssignedEmail = async (req, res) => { id: newTask.id }); + const dateLine = moment().tz(tasks_by_pk.bodyshop.timezone).format("M/DD/YYYY @ hh:mm a"); + sendMail( "assigned", tasks_by_pk.assigned_to_employee.user_email, @@ -190,7 +193,8 @@ const taskAssignedEmail = async (req, res) => { newTask.due_date, tasks_by_pk.bodyshop, tasks_by_pk.job, - newTask.id + newTask.id, + dateLine ) ), null, @@ -247,7 +251,7 @@ const tasksRemindEmail = async (req, res) => { const fromEmails = InstanceManager({ imex: "ImEX Online ", rome: - tasksRequest?.tasks[0].bodyshop.convenient_company === "promanager" + tasksRequest?.tasks[0].bodyshop.convenient_company === "promanager" ? "ProManager " : "Rome Online " }); @@ -259,6 +263,8 @@ const tasksRemindEmail = async (req, res) => { const taskIds = groupedTasks[recipient.email].map((task) => task.id); + const dateLine = moment().tz(tasksRequest?.tasks[0].bodyshop.timezone).format("M/DD/YYYY @ hh:mm a"); + // There is only the one email to send to this author. if (recipient.count === 1) { const onlyTask = groupedTasks[recipient.email][0]; @@ -274,7 +280,8 @@ const tasksRemindEmail = async (req, res) => { onlyTask.due_date, onlyTask.bodyshop, onlyTask.job, - onlyTask.id + onlyTask.id, + dateLine ) ); } @@ -283,7 +290,7 @@ const tasksRemindEmail = async (req, res) => { const endPoints = InstanceManager({ imex: process.env?.NODE_ENV === "test" ? "https://test.imex.online" : "https://imex.online", rome: - tasksRequest?.tasks[0].bodyshop.convenient_company === "promanager" + tasksRequest?.tasks[0].bodyshop.convenient_company === "promanager" ? process.env?.NODE_ENV === "test" ? "https//test.promanager.web-est.com" : "https://promanager.web-est.com" @@ -297,6 +304,7 @@ const tasksRemindEmail = async (req, res) => { emailData.html = generateEmailTemplate({ header: `${allTasks.length} Tasks require your attention`, subHeader: `Please click on the Tasks below to view the Task.`, + dateLine, body: `
    ${allTasks .map((task) => diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index ff643de8b..b1de44a34 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -2489,6 +2489,7 @@ exports.QUERY_REMIND_TASKS = ` bodyshop { shopname convenient_company + timezone } bodyshopid } @@ -2512,6 +2513,7 @@ query QUERY_TASK_BY_ID($id: uuid!) { bodyshop{ shopname convenient_company + timezone } job{ ro_number From a883b817b078cdac5d93b6c4eccc9fabf78b8c9b Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Tue, 1 Oct 2024 13:37:34 -0400 Subject: [PATCH 02/79] release/2024-10-04: Hotfix Signed-off-by: Dave Richer --- server/web-sockets/redisSocketEvents.js | 33 ++++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/server/web-sockets/redisSocketEvents.js b/server/web-sockets/redisSocketEvents.js index 5cda88569..9e35b00c0 100644 --- a/server/web-sockets/redisSocketEvents.js +++ b/server/web-sockets/redisSocketEvents.js @@ -33,12 +33,14 @@ const redisSocketEvents = (io, { addUserToRoom, getUsersInRoom, removeUserFromRo try { const room = getBodyshopRoom(bodyshopUUID); socket.join(room); - await addUserToRoom(room, { uid: socket.user.uid, email: socket.user.email, socket: socket.id }); + createLogEvent(socket, "DEBUG", `Client joined bodyshop room: ${room}`); + // TODO Removed room functionality for now + // await addUserToRoom(room, { uid: socket.user.uid, email: socket.user.email, socket: socket.id }); // Notify all users in the room about the updated user list - const usersInRoom = await getUsersInRoom(room); - io.to(room).emit("room-users-updated", usersInRoom); + // const usersInRoom = await getUsersInRoom(room); + // io.to(room).emit("room-users-updated", usersInRoom); } catch (error) { createLogEvent(socket, "ERROR", `Error joining room: ${error}`); } @@ -54,14 +56,14 @@ const redisSocketEvents = (io, { addUserToRoom, getUsersInRoom, removeUserFromRo } }); - socket.on("get-room-users", async (bodyshopUUID, callback) => { - try { - const usersInRoom = await getUsersInRoom(getBodyshopRoom(bodyshopUUID)); - callback(usersInRoom); - } catch (error) { - createLogEvent(socket, "ERROR", `Error getting room: ${error}`); - } - }); + // socket.on("get-room-users", async (bodyshopUUID, callback) => { + // try { + // const usersInRoom = await getUsersInRoom(getBodyshopRoom(bodyshopUUID)); + // callback(usersInRoom); + // } catch (error) { + // createLogEvent(socket, "ERROR", `Error getting room: ${error}`); + // } + // }); socket.on("broadcast-to-bodyshop", async (bodyshopUUID, message) => { try { @@ -77,11 +79,12 @@ const redisSocketEvents = (io, { addUserToRoom, getUsersInRoom, removeUserFromRo try { createLogEvent(socket, "DEBUG", `User disconnected.`); + // TODO Remove room functionality for now // Get all rooms the socket is part of - const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id); - for (const room of rooms) { - await removeUserFromRoom(room, { uid: socket.user.uid, email: socket.user.email, socket: socket.id }); - } + // const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id); + // for (const room of rooms) { + // await removeUserFromRoom(room, { uid: socket.user.uid, email: socket.user.email, socket: socket.id }); + // } } catch (error) { createLogEvent(socket, "ERROR", `Error getting room: ${error}`); } From 04dec6d91cf3510037d175c204f77042ce1cd9db Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 2 Oct 2024 00:27:11 -0400 Subject: [PATCH 03/79] docker-redis - local tests Signed-off-by: Dave Richer --- .dockerignore | 25 +++++++ Dockerfile | 39 ++++++++++ _reference/dockerreadme.md | 134 +++++++++++++++++++++++++++++++++++ docker-compose.yml | 69 ++++++++++++++++++ package-lock.json | 79 +++++++++++++++++++++ package.json | 1 + redis/.gitignore | 2 + redis/Dockerfile | 20 ++++++ redis/dockerdata/.gitignore | 3 + redis/dockerdata/.gitkeep | 0 redis/entrypoint.sh | 30 ++++++++ redis/redis.conf | 6 ++ server.js | 48 ++++++++++--- server/utils/redisHelpers.js | 18 ++--- 14 files changed, 456 insertions(+), 18 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 _reference/dockerreadme.md create mode 100644 docker-compose.yml create mode 100644 redis/.gitignore create mode 100644 redis/Dockerfile create mode 100644 redis/dockerdata/.gitignore create mode 100644 redis/dockerdata/.gitkeep create mode 100644 redis/entrypoint.sh create mode 100644 redis/redis.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..da9a0d123 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +# Directories to exclude +.circleci +.idea +.platform +.vscode +_reference +client +redis/dockerdata +hasura +node_modules + +# Files to exclude +.ebignore +.editorconfig +.eslintrc.json +.gitignore +.prettierrc.js +Dockerfile +README.MD +bodyshop_translations.babel +docker-compose.yml +ecosystem.config.js + +# Optional: Exclude logs and temporary files +*.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..810e8b3b2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,39 @@ +# Use Amazon Linux 2023 as the base image +FROM amazonlinux:2023 + +# Install Git and Node.js (Amazon Linux 2023 uses the DNF package manager) +RUN dnf install -y git \ + && curl -sL https://rpm.nodesource.com/setup_20.x | bash - \ + && dnf install -y nodejs \ + && dnf clean all + + +# Install dependencies required by node-canvas +RUN dnf install -y \ + gcc \ + gcc-c++ \ + cairo-devel \ + pango-devel \ + libjpeg-turbo-devel \ + giflib-devel \ + libpng-devel \ + make \ + && dnf clean all + +# Set the working directory +WORKDIR /app + +# Copy package.json and package-lock.json +COPY package*.json ./ + +# Install dependencies +RUN npm install --omit=dev + +# Copy the rest of your application code +COPY . . + +# Expose the port your app runs on (adjust if necessary) +EXPOSE 4000 + +# Start the application +CMD ["node", "server.js"] diff --git a/_reference/dockerreadme.md b/_reference/dockerreadme.md new file mode 100644 index 000000000..73d1ac346 --- /dev/null +++ b/_reference/dockerreadme.md @@ -0,0 +1,134 @@ +# Setting up External Networking and Static IP for WSL2 using Hyper-V + +This guide will walk you through the steps to configure your WSL2 (Windows Subsystem for Linux) instance to use an external Hyper-V virtual switch, enabling it to connect directly to your local network. Additionally, you'll learn how to assign a static IP address to your WSL2 instance. + +## Prerequisites + +1. **Windows 10/11** with **WSL2** installed. +2. **Hyper-V** enabled on your system. If not, follow these steps to enable it: + - Open PowerShell as Administrator and run: + ```powershell + dism.exe /Online /Enable-Feature /All /FeatureName:Microsoft-Hyper-V + ``` + - Restart your computer. + +3. A basic understanding of networking and WSL2 configuration. + +--- + +## Step 1: Create an External Hyper-V Switch + +1. **Open Hyper-V Manager**: + - Press `Windows Key + X`, select `Hyper-V Manager`. + +2. **Create a Virtual Switch**: + - In the right-hand pane, click `Virtual Switch Manager`. + - Choose `External` and click `Create Virtual Switch`. + - Select your external network adapter (this is usually your Ethernet or Wi-Fi adapter). + - Give the switch a name (e.g., `WSL External Switch`), then click `Apply` and `OK`. + +--- + +## Step 2: Configure WSL2 to Use the External Hyper-V Switch + +Now that you've created the external virtual switch, follow these steps to configure your WSL2 instance to use this switch. + +1. **Set WSL2 to Use the External Switch**: + - By default, WSL2 uses NAT to connect to your local network. You need to configure WSL2 to use the external Hyper-V switch instead. + +2. **Check WSL2 Networking**: + - Inside WSL, run: + ```bash + ip a + ``` + - You should see an IP address in the range of your local network (e.g., `192.168.x.x`). + +--- + +## Step 3: Configure a Static IP Address for WSL2 + +Once WSL2 is connected to the external network, you can assign a static IP address to your WSL2 instance. + +1. **Open WSL2** and Edit the Network Configuration: + - Depending on your Linux distribution, the file paths may vary, but typically for Ubuntu-based systems: + ```bash + sudo nano /etc/netplan/01-netcfg.yaml + ``` + - If this file doesn’t exist, create a new file or use the correct configuration file path. + +2. **Configure Static IP**: + - Add or update the following configuration: + ```yaml + network: + version: 2 + renderer: networkd + ethernets: + eth0: + dhcp4: no + addresses: + - 192.168.1.100/24 # Choose an IP address in your network range + gateway4: 192.168.1.1 # Your router's IP address + nameservers: + addresses: + - 8.8.8.8 + - 8.8.4.4 + ``` + - Adjust the values according to your local network settings: + - `addresses`: This is the static IP you want to assign. + - `gateway4`: This should be the IP address of your router. + - `nameservers`: These are DNS servers, you can use Google's public DNS or any other DNS provider. + +3. **Apply the Changes**: + - Run the following command to apply the network configuration: + ```bash + sudo netplan apply + ``` + +4. **Verify the Static IP**: + - Check if the static IP is correctly set by running: + ```bash + ip a + ``` + - You should see the static IP you configured (e.g., `192.168.1.100`) on the appropriate network interface (usually `eth0`). + +--- + +## Step 4: Restart WSL2 to Apply Changes + +To ensure the changes are fully applied, restart WSL2: + +1. Open PowerShell or Command Prompt and run: + ```powershell + wsl --shutdown +2. Then, start your WSL2 instance again. + +## Step 5: Verify Connectivity + +1. Check Internet and Local Network Connectivity: + - Run a ping command from within WSL to verify that it can reach the internet: ```ping 8.8.8.8``` +2. Test Access from other Devices: + - If you're running services inside WSL (e.g., a web server), ensure they are accessible from other devices on your local network using the static IP address you configured (e.g., `http://192.168.1.100:4000`). + +## Step 6: Configuring `vm.overcommit_memory` in sysctl for WSL2 + +To prevent memory overcommitment issues and optimize performance, you can configure the `vm.overcommit_memory` setting in WSL2. This is particularly useful when running Redis or other memory-intensive services inside WSL2, as it helps control how the Linux kernel handles memory allocation. + +### 1. **Open the sysctl Configuration File**: +To set the `vm.overcommit_memory` value, you'll need to edit the sysctl configuration file. Inside your WSL2 instance, run the following command to open the `sysctl.conf` file for editing: +```bash + sudo nano /etc/sysctl.conf +``` +### 2. Add the Overcommit Memory Setting: +Add the following line at the end of the file to allow memory overcommitment: +```bash +vm.overcommit_memory = 1 +``` + +This setting tells the Linux kernel to always allow memory allocation, regardless of how much memory is available, which can prevent out-of-memory errors when running certain applications. + +### 3. Apply the Changes: +After editing the file, save it and then apply the new sysctl configuration by running: + +```bash +sudo sysctl -p +``` diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..96febae61 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,69 @@ +version: '3.9' + +services: + redis-node-1: + build: + context: ./redis + container_name: redis-node-1 + hostname: redis-node-1 + networks: + - redis-cluster-net + volumes: + - ./redis/dockerdata/redis-node-1:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 5 + + redis-node-2: + build: + context: ./redis + container_name: redis-node-2 + hostname: redis-node-2 + networks: + - redis-cluster-net + volumes: + - ./redis/dockerdata/redis-node-2:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 5 + + redis-node-3: + build: + context: ./redis + container_name: redis-node-3 + hostname: redis-node-3 + networks: + - redis-cluster-net + volumes: + - ./redis/dockerdata/redis-node-3:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 5 + + node-app: + build: + context: . + container_name: node-app + networks: + - redis-cluster-net + env_file: + - .env.development + depends_on: + redis-node-1: + condition: service_healthy + redis-node-2: + condition: service_healthy + redis-node-3: + condition: service_healthy + ports: + - "4000:4000" + +networks: + redis-cluster-net: + driver: bridge diff --git a/package-lock.json b/package-lock.json index be917a0e0..d5a87fdaa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,7 @@ "graylog2": "^0.2.1", "inline-css": "^4.0.2", "intuit-oauth": "^4.1.2", + "ioredis": "^5.4.1", "json-2-csv": "^5.5.5", "lodash": "^4.17.21", "moment": "^2.30.1", @@ -1397,6 +1398,12 @@ "node": ">=6" } }, + "node_modules/@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==", + "license": "MIT" + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -3701,6 +3708,15 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -5008,6 +5024,30 @@ "node": ">=10" } }, + "node_modules/ioredis": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.4.1.tgz", + "integrity": "sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==", + "license": "MIT", + "dependencies": { + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, "node_modules/ip": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", @@ -5357,11 +5397,23 @@ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", + "license": "MIT" + }, "node_modules/lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", @@ -6284,6 +6336,27 @@ "@redis/time-series": "1.1.0" } }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "license": "MIT", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", @@ -6934,6 +7007,12 @@ "node": "*" } }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", diff --git a/package.json b/package.json index ef95ef36d..ecda708b6 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "graylog2": "^0.2.1", "inline-css": "^4.0.2", "intuit-oauth": "^4.1.2", + "ioredis": "^5.4.1", "json-2-csv": "^5.5.5", "lodash": "^4.17.21", "moment": "^2.30.1", diff --git a/redis/.gitignore b/redis/.gitignore new file mode 100644 index 000000000..d3461533b --- /dev/null +++ b/redis/.gitignore @@ -0,0 +1,2 @@ +redis-cluster-init.lock +dockerdata/ diff --git a/redis/Dockerfile b/redis/Dockerfile new file mode 100644 index 000000000..b68d8fb2b --- /dev/null +++ b/redis/Dockerfile @@ -0,0 +1,20 @@ +# Use the official Redis image +FROM redis:7.0-alpine + +# Copy the Redis configuration file +COPY redis.conf /usr/local/etc/redis/redis.conf + +# Copy the entrypoint script +COPY entrypoint.sh /usr/local/bin/entrypoint.sh + +# Make the entrypoint script executable +RUN chmod +x /usr/local/bin/entrypoint.sh + +# Debugging step: List contents of /usr/local/bin +RUN ls -l /usr/local/bin + +# Expose Redis ports +EXPOSE 6379 16379 + +# Set the entrypoint +ENTRYPOINT ["entrypoint.sh"] diff --git a/redis/dockerdata/.gitignore b/redis/dockerdata/.gitignore new file mode 100644 index 000000000..2dfe1c02b --- /dev/null +++ b/redis/dockerdata/.gitignore @@ -0,0 +1,3 @@ +.gitkeep +!.gitignore +!.gitkeep diff --git a/redis/dockerdata/.gitkeep b/redis/dockerdata/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/redis/entrypoint.sh b/redis/entrypoint.sh new file mode 100644 index 000000000..95228af31 --- /dev/null +++ b/redis/entrypoint.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +LOCK_FILE="redis-cluster-init.lock" + +# Start Redis server in the background +redis-server /usr/local/etc/redis/redis.conf & + +# Wait for Redis server to start +sleep 5 + +# Initialize the cluster only if the lock file does not exist +if [ ! -f "$LOCK_FILE" ]; then + echo "Initializing Redis Cluster..." + + # Run the Redis cluster initialization + yes yes | redis-cli --cluster create \ + redis-node-1:6379 \ + redis-node-2:6379 \ + redis-node-3:6379 \ + --cluster-replicas 0 + + # Create the lock file after initialization + touch "$LOCK_FILE" + echo "Cluster initialization complete. Lock file created." +else + echo "Cluster has already been initialized. Skipping initialization." +fi + +# Keep the container running +tail -f /dev/null diff --git a/redis/redis.conf b/redis/redis.conf new file mode 100644 index 000000000..22533e22d --- /dev/null +++ b/redis/redis.conf @@ -0,0 +1,6 @@ +bind 0.0.0.0 +port 6379 +cluster-enabled yes +cluster-config-file nodes.conf +cluster-node-timeout 5000 +appendonly yes diff --git a/server.js b/server.js index 0ccfd9ed3..8800f6632 100644 --- a/server.js +++ b/server.js @@ -6,7 +6,8 @@ const compression = require("compression"); const cookieParser = require("cookie-parser"); const http = require("http"); const { Server } = require("socket.io"); -const { createClient } = require("redis"); +// const { createClient } = require("redis"); +const Redis = require("ioredis"); const { createAdapter } = require("@socket.io/redis-adapter"); const logger = require("./server/utils/logger"); const { redisSocketEvents } = require("./server/web-sockets/redisSocketEvents"); @@ -108,19 +109,48 @@ const applyRoutes = (app) => { * @param app */ const applySocketIO = async (server, app) => { - // Redis client setup for Pub/Sub and Key-Value Store - const pubClient = createClient({ url: process.env.REDIS_URL || "redis://localhost:6379" }); + const redisCluster = new Redis.Cluster( + process.env.REDIS_URL + ? JSON.parse(process.env.REDIS_URL) + : [ + { + host: "redis://localhost:6379" + } + ], + { + clusterRetryStrategy: function (times) { + const delay = Math.min(100 + times * 50, 2000); + logger.log( + `[${process.env.NODE_ENV}] Redis cluster not yet ready. Retrying in ${delay}ms`, + "ERROR", + "redis", + "api" + ); + return delay; + } + } + ); + + // Handle errors + redisCluster.on("error", (err) => { + logger.log(`[${process.env.NODE_ENV}] Redis ERROR`, "ERROR", "redis", "api"); + }); + + const pubClient = redisCluster; const subClient = pubClient.duplicate(); + // https://github.com/redis/node-redis/blob/master/docs/clustering.md + // https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/accessing-elasticache.html + pubClient.on("error", (err) => logger.log(`Redis pubClient error: ${err}`, "ERROR", "redis")); subClient.on("error", (err) => logger.log(`Redis subClient error: ${err}`, "ERROR", "redis")); - try { - await Promise.all([pubClient.connect(), subClient.connect()]); - logger.log(`[${process.env.NODE_ENV}] Connected to Redis`, "INFO", "redis", "api"); - } catch (redisError) { - logger.log("Failed to connect to Redis", "ERROR", "redis", redisError); - } + // try { + // // await Promise.all([pubClient.connect(), subClient.connect()]); + // // logger.log(`[${process.env.NODE_ENV}] Connected to Redis`, "INFO", "redis", "api"); + // // } catch (redisError) { + // // logger.log("Failed to connect to Redis", "ERROR", "redis", redisError); + // // } process.on("SIGINT", async () => { logger.log("Closing Redis connections...", "INFO", "redis", "api"); diff --git a/server/utils/redisHelpers.js b/server/utils/redisHelpers.js index 99801000b..c96e7454f 100644 --- a/server/utils/redisHelpers.js +++ b/server/utils/redisHelpers.js @@ -8,7 +8,7 @@ const applyRedisHelpers = (pubClient, app, logger) => { // Store session data in Redis const setSessionData = async (socketId, key, value) => { try { - await pubClient.hSet(`socket:${socketId}`, key, JSON.stringify(value)); // Use Redis pubClient + await pubClient.hset(`socket:${socketId}`, key, JSON.stringify(value)); // Use Redis pubClient } catch (error) { logger.log(`Error Setting Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); } @@ -17,7 +17,7 @@ const applyRedisHelpers = (pubClient, app, logger) => { // Retrieve session data from Redis const getSessionData = async (socketId, key) => { try { - const data = await pubClient.hGet(`socket:${socketId}`, key); + const data = await pubClient.hget(`socket:${socketId}`, key); return data ? JSON.parse(data) : null; } catch (error) { logger.log(`Error Getting Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); @@ -38,7 +38,7 @@ const applyRedisHelpers = (pubClient, app, logger) => { try { // keyValues is expected to be an object { key1: value1, key2: value2, ... } const entries = Object.entries(keyValues).map(([key, value]) => [key, JSON.stringify(value)]); - await pubClient.hSet(`socket:${socketId}`, ...entries.flat()); + await pubClient.hset(`socket:${socketId}`, ...entries.flat()); } catch (error) { logger.log(`Error Setting Multiple Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); } @@ -47,7 +47,7 @@ const applyRedisHelpers = (pubClient, app, logger) => { // Retrieve multiple session data from Redis const getMultipleSessionData = async (socketId, keys) => { try { - const data = await pubClient.hmGet(`socket:${socketId}`, keys); + const data = await pubClient.hmget(`socket:${socketId}`, keys); // Redis returns an object with null values for missing keys, so we parse the non-null ones return Object.fromEntries(keys.map((key, index) => [key, data[index] ? JSON.parse(data[index]) : null])); } catch (error) { @@ -71,7 +71,7 @@ const applyRedisHelpers = (pubClient, app, logger) => { // Helper function to add an item to the end of the Redis list const addItemToEndOfList = async (socketId, key, newItem) => { try { - await pubClient.rPush(`socket:${socketId}:${key}`, JSON.stringify(newItem)); + await pubClient.rpush(`socket:${socketId}:${key}`, JSON.stringify(newItem)); } catch (error) { logger.log(`Error adding item to the end of the list for socket ${socketId}: ${error}`, "ERROR", "redis"); } @@ -80,7 +80,7 @@ const applyRedisHelpers = (pubClient, app, logger) => { // Helper function to add an item to the beginning of the Redis list const addItemToBeginningOfList = async (socketId, key, newItem) => { try { - await pubClient.lPush(`socket:${socketId}:${key}`, JSON.stringify(newItem)); + await pubClient.lpush(`socket:${socketId}:${key}`, JSON.stringify(newItem)); } catch (error) { logger.log(`Error adding item to the beginning of the list for socket ${socketId}: ${error}`, "ERROR", "redis"); } @@ -98,7 +98,7 @@ const applyRedisHelpers = (pubClient, app, logger) => { // Add methods to manage room users const addUserToRoom = async (room, user) => { try { - await pubClient.sAdd(room, JSON.stringify(user)); + await pubClient.sadd(room, JSON.stringify(user)); } catch (error) { logger.log(`Error adding user to room ${room}: ${error}`, "ERROR", "redis"); } @@ -106,7 +106,7 @@ const applyRedisHelpers = (pubClient, app, logger) => { const removeUserFromRoom = async (room, user) => { try { - await pubClient.sRem(room, JSON.stringify(user)); + await pubClient.srem(room, JSON.stringify(user)); } catch (error) { logger.log(`Error removing user to room ${room}: ${error}`, "ERROR", "redis"); } @@ -114,7 +114,7 @@ const applyRedisHelpers = (pubClient, app, logger) => { const getUsersInRoom = async (room) => { try { - const users = await pubClient.sMembers(room); + const users = await pubClient.smembers(room); return users.map((user) => JSON.parse(user)); } catch (error) { logger.log(`Error getting users in room ${room}: ${error}`, "ERROR", "redis"); From ddb0990645a7f8435cc207286be91dcf3016868e Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 2 Oct 2024 00:50:40 -0400 Subject: [PATCH 04/79] docker-redis - local tests Signed-off-by: Dave Richer --- Dockerfile | 5 ++++- _reference/dockerreadme.md | 1 + docker-compose.yml | 4 +++- redis/entrypoint.sh | 14 ++------------ 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Dockerfile b/Dockerfile index 810e8b3b2..1f3b8db99 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,6 +26,9 @@ WORKDIR /app # Copy package.json and package-lock.json COPY package*.json ./ +# Install Nodemon +RUN npm install -g nodemon + # Install dependencies RUN npm install --omit=dev @@ -36,4 +39,4 @@ COPY . . EXPOSE 4000 # Start the application -CMD ["node", "server.js"] +CMD ["nodemon", "--legacy-watch", "server.js"] diff --git a/_reference/dockerreadme.md b/_reference/dockerreadme.md index 73d1ac346..a7f8e2aef 100644 --- a/_reference/dockerreadme.md +++ b/_reference/dockerreadme.md @@ -132,3 +132,4 @@ After editing the file, save it and then apply the new sysctl configuration by r ```bash sudo sysctl -p ``` + diff --git a/docker-compose.yml b/docker-compose.yml index 96febae61..4bcad6f73 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -63,7 +63,9 @@ services: condition: service_healthy ports: - "4000:4000" - + volumes: + - .:/app + - /app/node_modules # Prevents overwriting node_modules networks: redis-cluster-net: driver: bridge diff --git a/redis/entrypoint.sh b/redis/entrypoint.sh index 95228af31..a3d93feda 100644 --- a/redis/entrypoint.sh +++ b/redis/entrypoint.sh @@ -1,29 +1,19 @@ #!/bin/sh -LOCK_FILE="redis-cluster-init.lock" - # Start Redis server in the background redis-server /usr/local/etc/redis/redis.conf & # Wait for Redis server to start sleep 5 -# Initialize the cluster only if the lock file does not exist -if [ ! -f "$LOCK_FILE" ]; then +# Only initialize the cluster from one node to prevent race conditions +if [ "$HOSTNAME" = "redis-node-1" ]; then echo "Initializing Redis Cluster..." - - # Run the Redis cluster initialization yes yes | redis-cli --cluster create \ redis-node-1:6379 \ redis-node-2:6379 \ redis-node-3:6379 \ --cluster-replicas 0 - - # Create the lock file after initialization - touch "$LOCK_FILE" - echo "Cluster initialization complete. Lock file created." -else - echo "Cluster has already been initialized. Skipping initialization." fi # Keep the container running From 05e554546634e732a69d1e096041733e9dd44002 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 2 Oct 2024 01:04:05 -0400 Subject: [PATCH 05/79] docker-redis - local tests Signed-off-by: Dave Richer --- docker-compose.yml | 9 +++++++++ server.js | 41 ++++++++++++++++++++++++++--------------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4bcad6f73..7b867c0e3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -66,6 +66,15 @@ services: volumes: - .:/app - /app/node_modules # Prevents overwriting node_modules + + socketio-admin-ui: + image: maitrungduc1410/socket.io-admin-ui + container_name: socketio-admin-ui + networks: + - redis-cluster-net + ports: + - "3333:80" + networks: redis-cluster-net: driver: bridge diff --git a/server.js b/server.js index 8800f6632..e0bdd0a2e 100644 --- a/server.js +++ b/server.js @@ -11,7 +11,7 @@ const Redis = require("ioredis"); const { createAdapter } = require("@socket.io/redis-adapter"); const logger = require("./server/utils/logger"); const { redisSocketEvents } = require("./server/web-sockets/redisSocketEvents"); -const { instrument } = require("@socket.io/admin-ui"); +const { instrument, RedisStore } = require("@socket.io/admin-ui"); const { isString, isEmpty } = require("lodash"); const applyRedisHelpers = require("./server/utils/redisHelpers"); @@ -103,18 +103,14 @@ const applyRoutes = (app) => { }); }; -/** - * Apply Redis to the server - * @param server - * @param app - */ -const applySocketIO = async (server, app) => { +const connectToRedisCluster = () => { const redisCluster = new Redis.Cluster( process.env.REDIS_URL ? JSON.parse(process.env.REDIS_URL) : [ { - host: "redis://localhost:6379" + host: "localhost", + port: 6379 } ], { @@ -131,6 +127,27 @@ const applySocketIO = async (server, app) => { } ); + return new Promise((resolve, reject) => { + redisCluster.on("ready", () => { + logger.log(`[${process.env.NODE_ENV}] Redis cluster connection established.`, "INFO", "redis", "api"); + resolve(redisCluster); + }); + + redisCluster.on("error", (err) => { + logger.log(`[${process.env.NODE_ENV}] Redis cluster connection failed: ${err.message}`, "ERROR", "redis", "api"); + reject(err); + }); + }); +}; + +/** + * Apply Redis to the server + * @param server + * @param app + */ +const applySocketIO = async (server, app) => { + const redisCluster = await connectToRedisCluster(); + // Handle errors redisCluster.on("error", (err) => { logger.log(`[${process.env.NODE_ENV}] Redis ERROR`, "ERROR", "redis", "api"); @@ -145,13 +162,6 @@ const applySocketIO = async (server, app) => { pubClient.on("error", (err) => logger.log(`Redis pubClient error: ${err}`, "ERROR", "redis")); subClient.on("error", (err) => logger.log(`Redis subClient error: ${err}`, "ERROR", "redis")); - // try { - // // await Promise.all([pubClient.connect(), subClient.connect()]); - // // logger.log(`[${process.env.NODE_ENV}] Connected to Redis`, "INFO", "redis", "api"); - // // } catch (redisError) { - // // logger.log("Failed to connect to Redis", "ERROR", "redis", redisError); - // // } - process.on("SIGINT", async () => { logger.log("Closing Redis connections...", "INFO", "redis", "api"); await Promise.all([pubClient.disconnect(), subClient.disconnect()]); @@ -161,6 +171,7 @@ const applySocketIO = async (server, app) => { const ioRedis = new Server(server, { path: "/wss", adapter: createAdapter(pubClient, subClient), + store: new RedisStore(pubClient, subClient), cors: { origin: SOCKETIO_CORS_ORIGIN, methods: ["GET", "POST"], From 7e7e109cfe36c9b9b6d41e475e8d0e30b4a99ea7 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 3 Oct 2024 11:59:42 -0400 Subject: [PATCH 06/79] docker-redis - local refactors Signed-off-by: Dave Richer --- server.js | 116 ++++++++++++++++++++++------------- server/utils/redisHelpers.js | 91 ++++++++++++++++----------- 2 files changed, 128 insertions(+), 79 deletions(-) diff --git a/server.js b/server.js index e0bdd0a2e..10182fe18 100644 --- a/server.js +++ b/server.js @@ -1,27 +1,30 @@ -const express = require("express"); const cors = require("cors"); -const bodyParser = require("body-parser"); const path = require("path"); +const http = require("http"); +const Redis = require("ioredis"); +const express = require("express"); +const bodyParser = require("body-parser"); const compression = require("compression"); const cookieParser = require("cookie-parser"); -const http = require("http"); const { Server } = require("socket.io"); -// const { createClient } = require("redis"); -const Redis = require("ioredis"); const { createAdapter } = require("@socket.io/redis-adapter"); -const logger = require("./server/utils/logger"); -const { redisSocketEvents } = require("./server/web-sockets/redisSocketEvents"); -const { instrument, RedisStore } = require("@socket.io/admin-ui"); - +const { instrument } = require("@socket.io/admin-ui"); const { isString, isEmpty } = require("lodash"); + +const logger = require("./server/utils/logger"); const applyRedisHelpers = require("./server/utils/redisHelpers"); const applyIOHelpers = require("./server/utils/ioHelpers"); +const { redisSocketEvents } = require("./server/web-sockets/redisSocketEvents"); // Load environment variables require("dotenv").config({ path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) }); +const CLUSTER_RETRY_BASE_DELAY = 100; +const CLUSTER_RETRY_MAX_DELAY = 5000; +const CLUSTER_RETRY_JITTER = 100; + /** * CORS Origin for Socket.IO * @type {string[][]} @@ -50,11 +53,11 @@ const SOCKETIO_CORS_ORIGIN = [ "https://old.imex.online", "https://www.old.imex.online", "https://wsadmin.imex.online", - "https://www.wsadmin.imex.online", - "http://localhost:3333", - "https://localhost:3333" + "https://www.wsadmin.imex.online" ]; +const SOCKETIO_CORS_ORIGIN_DEV = ["http://localhost:3333", "https://localhost:3333"]; + /** * Middleware for Express app * @param app @@ -103,29 +106,52 @@ const applyRoutes = (app) => { }); }; +/** + * Connect to Redis Cluster + * @returns {Promise} + */ const connectToRedisCluster = () => { - const redisCluster = new Redis.Cluster( - process.env.REDIS_URL - ? JSON.parse(process.env.REDIS_URL) - : [ - { - host: "localhost", - port: 6379 - } - ], - { - clusterRetryStrategy: function (times) { - const delay = Math.min(100 + times * 50, 2000); - logger.log( - `[${process.env.NODE_ENV}] Redis cluster not yet ready. Retrying in ${delay}ms`, - "ERROR", - "redis", - "api" - ); - return delay; - } + if (isEmpty(process.env?.REDIS_URL) || !isString(process.env?.REDIS_URL)) { + logger.log(`[${process.env.NODE_ENV}] No or Malformed REDIS_URL present.`, "ERROR", "redis", "api"); + process.exit(1); + } + + let redisServers; + + try { + redisServers = JSON.parse(process.env.REDIS_URL); + } catch (error) { + logger.log( + `[${process.env.NODE_ENV}] Failed to parse REDIS_URL: ${error.message}. Exiting...`, + "ERROR", + "redis", + "api" + ); + process.exit(1); + } + + const clusterRetryStrategy = (times) => { + const delay = + Math.min(CLUSTER_RETRY_BASE_DELAY + times * 50, CLUSTER_RETRY_MAX_DELAY) + Math.random() * CLUSTER_RETRY_JITTER; + logger.log( + `[${process.env.NODE_ENV}] Redis cluster not yet ready. Retrying in ${delay.toFixed(2)}ms`, + "ERROR", + "redis", + "api" + ); + return delay; + }; + + const redisCluster = new Redis.Cluster(redisServers, { + clusterRetryStrategy, + enableAutoPipelining: true, + enableReadyCheck: true, + redisOptions: { + // connectTimeout: 10000, // Timeout for connecting in ms + // idleTimeoutMillis: 30000, // Close idle connections after 30s + // maxRetriesPerRequest: 5 // Retry a maximum of 5 times per request } - ); + }); return new Promise((resolve, reject) => { redisCluster.on("ready", () => { @@ -171,9 +197,11 @@ const applySocketIO = async (server, app) => { const ioRedis = new Server(server, { path: "/wss", adapter: createAdapter(pubClient, subClient), - store: new RedisStore(pubClient, subClient), cors: { - origin: SOCKETIO_CORS_ORIGIN, + origin: + process.env?.NODE_ENV === "development" + ? [...SOCKETIO_CORS_ORIGIN, ...SOCKETIO_CORS_ORIGIN_DEV] + : SOCKETIO_CORS_ORIGIN, methods: ["GET", "POST"], credentials: true, exposedHeaders: ["set-cookie"] @@ -188,6 +216,7 @@ const applySocketIO = async (server, app) => { username: "admin", password: process.env.REDIS_ADMIN_PASS }, + mode: process.env.REDIS_ADMIN_MODE || "development" }); } @@ -202,19 +231,22 @@ const applySocketIO = async (server, app) => { } }); + const api = { + pubClient, + io, + ioRedis, + redisCluster + }; + app.use((req, res, next) => { - Object.assign(req, { - pubClient, - io, - ioRedis - }); + Object.assign(req, api); next(); }); - Object.assign(module.exports, { io, pubClient, ioRedis }); + Object.assign(module.exports, api); - return { pubClient, io, ioRedis }; + return api; }; /** diff --git a/server/utils/redisHelpers.js b/server/utils/redisHelpers.js index c96e7454f..3ab824be4 100644 --- a/server/utils/redisHelpers.js +++ b/server/utils/redisHelpers.js @@ -1,8 +1,8 @@ -const logger = require("./logger"); /** * Apply Redis helper functions * @param pubClient * @param app + * @param logger */ const applyRedisHelpers = (pubClient, app, logger) => { // Store session data in Redis @@ -60,7 +60,7 @@ const applyRedisHelpers = (pubClient, app, logger) => { // Use Redis multi/pipeline to batch the commands const multi = pubClient.multi(); keyValueArray.forEach(([key, value]) => { - multi.hSet(`socket:${socketId}`, key, JSON.stringify(value)); + multi.hset(`socket:${socketId}`, key, JSON.stringify(value)); }); await multi.exec(); // Execute all queued commands } catch (error) { @@ -143,70 +143,87 @@ const applyRedisHelpers = (pubClient, app, logger) => { next(); }); - // // Demo to show how all the helper functions work + // Demo to show how all the helper functions work // const demoSessionData = async () => { // const socketId = "testSocketId"; // - // // Store session data using setSessionData - // await exports.setSessionData(socketId, "field1", "Hello, Redis!"); - // - // // Retrieve session data using getSessionData - // const field1Value = await exports.getSessionData(socketId, "field1"); + // // 1. Test setSessionData and getSessionData + // await setSessionData(socketId, "field1", "Hello, Redis!"); + // const field1Value = await getSessionData(socketId, "field1"); // console.log("Retrieved single field value:", field1Value); // - // // Store multiple session data using setMultipleSessionData - // await exports.setMultipleSessionData(socketId, { field2: "Second Value", field3: "Third Value" }); - // - // // Retrieve multiple session data using getMultipleSessionData - // const multipleFields = await exports.getMultipleSessionData(socketId, ["field2", "field3"]); + // // 2. Test setMultipleSessionData and getMultipleSessionData + // await setMultipleSessionData(socketId, { field2: "Second Value", field3: "Third Value" }); + // const multipleFields = await getMultipleSessionData(socketId, ["field2", "field3"]); // console.log("Retrieved multiple field values:", multipleFields); // - // // Store multiple session data using setMultipleFromArraySessionData - // await exports.setMultipleFromArraySessionData(socketId, [ + // // 3. Test setMultipleFromArraySessionData + // await setMultipleFromArraySessionData(socketId, [ // ["field4", "Fourth Value"], // ["field5", "Fifth Value"] // ]); // // // Retrieve and log all fields - // const allFields = await exports.getMultipleSessionData(socketId, [ - // "field1", - // "field2", - // "field3", - // "field4", - // "field5" - // ]); + // const allFields = await getMultipleSessionData(socketId, ["field1", "field2", "field3", "field4", "field5"]); // console.log("Retrieved all field values:", allFields); // + // // 4. Test list functions // // Add item to the end of a Redis list - // await exports.addItemToEndOfList(socketId, "logEvents", { event: "Log Event 1", timestamp: new Date() }); - // await exports.addItemToEndOfList(socketId, "logEvents", { event: "Log Event 2", timestamp: new Date() }); + // await addItemToEndOfList(socketId, "logEvents", { event: "Log Event 1", timestamp: new Date() }); + // await addItemToEndOfList(socketId, "logEvents", { event: "Log Event 2", timestamp: new Date() }); // // // Add item to the beginning of a Redis list - // await exports.addItemToBeginningOfList(socketId, "logEvents", { event: "First Log Event", timestamp: new Date() }); + // await addItemToBeginningOfList(socketId, "logEvents", { event: "First Log Event", timestamp: new Date() }); // - // // Retrieve the entire list (using lRange) - // const logEvents = await pubClient.lRange(`socket:${socketId}:logEvents`, 0, -1); - // console.log("Log Events List:", logEvents.map(JSON.parse)); + // // Retrieve the entire list + // const logEventsData = await pubClient.lrange(`socket:${socketId}:logEvents`, 0, -1); + // const logEvents = logEventsData.map((item) => JSON.parse(item)); + // console.log("Log Events List:", logEvents); // - // // **Add the new code below to test clearList** - // - // // Clear the list using clearList - // await exports.clearList(socketId, "logEvents"); + // // 5. Test clearList + // await clearList(socketId, "logEvents"); // console.log("Log Events List cleared."); // // // Retrieve the list after clearing to confirm it's empty - // const logEventsAfterClear = await pubClient.lRange(`socket:${socketId}:logEvents`, 0, -1); + // const logEventsAfterClear = await pubClient.lrange(`socket:${socketId}:logEvents`, 0, -1); // console.log("Log Events List after clearing:", logEventsAfterClear); // Should be an empty array // - // // Clear session data - // await exports.clearSessionData(socketId); + // // 6. Test clearSessionData + // await clearSessionData(socketId); // console.log("Session data cleared."); - // }; // + // // 7. Test room functions + // const roomName = "testRoom"; + // const user1 = { id: 1, name: "Alice" }; + // const user2 = { id: 2, name: "Bob" }; + // + // // Add users to room + // await addUserToRoom(roomName, user1); + // await addUserToRoom(roomName, user2); + // + // // Get users in room + // const usersInRoom = await getUsersInRoom(roomName); + // console.log(`Users in room ${roomName}:`, usersInRoom); + // + // // Remove a user from room + // await removeUserFromRoom(roomName, user1); + // + // // Get users in room after removal + // const usersInRoomAfterRemoval = await getUsersInRoom(roomName); + // console.log(`Users in room ${roomName} after removal:`, usersInRoomAfterRemoval); + // + // // Clean up: remove remaining users from room + // await removeUserFromRoom(roomName, user2); + // + // // Verify room is empty + // const usersInRoomAfterCleanup = await getUsersInRoom(roomName); + // console.log(`Users in room ${roomName} after cleanup:`, usersInRoomAfterCleanup); // Should be empty + // }; // if (process.env.NODE_ENV === "development") { // demoSessionData(); // } - // "th1s1sr3d1s" (BCrypt) + return api; }; module.exports = applyRedisHelpers; +// "th1s1sr3d1s" (BCrypt) From 8f312bfffba9ee1d90cb10be38b3a5b7f2e6c820 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 3 Oct 2024 13:12:42 -0400 Subject: [PATCH 07/79] docker-redis - local refactors Signed-off-by: Dave Richer --- redis/.gitignore | 2 -- redis/dockerdata/.gitignore | 6 +++--- redis/dockerdata/.gitkeep | 0 3 files changed, 3 insertions(+), 5 deletions(-) delete mode 100644 redis/.gitignore delete mode 100644 redis/dockerdata/.gitkeep diff --git a/redis/.gitignore b/redis/.gitignore deleted file mode 100644 index d3461533b..000000000 --- a/redis/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -redis-cluster-init.lock -dockerdata/ diff --git a/redis/dockerdata/.gitignore b/redis/dockerdata/.gitignore index 2dfe1c02b..015f42bed 100644 --- a/redis/dockerdata/.gitignore +++ b/redis/dockerdata/.gitignore @@ -1,3 +1,3 @@ -.gitkeep -!.gitignore -!.gitkeep +* +!lock\ +lock\redis-cluster-init.lock diff --git a/redis/dockerdata/.gitkeep b/redis/dockerdata/.gitkeep deleted file mode 100644 index e69de29bb..000000000 From 68b874300252d73b392afcee91d2331756fe356b Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 3 Oct 2024 13:17:04 -0400 Subject: [PATCH 08/79] docker-redis - improve lockfile for redis, add redis-insights, make sure app image has all it needs to build canvas Signed-off-by: Dave Richer --- Dockerfile | 4 +++- docker-compose.yml | 41 +++++++++++++++++++++++----------- redis/dockerdata/.gitignore | 5 +++-- redis/dockerdata/lock/.gitkeep | 0 redis/entrypoint.sh | 20 +++++++++++++++-- 5 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 redis/dockerdata/lock/.gitkeep diff --git a/Dockerfile b/Dockerfile index 1f3b8db99..60f1193ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,8 @@ RUN dnf install -y \ giflib-devel \ libpng-devel \ make \ + python3 \ + python3-pip \ && dnf clean all # Set the working directory @@ -39,4 +41,4 @@ COPY . . EXPOSE 4000 # Start the application -CMD ["nodemon", "--legacy-watch", "server.js"] +CMD ["nodemon", "--exitcrash" , "--legacy-watch", "server.js"] diff --git a/docker-compose.yml b/docker-compose.yml index 7b867c0e3..0c0494b0c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,55 +1,60 @@ -version: '3.9' - services: redis-node-1: build: context: ./redis container_name: redis-node-1 hostname: redis-node-1 + restart: always networks: - redis-cluster-net volumes: - ./redis/dockerdata/redis-node-1:/data + - ./redis/dockerdata/lock:/redis-lock healthcheck: test: ["CMD", "redis-cli", "ping"] - interval: 5s - timeout: 3s - retries: 5 - + interval: 10s + timeout: 5s + retries: 10 + redis-node-2: build: context: ./redis container_name: redis-node-2 hostname: redis-node-2 + restart: always networks: - redis-cluster-net volumes: - ./redis/dockerdata/redis-node-2:/data + - ./redis/dockerdata/lock:/redis-lock healthcheck: test: ["CMD", "redis-cli", "ping"] - interval: 5s - timeout: 3s - retries: 5 + interval: 10s + timeout: 5s + retries: 10 redis-node-3: build: context: ./redis container_name: redis-node-3 hostname: redis-node-3 + restart: always networks: - redis-cluster-net volumes: - ./redis/dockerdata/redis-node-3:/data + - ./redis/dockerdata/lock:/redis-lock healthcheck: test: ["CMD", "redis-cli", "ping"] - interval: 5s - timeout: 3s - retries: 5 + interval: 10s + timeout: 5s + retries: 10 node-app: build: context: . container_name: node-app + hostname: imex-api networks: - redis-cluster-net env_file: @@ -65,7 +70,7 @@ services: - "4000:4000" volumes: - .:/app - - /app/node_modules # Prevents overwriting node_modules + - /app/node_modules socketio-admin-ui: image: maitrungduc1410/socket.io-admin-ui @@ -74,6 +79,16 @@ services: - redis-cluster-net ports: - "3333:80" + + redis-insight: + image: redislabs/redisinsight:latest + container_name: redis-insight + hostname: redis-insight + restart: always + ports: + - "3334:5540" + networks: + - redis-cluster-net networks: redis-cluster-net: diff --git a/redis/dockerdata/.gitignore b/redis/dockerdata/.gitignore index 015f42bed..d65193fa1 100644 --- a/redis/dockerdata/.gitignore +++ b/redis/dockerdata/.gitignore @@ -1,3 +1,4 @@ * -!lock\ -lock\redis-cluster-init.lock +!lock/ +lock/* +!lock/.gitkeep diff --git a/redis/dockerdata/lock/.gitkeep b/redis/dockerdata/lock/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/redis/entrypoint.sh b/redis/entrypoint.sh index a3d93feda..a5a527e30 100644 --- a/redis/entrypoint.sh +++ b/redis/entrypoint.sh @@ -1,19 +1,35 @@ #!/bin/sh +LOCKFILE="/redis-lock/redis-cluster-init.lock" + # Start Redis server in the background redis-server /usr/local/etc/redis/redis.conf & # Wait for Redis server to start sleep 5 -# Only initialize the cluster from one node to prevent race conditions -if [ "$HOSTNAME" = "redis-node-1" ]; then +# Only initialize the cluster if the lock file doesn't exist +if [ ! -f "$LOCKFILE" ]; then echo "Initializing Redis Cluster..." + + # Create lock file to prevent further initialization attempts + touch "$LOCKFILE" + if [ $? -eq 0 ]; then + echo "Lock file created successfully at $LOCKFILE." + else + echo "Failed to create lock file." + fi + + # Initialize the Redis cluster yes yes | redis-cli --cluster create \ redis-node-1:6379 \ redis-node-2:6379 \ redis-node-3:6379 \ --cluster-replicas 0 + + echo "Redis Cluster initialized." +else + echo "Cluster already initialized, skipping initialization." fi # Keep the container running From 5114138c672d774fcd67ba4cdd96bdfaa12cfa0f Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 3 Oct 2024 16:30:15 -0400 Subject: [PATCH 09/79] docker-redis - final cleanup Signed-off-by: Dave Richer --- Dockerfile | 2 +- docker-compose.yml | 7 + server.js | 33 ++-- server/email/tasksEmails.js | 10 +- server/utils/ioHelpers.js | 4 +- server/utils/redisHelpers.js | 6 +- server/web-sockets/redisSocketEvents.js | 205 +++++++++++++----------- 7 files changed, 142 insertions(+), 125 deletions(-) diff --git a/Dockerfile b/Dockerfile index 60f1193ee..dab748c1b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,4 +41,4 @@ COPY . . EXPOSE 4000 # Start the application -CMD ["nodemon", "--exitcrash" , "--legacy-watch", "server.js"] +CMD ["nodemon", "--legacy-watch", "server.js"] diff --git a/docker-compose.yml b/docker-compose.yml index 0c0494b0c..054de22ab 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,10 @@ +############################# +# Ports Exposed +# 4000 - Imex Node API +# 3333 - SocketIO Admin-UI +# 3334 - Redis-Insights +############################# + services: redis-node-1: build: diff --git a/server.js b/server.js index 10182fe18..b57cc667d 100644 --- a/server.js +++ b/server.js @@ -12,8 +12,8 @@ const { instrument } = require("@socket.io/admin-ui"); const { isString, isEmpty } = require("lodash"); const logger = require("./server/utils/logger"); -const applyRedisHelpers = require("./server/utils/redisHelpers"); -const applyIOHelpers = require("./server/utils/ioHelpers"); +const { applyRedisHelpers } = require("./server/utils/redisHelpers"); +const { applyIOHelpers } = require("./server/utils/ioHelpers"); const { redisSocketEvents } = require("./server/web-sockets/redisSocketEvents"); // Load environment variables @@ -62,7 +62,7 @@ const SOCKETIO_CORS_ORIGIN_DEV = ["http://localhost:3333", "https://localhost:33 * Middleware for Express app * @param app */ -const applyMiddleware = (app) => { +const applyMiddleware = ({ app }) => { app.use(compression()); app.use(cookieParser()); app.use(bodyParser.json({ limit: "50mb" })); @@ -80,7 +80,7 @@ const applyMiddleware = (app) => { * Route groupings for Express app * @param app */ -const applyRoutes = (app) => { +const applyRoutes = ({ app }) => { app.use("/", require("./server/routes/miscellaneousRoutes")); app.use("/notifications", require("./server/routes/notificationsRoutes")); app.use("/render", require("./server/routes/renderRoutes")); @@ -171,7 +171,7 @@ const connectToRedisCluster = () => { * @param server * @param app */ -const applySocketIO = async (server, app) => { +const applySocketIO = async ({ server, app }) => { const redisCluster = await connectToRedisCluster(); // Handle errors @@ -182,16 +182,17 @@ const applySocketIO = async (server, app) => { const pubClient = redisCluster; const subClient = pubClient.duplicate(); - // https://github.com/redis/node-redis/blob/master/docs/clustering.md - // https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/accessing-elasticache.html - pubClient.on("error", (err) => logger.log(`Redis pubClient error: ${err}`, "ERROR", "redis")); subClient.on("error", (err) => logger.log(`Redis subClient error: ${err}`, "ERROR", "redis")); process.on("SIGINT", async () => { logger.log("Closing Redis connections...", "INFO", "redis", "api"); - await Promise.all([pubClient.disconnect(), subClient.disconnect()]); - process.exit(0); + try { + await Promise.all([pubClient.disconnect(), subClient.disconnect()]); + logger.log("Redis connections closed. Process will exit.", "INFO", "redis", "api"); + } catch (error) { + logger.log(`Error closing Redis connections: ${error.message}`, "ERROR", "redis", "api"); + } }); const ioRedis = new Server(server, { @@ -259,16 +260,16 @@ const main = async () => { const server = http.createServer(app); - const { pubClient, ioRedis } = await applySocketIO(server, app); - const api = applyRedisHelpers(pubClient, app, logger); - const ioHelpers = applyIOHelpers(app, api, ioRedis, logger); + const { pubClient, ioRedis } = await applySocketIO({ server, app }); + const redisHelpers = applyRedisHelpers({ pubClient, app, logger }); + const ioHelpers = applyIOHelpers({ app, redisHelpers, ioRedis, logger }); // Legacy Socket Events require("./server/web-sockets/web-socket"); - applyMiddleware(app); - applyRoutes(app); - redisSocketEvents(ioRedis, api, ioHelpers); + applyMiddleware({ app }); + applyRoutes({ app }); + redisSocketEvents({ io: ioRedis, redisHelpers, ioHelpers, logger }); try { await server.listen(port); diff --git a/server/email/tasksEmails.js b/server/email/tasksEmails.js index 1f508be31..7fe0f7808 100644 --- a/server/email/tasksEmails.js +++ b/server/email/tasksEmails.js @@ -45,22 +45,20 @@ if (process.env.NODE_ENV !== "development") { // Handling SIGINT (e.g., Ctrl+C) process.on("SIGINT", async () => { await tasksEmailQueueCleanup(); - process.exit(0); }); // Handling SIGTERM (e.g., sent by system shutdown) process.on("SIGTERM", async () => { await tasksEmailQueueCleanup(); - process.exit(0); }); // Handling uncaught exceptions process.on("uncaughtException", async (err) => { await tasksEmailQueueCleanup(); - process.exit(1); // Exit with an 'error' code + throw err; }); // Handling unhandled promise rejections process.on("unhandledRejection", async (reason, promise) => { await tasksEmailQueueCleanup(); - process.exit(1); // Exit with an 'error' code + throw reason; }); } @@ -247,7 +245,7 @@ const tasksRemindEmail = async (req, res) => { const fromEmails = InstanceManager({ imex: "ImEX Online ", rome: - tasksRequest?.tasks[0].bodyshop.convenient_company === "promanager" + tasksRequest?.tasks[0].bodyshop.convenient_company === "promanager" ? "ProManager " : "Rome Online " }); @@ -283,7 +281,7 @@ const tasksRemindEmail = async (req, res) => { const endPoints = InstanceManager({ imex: process.env?.NODE_ENV === "test" ? "https://test.imex.online" : "https://imex.online", rome: - tasksRequest?.tasks[0].bodyshop.convenient_company === "promanager" + tasksRequest?.tasks[0].bodyshop.convenient_company === "promanager" ? process.env?.NODE_ENV === "test" ? "https//test.promanager.web-est.com" : "https://promanager.web-est.com" diff --git a/server/utils/ioHelpers.js b/server/utils/ioHelpers.js index 2a68925f9..3b3b15adb 100644 --- a/server/utils/ioHelpers.js +++ b/server/utils/ioHelpers.js @@ -1,4 +1,4 @@ -const applyIOHelpers = (app, api, io, logger) => { +const applyIOHelpers = ({ app, api, io, logger }) => { const getBodyshopRoom = (bodyshopID) => `bodyshop-broadcast-room:${bodyshopID}`; const ioHelpersAPI = { @@ -14,4 +14,4 @@ const applyIOHelpers = (app, api, io, logger) => { return ioHelpersAPI; }; -module.exports = applyIOHelpers; +module.exports = { applyIOHelpers }; diff --git a/server/utils/redisHelpers.js b/server/utils/redisHelpers.js index 3ab824be4..54d68773d 100644 --- a/server/utils/redisHelpers.js +++ b/server/utils/redisHelpers.js @@ -4,7 +4,7 @@ * @param app * @param logger */ -const applyRedisHelpers = (pubClient, app, logger) => { +const applyRedisHelpers = ({ pubClient, app, logger }) => { // Store session data in Redis const setSessionData = async (socketId, key, value) => { try { @@ -225,5 +225,5 @@ const applyRedisHelpers = (pubClient, app, logger) => { return api; }; -module.exports = applyRedisHelpers; -// "th1s1sr3d1s" (BCrypt) + +module.exports = { applyRedisHelpers }; diff --git a/server/web-sockets/redisSocketEvents.js b/server/web-sockets/redisSocketEvents.js index 5cda88569..381436c1a 100644 --- a/server/web-sockets/redisSocketEvents.js +++ b/server/web-sockets/redisSocketEvents.js @@ -1,102 +1,18 @@ -const path = require("path"); -require("dotenv").config({ - path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) -}); -const logger = require("../utils/logger"); const { admin } = require("../firebase/firebase-handler"); -// Logging helper functions -function createLogEvent(socket, level, message) { - console.log(`[IOREDIS LOG EVENT] - ${socket.user.email} - ${socket.id} - ${message}`); - logger.log("ioredis-log-event", level, socket.user.email, null, { wsmessage: message }); -} - -const registerUpdateEvents = (socket) => { - socket.on("update-token", async (newToken) => { - try { - socket.user = await admin.auth().verifyIdToken(newToken); - createLogEvent(socket, "INFO", "Token updated successfully"); - socket.emit("token-updated", { success: true }); - } catch (error) { - createLogEvent(socket, "ERROR", `Token update failed: ${error.message}`); - socket.emit("token-updated", { success: false, error: error.message }); - // Optionally disconnect the socket if token verification fails - socket.disconnect(); - } - }); -}; - -const redisSocketEvents = (io, { addUserToRoom, getUsersInRoom, removeUserFromRoom }, { getBodyshopRoom }) => { - // Room management and broadcasting events - function registerRoomAndBroadcastEvents(socket) { - socket.on("join-bodyshop-room", async (bodyshopUUID) => { - try { - const room = getBodyshopRoom(bodyshopUUID); - socket.join(room); - await addUserToRoom(room, { uid: socket.user.uid, email: socket.user.email, socket: socket.id }); - createLogEvent(socket, "DEBUG", `Client joined bodyshop room: ${room}`); - - // Notify all users in the room about the updated user list - const usersInRoom = await getUsersInRoom(room); - io.to(room).emit("room-users-updated", usersInRoom); - } catch (error) { - createLogEvent(socket, "ERROR", `Error joining room: ${error}`); - } - }); - - socket.on("leave-bodyshop-room", async (bodyshopUUID) => { - try { - const room = getBodyshopRoom(bodyshopUUID); - socket.leave(room); - createLogEvent(socket, "DEBUG", `Client left bodyshop room: ${room}`); - } catch (error) { - createLogEvent(socket, "ERROR", `Error joining room: ${error}`); - } - }); - - socket.on("get-room-users", async (bodyshopUUID, callback) => { - try { - const usersInRoom = await getUsersInRoom(getBodyshopRoom(bodyshopUUID)); - callback(usersInRoom); - } catch (error) { - createLogEvent(socket, "ERROR", `Error getting room: ${error}`); - } - }); - - socket.on("broadcast-to-bodyshop", async (bodyshopUUID, message) => { - try { - const room = getBodyshopRoom(bodyshopUUID); - io.to(room).emit("bodyshop-message", message); - createLogEvent(socket, "INFO", `Broadcast message to bodyshop ${room}`); - } catch (error) { - createLogEvent(socket, "ERROR", `Error getting room: ${error}`); - } - }); - - socket.on("disconnect", async () => { - try { - createLogEvent(socket, "DEBUG", `User disconnected.`); - - // Get all rooms the socket is part of - const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id); - for (const room of rooms) { - await removeUserFromRoom(room, { uid: socket.user.uid, email: socket.user.email, socket: socket.id }); - } - } catch (error) { - createLogEvent(socket, "ERROR", `Error getting room: ${error}`); - } - }); - } - - // Register all socket events for a given socket connection - function registerSocketEvents(socket) { - createLogEvent(socket, "DEBUG", `Registering RedisIO Socket Events.`); - - // Register room and broadcasting events - registerRoomAndBroadcastEvents(socket); - registerUpdateEvents(socket); - } +const redisSocketEvents = ({ + io, + redisHelpers: { setSessionData, clearSessionData }, + ioHelpers: { getBodyshopRoom }, + logger +}) => { + // Logging helper functions + const createLogEvent = (socket, level, message) => { + console.log(`[IOREDIS LOG EVENT] - ${socket?.user?.email} - ${socket.id} - ${message}`); + logger.log("ioredis-log-event", level, socket?.user?.email, null, { wsmessage: message }); + }; + // Socket Auth Middleware const authMiddleware = (socket, next) => { try { if (socket.handshake.auth.token) { @@ -105,6 +21,9 @@ const redisSocketEvents = (io, { addUserToRoom, getUsersInRoom, removeUserFromRo .verifyIdToken(socket.handshake.auth.token) .then((user) => { socket.user = user; + return setSessionData(socket.id, "user", user); + }) + .then(() => { next(); }) .catch((error) => { @@ -122,7 +41,99 @@ const redisSocketEvents = (io, { addUserToRoom, getUsersInRoom, removeUserFromRo } }; - // Socket.IO Middleware and Connection + // Register Socket Events + const registerSocketEvents = (socket) => { + createLogEvent(socket, "DEBUG", `Registering RedisIO Socket Events.`); + + // Token Update Events + const registerUpdateEvents = (socket) => { + const updateToken = async (newToken) => { + try { + // noinspection UnnecessaryLocalVariableJS + const user = await admin.auth().verifyIdToken(newToken, true); + socket.user = user; + + // If We ever want to persist user Data across workers + // await setSessionData(socket.id, "user", user); + + createLogEvent(socket, "INFO", "Token updated successfully"); + + socket.emit("token-updated", { success: true }); + } catch (error) { + if (error.code === "auth/id-token-expired") { + createLogEvent(socket, "WARNING", "Stale token received, waiting for new token"); + socket.emit("token-updated", { + success: false, + error: "Stale token." + }); + } else { + createLogEvent(socket, "ERROR", `Token update failed: ${error.message}`); + socket.emit("token-updated", { success: false, error: error.message }); + // For any other errors, optionally disconnect the socket + socket.disconnect(); + } + } + }; + socket.on("update-token", updateToken); + }; + // Room Broadcast Events + const registerRoomAndBroadcastEvents = (socket) => { + const joinBodyshopRoom = (bodyshopUUID) => { + try { + const room = getBodyshopRoom(bodyshopUUID); + socket.join(room); + createLogEvent(socket, "DEBUG", `Client joined bodyshop room: ${room}`); + } catch (error) { + createLogEvent(socket, "ERROR", `Error joining room: ${error}`); + } + }; + + const leaveBodyshopRoom = (bodyshopUUID) => { + try { + const room = getBodyshopRoom(bodyshopUUID); + socket.leave(room); + createLogEvent(socket, "DEBUG", `Client left bodyshop room: ${room}`); + } catch (error) { + createLogEvent(socket, "ERROR", `Error joining room: ${error}`); + } + }; + + const broadcastToBodyshopRoom = (bodyshopUUID, message) => { + try { + const room = getBodyshopRoom(bodyshopUUID); + io.to(room).emit("bodyshop-message", message); + createLogEvent(socket, "DEBUG", `Broadcast message to bodyshop ${room}`); + } catch (error) { + createLogEvent(socket, "ERROR", `Error getting room: ${error}`); + } + }; + + socket.on("join-bodyshop-room", joinBodyshopRoom); + socket.on("leave-bodyshop-room", leaveBodyshopRoom); + socket.on("broadcast-to-bodyshop", broadcastToBodyshopRoom); + }; + // Disconnect Events + const registerDisconnectEvents = (socket) => { + const disconnect = () => { + createLogEvent(socket, "DEBUG", `User disconnected.`); + const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id); + for (const room of rooms) { + socket.leave(room); + } + // If we ever want to persist the user across workers + // clearSessionData(socket.id); + }; + + socket.on("disconnect", disconnect); + }; + + // Call Handlers + registerRoomAndBroadcastEvents(socket); + registerUpdateEvents(socket); + registerDisconnectEvents(socket); + }; + + // Associate Middleware and Handlers io.use(authMiddleware); io.on("connection", registerSocketEvents); }; From e4dc711481a88ab640b83211c1ba1dc2e384e7b0 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 4 Oct 2024 13:43:45 -0400 Subject: [PATCH 10/79] docker-redis - final cleanup Signed-off-by: Dave Richer --- _reference/dockerreadme.md | 49 +++++++++++++++++++++++++++++++++- docker-compose.yml | 21 ++++++++++----- redis/dockerdata/.gitignore | 4 --- redis/dockerdata/lock/.gitkeep | 0 4 files changed, 63 insertions(+), 11 deletions(-) delete mode 100644 redis/dockerdata/.gitignore delete mode 100644 redis/dockerdata/lock/.gitkeep diff --git a/_reference/dockerreadme.md b/_reference/dockerreadme.md index a7f8e2aef..b65c6b23d 100644 --- a/_reference/dockerreadme.md +++ b/_reference/dockerreadme.md @@ -109,7 +109,9 @@ To ensure the changes are fully applied, restart WSL2: 2. Test Access from other Devices: - If you're running services inside WSL (e.g., a web server), ensure they are accessible from other devices on your local network using the static IP address you configured (e.g., `http://192.168.1.100:4000`). -## Step 6: Configuring `vm.overcommit_memory` in sysctl for WSL2 + + +# Configuring `vm.overcommit_memory` in sysctl for WSL2 To prevent memory overcommitment issues and optimize performance, you can configure the `vm.overcommit_memory` setting in WSL2. This is particularly useful when running Redis or other memory-intensive services inside WSL2, as it helps control how the Linux kernel handles memory allocation. @@ -133,3 +135,48 @@ After editing the file, save it and then apply the new sysctl configuration by r sudo sysctl -p ``` +# Install Docker and Docker Compose in WSL2 +- https://docs.docker.com/desktop/wsl/ + +# Docker Commands + +## General `docker-compose` Commands: +1. Bring up the services, force a rebuild of all services, and do not use the cache: `docker-compose up --build --no-cache` +2. Start Containers in Detached Mode: This will run the containers in the background (detached mode): `docker-compose up -d` +3. Stop and Remove Containers: Stops and removes the containers gracefully: `docker-compose down` +4. Stop containers without removing them: `docker-compose stop` +5. Remove Containers, Volumes, and Networks: `docker-compose down --volumes` +6. Force rebuild of containers: `docker-compose build --no-cache` +7. View running Containers: `docker-compose ps` +8. View a specific containers logs: `docker-compose logs ` +9. Scale services (multiple instances of a service): `docker-compose up --scale = -d` + +## Volume Management Commands +1. List Docker volumes: `docker volume ls` +2. Remove Unused volumes `docker volume prune` +3. Remove specific volumes `docker volume rm ` +4. Inspect a volume: `docker volume inspect ` + +## Container Image Management Commands: +1. List running containers: `docker ps` +2. List all containers: `docker os -a` +3. Remove Stopped containers: `docker container prune` +4. Remove a specific container: `docker container rm ` +5. Remove a specific image: `docker rmi :` +6. Remove all unused images: `docker image prune -a` + +## Network Management Commands: +1. List networks: `docker network ls` +2. Inspect a specific network: `docker network inspect ` +3. Remove a specific network: `docker network rm ` +4. Remove unused networks: `docker network prune` + +## Debugging and maintenance: +1. Enter a Running container: `docker exec -it /bin/bash` (could also be `/bin/sh` or for example `redis-cli` on a redis node) +2. View container resource usage: `docker stats` +3. Check Disk space used by Docker: `docker system df` +4. Remove all unused Data (Nuclear option): `docker system prune` + +## Specific examples +1. To simulate a Clean state, one should run `docker system prune` followed by `docker volume prune -a` +2. You can run `docker-compose up` without the `-d` option, and you will get what is identical to the experience you were used to, this includes being able to control-c and bring the entire stack down diff --git a/docker-compose.yml b/docker-compose.yml index 054de22ab..4e8ecf9d4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,8 +15,8 @@ services: networks: - redis-cluster-net volumes: - - ./redis/dockerdata/redis-node-1:/data - - ./redis/dockerdata/lock:/redis-lock + - redis-node-1-data:/data + - redis-lock:/redis-lock healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s @@ -32,8 +32,8 @@ services: networks: - redis-cluster-net volumes: - - ./redis/dockerdata/redis-node-2:/data - - ./redis/dockerdata/lock:/redis-lock + - redis-node-2-data:/data + - redis-lock:/redis-lock healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s @@ -49,8 +49,8 @@ services: networks: - redis-cluster-net volumes: - - ./redis/dockerdata/redis-node-3:/data - - ./redis/dockerdata/lock:/redis-lock + - redis-node-3-data:/data + - redis-lock:/redis-lock healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s @@ -96,7 +96,16 @@ services: - "3334:5540" networks: - redis-cluster-net + volumes: + - redis-insight-data:/db networks: redis-cluster-net: driver: bridge + +volumes: + redis-node-1-data: + redis-node-2-data: + redis-node-3-data: + redis-lock: + redis-insight-data: diff --git a/redis/dockerdata/.gitignore b/redis/dockerdata/.gitignore deleted file mode 100644 index d65193fa1..000000000 --- a/redis/dockerdata/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -* -!lock/ -lock/* -!lock/.gitkeep diff --git a/redis/dockerdata/lock/.gitkeep b/redis/dockerdata/lock/.gitkeep deleted file mode 100644 index e69de29bb..000000000 From 4be71726d4d9af8c6449dfdc1475c7fef021be27 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 7 Oct 2024 16:18:11 -0400 Subject: [PATCH 11/79] feature/IO-2972-Final-Redis-Sockets-Add Redis Cluster aware logic Signed-off-by: Dave Richer --- package-lock.json | 869 +++++++++++++++++++++++++++++------- package.json | 1 + server.js | 71 ++- server/email/sendemail.js | 4 +- server/email/tasksEmails.js | 2 +- 5 files changed, 756 insertions(+), 191 deletions(-) diff --git a/package-lock.json b/package-lock.json index d5a87fdaa..822bb487e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.2.0", "license": "UNLICENSED", "dependencies": { + "@aws-sdk/client-elasticache": "^3.665.0", "@aws-sdk/client-secrets-manager": "^3.654.0", "@aws-sdk/client-ses": "^3.654.0", "@aws-sdk/credential-provider-node": "^3.654.0", @@ -184,6 +185,530 @@ "node": ">=14.0.0" } }, + "node_modules/@aws-sdk/client-elasticache": { + "version": "3.665.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-elasticache/-/client-elasticache-3.665.0.tgz", + "integrity": "sha512-r1T7Yhv+jdVEoOT3h1oJtsKPYt82rEHv1PPYAknyYWUOYxb4tgpmaPusw50nqnNi47W7n/9jkqnk75IwMKEjfQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.665.0", + "@aws-sdk/client-sts": "3.665.0", + "@aws-sdk/core": "3.665.0", + "@aws-sdk/credential-provider-node": "3.665.0", + "@aws-sdk/middleware-host-header": "3.664.0", + "@aws-sdk/middleware-logger": "3.664.0", + "@aws-sdk/middleware-recursion-detection": "3.664.0", + "@aws-sdk/middleware-user-agent": "3.664.0", + "@aws-sdk/region-config-resolver": "3.664.0", + "@aws-sdk/types": "3.664.0", + "@aws-sdk/util-endpoints": "3.664.0", + "@aws-sdk/util-user-agent-browser": "3.664.0", + "@aws-sdk/util-user-agent-node": "3.664.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.7", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.22", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.3.6", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.22", + "@smithy/util-defaults-mode-node": "^3.0.22", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", + "@smithy/util-utf8": "^3.0.0", + "@smithy/util-waiter": "^3.1.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/client-sso": { + "version": "3.665.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.665.0.tgz", + "integrity": "sha512-zje+oaIiyviDv5dmBWhGHifPTb0Idq/HatNPy+VEiwo2dxcQBexibD5CQE5e8CWZK123Br/9DHft+iNKdiY5bA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.665.0", + "@aws-sdk/middleware-host-header": "3.664.0", + "@aws-sdk/middleware-logger": "3.664.0", + "@aws-sdk/middleware-recursion-detection": "3.664.0", + "@aws-sdk/middleware-user-agent": "3.664.0", + "@aws-sdk/region-config-resolver": "3.664.0", + "@aws-sdk/types": "3.664.0", + "@aws-sdk/util-endpoints": "3.664.0", + "@aws-sdk/util-user-agent-browser": "3.664.0", + "@aws-sdk/util-user-agent-node": "3.664.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.7", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.22", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.3.6", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.22", + "@smithy/util-defaults-mode-node": "^3.0.22", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.665.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.665.0.tgz", + "integrity": "sha512-FQ2YyM9/6y3clWkf3d60/W4c/HZy61hbfIsR4KIh8aGOifwfIx/UpZQ61pCr/TXTNqbaAVU2/sK+J1zFkGEoLw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.665.0", + "@aws-sdk/credential-provider-node": "3.665.0", + "@aws-sdk/middleware-host-header": "3.664.0", + "@aws-sdk/middleware-logger": "3.664.0", + "@aws-sdk/middleware-recursion-detection": "3.664.0", + "@aws-sdk/middleware-user-agent": "3.664.0", + "@aws-sdk/region-config-resolver": "3.664.0", + "@aws-sdk/types": "3.664.0", + "@aws-sdk/util-endpoints": "3.664.0", + "@aws-sdk/util-user-agent-browser": "3.664.0", + "@aws-sdk/util-user-agent-node": "3.664.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.7", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.22", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.3.6", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.22", + "@smithy/util-defaults-mode-node": "^3.0.22", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.665.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/client-sts": { + "version": "3.665.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.665.0.tgz", + "integrity": "sha512-/OQEaWB1euXhZ/hV+wetDw1tynlrkNKzirzoiFuJ1EQsiIb9Ih/qjUF9KLdF1+/bXbnGu5YvIaAx80YReUchjg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.665.0", + "@aws-sdk/core": "3.665.0", + "@aws-sdk/credential-provider-node": "3.665.0", + "@aws-sdk/middleware-host-header": "3.664.0", + "@aws-sdk/middleware-logger": "3.664.0", + "@aws-sdk/middleware-recursion-detection": "3.664.0", + "@aws-sdk/middleware-user-agent": "3.664.0", + "@aws-sdk/region-config-resolver": "3.664.0", + "@aws-sdk/types": "3.664.0", + "@aws-sdk/util-endpoints": "3.664.0", + "@aws-sdk/util-user-agent-browser": "3.664.0", + "@aws-sdk/util-user-agent-node": "3.664.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.7", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.22", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.3.6", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.22", + "@smithy/util-defaults-mode-node": "^3.0.22", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/core": { + "version": "3.665.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.665.0.tgz", + "integrity": "sha512-nqmNNf7Ml7qDXTIisDv+OYe/rl3nAW4cmR+HxrOCWdhTHe8xRdR5c45VPoh8nv1KIry5xtd+iqPrzzjydes+Og==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@smithy/core": "^2.4.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/property-provider": "^3.1.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/signature-v4": "^4.2.0", + "@smithy/smithy-client": "^3.3.6", + "@smithy/types": "^3.5.0", + "@smithy/util-middleware": "^3.0.7", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.664.0.tgz", + "integrity": "sha512-95rE+9Voaco0nmKJrXqfJAxSSkSWqlBy76zomiZrUrv7YuijQtHCW8jte6v6UHAFAaBzgFsY7QqBxs15u9SM7g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.664.0.tgz", + "integrity": "sha512-svaPwVfWV3g/qjd4cYHTUyBtkdOwcVjC+tSj6EjoMrpZwGUXcCbYe04iU0ARZ6tuH/u3vySbTLOGjSa7g8o9Qw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.3.6", + "@smithy/types": "^3.5.0", + "@smithy/util-stream": "^3.1.9", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.665.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.665.0.tgz", + "integrity": "sha512-CSWBV5GqCkK78TTXq6qx40MWCt90t8rS/O7FIR4nbmoUhG/DysaC1G0om1fSx6k+GWcvIIIsSvD4hdbh8FRWKA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.664.0", + "@aws-sdk/credential-provider-http": "3.664.0", + "@aws-sdk/credential-provider-process": "3.664.0", + "@aws-sdk/credential-provider-sso": "3.665.0", + "@aws-sdk/credential-provider-web-identity": "3.664.0", + "@aws-sdk/types": "3.664.0", + "@smithy/credential-provider-imds": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.665.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.665.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.665.0.tgz", + "integrity": "sha512-cmJfVi4IM0WaKMQvPXhiS5mdIZyCoa04I3D+IEKpD2GAuVZa6tgwqfPyaApFDLjyedGGNFkC4MRgAjCcCl4WFg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.664.0", + "@aws-sdk/credential-provider-http": "3.664.0", + "@aws-sdk/credential-provider-ini": "3.665.0", + "@aws-sdk/credential-provider-process": "3.664.0", + "@aws-sdk/credential-provider-sso": "3.665.0", + "@aws-sdk/credential-provider-web-identity": "3.664.0", + "@aws-sdk/types": "3.664.0", + "@smithy/credential-provider-imds": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.664.0.tgz", + "integrity": "sha512-sQicIw/qWTsmMw8EUQNJXdrWV5SXaZc2zGdCQsQxhR6wwNO2/rZ5JmzdcwUADmleBVyPYk3KGLhcofF/qXT2Ng==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.665.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.665.0.tgz", + "integrity": "sha512-Xe8WW4r70bsetGQG3azFeK/gd+Q4OmNiidtRrG64y/V9TIvIqc7Y/yUZNhEgFkpG19o188VmXg/ulnG3E+MvLg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.665.0", + "@aws-sdk/token-providers": "3.664.0", + "@aws-sdk/types": "3.664.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.664.0.tgz", + "integrity": "sha512-10ltP1BfSKRJVXd8Yr5oLbo+VSDskWbps0X3szSsxTk0Dju1xvkz7hoIjylWLvtGbvQ+yb2pmsJYKCudW/4DJg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.664.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.664.0.tgz", + "integrity": "sha512-4tCXJ+DZWTq38eLmFgnEmO8X4jfWpgPbWoCyVYpRHCPHq6xbrU65gfwS9jGx25L4YdEce641ChI9TKLryuUgRA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/middleware-logger": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.664.0.tgz", + "integrity": "sha512-eNykMqQuv7eg9pAcaLro44fscIe1VkFfhm+gYnlxd+PH6xqapRki1E68VHehnIptnVBdqnWfEqLUSLGm9suqhg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.664.0.tgz", + "integrity": "sha512-jq27WMZhm+dY8BWZ9Ipy3eXtZj0lJzpaKQE3A3tH5AOIlUV/gqrmnJ9CdqVVef4EJsq9Yil4ZzQjKKmPsxveQg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.664.0.tgz", + "integrity": "sha512-Kp5UwXwayO6d472nntiwgrxqay2KS9ozXNmKjQfDrUWbEzvgKI+jgKNMia8MMnjSxYoBGpQ1B8NGh8a6KMEJJg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@aws-sdk/util-endpoints": "3.664.0", + "@smithy/core": "^2.4.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.664.0.tgz", + "integrity": "sha512-o/B8dg8K+9714RGYPgMxZgAChPe/MTSMkf/eHXTUFHNik5i1HgVKfac22njV2iictGy/6GhpFsKa1OWNYAkcUg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/types": "^3.5.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/token-providers": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.664.0.tgz", + "integrity": "sha512-dBAvXW2/6bAxidvKARFxyCY2uCynYBKRFN00NhS1T5ggxm3sUnuTpWw1DTjl02CVPkacBOocZf10h8pQbHSK8w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.664.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/types": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.664.0.tgz", + "integrity": "sha512-+GtXktvVgpreM2b+NJL9OqZGsOzHwlCUrO8jgQUvH/yA6Kd8QO2YFhQCp0C9sSzTteZJVqGBu8E0CQurxJHPbw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/util-endpoints": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.664.0.tgz", + "integrity": "sha512-KrXoHz6zmAahVHkyWMRT+P6xJaxItgmklxEDrT+npsUB4d5C/lhw16Crcp9TDi828fiZK3GYKRAmmNhvmzvBNg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@smithy/types": "^3.5.0", + "@smithy/util-endpoints": "^2.1.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.664.0.tgz", + "integrity": "sha512-c/PV3+f1ss4PpskHbcOxTZ6fntV2oXy/xcDR9nW+kVaz5cM1G702gF0rvGLKPqoBwkj2rWGe6KZvEBeLzynTUQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.664.0", + "@smithy/types": "^3.5.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.664.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.664.0.tgz", + "integrity": "sha512-l/m6KkgrTw1p/VTJTk0IoP9I2OnpWp3WbBgzxoNeh9cUcxTufIn++sBxKj5hhDql57LKWsckScG/MhFuH0vZZA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.664.0", + "@aws-sdk/types": "3.664.0", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, "node_modules/@aws-sdk/client-secrets-manager": { "version": "3.654.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.654.0.tgz", @@ -1830,12 +2355,12 @@ } }, "node_modules/@smithy/abort-controller": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.4.tgz", - "integrity": "sha512-VupaALAQlXViW3/enTf/f5l5JZYSAxoJL7f0nanhNNKnww6DGCg1oYIuNP78KDugnkwthBO6iEcym16HhWV8RQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.5.tgz", + "integrity": "sha512-DhNPnqTqPoG8aZ5dWkFOgsuY+i0GQ3CI6hMmvCoduNsnU9gUZWZBwGfDQsTTB7NvFPkom1df7jMIJWU90kuXXg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -1843,15 +2368,15 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.8.tgz", - "integrity": "sha512-Tv1obAC18XOd2OnDAjSWmmthzx6Pdeh63FbLin8MlPiuJ2ATpKkq0NcNOJFr0dO+JmZXnwu8FQxKJ3TKJ3Hulw==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.9.tgz", + "integrity": "sha512-5d9oBf40qC7n2xUoHmntKLdqsyTMMo/r49+eqSIjJ73eDfEtljAxEhzIQ3bkgXJtR3xiv7YzMT/3FF3ORkjWdg==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.7", - "@smithy/types": "^3.4.2", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/types": "^3.5.0", "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.6", + "@smithy/util-middleware": "^3.0.7", "tslib": "^2.6.2" }, "engines": { @@ -1859,19 +2384,19 @@ } }, "node_modules/@smithy/core": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.4.6.tgz", - "integrity": "sha512-6lQQp99hnyuNNIzeTYSzCUXJHwvvFLY7hfdFGSJM95tjRDJGfzWYFRBXPaM9766LiiTsQ561KErtbufzUFSYUg==", + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.4.8.tgz", + "integrity": "sha512-x4qWk7p/a4dcf7Vxb2MODIf4OIcqNbK182WxRvZ/3oKPrf/6Fdic5sSElhO1UtXpWKBazWfqg0ZEK9xN1DsuHA==", "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-endpoint": "^3.1.3", - "@smithy/middleware-retry": "^3.0.21", - "@smithy/middleware-serde": "^3.0.6", - "@smithy/protocol-http": "^4.1.3", - "@smithy/smithy-client": "^3.3.5", - "@smithy/types": "^3.4.2", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-middleware": "^3.0.6", + "@smithy/util-middleware": "^3.0.7", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -1880,15 +2405,15 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.3.tgz", - "integrity": "sha512-VoxMzSzdvkkjMJNE38yQgx4CfnmT+Z+5EUXkg4x7yag93eQkVQgZvN3XBSHC/ylfBbLbAtdu7flTCChX9I+mVg==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.4.tgz", + "integrity": "sha512-S9bb0EIokfYEuar4kEbLta+ivlKCWOCFsLZuilkNy9i0uEUEHSi47IFLPaxqqCl+0ftKmcOTHayY5nQhAuq7+w==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.7", - "@smithy/property-provider": "^3.1.6", - "@smithy/types": "^3.4.2", - "@smithy/url-parser": "^3.0.6", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/property-provider": "^3.1.7", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", "tslib": "^2.6.2" }, "engines": { @@ -1896,25 +2421,25 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.8.tgz", - "integrity": "sha512-Lqe0B8F5RM7zkw//6avq1SJ8AfaRd3ubFUS1eVp5WszV7p6Ne5hQ4dSuMHDpNRPhgTvj4va9Kd/pcVigHEHRow==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.9.tgz", + "integrity": "sha512-hYNVQOqhFQ6vOpenifFME546f0GfJn2OiQ3M0FDmuUu8V/Uiwy2wej7ZXxFBNqdx0R5DZAqWM1l6VRhGz8oE6A==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^4.1.3", - "@smithy/querystring-builder": "^3.0.6", - "@smithy/types": "^3.4.2", + "@smithy/protocol-http": "^4.1.4", + "@smithy/querystring-builder": "^3.0.7", + "@smithy/types": "^3.5.0", "@smithy/util-base64": "^3.0.0", "tslib": "^2.6.2" } }, "node_modules/@smithy/hash-node": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.6.tgz", - "integrity": "sha512-c/FHEdKK/7DU2z6ZE91L36ahyXWayR3B+FzELjnYq7wH5YqIseM24V+pWCS9kFn1Ln8OFGTf+pyYPiHZuX0s/Q==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.7.tgz", + "integrity": "sha512-SAGHN+QkrwcHFjfWzs/czX94ZEjPJ0CrWJS3M43WswDXVEuP4AVy9gJ3+AF6JQHZD13bojmuf/Ap/ItDeZ+Qfw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" @@ -1924,12 +2449,12 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.6.tgz", - "integrity": "sha512-czM7Ioq3s8pIXht7oD+vmgy4Wfb4XavU/k/irO8NdXFFOx7YAlsCCcKOh/lJD1mJSYQqiR7NmpZ9JviryD/7AQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.7.tgz", + "integrity": "sha512-Bq00GsAhHeYSuZX8Kpu4sbI9agH2BNYnqUmmbTGWOhki9NVsWn2jFr896vvoTMH8KAjNX/ErC/8t5QHuEXG+IA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" } }, @@ -1945,13 +2470,13 @@ } }, "node_modules/@smithy/middleware-content-length": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.8.tgz", - "integrity": "sha512-VuyszlSO49WKh3H9/kIO2kf07VUwGV80QRiaDxUfP8P8UKlokz381ETJvwLhwuypBYhLymCYyNhB3fLAGBX2og==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.9.tgz", + "integrity": "sha512-t97PidoGElF9hTtLCrof32wfWMqC5g2SEJNxaVH3NjlatuNGsdxXRYO/t+RPnxA15RpYiS0f+zG7FuE2DeGgjA==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^4.1.3", - "@smithy/types": "^3.4.2", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -1959,17 +2484,17 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.3.tgz", - "integrity": "sha512-KeM/OrK8MVFUsoJsmCN0MZMVPjKKLudn13xpgwIMpGTYpA8QZB2Xq5tJ+RE6iu3A6NhOI4VajDTwBsm8pwwrhg==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.4.tgz", + "integrity": "sha512-/ChcVHekAyzUbyPRI8CzPPLj6y8QRAfJngWcLMgsWxKVzw/RzBV69mSOzJYDD3pRwushA1+5tHtPF8fjmzBnrQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-serde": "^3.0.6", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/shared-ini-file-loader": "^3.1.7", - "@smithy/types": "^3.4.2", - "@smithy/url-parser": "^3.0.6", - "@smithy/util-middleware": "^3.0.6", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@smithy/util-middleware": "^3.0.7", "tslib": "^2.6.2" }, "engines": { @@ -1977,18 +2502,18 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.21.tgz", - "integrity": "sha512-/h0fElV95LekVVEJuSw+aI11S1Y3zIUwBc6h9ZbUv43Gl2weXsbQwjLoet6j/Qtb0phfrSxS6pNg6FqgJOWZkA==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.23.tgz", + "integrity": "sha512-x9PbGXxkcXIpm6L26qRSCC+eaYcHwybRmqU8LO/WM2RRlW0g8lz6FIiKbKgGvHuoK3dLZRiQVSQJveiCzwnA5A==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.7", - "@smithy/protocol-http": "^4.1.3", - "@smithy/service-error-classification": "^3.0.6", - "@smithy/smithy-client": "^3.3.5", - "@smithy/types": "^3.4.2", - "@smithy/util-middleware": "^3.0.6", - "@smithy/util-retry": "^3.0.6", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/protocol-http": "^4.1.4", + "@smithy/service-error-classification": "^3.0.7", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", "tslib": "^2.6.2", "uuid": "^9.0.1" }, @@ -2010,12 +2535,12 @@ } }, "node_modules/@smithy/middleware-serde": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.6.tgz", - "integrity": "sha512-KKTUSl1MzOM0MAjGbudeaVNtIDo+PpekTBkCNwvfZlKndodrnvRo+00USatiyLOc0ujjO9UydMRu3O9dYML7ag==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.7.tgz", + "integrity": "sha512-VytaagsQqtH2OugzVTq4qvjkLNbWehHfGcGr0JLJmlDRrNCeZoWkWsSOw1nhS/4hyUUWF/TLGGml4X/OnEep5g==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2023,12 +2548,12 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.6.tgz", - "integrity": "sha512-2c0eSYhTQ8xQqHMcRxLMpadFbTXg6Zla5l0mwNftFCZMQmuhI7EbAJMx6R5eqfuV3YbJ3QGyS3d5uSmrHV8Khg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.7.tgz", + "integrity": "sha512-EyTbMCdqS1DoeQsO4gI7z2Gzq1MoRFAeS8GkFYIwbedB7Lp5zlLHJdg+56tllIIG5Hnf9ZWX48YKSHlsKvugGA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2036,14 +2561,14 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.7.tgz", - "integrity": "sha512-g3mfnC3Oo8pOI0dYuPXLtdW1WGVb3bR2tkV21GNkm0ZvQjLTtamXAwCWt/FCb0HGvKt3gHHmF1XerG0ICfalOg==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.8.tgz", + "integrity": "sha512-E0rU0DglpeJn5ge64mk8wTGEXcQwmpUTY5Zr7IzTpDLmHKiIamINERNZYrPQjg58Ck236sEKSwRSHA4CwshU6Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^3.1.6", - "@smithy/shared-ini-file-loader": "^3.1.7", - "@smithy/types": "^3.4.2", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2051,15 +2576,15 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.2.3.tgz", - "integrity": "sha512-/gcm5DJ3k1b1zEInzBGAZC8ntJ+jwrz1NcSIu+9dSXd1FfG0G6QgkDI40tt8/WYUbHtLyo8fEqtm2v29koWo/w==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.2.4.tgz", + "integrity": "sha512-49reY3+JgLMFNm7uTAKBWiKCA6XSvkNp9FqhVmusm2jpVnHORYFeFZ704LShtqWfjZW/nhX+7Iexyb6zQfXYIQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^3.1.4", - "@smithy/protocol-http": "^4.1.3", - "@smithy/querystring-builder": "^3.0.6", - "@smithy/types": "^3.4.2", + "@smithy/abort-controller": "^3.1.5", + "@smithy/protocol-http": "^4.1.4", + "@smithy/querystring-builder": "^3.0.7", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2067,12 +2592,12 @@ } }, "node_modules/@smithy/property-provider": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.6.tgz", - "integrity": "sha512-NK3y/T7Q/Bw+Z8vsVs9MYIQ5v7gOX7clyrXcwhhIBQhbPgRl6JDrZbusO9qWDhcEus75Tg+VCxtIRfo3H76fpw==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.7.tgz", + "integrity": "sha512-QfzLi1GPMisY7bAM5hOUqBdGYnY5S2JAlr201pghksrQv139f8iiiMalXtjczIP5f6owxFn3MINLNUNvUkgtPw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2080,12 +2605,12 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.3.tgz", - "integrity": "sha512-GcbMmOYpH9iRqtC05RbRnc/0FssxSTHlmaNhYBTgSgNCYpdR3Kt88u5GAZTBmouzv+Zlj/VRv92J9ruuDeJuEw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.4.tgz", + "integrity": "sha512-MlWK8eqj0JlpZBnWmjQLqmFp71Ug00P+m72/1xQB3YByXD4zZ+y9N4hYrR0EDmrUCZIkyATWHOXFgtavwGDTzQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2093,12 +2618,12 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.6.tgz", - "integrity": "sha512-sQe08RunoObe+Usujn9+R2zrLuQERi3CWvRO3BvnoWSYUaIrLKuAIeY7cMeDax6xGyfIP3x/yFWbEKSXvOnvVg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.7.tgz", + "integrity": "sha512-65RXGZZ20rzqqxTsChdqSpbhA6tdt5IFNgG6o7e1lnPVLCe6TNWQq4rTl4N87hTDD8mV4IxJJnvyE7brbnRkQw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" }, @@ -2107,12 +2632,12 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.6.tgz", - "integrity": "sha512-UJKw4LlEkytzz2Wq+uIdHf6qOtFfee/o7ruH0jF5I6UAuU+19r9QV7nU3P/uI0l6+oElRHmG/5cBBcGJrD7Ozg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.7.tgz", + "integrity": "sha512-Fouw4KJVWqqUVIu1gZW8BH2HakwLz6dvdrAhXeXfeymOBrZw+hcqaWs+cS1AZPVp4nlbeIujYrKA921ZW2WMPA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2120,24 +2645,24 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.6.tgz", - "integrity": "sha512-53SpchU3+DUZrN7J6sBx9tBiCVGzsib2e4sc512Q7K9fpC5zkJKs6Z9s+qbMxSYrkEkle6hnMtrts7XNkMJJMg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.7.tgz", + "integrity": "sha512-91PRkTfiBf9hxkIchhRKJfl1rsplRDyBnmyFca3y0Z3x/q0JJN480S83LBd8R6sBCkm2bBbqw2FHp0Mbh+ecSA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2" + "@smithy/types": "^3.5.0" }, "engines": { "node": ">=16.0.0" } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.7.tgz", - "integrity": "sha512-IA4K2qTJYXkF5OfVN4vsY1hfnUZjaslEE8Fsr/gGFza4TAC2A9NfnZuSY2srQIbt9bwtjHiAayrRVgKse4Q7fA==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.8.tgz", + "integrity": "sha512-0NHdQiSkeGl0ICQKcJQ2lCOKH23Nb0EaAa7RDRId6ZqwXkw4LJyIyZ0t3iusD4bnKYDPLGy2/5e2rfUhrt0Acw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2145,16 +2670,16 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.1.4.tgz", - "integrity": "sha512-72MiK7xYukNsnLJI9NqvUHqTu0ziEsfMsYNlWpiJfuGQnCTFKpckThlEatirvcA/LmT1h7rRO+pJD06PYsPu9Q==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.0.tgz", + "integrity": "sha512-LafbclHNKnsorMgUkKm7Tk7oJ7xizsZ1VwqhGKqoCIrXh4fqDDp73fK99HOEEgcsQbtemmeY/BPv0vTVYYUNEQ==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^3.0.0", - "@smithy/protocol-http": "^4.1.3", - "@smithy/types": "^3.4.2", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-middleware": "^3.0.6", + "@smithy/util-middleware": "^3.0.7", "@smithy/util-uri-escape": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" @@ -2164,16 +2689,16 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.3.5.tgz", - "integrity": "sha512-7IZi8J3Dr9n3tX+lcpmJ/5tCYIqoXdblFBaPuv0SEKZFRpCxE+TqIWL6I3t7jLlk9TWu3JSvEZAhtjB9yvB+zA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.4.0.tgz", + "integrity": "sha512-nOfJ1nVQsxiP6srKt43r2My0Gp5PLWCW2ASqUioxIiGmu6d32v4Nekidiv5qOmmtzIrmaD+ADX5SKHUuhReeBQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-endpoint": "^3.1.3", - "@smithy/middleware-stack": "^3.0.6", - "@smithy/protocol-http": "^4.1.3", - "@smithy/types": "^3.4.2", - "@smithy/util-stream": "^3.1.8", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", + "@smithy/util-stream": "^3.1.9", "tslib": "^2.6.2" }, "engines": { @@ -2181,9 +2706,9 @@ } }, "node_modules/@smithy/types": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.4.2.tgz", - "integrity": "sha512-tHiFcfcVedVBHpmHUEUHOCCih8iZbIAYn9NvPsNzaPm/237I3imdDdZoOC8c87H5HBAVEa06tTgb+OcSWV9g5w==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.5.0.tgz", + "integrity": "sha512-QN0twHNfe8mNJdH9unwsCK13GURU7oEAZqkBI+rsvpv1jrmserO+WnLE7jidR9W/1dxwZ0u/CB01mV2Gms/K2Q==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -2193,13 +2718,13 @@ } }, "node_modules/@smithy/url-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.6.tgz", - "integrity": "sha512-47Op/NU8Opt49KyGpHtVdnmmJMsp2hEwBdyjuFB9M2V5QVOwA7pBhhxKN5z6ztKGrMw76gd8MlbPuzzvaAncuQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.7.tgz", + "integrity": "sha512-70UbSSR8J97c1rHZOWhl+VKiZDqHWxs/iW8ZHrHp5fCCPLSBE7GcUlUvKSle3Ca+J9LLbYCj/A79BxztBvAfpA==", "license": "Apache-2.0", "dependencies": { - "@smithy/querystring-parser": "^3.0.6", - "@smithy/types": "^3.4.2", + "@smithy/querystring-parser": "^3.0.7", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" } }, @@ -2260,14 +2785,14 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.21.tgz", - "integrity": "sha512-M/FhTBk4c/SsB91dD/M4gMGfJO7z/qJaM9+XQQIqBOf4qzZYMExnP7R4VdGwxxH8IKMGW+8F0I4rNtVRrcfPoA==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.23.tgz", + "integrity": "sha512-Y07qslyRtXDP/C5aWKqxTPBl4YxplEELG3xRrz2dnAQ6Lq/FgNrcKWmV561nNaZmFH+EzeGOX3ZRMbU8p1T6Nw==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^3.1.6", - "@smithy/smithy-client": "^3.3.5", - "@smithy/types": "^3.4.2", + "@smithy/property-provider": "^3.1.7", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", "bowser": "^2.11.0", "tslib": "^2.6.2" }, @@ -2276,17 +2801,17 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.21.tgz", - "integrity": "sha512-NiLinPvF86U3S2Pdx/ycqd4bnY5dmFSPNL5KYRwbNjqQFS09M5Wzqk8BNk61/47xCYz1X/6KeiSk9qgYPTtuDw==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.23.tgz", + "integrity": "sha512-9Y4WH7f0vnDGuHUa4lGX9e2p+sMwODibsceSV6rfkZOvMC+BY3StB2LdO1NHafpsyHJLpwAgChxQ38tFyd6vkg==", "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^3.0.8", - "@smithy/credential-provider-imds": "^3.2.3", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/property-provider": "^3.1.6", - "@smithy/smithy-client": "^3.3.5", - "@smithy/types": "^3.4.2", + "@smithy/config-resolver": "^3.0.9", + "@smithy/credential-provider-imds": "^3.2.4", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/property-provider": "^3.1.7", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2294,13 +2819,13 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.2.tgz", - "integrity": "sha512-FEISzffb4H8DLzGq1g4MuDpcv6CIG15fXoQzDH9SjpRJv6h7J++1STFWWinilG0tQh9H1v2UKWG19Jjr2B16zQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.3.tgz", + "integrity": "sha512-34eACeKov6jZdHqS5hxBMJ4KyWKztTMulhuQ2UdOoP6vVxMLrOKUqIXAwJe/wiWMhXhydLW664B02CNpQBQ4Aw==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.7", - "@smithy/types": "^3.4.2", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2320,12 +2845,12 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.6.tgz", - "integrity": "sha512-BxbX4aBhI1O9p87/xM+zWy0GzT3CEVcXFPBRDoHAM+pV0eSW156pR+PSYEz0DQHDMYDsYAflC2bQNz2uaDBUZQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.7.tgz", + "integrity": "sha512-OVA6fv/3o7TMJTpTgOi1H5OTwnuUa8hzRzhSFDtZyNxi6OZ70L/FHattSmhE212I7b6WSOJAAmbYnvcjTHOJCA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2333,13 +2858,13 @@ } }, "node_modules/@smithy/util-retry": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.6.tgz", - "integrity": "sha512-BRZiuF7IwDntAbevqMco67an0Sr9oLQJqqRCsSPZZHYRnehS0LHDAkJk/pSmI7Z8c/1Vet294H7fY2fWUgB+Rg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.7.tgz", + "integrity": "sha512-nh1ZO1vTeo2YX1plFPSe/OXaHkLAHza5jpokNiiKX2M5YpNUv6RxGJZhpfmiR4jSvVHCjIDmILjrxKmP+/Ghug==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^3.0.6", - "@smithy/types": "^3.4.2", + "@smithy/service-error-classification": "^3.0.7", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2347,14 +2872,14 @@ } }, "node_modules/@smithy/util-stream": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.8.tgz", - "integrity": "sha512-hoKOqSmb8FD3WLObuB5hwbM7bNIWgcnvkThokTvVq7J5PKjlLUK5qQQcB9zWLHIoSaIlf3VIv2OxZY2wtQjcRQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.9.tgz", + "integrity": "sha512-7YAR0Ub3MwTMjDfjnup4qa6W8gygZMxikBhFMPESi6ASsl/rZJhwLpF/0k9TuezScCojsM0FryGdz4LZtjKPPQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^3.2.8", - "@smithy/node-http-handler": "^3.2.3", - "@smithy/types": "^3.4.2", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/types": "^3.5.0", "@smithy/util-base64": "^3.0.0", "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-hex-encoding": "^3.0.0", @@ -2390,13 +2915,13 @@ } }, "node_modules/@smithy/util-waiter": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.1.5.tgz", - "integrity": "sha512-jYOSvM3H6sZe3CHjzD2VQNCjWBJs+4DbtwBMvUp9y5EnnwNa7NQxTeYeQw0CKCAdGGZ3QvVkyJmvbvs5M/B10A==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.1.6.tgz", + "integrity": "sha512-xs/KAwWOeCklq8aMlnpk25LgxEYHKOEodfjfKclDMLcBJEVEKzDLxZxBQyztcuPJ7F54213NJS8PxoiHNMdItQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^3.1.4", - "@smithy/types": "^3.4.2", + "@smithy/abort-controller": "^3.1.5", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { diff --git a/package.json b/package.json index ecda708b6..b170d0045 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "makeitpretty": "prettier --write \"**/*.{css,js,json,jsx,scss}\"" }, "dependencies": { + "@aws-sdk/client-elasticache": "^3.665.0", "@aws-sdk/client-secrets-manager": "^3.654.0", "@aws-sdk/client-ses": "^3.654.0", "@aws-sdk/credential-provider-node": "^3.654.0", diff --git a/server.js b/server.js index b57cc667d..d84aa907e 100644 --- a/server.js +++ b/server.js @@ -15,6 +15,8 @@ const logger = require("./server/utils/logger"); const { applyRedisHelpers } = require("./server/utils/redisHelpers"); const { applyIOHelpers } = require("./server/utils/ioHelpers"); const { redisSocketEvents } = require("./server/web-sockets/redisSocketEvents"); +const { ElastiCacheClient, DescribeCacheClustersCommand } = require("@aws-sdk/client-elasticache"); +const { default: InstanceManager } = require("./server/utils/instanceMgr"); // Load environment variables require("dotenv").config({ @@ -106,28 +108,65 @@ const applyRoutes = ({ app }) => { }); }; +/** + * Fetch Redis nodes from AWS ElastiCache + * @returns {Promise} + */ +const getRedisNodesFromAWS = async () => { + const client = new ElastiCacheClient({ + region: InstanceManager({ + imex: "ca-central-1", + rome: "us-east-2" + }) + }); + + const params = { + ReplicationGroupId: process.env.REDIS_CLUSTER_ID, + ShowCacheNodeInfo: true + }; + + try { + // Fetch the cache clusters associated with the replication group + const command = new DescribeCacheClustersCommand(params); + const response = await client.send(command); + const cacheClusters = response.CacheClusters; + + return cacheClusters.flatMap((cluster) => + cluster.CacheNodes.map((node) => `${node.Endpoint.Address}:${node.Endpoint.Port}`) + ); + } catch (err) { + logger.log(`Error fetching Redis nodes from AWS: ${err.message}`, "ERROR", "redis", "api"); + throw err; + } +}; + /** * Connect to Redis Cluster * @returns {Promise} */ -const connectToRedisCluster = () => { - if (isEmpty(process.env?.REDIS_URL) || !isString(process.env?.REDIS_URL)) { - logger.log(`[${process.env.NODE_ENV}] No or Malformed REDIS_URL present.`, "ERROR", "redis", "api"); - process.exit(1); - } - +const connectToRedisCluster = async () => { let redisServers; - try { - redisServers = JSON.parse(process.env.REDIS_URL); - } catch (error) { - logger.log( - `[${process.env.NODE_ENV}] Failed to parse REDIS_URL: ${error.message}. Exiting...`, - "ERROR", - "redis", - "api" - ); - process.exit(1); + if (isString(process.env?.REDIS_CLUSTER_ID) && !isEmpty(process.env?.REDIS_CLUSTER_ID)) { + // Fetch Redis nodes from AWS if AWS environment variables are present + redisServers = await getRedisNodesFromAWS(); + } else { + // Use the Dockerized Redis cluster in development + if (isEmpty(process.env?.REDIS_URL) || !isString(process.env?.REDIS_URL)) { + logger.log(`[${process.env.NODE_ENV}] No or Malformed REDIS_URL present.`, "ERROR", "redis", "api"); + process.exit(1); + } + try { + redisServers = JSON.parse(process.env.REDIS_URL); + } catch (error) { + logger.log( + `[${process.env.NODE_ENV}] Failed to parse REDIS_URL: ${error.message}. Exiting...`, + "ERROR", + "redis", + "api" + ); + process.exit(1); + } } const clusterRetryStrategy = (times) => { diff --git a/server/email/sendemail.js b/server/email/sendemail.js index 5dea4a075..f1586dbec 100644 --- a/server/email/sendemail.js +++ b/server/email/sendemail.js @@ -18,7 +18,7 @@ const ses = new aws.SES({ // The key apiVersion is no longer supported in v3, and can be removed. // @deprecated The client uses the "latest" apiVersion. apiVersion: "latest", - defaultProvider, + credentials: defaultProvider(), region: InstanceManager({ imex: "ca-central-1", rome: "us-east-2" @@ -96,7 +96,7 @@ const sendServerEmail = async ({ subject, text }) => { } }; -const sendProManagerWelcomeEmail = async ({to, subject, html}) => { +const sendProManagerWelcomeEmail = async ({ to, subject, html }) => { try { await transporter.sendMail({ from: `ProManager `, diff --git a/server/email/tasksEmails.js b/server/email/tasksEmails.js index 7fe0f7808..50ae88be7 100644 --- a/server/email/tasksEmails.js +++ b/server/email/tasksEmails.js @@ -15,7 +15,7 @@ const { taskEmailQueue } = require("./tasksEmailsQueue"); const ses = new aws.SES({ apiVersion: "latest", - defaultProvider, + credentials: defaultProvider(), region: InstanceManager({ imex: "ca-central-1", rome: "us-east-2" From 2bf074d85a94304aa51b5fe6e7e9bcfd7c007f3b Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 9 Oct 2024 13:00:16 -0400 Subject: [PATCH 12/79] feature/IO-2979-DST-Handling - Add LocalStack and Adjust local Emailing Signed-off-by: Dave Richer --- .dockerignore | 1 - Dockerfile | 5 +- _reference/dockerreadme.md | 5 ++ client/src/redux/user/user.sagas.js | 4 +- docker-compose.yml | 106 +++++++++++++++++++++------- server/email/mailer.js | 49 +++++++++++++ server/email/sendemail.js | 29 ++------ server/email/tasksEmails.js | 23 +----- 8 files changed, 151 insertions(+), 71 deletions(-) create mode 100644 server/email/mailer.js diff --git a/.dockerignore b/.dockerignore index da9a0d123..b6ef4a047 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,7 +7,6 @@ _reference client redis/dockerdata hasura -node_modules # Files to exclude .ebignore diff --git a/Dockerfile b/Dockerfile index dab748c1b..01a1522cd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,6 +25,9 @@ RUN dnf install -y \ # Set the working directory WORKDIR /app +# This is because our test route uses a git commit hash +RUN git config --global --add safe.directory /app + # Copy package.json and package-lock.json COPY package*.json ./ @@ -32,7 +35,7 @@ COPY package*.json ./ RUN npm install -g nodemon # Install dependencies -RUN npm install --omit=dev +RUN npm ci # Copy the rest of your application code COPY . . diff --git a/_reference/dockerreadme.md b/_reference/dockerreadme.md index b65c6b23d..9ae7c140e 100644 --- a/_reference/dockerreadme.md +++ b/_reference/dockerreadme.md @@ -138,6 +138,10 @@ sudo sysctl -p # Install Docker and Docker Compose in WSL2 - https://docs.docker.com/desktop/wsl/ +# Local Stack +- LocalStack Front end (Optional) - https://apps.microsoft.com/detail/9ntrnft9zws2?hl=en-us&gl=US +- http://localhost:4566/_aws/ses will allow you to see emails sent + # Docker Commands ## General `docker-compose` Commands: @@ -150,6 +154,7 @@ sudo sysctl -p 7. View running Containers: `docker-compose ps` 8. View a specific containers logs: `docker-compose logs ` 9. Scale services (multiple instances of a service): `docker-compose up --scale = -d` +10. Watch a specific containers logs in realtime with timestamps: `docker-compose logs -f --timestamps ` ## Volume Management Commands 1. List Docker volumes: `docker volume ls` diff --git a/client/src/redux/user/user.sagas.js b/client/src/redux/user/user.sagas.js index b399c0052..f565ea544 100644 --- a/client/src/redux/user/user.sagas.js +++ b/client/src/redux/user/user.sagas.js @@ -314,8 +314,8 @@ export function* SetAuthLevelFromShopDetails({ payload }) { try { const userEmail = yield select((state) => state.user.currentUser.email); try { - //console.log("Setting shop timezone."); - // dayjs.tz.setDefault(payload.timezone); + console.log("Setting shop timezone."); + day.tz.setDefault(payload.timezone); } catch (error) { console.log(error); } diff --git a/docker-compose.yml b/docker-compose.yml index 4e8ecf9d4..1bd0bc423 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,14 @@ ############################# # Ports Exposed -# 4000 - Imex Node API -# 3333 - SocketIO Admin-UI -# 3334 - Redis-Insights +# 4000 - Imex Node API +# 4556 - LocalStack (Local AWS) +# 3333 - SocketIO Admin-UI (Optional) +# 3334 - Redis-Insights (Optional) ############################# services: + + # Redis Node 1 redis-node-1: build: context: ./redis @@ -22,7 +25,8 @@ services: interval: 10s timeout: 5s retries: 10 - + + # Redis Node 2 redis-node-2: build: context: ./redis @@ -40,6 +44,7 @@ services: timeout: 5s retries: 10 + # Redis Node 3 redis-node-3: build: context: ./redis @@ -57,6 +62,52 @@ services: timeout: 5s retries: 10 + # LocalStack: Used to emulate AWS services locally, currently setup for SES + localstack: + image: localstack/localstack + container_name: localstack + hostname: localstack + networks: + - redis-cluster-net + restart: always + volumes: + - /var/run/docker.sock:/var/run/docker.sock + environment: + - SERVICES=ses + - DEBUG=1 + - AWS_ACCESS_KEY_ID=test + - AWS_SECRET_ACCESS_KEY=test + - AWS_DEFAULT_REGION=ca-central-1 + ports: + - "4566:4566" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:4566/_localstack/health"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 20s + + # AWS-CLI - Used in conjunction with LocalStack to set required permission to send emails + aws-cli: + image: amazon/aws-cli + container_name: aws-cli + hostname: aws-cli + networks: + - redis-cluster-net + depends_on: + localstack: + condition: service_healthy + environment: + - AWS_ACCESS_KEY_ID=test + - AWS_SECRET_ACCESS_KEY=test + - AWS_DEFAULT_REGION=ca-central-1 + entrypoint: /bin/sh -c + command: > + " + aws --endpoint-url=http://localstack:4566 ses verify-domain-identity --domain imex.online --region ca-central-1 + aws --endpoint-url=http://localstack:4566 ses verify-email-identity --email-address noreply@imex.online --region ca-central-1 + " + # Node App: The Main IMEX API node-app: build: context: . @@ -73,37 +124,44 @@ services: condition: service_healthy redis-node-3: condition: service_healthy + localstack: + condition: service_healthy + aws-cli: + condition: service_completed_successfully ports: - "4000:4000" volumes: - .:/app - - /app/node_modules + - node-app-npm-cache:/app/node_modules - socketio-admin-ui: - image: maitrungduc1410/socket.io-admin-ui - container_name: socketio-admin-ui - networks: - - redis-cluster-net - ports: - - "3333:80" - - redis-insight: - image: redislabs/redisinsight:latest - container_name: redis-insight - hostname: redis-insight - restart: always - ports: - - "3334:5540" - networks: - - redis-cluster-net - volumes: - - redis-insight-data:/db +# ## Optional Container to Observe SocketIO data +# socketio-admin-ui: +# image: maitrungduc1410/socket.io-admin-ui +# container_name: socketio-admin-ui +# networks: +# - redis-cluster-net +# ports: +# - "3333:80" + +# ##Optional Container to Observe Redis Cluster Data +# redis-insight: +# image: redislabs/redisinsight:latest +# container_name: redis-insight +# hostname: redis-insight +# restart: always +# ports: +# - "3334:5540" +# networks: +# - redis-cluster-net +# volumes: +# - redis-insight-data:/db networks: redis-cluster-net: driver: bridge volumes: + node-app-npm-cache: redis-node-1-data: redis-node-2-data: redis-node-3-data: diff --git a/server/email/mailer.js b/server/email/mailer.js new file mode 100644 index 000000000..78e02037e --- /dev/null +++ b/server/email/mailer.js @@ -0,0 +1,49 @@ +const { isString, isEmpty } = require("lodash"); +const { defaultProvider } = require("@aws-sdk/credential-provider-node"); +const { default: InstanceManager } = require("../utils/instanceMgr"); +const aws = require("@aws-sdk/client-ses"); +const nodemailer = require("nodemailer"); + +const isLocal = isString(process.env?.LOCALSTACK_HOSTNAME) && !isEmpty(process.env?.LOCALSTACK_HOSTNAME); + +const sesConfig = { + apiVersion: "latest", + credentials: defaultProvider(), + region: isLocal + ? "ca-central-1" + : InstanceManager({ + imex: "ca-central-1", + rome: "us-east-2" + }) +}; + +if (isLocal) { + sesConfig.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`; + console.log(`SES Mailer set to LocalStack end point: ${sesConfig.endpoint}`); +} + +const ses = new aws.SES(sesConfig); + +let transporter = nodemailer.createTransport({ + SES: { ses, aws } +}); + +if (isLocal) { + // Wrap the sendMail function to log the email contents to the console in local environment + const originalSendMail = transporter.sendMail.bind(transporter); + transporter.sendMail = async (mailOptions) => { + try { + const result = await originalSendMail(mailOptions); + console.log( + `Email sent successfully - From: ${result?.envelope?.from} - To: ${result?.envelope?.to} - MessageID ${result.messageId} - Check LocalStack to see message` + ); + + return result; + } catch (error) { + console.error("Failed to send email:", error); + throw error; + } + }; +} + +module.exports = transporter; diff --git a/server/email/sendemail.js b/server/email/sendemail.js index f1586dbec..97e8f74ad 100644 --- a/server/email/sendemail.js +++ b/server/email/sendemail.js @@ -3,30 +3,13 @@ require("dotenv").config({ path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) }); const axios = require("axios"); -let nodemailer = require("nodemailer"); -let aws = require("@aws-sdk/client-ses"); -let { defaultProvider } = require("@aws-sdk/credential-provider-node"); const InstanceManager = require("../utils/instanceMgr").default; const logger = require("../utils/logger"); const client = require("../graphql-client/graphql-client").client; const queries = require("../graphql-client/queries"); const { isObject } = require("lodash"); const generateEmailTemplate = require("./generateTemplate"); -const moment = require("moment"); - -const ses = new aws.SES({ - // The key apiVersion is no longer supported in v3, and can be removed. - // @deprecated The client uses the "latest" apiVersion. - apiVersion: "latest", - credentials: defaultProvider(), - region: InstanceManager({ - imex: "ca-central-1", - rome: "us-east-2" - }) -}); -let transporter = nodemailer.createTransport({ - SES: { ses, aws } -}); +const mailer = require("./mailer"); // Get the image from the URL and return it as a base64 string const getImage = async (imageUrl) => { @@ -66,7 +49,7 @@ const logEmail = async (req, email) => { const sendServerEmail = async ({ subject, text }) => { if (process.env.NODE_ENV === undefined) return; try { - transporter.sendMail( + mailer.sendMail( { from: InstanceManager({ imex: `ImEX Online API - ${process.env.NODE_ENV} `, @@ -98,7 +81,7 @@ const sendServerEmail = async ({ subject, text }) => { const sendProManagerWelcomeEmail = async ({ to, subject, html }) => { try { - await transporter.sendMail({ + await mailer.sendMail({ from: `ProManager `, to, subject, @@ -112,7 +95,7 @@ const sendProManagerWelcomeEmail = async ({ to, subject, html }) => { const sendTaskEmail = async ({ to, subject, type = "text", html, text, attachments }) => { try { - transporter.sendMail( + mailer.sendMail( { from: InstanceManager({ imex: `ImEX Online `, @@ -166,7 +149,7 @@ const sendEmail = async (req, res) => { ); } - transporter.sendMail( + mailer.sendMail( { from: `${req.body.from.name} <${req.body.from.address}>`, replyTo: req.body.ReplyTo.Email, @@ -280,7 +263,7 @@ const emailBounce = async (req, res) => { status: "Bounced", context: message.bounce?.bouncedRecipients }); - transporter.sendMail( + mailer.sendMail( { from: InstanceMgr({ imex: `ImEX Online `, diff --git a/server/email/tasksEmails.js b/server/email/tasksEmails.js index 088c36a66..ea99a2d23 100644 --- a/server/email/tasksEmails.js +++ b/server/email/tasksEmails.js @@ -2,9 +2,6 @@ const path = require("path"); require("dotenv").config({ path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) }); -let nodemailer = require("nodemailer"); -let aws = require("@aws-sdk/client-ses"); -let { defaultProvider } = require("@aws-sdk/credential-provider-node"); const InstanceManager = require("../utils/instanceMgr").default; const logger = require("../utils/logger"); const client = require("../graphql-client/graphql-client").client; @@ -12,20 +9,7 @@ const queries = require("../graphql-client/queries"); const generateEmailTemplate = require("./generateTemplate"); const moment = require("moment-timezone"); const { taskEmailQueue } = require("./tasksEmailsQueue"); - -const ses = new aws.SES({ - apiVersion: "latest", - credentials: defaultProvider(), - region: InstanceManager({ - imex: "ca-central-1", - rome: "us-east-2" - }) -}); - -const transporter = nodemailer.createTransport({ - SES: { ses, aws }, - sendingRate: InstanceManager({ imex: 40, rome: 10 }) -}); +const mailer = require("./mailer"); // Initialize the Tasks Email Queue const tasksEmailQueue = taskEmailQueue(); @@ -124,6 +108,7 @@ const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, j * @param html * @param taskIds * @param successCallback + * @param requestInstance */ const sendMail = (type, to, subject, html, taskIds, successCallback, requestInstance) => { const fromEmails = InstanceManager({ @@ -134,7 +119,7 @@ const sendMail = (type, to, subject, html, taskIds, successCallback, requestInst : "Rome Online " }); - transporter.sendMail( + mailer.sendMail( { from: fromEmails, to, @@ -151,8 +136,6 @@ const sendMail = (type, to, subject, html, taskIds, successCallback, requestInst } } ); - // } - // }); }; /** From 5a908548617c56e5aca928d4151593eb95a14ed4 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 10 Oct 2024 13:01:36 -0400 Subject: [PATCH 13/79] feature/IO-2979-DST-Handling - Checkpoint Signed-off-by: Dave Richer --- docker-compose.yml | 6 +++++- nodemon.json | 35 ++++++++++++++++++++++++++++++++ server/email/mailer.js | 18 ---------------- server/email/tasksEmails.js | 23 +++++++++++++++++++++ server/email/tasksEmailsQueue.js | 2 +- 5 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 nodemon.json diff --git a/docker-compose.yml b/docker-compose.yml index 1bd0bc423..dd8dac175 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -63,6 +63,7 @@ services: retries: 10 # LocalStack: Used to emulate AWS services locally, currently setup for SES + # Notes: Set the ENV Debug to 1 for additional logging localstack: image: localstack/localstack container_name: localstack @@ -74,10 +75,13 @@ services: - /var/run/docker.sock:/var/run/docker.sock environment: - SERVICES=ses - - DEBUG=1 + - DEBUG=0 - AWS_ACCESS_KEY_ID=test - AWS_SECRET_ACCESS_KEY=test - AWS_DEFAULT_REGION=ca-central-1 + - EXTRA_CORS_ALLOWED_HEADERS=Authorization,Content-Type + - EXTRA_CORS_ALLOWED_ORIGINS=* + - EXTRA_CORS_EXPOSE_HEADERS=Authorization,Content-Type ports: - "4566:4566" healthcheck: diff --git a/nodemon.json b/nodemon.json new file mode 100644 index 000000000..e267a23c7 --- /dev/null +++ b/nodemon.json @@ -0,0 +1,35 @@ +{ + "watch": [ + "server.js", + "server" + ], + "ignore": [ + "client", + ".circleci", + ".platform", + ".idea", + ".vscode", + "_reference", + "firebase", + "hasura", + "logs", + "redis", + ".dockerignore", + ".ebignore", + ".editorconfig", + ".env.development", + ".env.development.rome", + ".eslintrc.json", + ".gitignore", + ".npmmrc", + ".prettierrc.js", + "bodyshop_translations.babel", + "Dockerfile", + "ecosystem.config.js", + "job-totals-testing-util.js", + "nodemon.json", + "package.json", + "package-lock.json", + "setadmin.js" + ] +} diff --git a/server/email/mailer.js b/server/email/mailer.js index 78e02037e..6503e1f8c 100644 --- a/server/email/mailer.js +++ b/server/email/mailer.js @@ -28,22 +28,4 @@ let transporter = nodemailer.createTransport({ SES: { ses, aws } }); -if (isLocal) { - // Wrap the sendMail function to log the email contents to the console in local environment - const originalSendMail = transporter.sendMail.bind(transporter); - transporter.sendMail = async (mailOptions) => { - try { - const result = await originalSendMail(mailOptions); - console.log( - `Email sent successfully - From: ${result?.envelope?.from} - To: ${result?.envelope?.to} - MessageID ${result.messageId} - Check LocalStack to see message` - ); - - return result; - } catch (error) { - console.error("Failed to send email:", error); - throw error; - } - }; -} - module.exports = transporter; diff --git a/server/email/tasksEmails.js b/server/email/tasksEmails.js index ea99a2d23..189471e5a 100644 --- a/server/email/tasksEmails.js +++ b/server/email/tasksEmails.js @@ -324,6 +324,29 @@ const tasksRemindEmail = async (req, res) => { } }; +// Note: Uncomment this to test locally, it will call the remind_at email check every 20 seconds +// const callTaskRemindEmailInternally = () => { +// const req = { +// body: { +// // You can mock any request data here if needed +// } +// }; +// +// const res = { +// status: (code) => { +// return { +// json: (data) => { +// console.log(`Response Status: ${code}`, data); +// } +// }; +// } +// }; +// +// // Call the taskRemindEmail function with mock req and res +// tasksRemindEmail(req, res); +// }; +// setInterval(callTaskRemindEmailInternally, 20000); + module.exports = { taskAssignedEmail, tasksRemindEmail, diff --git a/server/email/tasksEmailsQueue.js b/server/email/tasksEmailsQueue.js index dc004abc1..b01c9aa14 100644 --- a/server/email/tasksEmailsQueue.js +++ b/server/email/tasksEmailsQueue.js @@ -13,7 +13,7 @@ const taskEmailQueue = () => console.log("Processing reminds for taskIds: ", taskIds.join(", ")); // Set the remind_at_sent to the current time. - const now = moment().toISOString(); + const now = moment.utc().toISOString(); client .request(UPDATE_TASKS_REMIND_AT_SENT, { taskIds, now }) From 7fc6556866704b3bdd8e93ad23a40837d49aa246 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Fri, 11 Oct 2024 16:03:40 -0400 Subject: [PATCH 14/79] IO-2791 Stop gap change to limit exports to 10 records at a time. --- .../jobs-export-all-button/jobs-export-all-button.component.jsx | 2 +- .../payable-export-all-button.component.jsx | 2 +- .../payments-export-all-button.component.jsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx b/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx index 70f7763f2..d8e4da7ce 100644 --- a/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx +++ b/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx @@ -219,7 +219,7 @@ export function JobsExportAllButton({ }; return ( - ); diff --git a/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx b/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx index 4194983bb..b6d39e915 100644 --- a/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx +++ b/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx @@ -200,7 +200,7 @@ export function PayableExportAll({ ); return ( - ); diff --git a/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx b/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx index ba3334d14..23890abb7 100644 --- a/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx +++ b/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx @@ -180,7 +180,7 @@ export function PaymentsExportAllButton({ }; return ( - ); From 7879591bcf46b70687ca55768d7f36f8d2202f9f Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Fri, 11 Oct 2024 16:05:30 -0400 Subject: [PATCH 15/79] IO-2971 add null coalescing --- .../jobs-export-all-button/jobs-export-all-button.component.jsx | 2 +- .../payable-export-all-button.component.jsx | 2 +- .../payments-export-all-button.component.jsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx b/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx index d8e4da7ce..e149f39f0 100644 --- a/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx +++ b/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx @@ -219,7 +219,7 @@ export function JobsExportAllButton({ }; return ( - ); diff --git a/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx b/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx index b6d39e915..dc8316be8 100644 --- a/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx +++ b/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx @@ -200,7 +200,7 @@ export function PayableExportAll({ ); return ( - ); diff --git a/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx b/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx index 23890abb7..5c4246890 100644 --- a/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx +++ b/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx @@ -180,7 +180,7 @@ export function PaymentsExportAllButton({ }; return ( - ); From 25e6e61d10971a8a84438e89c0c581cc87aee14c Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 11 Oct 2024 22:59:44 -0400 Subject: [PATCH 16/79] release/2024-10-11: Final touchups Signed-off-by: Dave Richer --- .dockerignore | 2 +- Dockerfile | 4 ++-- docker-compose.yml | 15 ++++++++++----- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.dockerignore b/.dockerignore index b6ef4a047..17605d357 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,7 +7,7 @@ _reference client redis/dockerdata hasura - +node_modules # Files to exclude .ebignore .editorconfig diff --git a/Dockerfile b/Dockerfile index 01a1522cd..27a8254e9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,13 +29,13 @@ WORKDIR /app RUN git config --global --add safe.directory /app # Copy package.json and package-lock.json -COPY package*.json ./ +COPY package.json ./ # Install Nodemon RUN npm install -g nodemon # Install dependencies -RUN npm ci +RUN npm i --no-package-lock # Copy the rest of your application code COPY . . diff --git a/docker-compose.yml b/docker-compose.yml index dd8dac175..8b38349fc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,7 @@ services: context: ./redis container_name: redis-node-1 hostname: redis-node-1 - restart: always + restart: unless-stopped networks: - redis-cluster-net volumes: @@ -32,7 +32,7 @@ services: context: ./redis container_name: redis-node-2 hostname: redis-node-2 - restart: always + restart: unless-stopped networks: - redis-cluster-net volumes: @@ -50,7 +50,7 @@ services: context: ./redis container_name: redis-node-3 hostname: redis-node-3 - restart: always + restart: unless-stopped networks: - redis-cluster-net volumes: @@ -70,7 +70,7 @@ services: hostname: localstack networks: - redis-cluster-net - restart: always + restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock environment: @@ -134,6 +134,11 @@ services: condition: service_completed_successfully ports: - "4000:4000" + develop: + watch: + # rebuild image and recreate service + - path: package.json + action: rebuild volumes: - .:/app - node-app-npm-cache:/app/node_modules @@ -152,7 +157,7 @@ services: # image: redislabs/redisinsight:latest # container_name: redis-insight # hostname: redis-insight -# restart: always +# restart: unless-stopped # ports: # - "3334:5540" # networks: From 8a047d14a18f3878c63878336f79a21b6a14bbff Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 11 Oct 2024 23:51:39 -0400 Subject: [PATCH 17/79] release/2024-10-11: Final touchups Signed-off-by: Dave Richer --- docker-compose.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8b38349fc..57232cdfb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -134,11 +134,6 @@ services: condition: service_completed_successfully ports: - "4000:4000" - develop: - watch: - # rebuild image and recreate service - - path: package.json - action: rebuild volumes: - .:/app - node-app-npm-cache:/app/node_modules From 87d3ceb4085e614529ad163638a693ee9bbf9efa Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Sat, 12 Oct 2024 12:05:13 -0400 Subject: [PATCH 18/79] release/2024-10-11: Hotfix Signed-off-by: Dave Richer --- server/email/tasksEmails.js | 2 ++ server/email/tasksEmailsQueue.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/server/email/tasksEmails.js b/server/email/tasksEmails.js index 189471e5a..ff20af151 100644 --- a/server/email/tasksEmails.js +++ b/server/email/tasksEmails.js @@ -29,10 +29,12 @@ if (process.env.NODE_ENV !== "development") { // Handling SIGINT (e.g., Ctrl+C) process.on("SIGINT", async () => { await tasksEmailQueueCleanup(); + process.exit(0); }); // Handling SIGTERM (e.g., sent by system shutdown) process.on("SIGTERM", async () => { await tasksEmailQueueCleanup(); + process.exit(0); }); // Handling uncaught exceptions process.on("uncaughtException", async (err) => { diff --git a/server/email/tasksEmailsQueue.js b/server/email/tasksEmailsQueue.js index b01c9aa14..dc004abc1 100644 --- a/server/email/tasksEmailsQueue.js +++ b/server/email/tasksEmailsQueue.js @@ -13,7 +13,7 @@ const taskEmailQueue = () => console.log("Processing reminds for taskIds: ", taskIds.join(", ")); // Set the remind_at_sent to the current time. - const now = moment.utc().toISOString(); + const now = moment().toISOString(); client .request(UPDATE_TASKS_REMIND_AT_SENT, { taskIds, now }) From 05cc4dd18894100ab2f1a2609b2f9bacaae6cfca Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Sat, 12 Oct 2024 12:26:30 -0400 Subject: [PATCH 19/79] release/2024-10-11: Hotfix Signed-off-by: Dave Richer --- server/email/tasksEmails.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/email/tasksEmails.js b/server/email/tasksEmails.js index ff20af151..94deb2be2 100644 --- a/server/email/tasksEmails.js +++ b/server/email/tasksEmails.js @@ -39,12 +39,12 @@ if (process.env.NODE_ENV !== "development") { // Handling uncaught exceptions process.on("uncaughtException", async (err) => { await tasksEmailQueueCleanup(); - throw err; + process.exit(1); }); // Handling unhandled promise rejections process.on("unhandledRejection", async (reason, promise) => { await tasksEmailQueueCleanup(); - throw reason; + process.exit(1); }); } From 23467280b4fa60431a90f9aa088f21d6c0add400 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 16 Oct 2024 13:18:48 -0400 Subject: [PATCH 20/79] release/2024-10-11: Remove Task Emails Cleanup Signed-off-by: Dave Richer --- server/email/tasksEmails.js | 48 ++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/server/email/tasksEmails.js b/server/email/tasksEmails.js index 94deb2be2..c8aebaa64 100644 --- a/server/email/tasksEmails.js +++ b/server/email/tasksEmails.js @@ -25,28 +25,32 @@ const tasksEmailQueueCleanup = async () => { } }; -if (process.env.NODE_ENV !== "development") { - // Handling SIGINT (e.g., Ctrl+C) - process.on("SIGINT", async () => { - await tasksEmailQueueCleanup(); - process.exit(0); - }); - // Handling SIGTERM (e.g., sent by system shutdown) - process.on("SIGTERM", async () => { - await tasksEmailQueueCleanup(); - process.exit(0); - }); - // Handling uncaught exceptions - process.on("uncaughtException", async (err) => { - await tasksEmailQueueCleanup(); - process.exit(1); - }); - // Handling unhandled promise rejections - process.on("unhandledRejection", async (reason, promise) => { - await tasksEmailQueueCleanup(); - process.exit(1); - }); -} +// if (process.env.NODE_ENV !== "development") { +// // Handling SIGINT (e.g., Ctrl+C) +// process.on("SIGINT", async () => { +// console.log("Handling SIGNIT For Tasks Cleanup"); +// await tasksEmailQueueCleanup(); +// process.exit(0); +// }); +// // Handling SIGTERM (e.g., sent by system shutdown) +// process.on("SIGTERM", async () => { +// console.log("Handling SIGTERM For Tasks Cleanup"); +// await tasksEmailQueueCleanup(); +// process.exit(0); +// }); +// // Handling uncaught exceptions +// process.on("uncaughtException", async (err) => { +// console.log("Handling uncaughtException For Tasks Cleanup"); +// await tasksEmailQueueCleanup(); +// process.exit(1); +// }); +// // Handling unhandled promise rejections +// process.on("unhandledRejection", async (reason, promise) => { +// console.log("Handling unhandledRejection For Tasks Cleanup"); +// await tasksEmailQueueCleanup(); +// process.exit(1); +// }); +// } /** * Format the date for the email. From 68d1a404b3ffe0645490f60af7f9e7fee69ef794 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 16 Oct 2024 15:28:04 -0400 Subject: [PATCH 21/79] release/2024-10-18: Fixes from Docker meeting Signed-off-by: Dave Richer --- _reference/dockerreadme.md | 139 +++---------------------------------- 1 file changed, 8 insertions(+), 131 deletions(-) diff --git a/_reference/dockerreadme.md b/_reference/dockerreadme.md index 9ae7c140e..d1201564d 100644 --- a/_reference/dockerreadme.md +++ b/_reference/dockerreadme.md @@ -4,139 +4,16 @@ This guide will walk you through the steps to configure your WSL2 (Windows Subsy ## Prerequisites -1. **Windows 10/11** with **WSL2** installed. -2. **Hyper-V** enabled on your system. If not, follow these steps to enable it: - - Open PowerShell as Administrator and run: - ```powershell - dism.exe /Online /Enable-Feature /All /FeatureName:Microsoft-Hyper-V - ``` - - Restart your computer. +1. **Windows 11** +2. **Docker Desktop For Windows (Latest Version) -3. A basic understanding of networking and WSL2 configuration. +# Docker Setup +Inside the root of the project exists the `docker-compose.yaml` file, you can simply run +`docker-compose up` to launch the backend. ---- - -## Step 1: Create an External Hyper-V Switch - -1. **Open Hyper-V Manager**: - - Press `Windows Key + X`, select `Hyper-V Manager`. - -2. **Create a Virtual Switch**: - - In the right-hand pane, click `Virtual Switch Manager`. - - Choose `External` and click `Create Virtual Switch`. - - Select your external network adapter (this is usually your Ethernet or Wi-Fi adapter). - - Give the switch a name (e.g., `WSL External Switch`), then click `Apply` and `OK`. - ---- - -## Step 2: Configure WSL2 to Use the External Hyper-V Switch - -Now that you've created the external virtual switch, follow these steps to configure your WSL2 instance to use this switch. - -1. **Set WSL2 to Use the External Switch**: - - By default, WSL2 uses NAT to connect to your local network. You need to configure WSL2 to use the external Hyper-V switch instead. - -2. **Check WSL2 Networking**: - - Inside WSL, run: - ```bash - ip a - ``` - - You should see an IP address in the range of your local network (e.g., `192.168.x.x`). - ---- - -## Step 3: Configure a Static IP Address for WSL2 - -Once WSL2 is connected to the external network, you can assign a static IP address to your WSL2 instance. - -1. **Open WSL2** and Edit the Network Configuration: - - Depending on your Linux distribution, the file paths may vary, but typically for Ubuntu-based systems: - ```bash - sudo nano /etc/netplan/01-netcfg.yaml - ``` - - If this file doesn’t exist, create a new file or use the correct configuration file path. - -2. **Configure Static IP**: - - Add or update the following configuration: - ```yaml - network: - version: 2 - renderer: networkd - ethernets: - eth0: - dhcp4: no - addresses: - - 192.168.1.100/24 # Choose an IP address in your network range - gateway4: 192.168.1.1 # Your router's IP address - nameservers: - addresses: - - 8.8.8.8 - - 8.8.4.4 - ``` - - Adjust the values according to your local network settings: - - `addresses`: This is the static IP you want to assign. - - `gateway4`: This should be the IP address of your router. - - `nameservers`: These are DNS servers, you can use Google's public DNS or any other DNS provider. - -3. **Apply the Changes**: - - Run the following command to apply the network configuration: - ```bash - sudo netplan apply - ``` - -4. **Verify the Static IP**: - - Check if the static IP is correctly set by running: - ```bash - ip a - ``` - - You should see the static IP you configured (e.g., `192.168.1.100`) on the appropriate network interface (usually `eth0`). - ---- - -## Step 4: Restart WSL2 to Apply Changes - -To ensure the changes are fully applied, restart WSL2: - -1. Open PowerShell or Command Prompt and run: - ```powershell - wsl --shutdown -2. Then, start your WSL2 instance again. - -## Step 5: Verify Connectivity - -1. Check Internet and Local Network Connectivity: - - Run a ping command from within WSL to verify that it can reach the internet: ```ping 8.8.8.8``` -2. Test Access from other Devices: - - If you're running services inside WSL (e.g., a web server), ensure they are accessible from other devices on your local network using the static IP address you configured (e.g., `http://192.168.1.100:4000`). - - - -# Configuring `vm.overcommit_memory` in sysctl for WSL2 - -To prevent memory overcommitment issues and optimize performance, you can configure the `vm.overcommit_memory` setting in WSL2. This is particularly useful when running Redis or other memory-intensive services inside WSL2, as it helps control how the Linux kernel handles memory allocation. - -### 1. **Open the sysctl Configuration File**: -To set the `vm.overcommit_memory` value, you'll need to edit the sysctl configuration file. Inside your WSL2 instance, run the following command to open the `sysctl.conf` file for editing: -```bash - sudo nano /etc/sysctl.conf -``` -### 2. Add the Overcommit Memory Setting: -Add the following line at the end of the file to allow memory overcommitment: -```bash -vm.overcommit_memory = 1 -``` - -This setting tells the Linux kernel to always allow memory allocation, regardless of how much memory is available, which can prevent out-of-memory errors when running certain applications. - -### 3. Apply the Changes: -After editing the file, save it and then apply the new sysctl configuration by running: - -```bash -sudo sysctl -p -``` - -# Install Docker and Docker Compose in WSL2 -- https://docs.docker.com/desktop/wsl/ +Things to note: +- When installing NPM packages, you will need to rebuild the `node-app` container +- Making changes to the server files will restart the `node-app` # Local Stack - LocalStack Front end (Optional) - https://apps.microsoft.com/detail/9ntrnft9zws2?hl=en-us&gl=US From 30ca34ea93e89ad7edb3879655b2b948428d99a8 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Wed, 16 Oct 2024 13:43:25 -0700 Subject: [PATCH 22/79] IO-2971 Export Table Size limit to 10 Signed-off-by: Allan Carr --- .../accounting-payables-table.component.jsx | 4 ++-- .../accounting-payments-table.component.jsx | 4 ++-- .../accounting-receivables-table.component.jsx | 14 +++++++------- client/src/utils/config.js | 1 + 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/client/src/components/accounting-payables-table/accounting-payables-table.component.jsx b/client/src/components/accounting-payables-table/accounting-payables-table.component.jsx index f501b3dbb..1e21ebe34 100644 --- a/client/src/components/accounting-payables-table/accounting-payables-table.component.jsx +++ b/client/src/components/accounting-payables-table/accounting-payables-table.component.jsx @@ -9,7 +9,7 @@ import { logImEXEvent } from "../../firebase/firebase.utils"; import { selectBodyshop } from "../../redux/user/user.selectors"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; import { DateFormatter } from "../../utils/DateFormatter"; -import { pageLimit } from "../../utils/config"; +import { exportPageLimit } from "../../utils/config"; import { alphaSort, dateSort } from "../../utils/sorters"; import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component"; import PayableExportAll from "../payable-export-all-button/payable-export-all-button.component"; @@ -175,7 +175,7 @@ export function AccountingPayablesTableComponent({ bodyshop, loading, bills, ref Date: Wed, 16 Oct 2024 16:38:59 -0700 Subject: [PATCH 23/79] IO-2984 Open in Explorer correction encodeURL Signed-off-by: Allan Carr --- client/src/utils/localmedia.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/utils/localmedia.js b/client/src/utils/localmedia.js index 7734d4b2b..4c776bc25 100644 --- a/client/src/utils/localmedia.js +++ b/client/src/utils/localmedia.js @@ -2,5 +2,5 @@ import { store } from "../redux/store"; export function CreateExplorerLinkForJob({ jobid }) { const bodyshop = store.getState().user.bodyshop; - return `imexmedia://${bodyshop.localmediaservernetwork}\\Jobs\\${jobid}`; + return `imexmedia://`.concat(encodeURIComponent(`${bodyshop.localmediaservernetwork}\\Jobs\\${jobid}`)); } From 9ce419b9497e217019dcfee9e6b9fe376b4ca009 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 17 Oct 2024 11:42:03 -0400 Subject: [PATCH 24/79] feature/IO-2985-Production-List-View-Null-Handling - Handle Null md_production_config Signed-off-by: Dave Richer --- .../production-board-kanban.component.jsx | 2 +- ...oduction-list-config-manager.component.jsx | 69 ++++++++++--------- .../production-list-table.component.jsx | 8 +-- 3 files changed, 40 insertions(+), 39 deletions(-) diff --git a/client/src/components/production-board-kanban/production-board-kanban.component.jsx b/client/src/components/production-board-kanban/production-board-kanban.component.jsx index 0c515132b..ef10f99b9 100644 --- a/client/src/components/production-board-kanban/production-board-kanban.component.jsx +++ b/client/src/components/production-board-kanban/production-board-kanban.component.jsx @@ -185,7 +185,7 @@ function ProductionBoardKanbanComponent({ data, bodyshop, refetch, insertAuditTr const cardSettings = useMemo(() => { const kanbanSettings = associationSettings?.kanban_settings; return mergeWithDefaults(kanbanSettings); - }, [associationSettings]); + }, [associationSettings?.kanban_settings]); const handleSettingsChange = () => { setFilter(defaultFilters); diff --git a/client/src/components/production-list-table/production-list-config-manager.component.jsx b/client/src/components/production-list-table/production-list-config-manager.component.jsx index b34fb92d7..ef8b07af7 100644 --- a/client/src/components/production-list-table/production-list-config-manager.component.jsx +++ b/client/src/components/production-list-table/production-list-config-manager.component.jsx @@ -457,41 +457,42 @@ export function ProductionListConfigManager({ value={activeView} disabled={open || isAddingNewProfile} // Disable the Select box when the popover is open or adding a new profile > - {bodyshop.production_config - .slice() - .sort((a, b) => - a.name === t("production.constants.main_profile") - ? -1 - : b.name === t("production.constants.main_profile") - ? 1 - : 0 - ) // - .map((config) => ( - -
    - - {config.name} - - {config.name !== t("production.constants.main_profile") && ( - handleTrash(config.name)} - onCancel={(e) => e.stopPropagation()} + {bodyshop?.production_config && + bodyshop.production_config + .slice() + .sort((a, b) => + a.name === t("production.constants.main_profile") + ? -1 + : b.name === t("production.constants.main_profile") + ? 1 + : 0 + ) // + .map((config) => ( + +
    + - e.stopPropagation()} /> - - )} -
    -
    - ))} + {config.name} + + {config.name !== t("production.constants.main_profile") && ( + handleTrash(config.name)} + onCancel={(e) => e.stopPropagation()} + > + e.stopPropagation()} /> + + )} +
    +
    + ))}
    diff --git a/client/src/components/production-list-table/production-list-table.component.jsx b/client/src/components/production-list-table/production-list-table.component.jsx index ea3d9c2a2..c8763ad13 100644 --- a/client/src/components/production-list-table/production-list-table.component.jsx +++ b/client/src/components/production-list-table/production-list-table.component.jsx @@ -51,8 +51,8 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici const initialColumnsRef = useRef( (initialStateRef.current && - bodyshop.production_config - .find((p) => p.name === defaultView) + bodyshop?.production_config + ?.find((p) => p.name === defaultView) ?.columns.columnKeys.map((k) => { return { ...ProductionListColumns({ @@ -76,8 +76,8 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici const { t } = useTranslation(); const matchingColumnConfig = useMemo(() => { - return bodyshop.production_config.find((p) => p.name === defaultView); - }, [bodyshop.production_config, defaultView]); + return bodyshop?.production_config?.find((p) => p.name === defaultView); + }, [bodyshop.production_config]); useEffect(() => { const newColumns = From a72a7948fe42defd89d8e8cfdc902a137d6f1066 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 17 Oct 2024 15:22:05 -0700 Subject: [PATCH 25/79] IO-2987 Non Production Board Status - Status Changes Signed-off-by: Allan Carr --- ...oduction-list-columns.status.component.jsx | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/client/src/components/production-list-columns/production-list-columns.status.component.jsx b/client/src/components/production-list-columns/production-list-columns.status.component.jsx index 23dc378ef..820f7f80a 100644 --- a/client/src/components/production-list-columns/production-list-columns.status.component.jsx +++ b/client/src/components/production-list-columns/production-list-columns.status.component.jsx @@ -21,25 +21,26 @@ export function ProductionListColumnStatus({ record, bodyshop, insertAuditTrail const [loading, setLoading] = useState(false); const handleSetStatus = async (e) => { - logImEXEvent("production_change_status"); - // e.stopPropagation(); - setLoading(true); - const { key } = e; - await updateJob({ - variables: { - jobId: record.id, - job: { - status: key + if (bodyshop.md_ro_statuses.production_statuses.includes(record.status) && !bodyshop.md_ro_statuses.post_production_statuses.includes(record.status)) { + logImEXEvent("production_change_status"); + // e.stopPropagation(); + setLoading(true); + const { key } = e; + await updateJob({ + variables: { + jobId: record.id, + job: { + status: key + } } - } - }); - insertAuditTrail({ - jobid: record.id, - operation: AuditTrailMapping.jobstatuschange(key), - type: "jobstatuschange" - }); - - setLoading(false); + }); + insertAuditTrail({ + jobid: record.id, + operation: AuditTrailMapping.jobstatuschange(key), + type: "jobstatuschange" + }); + setLoading(false); + } }; const menu = { From e6dade120687681a8af44219d6f0bfae42864790 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 17 Oct 2024 17:03:40 -0700 Subject: [PATCH 26/79] IO-2988 Jobline Upsert Undefined handling Signed-off-by: Allan Carr --- .../job-lines-upsert-modal.container.jsx | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx b/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx index 39cf2a2af..76f8b52bb 100644 --- a/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx +++ b/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx @@ -1,5 +1,8 @@ import { useMutation } from "@apollo/client"; +import { useSplitTreatments } from "@splitsoftware/splitio-react"; import { notification } from "antd"; +import Axios from "axios"; +import Dinero from "dinero.js"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -7,13 +10,10 @@ import { createStructuredSelector } from "reselect"; import { INSERT_NEW_JOB_LINE, UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries"; import { toggleModalVisible } from "../../redux/modals/modals.actions"; import { selectJobLineEditModal } from "../../redux/modals/modals.selectors"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import CriticalPartsScan from "../../utils/criticalPartsScan"; import UndefinedToNull from "../../utils/undefinedtonull"; import JobLinesUpdsertModal from "./job-lines-upsert-modal.component"; -import Axios from "axios"; -import Dinero from "dinero.js"; -import CriticalPartsScan from "../../utils/criticalPartsScan"; -import { selectBodyshop } from "../../redux/user/user.selectors"; -import { useSplitTreatments } from "@splitsoftware/splitio-react"; const mapStateToProps = createStructuredSelector({ jobLineEditModal: selectJobLineEditModal, @@ -82,13 +82,15 @@ function JobLinesUpsertModalContainer({ jobLineEditModal, toggleModalVisible, bo variables: { lineId: jobLineEditModal.context.id, line: { - ...values, - prt_dsmk_m: Dinero({ - amount: Math.round(values.act_price * 100) + ...UndefinedToNull({ + ...values, + prt_dsmk_m: Dinero({ + amount: Math.round(values.act_price * 100) + }) + .percentage(Math.abs(values.prt_dsmk_p || 0)) + .multiply(values.prt_dsmk_p >= 0 ? 1 : -1) + .toFormat(0.0) }) - .percentage(Math.abs(values.prt_dsmk_p || 0)) - .multiply(values.prt_dsmk_p >= 0 ? 1 : -1) - .toFormat(0.0) } }, refetchQueries: ["GET_LINE_TICKET_BY_PK"] From 71a26cc4acdf7821adbc5033b3cfdd3ead212dbf Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 18 Oct 2024 08:45:13 -0700 Subject: [PATCH 27/79] IO-2989 jobexported missing en_us translation Signed-off-by: Allan Carr --- client/src/translations/en_us/common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index bd4738eb8..3a4a86f33 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -119,7 +119,7 @@ "jobclosedwithbypass": "Job was invoiced using the master bypass password. ", "jobconverted": "Job converted and assigned number {{ro_number}}.", "jobdelivery": "Job intake completed. Status set to {{status}}. Actual completion is {{actual_completion}}.", - "jobexported": "", + "jobexported": "Job has been exported", "jobfieldchanged": "Job field $t(jobs.fields.{{field}}) changed to {{value}}.", "jobimported": "Job imported.", "jobinproductionchange": "Job production status set to {{inproduction}}", From d62f6e2116fea0d8c5bcf9e1459e088cf9a65dc7 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 18 Oct 2024 12:28:01 -0400 Subject: [PATCH 28/79] feature/IO-2977-Replace-On-Board-with-In-View - Replace production board terminology for Imex, on board vs in view Signed-off-by: Dave Richer --- .../settings/defaultKanbanSettings.js | 63 +++++++++++++-- client/src/translations/en_us/common.json | 16 +++- client/src/translations/es/common.json | 16 +++- client/src/translations/fr/common.json | 76 +++++++++++-------- 4 files changed, 129 insertions(+), 42 deletions(-) diff --git a/client/src/components/production-board-kanban/settings/defaultKanbanSettings.js b/client/src/components/production-board-kanban/settings/defaultKanbanSettings.js index 87b364ea2..c9a8c59c6 100644 --- a/client/src/components/production-board-kanban/settings/defaultKanbanSettings.js +++ b/client/src/components/production-board-kanban/settings/defaultKanbanSettings.js @@ -1,15 +1,66 @@ +import InstanceRenderManager from "../../../utils/instanceRenderMgr.js"; + const statisticsItems = [ { id: 0, name: "totalHrs", label: "total_hours_in_production" }, { id: 1, name: "totalAmountInProduction", label: "total_amount_in_production" }, { id: 2, name: "totalLAB", label: "total_lab_in_production" }, { id: 3, name: "totalLAR", label: "total_lar_in_production" }, { id: 4, name: "jobsInProduction", label: "jobs_in_production" }, - { id: 5, name: "totalHrsOnBoard", label: "total_hours_on_board" }, - { id: 6, name: "totalAmountOnBoard", label: "total_amount_on_board" }, - { id: 7, name: "totalLABOnBoard", label: "total_lab_on_board" }, - { id: 8, name: "totalLAROnBoard", label: "total_lar_on_board" }, - { id: 9, name: "jobsOnBoard", label: "total_jobs_on_board" }, - { id: 10, name: "tasksOnBoard", label: "tasks_on_board" }, + + { + id: 5, + name: "totalHrsOnBoard", + label: InstanceRenderManager({ + imex: "total_hours_in_view", + rome: "total_hours_on_board", + promanager: "total_hours_on_board" + }) + }, + { + id: 6, + name: "totalAmountOnBoard", + label: InstanceRenderManager({ + imex: "total_amount_in_view", + rome: "total_amount_on_board", + promanager: "total_amount_on_board" + }) + }, + { + id: 7, + name: "totalLABOnBoard", + label: InstanceRenderManager({ + imex: "total_lab_in_view", + rome: "total_lab_on_board", + promanager: "total_lab_on_board" + }) + }, + { + id: 8, + name: "totalLAROnBoard", + label: InstanceRenderManager({ + imex: "total_lar_in_view", + rome: "total_lar_on_board", + promanager: "total_lar_on_board" + }) + }, + { + id: 9, + name: "jobsOnBoard", + label: InstanceRenderManager({ + imex: "total_jobs_in_view", + rome: "total_jobs_on_board", + promanager: "total_jobs_on_board" + }) + }, + { + id: 10, + name: "tasksOnBoard", + label: InstanceRenderManager({ + imex: "tasks_in_view", + rome: "tasks_on_board", + promanager: "tasks_on_board" + }) + }, { id: 11, name: "tasksInProduction", label: "tasks_in_production" } ]; diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index bd4738eb8..c631f5d1a 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -2849,15 +2849,21 @@ "jobs_in_production": "Jobs in Production", "tasks_in_production": "Tasks in Production", "tasks_on_board": "Tasks on Board", + "tasks_in_view": "Tasks in View", "total_amount_in_production": "Dollars in Production", "total_amount_on_board": "Dollars on Board", + "total_amount_in_view": "Dollars in View", "total_hours_in_production": "Hours in Production", "total_hours_on_board": "Hours on Board", + "total_hours_in_view": "Hours in View", "total_jobs_on_board": "Jobs on Board", + "total_jobs_in_view": "Jobs in View", "total_lab_in_production": "Body Hours in Production", "total_lab_on_board": "Body Hours on Board", + "total_lab_in_view": "Body Hours in View", "total_lar_in_production": "Refinish Hours in Production", - "total_lar_on_board": "Refinish Hours on Board" + "total_lar_on_board": "Refinish Hours on Board", + "total_lar_in_view": "Refinish Hours in View" }, "statistics_title": "Statistics" }, @@ -2869,15 +2875,21 @@ "tasks": "Tasks", "tasks_in_production": "Tasks in Production", "tasks_on_board": "Tasks on Board", + "tasks_in_view": "Tasks in View", "total_amount_in_production": "Dollars in Production", "total_amount_on_board": "Dollars on Board", + "total_amount_in_view": "Dollars in View", "total_hours_in_production": "Hours in Production", "total_hours_on_board": "Hours on Board", + "total_hours_in_view": "Hours in View", "total_jobs_on_board": "Jobs on Board", + "total_jobs_in_view": "Jobs in View", "total_lab_in_production": "Body Hours in Production", "total_lab_on_board": "Body Hours on Board", + "total_lab_in_view": "Body Hours in View", "total_lar_in_production": "Refinish Hours in Production", - "total_lar_on_board": "Refinish Hours on Board" + "total_lar_on_board": "Refinish Hours on Board", + "total_lar_in_view": "Refinish Hours in View" }, "successes": { "removed": "Job removed from production." diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 6e9074c44..66d512cef 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -2849,15 +2849,21 @@ "jobs_in_production": "", "tasks_in_production": "", "tasks_on_board": "", + "tasks_in_view": "", "total_amount_in_production": "", "total_amount_on_board": "", + "total_amount_in_view": "", "total_hours_in_production": "", "total_hours_on_board": "", + "total_hours_in_view": "", "total_jobs_on_board": "", + "total_jobs_in_view": "", "total_lab_in_production": "", "total_lab_on_board": "", + "total_lab_in_view": "", "total_lar_in_production": "", - "total_lar_on_board": "" + "total_lar_on_board": "", + "total_lar_in_view": "" }, "statistics_title": "" }, @@ -2869,15 +2875,21 @@ "tasks": "", "tasks_in_production": "", "tasks_on_board": "", + "tasks_in_view": "", "total_amount_in_production": "", "total_amount_on_board": "", + "total_amount_in_view": "", "total_hours_in_production": "", "total_hours_on_board": "", + "total_hours_in_view": "", "total_jobs_on_board": "", + "total_jobs_in_view": "", "total_lab_in_production": "", "total_lab_on_board": "", + "total_lab_in_view": "", "total_lar_in_production": "", - "total_lar_on_board": "" + "total_lar_on_board": "", + "total_lar_in_view": "" }, "successes": { "removed": "" diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 48d5a05af..c4cdbf53f 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -2845,40 +2845,52 @@ "filters_title": "", "information": "", "layout": "", - "statistics": { - "jobs_in_production": "", - "tasks_in_production": "", - "tasks_on_board": "", - "total_amount_in_production": "", - "total_amount_on_board": "", - "total_hours_in_production": "", - "total_hours_on_board": "", - "total_jobs_on_board": "", - "total_lab_in_production": "", - "total_lab_on_board": "", - "total_lar_in_production": "", - "total_lar_on_board": "" - }, + "statistics": { + "jobs_in_production": "", + "tasks_in_production": "", + "tasks_on_board": "", + "tasks_in_view": "", + "total_amount_in_production": "", + "total_amount_on_board": "", + "total_amount_in_view": "", + "total_hours_in_production": "", + "total_hours_on_board": "", + "total_hours_in_view": "", + "total_jobs_on_board": "", + "total_jobs_in_view": "", + "total_lab_in_production": "", + "total_lab_on_board": "", + "total_lab_in_view": "", + "total_lar_in_production": "", + "total_lar_on_board": "", + "total_lar_in_view": "" + }, "statistics_title": "" }, - "statistics": { - "currency_symbol": "", - "hours": "", - "jobs": "", - "jobs_in_production": "", - "tasks": "", - "tasks_in_production": "", - "tasks_on_board": "", - "total_amount_in_production": "", - "total_amount_on_board": "", - "total_hours_in_production": "", - "total_hours_on_board": "", - "total_jobs_on_board": "", - "total_lab_in_production": "", - "total_lab_on_board": "", - "total_lar_in_production": "", - "total_lar_on_board": "" - }, + "statistics": { + "currency_symbol": "", + "hours": "", + "jobs": "", + "jobs_in_production": "", + "tasks": "", + "tasks_in_production": "", + "tasks_on_board": "", + "tasks_in_view": "", + "total_amount_in_production": "", + "total_amount_on_board": "", + "total_amount_in_view": "", + "total_hours_in_production": "", + "total_hours_on_board": "", + "total_hours_in_view": "", + "total_jobs_on_board": "", + "total_jobs_in_view": "", + "total_lab_in_production": "", + "total_lab_on_board": "", + "total_lab_in_view": "", + "total_lar_in_production": "", + "total_lar_on_board": "", + "total_lar_in_view": "" + }, "successes": { "removed": "" } From 1d98de6d4ddb285889e366bda621fc0a99581a88 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 18 Oct 2024 15:22:56 -0400 Subject: [PATCH 29/79] feature/IO-2976-GlobalSearch-First-link-Navigate - Fix global search so it goes to the first url if it is available, added an ID for rome tours. Signed-off-by: Dave Richer --- .../global-search-os.component.jsx | 17 +++++++++++++++-- .../global-search/global-search.component.jsx | 16 +++++++++++++--- .../parts-order-list-table.component.jsx | 3 ++- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/client/src/components/global-search/global-search-os.component.jsx b/client/src/components/global-search/global-search-os.component.jsx index f46a4c811..e8e51b3ac 100644 --- a/client/src/components/global-search/global-search-os.component.jsx +++ b/client/src/components/global-search/global-search-os.component.jsx @@ -3,13 +3,15 @@ import axios from "axios"; import _ from "lodash"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; -import { Link } from "react-router-dom"; +import { Link, useNavigate } from "react-router-dom"; import PhoneNumberFormatter from "../../utils/PhoneFormatter"; import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component"; import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component"; export default function GlobalSearchOs() { const { t } = useTranslation(); + const navigate = useNavigate(); + const [loading, setLoading] = useState(false); const [data, setData] = useState(false); @@ -177,7 +179,18 @@ export default function GlobalSearchOs() { }; return ( - setData([])}> + { + if (e.key !== "Enter") return; + const firstUrlForSearch = data?.[0]?.options?.[0]?.label?.props?.to; + if (!firstUrlForSearch) return; + navigate(firstUrlForSearch); + }} + defaultActiveFirstOption + onClear={() => setData([])} + > { if (v && v.variables.search && v.variables.search !== "" && v.variables.search.length >= 3) callSearch(v); @@ -20,7 +21,6 @@ export default function GlobalSearch() { const debouncedExecuteSearch = _.debounce(executeSearch, 750); const handleSearch = (value) => { - console.log("Handle Search"); debouncedExecuteSearch({ variables: { search: value } }); }; @@ -156,7 +156,17 @@ export default function GlobalSearch() { if (error) return ; return ( - + { + if (e.key !== "Enter") return; + const firstUrlForSearch = options?.[0]?.options?.[0]?.label?.props?.to; + if (!firstUrlForSearch) return; + navigate(firstUrlForSearch); + }} + > recordActions(record, true) + render: (text, record) => recordActions(record, true), + id: "parts-order-list-table-actions" } ]; From f50292f9bfe64f4e1c156fa7adaac4de70ee645a Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 21 Oct 2024 10:53:32 -0700 Subject: [PATCH 30/79] IO-2992 Bill Line column Width with Word Breaks Signed-off-by: Allan Carr --- .../bill-form/bill-form.lines.component.jsx | 15 +++++++++++---- .../bill-line-search-select.component.jsx | 6 +++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/client/src/components/bill-form/bill-form.lines.component.jsx b/client/src/components/bill-form/bill-form.lines.component.jsx index 555be39e3..b9576670c 100644 --- a/client/src/components/bill-form/bill-form.lines.component.jsx +++ b/client/src/components/bill-form/bill-form.lines.component.jsx @@ -7,10 +7,10 @@ import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors"; import CiecaSelect from "../../utils/Ciecaselect"; +import InstanceRenderManager from "../../utils/instanceRenderMgr"; import BillLineSearchSelect from "../bill-line-search-select/bill-line-search-select.component"; import BilllineAddInventory from "../billline-add-inventory/billline-add-inventory.component"; import CurrencyInput from "../form-items-formatted/currency-form-item.component"; -import InstanceRenderManager from "../../utils/instanceRenderMgr"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser @@ -72,7 +72,14 @@ export function BillEnterModalLinesComponent({ { setFieldsValue({ @@ -105,7 +112,7 @@ export function BillEnterModalLinesComponent({ title: t("billlines.fields.line_desc"), dataIndex: "line_desc", editable: true, - + width: "20rem", formItemProps: (field) => { return { key: `${field.index}line_desc`, @@ -119,7 +126,7 @@ export function BillEnterModalLinesComponent({ ] }; }, - formInput: (record, index) => + formInput: (record, index) => }, { title: t("billlines.fields.quantity"), diff --git a/client/src/components/bill-line-search-select/bill-line-search-select.component.jsx b/client/src/components/bill-line-search-select/bill-line-search-select.component.jsx index a52bfd145..0da329d6f 100644 --- a/client/src/components/bill-line-search-select/bill-line-search-select.component.jsx +++ b/client/src/components/bill-line-search-select/bill-line-search-select.component.jsx @@ -11,7 +11,7 @@ const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps }, disabled={disabled} ref={ref} showSearch - popupMatchSelectWidth={false} + popupMatchSelectWidth={true} optionLabelProp={"name"} // optionFilterProp="line_desc" filterOption={(inputValue, option) => { @@ -43,7 +43,7 @@ const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps }, item.oem_partno ? ` - ${item.oem_partno}` : "" }${item.alt_partno ? ` (${item.alt_partno})` : ""}`.trim(), label: ( - <> +
    {`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${ item.oem_partno ? ` - ${item.oem_partno}` : "" @@ -57,7 +57,7 @@ const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps }, {item.act_price ? `$${item.act_price && item.act_price.toFixed(2)}` : ``} - +
    ) })) ]} From fc75717d32231c70a65809246c26e70c96e8e76b Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 21 Oct 2024 12:43:20 -0700 Subject: [PATCH 31/79] IO-2921 CHATTER correct secertmanager call from undefined variable to string Signed-off-by: Allan Carr --- server/data/chatter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/data/chatter.js b/server/data/chatter.js index 85dbe4a9b..24173a872 100644 --- a/server/data/chatter.js +++ b/server/data/chatter.js @@ -154,7 +154,7 @@ exports.default = async (req, res) => { async function getPrivateKey() { // Connect to AWS Secrets Manager const client = new SecretsManagerClient({ region: "ca-central-1" }); - const command = new GetSecretValueCommand({ SecretId: CHATTER_PRIVATE_KEY }); + const command = new GetSecretValueCommand({ SecretId: "CHATTER_PRIVATE_KEY" }); logger.log("chatter-get-private-key", "DEBUG", "api", null, null); try { From 0f84adc752eb046c47732ad094182f9b53983b5d Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Tue, 22 Oct 2024 17:35:54 -0700 Subject: [PATCH 32/79] IO-2966 Contract Create Page Leave Warning Signed-off-by: Allan Carr --- .../contract-form/contract-form.component.jsx | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/client/src/components/contract-form/contract-form.component.jsx b/client/src/components/contract-form/contract-form.component.jsx index 1795449f4..5fe70177e 100644 --- a/client/src/components/contract-form/contract-form.component.jsx +++ b/client/src/components/contract-form/contract-form.component.jsx @@ -1,16 +1,17 @@ import { WarningFilled } from "@ant-design/icons"; import { Form, Input, InputNumber, Space } from "antd"; -import dayjs from "../../utils/day"; import React from "react"; import { useTranslation } from "react-i18next"; import { DateFormatter } from "../../utils/DateFormatter"; +import dayjs from "../../utils/day"; //import ContractLicenseDecodeButton from "../contract-license-decode-button/contract-license-decode-button.component"; import ContractStatusSelector from "../contract-status-select/contract-status-select.component"; import ContractsRatesChangeButton from "../contracts-rates-change-button/contracts-rates-change-button.component"; import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component"; -import FormDateTimePicker from "../form-date-time-picker/form-date-time-picker.component"; -import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component"; -import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component"; +import { + default as DateTimePicker, + default as FormDateTimePicker +} from "../form-date-time-picker/form-date-time-picker.component"; import InputPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import ContractFormJobPrefill from "./contract-form-job-prefill.component"; @@ -18,8 +19,7 @@ import ContractFormJobPrefill from "./contract-form-job-prefill.component"; export default function ContractFormComponent({ form, create = false, selectedJobState, selectedCar }) { const { t } = useTranslation(); return ( -
    - + <> {create ? null : ( )} -
    - - {selectedJobState && ( -
    - -
    - )} - { - // - } -
    -
    + + {selectedJobState && } + {/* {} */} + + + + <> {t("contracts.labels.dlexpirebeforereturn")} )} -
    + ); }} - @@ -315,6 +307,6 @@ export default function ContractFormComponent({ form, create = false, selectedJo -
    + ); } From d04fc7684011e51b31775d46a7440420bdd1af5c Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Tue, 22 Oct 2024 17:48:40 -0700 Subject: [PATCH 33/79] IO-2966 Contract Create Page Leave Warning Signed-off-by: Allan Carr --- .../contract-form/contract-form.component.jsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/client/src/components/contract-form/contract-form.component.jsx b/client/src/components/contract-form/contract-form.component.jsx index 5fe70177e..b71d7f92f 100644 --- a/client/src/components/contract-form/contract-form.component.jsx +++ b/client/src/components/contract-form/contract-form.component.jsx @@ -12,6 +12,7 @@ import { default as DateTimePicker, default as FormDateTimePicker } from "../form-date-time-picker/form-date-time-picker.component"; +import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component"; import InputPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import ContractFormJobPrefill from "./contract-form-job-prefill.component"; @@ -20,8 +21,9 @@ export default function ContractFormComponent({ form, create = false, selectedJo const { t } = useTranslation(); return ( <> + {!create && } - {create ? null : ( + {!create && ( - {create ? null : ( + {!create && ( @@ -122,7 +124,7 @@ export default function ContractFormComponent({ form, create = false, selectedJo }} )} - {create ? null : ( + {!create && ( @@ -145,7 +147,7 @@ export default function ContractFormComponent({ form, create = false, selectedJo > - {create ? null : ( + {!create && ( @@ -153,7 +155,9 @@ export default function ContractFormComponent({ form, create = false, selectedJo - {selectedJobState && } + {create && selectedJobState && ( + + )} {/* {} */} From b479684fe4060e93bcfe34b8fa2997475226bf3f Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 23 Oct 2024 13:00:51 -0400 Subject: [PATCH 34/79] feature/IO-2996-Package-Updates-Docker-Debugging - Maintenance Signed-off-by: Dave Richer --- .localstack/.gitkeep | 0 .vscode/launch.json | 15 + Dockerfile | 4 +- certs/id_rsa | 27 + certs/id_rsa.pub | 1 + docker-compose.yml | 8 +- package-lock.json | 1306 ++++++++++++++---------------------------- package.json | 26 +- 8 files changed, 497 insertions(+), 890 deletions(-) create mode 100644 .localstack/.gitkeep create mode 100644 certs/id_rsa create mode 100644 certs/id_rsa.pub diff --git a/.localstack/.gitkeep b/.localstack/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/.vscode/launch.json b/.vscode/launch.json index 032b2ea99..e9045d2fd 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,6 +14,21 @@ "request": "launch", "url": "http://localhost:3000", "webRoot": "${workspaceRoot}/client/src" + }, + { + "name": "Attach to Node.js in Docker", + "type": "node", + "request": "attach", + "address": "localhost", + "port": 9229, + "localRoot": "${workspaceFolder}", + "remoteRoot": "/app", + "protocol": "inspector", + "restart": true, + "sourceMaps": true, + "skipFiles": [ + "/**" + ] } ] } diff --git a/Dockerfile b/Dockerfile index 27a8254e9..b1d253808 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,7 +41,7 @@ RUN npm i --no-package-lock COPY . . # Expose the port your app runs on (adjust if necessary) -EXPOSE 4000 +EXPOSE 4000 9229 # Start the application -CMD ["nodemon", "--legacy-watch", "server.js"] +CMD ["nodemon", "--legacy-watch", "--inspect=0.0.0.0:9229", "server.js"] diff --git a/certs/id_rsa b/certs/id_rsa new file mode 100644 index 000000000..5e60af253 --- /dev/null +++ b/certs/id_rsa @@ -0,0 +1,27 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEAvNl5fuVmLNv72BZNxnTqX5CHf5Xi8UxjYaYxHITSCx7blnhpVYLd +qXvcOWXzbsfjch/den73QiW4n2FYz75oGMhUGlOYzdWKA9I9Sj09Qy1R06RhwDiZGd5qaM +swEeXpkNmi2u4Qd2kJeDfUQUigjC09V81O/vrniGtQAJScfiG/itdm+Ufn09Z4MYk0HWjq +iDokNEskoEPsibYIrb+Q6vdtuPkZO+wU/smXhPtgw5ST6oQdmm/gVNsRg5XNzxrire+z1G +WatnnVL3hPnnfpnf8W589dyms7GGJwhPerSGTN1bn0T4+9C69Cd7LBJtxiuFdRmdlGLLLP +RR48Rur71wAAA9AEfVsdBH1bHQAAAAdzc2gtcnNhAAABAQC82Xl+5WYs2/vYFk3GdOpfkI +d/leLxTGNhpjEchNILHtuWeGlVgt2pe9w5ZfNux+NyH916fvdCJbifYVjPvmgYyFQaU5jN +1YoD0j1KPT1DLVHTpGHAOJkZ3mpoyzAR5emQ2aLa7hB3aQl4N9RBSKCMLT1XzU7++ueIa1 +AAlJx+Ib+K12b5R+fT1ngxiTQdaOqIOiQ0SySgQ+yJtgitv5Dq9224+Rk77BT+yZeE+2DD +lJPqhB2ab+BU2xGDlc3PGuKt77PUZZq2edUveE+ed+md/xbnz13KazsYYnCE96tIZM3Vuf +RPj70Lr0J3ssEm3GK4V1GZ2UYsss9FHjxG6vvXAAAAAwEAAQAAAQAQTosSLQbMmtY9S3e9 +yjyusdExcCTfhyQRu4MEHmfws+JsNMuLqbgwOVTD1AzYJQR7x0qdmDcLjCxL/uDnV16vvS +Sd/Vf1dhnryIyoS29tzI0DRG94ZKq7tBvmHp1w/jRT4KcSVnovhW9e5Rs74+SRFhr06PKI +S+wQOIv48Nwue9+QUMsMCpWgKXHx7SHNTHvnAfqdhi9O29SWlMA+v+mELZ5Cl+HU0UTt2I +A1BxOe1N8FjN7KE2viJexsl3is1PuqMkpLl/wyHBJTVzUadl6DRALJQIm7/YO5goE72YOV +Lpo27do3zjhC87dlKdATvZUzfKV0LuUVdxq/PNDZMUbBAAAAgQDShAqDZiDrdTUaGXfUVm +QzcnVNbh2/KgZh4uux9QNHST562W6cnN7qxoRwVrM4BCOk1Kl73QQZW4nDvXX3PVC5j038 +8AXkcBHS9j9f4h72ue7D2jqlbHFa7aGU9zYgk9mbBF+GX3tDntkAIQjLtwOLfj1iiJ/clX +mHFUAY1V4L8AAAAIEA3E4t/v0yU5D9AOI0r17UNYqfeyDoKAEDR4QbbFjO1l0kLnEJy7Zx +Mhj18GilYg2y0P0v8dSM/oWXS8Hua2t5i9Exlv6gHhGlQ80mwYcVGIxewZ/pPeCPw0U+kt +EKUjt09m9Oe7+6xHQsTBj9hY8/vqPmQwRalZFcLdhHiDiVKTcAAACBANtykaPXdVzEFx7D +UOlsjVL7zM0EVOFXf9JJQ6BhazhmsEI2PYt3IpgGMo8cXkoUofAOIYjf421AabN1BqSO5J +XTMxM0ZV3JmLLi804Mu9h1iFrVTBdLYOMJdc2VCo1EwHWpo9SXOyjxce/znvcIOU04aZhu +TaPg816X+E+gw5JhAAAAFGRhdmVARGF2ZVJpY2hlci1JTUVYAQIDBAUG +-----END OPENSSH PRIVATE KEY----- diff --git a/certs/id_rsa.pub b/certs/id_rsa.pub new file mode 100644 index 000000000..11c1d78dc --- /dev/null +++ b/certs/id_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC82Xl+5WYs2/vYFk3GdOpfkId/leLxTGNhpjEchNILHtuWeGlVgt2pe9w5ZfNux+NyH916fvdCJbifYVjPvmgYyFQaU5jN1YoD0j1KPT1DLVHTpGHAOJkZ3mpoyzAR5emQ2aLa7hB3aQl4N9RBSKCMLT1XzU7++ueIa1AAlJx+Ib+K12b5R+fT1ngxiTQdaOqIOiQ0SySgQ+yJtgitv5Dq9224+Rk77BT+yZeE+2DDlJPqhB2ab+BU2xGDlc3PGuKt77PUZZq2edUveE+ed+md/xbnz13KazsYYnCE96tIZM3VufRPj70Lr0J3ssEm3GK4V1GZ2UYsss9FHjxG6vvX dave@DaveRicher-IMEX diff --git a/docker-compose.yml b/docker-compose.yml index 57232cdfb..933eb022d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -74,7 +74,7 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock environment: - - SERVICES=ses + - SERVICES=ses,secretsmanager - DEBUG=0 - AWS_ACCESS_KEY_ID=test - AWS_SECRET_ACCESS_KEY=test @@ -101,6 +101,10 @@ services: depends_on: localstack: condition: service_healthy + volumes: + - './localstack:/tmp/localstack' + - './certs:/tmp/certs' + environment: - AWS_ACCESS_KEY_ID=test - AWS_SECRET_ACCESS_KEY=test @@ -110,6 +114,7 @@ services: " aws --endpoint-url=http://localstack:4566 ses verify-domain-identity --domain imex.online --region ca-central-1 aws --endpoint-url=http://localstack:4566 ses verify-email-identity --email-address noreply@imex.online --region ca-central-1 + aws --endpoint-url=http://localstack:4566 secretsmanager create-secret --name CHATTER_PRIVATE_KEY --secret-string file:///tmp/certs/id_rsa " # Node App: The Main IMEX API node-app: @@ -134,6 +139,7 @@ services: condition: service_completed_successfully ports: - "4000:4000" + - "9229:9229" volumes: - .:/app - node-app-npm-cache:/app/node_modules diff --git a/package-lock.json b/package-lock.json index 822bb487e..e75f13b42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,10 @@ "version": "0.2.0", "license": "UNLICENSED", "dependencies": { - "@aws-sdk/client-elasticache": "^3.665.0", - "@aws-sdk/client-secrets-manager": "^3.654.0", - "@aws-sdk/client-ses": "^3.654.0", - "@aws-sdk/credential-provider-node": "^3.654.0", + "@aws-sdk/client-elasticache": "^3.675.0", + "@aws-sdk/client-secrets-manager": "^3.675.0", + "@aws-sdk/client-ses": "^3.675.0", + "@aws-sdk/credential-provider-node": "^3.675.0", "@opensearch-project/opensearch": "^2.12.0", "@socket.io/admin-ui": "^0.5.1", "@socket.io/redis-adapter": "^8.3.0", @@ -22,35 +22,35 @@ "bluebird": "^3.7.2", "body-parser": "^1.20.3", "canvas": "^2.11.2", - "chart.js": "^4.4.4", - "cloudinary": "^2.5.0", + "chart.js": "^4.4.5", + "cloudinary": "^2.5.1", "compression": "^1.7.4", - "cookie-parser": "^1.4.6", + "cookie-parser": "^1.4.7", "cors": "2.8.5", "csrf": "^3.1.0", "dinero.js": "^1.9.1", "dotenv": "^16.4.5", - "express": "^4.21.0", - "firebase-admin": "^12.5.0", + "express": "^4.21.1", + "firebase-admin": "^12.6.0", "graphql": "^16.9.0", "graphql-request": "^6.1.0", "graylog2": "^0.2.1", "inline-css": "^4.0.2", "intuit-oauth": "^4.1.2", "ioredis": "^5.4.1", - "json-2-csv": "^5.5.5", + "json-2-csv": "^5.5.6", "lodash": "^4.17.21", "moment": "^2.30.1", - "moment-timezone": "^0.5.45", + "moment-timezone": "^0.5.46", "multer": "^1.4.5-lts.1", "node-mailjet": "^6.0.6", "node-persist": "^4.0.3", "nodemailer": "^6.9.15", - "phone": "^3.1.50", + "phone": "^3.1.51", "recursive-diff": "^1.0.9", "redis": "^4.7.0", "rimraf": "^6.0.1", - "soap": "^1.1.4", + "soap": "^1.1.5", "socket.io": "^4.8.0", "socket.io-adapter": "^2.5.5", "ssh2-sftp-client": "^10.0.3", @@ -186,47 +186,47 @@ } }, "node_modules/@aws-sdk/client-elasticache": { - "version": "3.665.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-elasticache/-/client-elasticache-3.665.0.tgz", - "integrity": "sha512-r1T7Yhv+jdVEoOT3h1oJtsKPYt82rEHv1PPYAknyYWUOYxb4tgpmaPusw50nqnNi47W7n/9jkqnk75IwMKEjfQ==", + "version": "3.675.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-elasticache/-/client-elasticache-3.675.0.tgz", + "integrity": "sha512-OMdlxBrsrDdBw2/RHj80NSAbb4wQYR0TJMvSbuC/XYnF1W9OpNpNpzQ9ZdZwiLymkjQMgfrVk27FiEivEBwj1A==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.665.0", - "@aws-sdk/client-sts": "3.665.0", - "@aws-sdk/core": "3.665.0", - "@aws-sdk/credential-provider-node": "3.665.0", - "@aws-sdk/middleware-host-header": "3.664.0", - "@aws-sdk/middleware-logger": "3.664.0", - "@aws-sdk/middleware-recursion-detection": "3.664.0", - "@aws-sdk/middleware-user-agent": "3.664.0", - "@aws-sdk/region-config-resolver": "3.664.0", - "@aws-sdk/types": "3.664.0", - "@aws-sdk/util-endpoints": "3.664.0", - "@aws-sdk/util-user-agent-browser": "3.664.0", - "@aws-sdk/util-user-agent-node": "3.664.0", + "@aws-sdk/client-sso-oidc": "3.675.0", + "@aws-sdk/client-sts": "3.675.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-node": "3.675.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.669.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.675.0", + "@aws-sdk/util-user-agent-node": "3.669.0", "@smithy/config-resolver": "^3.0.9", - "@smithy/core": "^2.4.7", + "@smithy/core": "^2.4.8", "@smithy/fetch-http-handler": "^3.2.9", "@smithy/hash-node": "^3.0.7", "@smithy/invalid-dependency": "^3.0.7", "@smithy/middleware-content-length": "^3.0.9", "@smithy/middleware-endpoint": "^3.1.4", - "@smithy/middleware-retry": "^3.0.22", + "@smithy/middleware-retry": "^3.0.23", "@smithy/middleware-serde": "^3.0.7", "@smithy/middleware-stack": "^3.0.7", "@smithy/node-config-provider": "^3.1.8", "@smithy/node-http-handler": "^3.2.4", "@smithy/protocol-http": "^4.1.4", - "@smithy/smithy-client": "^3.3.6", + "@smithy/smithy-client": "^3.4.0", "@smithy/types": "^3.5.0", "@smithy/url-parser": "^3.0.7", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.22", - "@smithy/util-defaults-mode-node": "^3.0.22", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", "@smithy/util-endpoints": "^2.1.3", "@smithy/util-middleware": "^3.0.7", "@smithy/util-retry": "^3.0.7", @@ -238,523 +238,53 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/client-sso": { - "version": "3.665.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.665.0.tgz", - "integrity": "sha512-zje+oaIiyviDv5dmBWhGHifPTb0Idq/HatNPy+VEiwo2dxcQBexibD5CQE5e8CWZK123Br/9DHft+iNKdiY5bA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.665.0", - "@aws-sdk/middleware-host-header": "3.664.0", - "@aws-sdk/middleware-logger": "3.664.0", - "@aws-sdk/middleware-recursion-detection": "3.664.0", - "@aws-sdk/middleware-user-agent": "3.664.0", - "@aws-sdk/region-config-resolver": "3.664.0", - "@aws-sdk/types": "3.664.0", - "@aws-sdk/util-endpoints": "3.664.0", - "@aws-sdk/util-user-agent-browser": "3.664.0", - "@aws-sdk/util-user-agent-node": "3.664.0", - "@smithy/config-resolver": "^3.0.9", - "@smithy/core": "^2.4.7", - "@smithy/fetch-http-handler": "^3.2.9", - "@smithy/hash-node": "^3.0.7", - "@smithy/invalid-dependency": "^3.0.7", - "@smithy/middleware-content-length": "^3.0.9", - "@smithy/middleware-endpoint": "^3.1.4", - "@smithy/middleware-retry": "^3.0.22", - "@smithy/middleware-serde": "^3.0.7", - "@smithy/middleware-stack": "^3.0.7", - "@smithy/node-config-provider": "^3.1.8", - "@smithy/node-http-handler": "^3.2.4", - "@smithy/protocol-http": "^4.1.4", - "@smithy/smithy-client": "^3.3.6", - "@smithy/types": "^3.5.0", - "@smithy/url-parser": "^3.0.7", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.22", - "@smithy/util-defaults-mode-node": "^3.0.22", - "@smithy/util-endpoints": "^2.1.3", - "@smithy/util-middleware": "^3.0.7", - "@smithy/util-retry": "^3.0.7", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.665.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.665.0.tgz", - "integrity": "sha512-FQ2YyM9/6y3clWkf3d60/W4c/HZy61hbfIsR4KIh8aGOifwfIx/UpZQ61pCr/TXTNqbaAVU2/sK+J1zFkGEoLw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.665.0", - "@aws-sdk/credential-provider-node": "3.665.0", - "@aws-sdk/middleware-host-header": "3.664.0", - "@aws-sdk/middleware-logger": "3.664.0", - "@aws-sdk/middleware-recursion-detection": "3.664.0", - "@aws-sdk/middleware-user-agent": "3.664.0", - "@aws-sdk/region-config-resolver": "3.664.0", - "@aws-sdk/types": "3.664.0", - "@aws-sdk/util-endpoints": "3.664.0", - "@aws-sdk/util-user-agent-browser": "3.664.0", - "@aws-sdk/util-user-agent-node": "3.664.0", - "@smithy/config-resolver": "^3.0.9", - "@smithy/core": "^2.4.7", - "@smithy/fetch-http-handler": "^3.2.9", - "@smithy/hash-node": "^3.0.7", - "@smithy/invalid-dependency": "^3.0.7", - "@smithy/middleware-content-length": "^3.0.9", - "@smithy/middleware-endpoint": "^3.1.4", - "@smithy/middleware-retry": "^3.0.22", - "@smithy/middleware-serde": "^3.0.7", - "@smithy/middleware-stack": "^3.0.7", - "@smithy/node-config-provider": "^3.1.8", - "@smithy/node-http-handler": "^3.2.4", - "@smithy/protocol-http": "^4.1.4", - "@smithy/smithy-client": "^3.3.6", - "@smithy/types": "^3.5.0", - "@smithy/url-parser": "^3.0.7", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.22", - "@smithy/util-defaults-mode-node": "^3.0.22", - "@smithy/util-endpoints": "^2.1.3", - "@smithy/util-middleware": "^3.0.7", - "@smithy/util-retry": "^3.0.7", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.665.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/client-sts": { - "version": "3.665.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.665.0.tgz", - "integrity": "sha512-/OQEaWB1euXhZ/hV+wetDw1tynlrkNKzirzoiFuJ1EQsiIb9Ih/qjUF9KLdF1+/bXbnGu5YvIaAx80YReUchjg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.665.0", - "@aws-sdk/core": "3.665.0", - "@aws-sdk/credential-provider-node": "3.665.0", - "@aws-sdk/middleware-host-header": "3.664.0", - "@aws-sdk/middleware-logger": "3.664.0", - "@aws-sdk/middleware-recursion-detection": "3.664.0", - "@aws-sdk/middleware-user-agent": "3.664.0", - "@aws-sdk/region-config-resolver": "3.664.0", - "@aws-sdk/types": "3.664.0", - "@aws-sdk/util-endpoints": "3.664.0", - "@aws-sdk/util-user-agent-browser": "3.664.0", - "@aws-sdk/util-user-agent-node": "3.664.0", - "@smithy/config-resolver": "^3.0.9", - "@smithy/core": "^2.4.7", - "@smithy/fetch-http-handler": "^3.2.9", - "@smithy/hash-node": "^3.0.7", - "@smithy/invalid-dependency": "^3.0.7", - "@smithy/middleware-content-length": "^3.0.9", - "@smithy/middleware-endpoint": "^3.1.4", - "@smithy/middleware-retry": "^3.0.22", - "@smithy/middleware-serde": "^3.0.7", - "@smithy/middleware-stack": "^3.0.7", - "@smithy/node-config-provider": "^3.1.8", - "@smithy/node-http-handler": "^3.2.4", - "@smithy/protocol-http": "^4.1.4", - "@smithy/smithy-client": "^3.3.6", - "@smithy/types": "^3.5.0", - "@smithy/url-parser": "^3.0.7", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.22", - "@smithy/util-defaults-mode-node": "^3.0.22", - "@smithy/util-endpoints": "^2.1.3", - "@smithy/util-middleware": "^3.0.7", - "@smithy/util-retry": "^3.0.7", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/core": { - "version": "3.665.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.665.0.tgz", - "integrity": "sha512-nqmNNf7Ml7qDXTIisDv+OYe/rl3nAW4cmR+HxrOCWdhTHe8xRdR5c45VPoh8nv1KIry5xtd+iqPrzzjydes+Og==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@smithy/core": "^2.4.7", - "@smithy/node-config-provider": "^3.1.8", - "@smithy/property-provider": "^3.1.7", - "@smithy/protocol-http": "^4.1.4", - "@smithy/signature-v4": "^4.2.0", - "@smithy/smithy-client": "^3.3.6", - "@smithy/types": "^3.5.0", - "@smithy/util-middleware": "^3.0.7", - "fast-xml-parser": "4.4.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.664.0.tgz", - "integrity": "sha512-95rE+9Voaco0nmKJrXqfJAxSSkSWqlBy76zomiZrUrv7YuijQtHCW8jte6v6UHAFAaBzgFsY7QqBxs15u9SM7g==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@smithy/property-provider": "^3.1.7", - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.664.0.tgz", - "integrity": "sha512-svaPwVfWV3g/qjd4cYHTUyBtkdOwcVjC+tSj6EjoMrpZwGUXcCbYe04iU0ARZ6tuH/u3vySbTLOGjSa7g8o9Qw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@smithy/fetch-http-handler": "^3.2.9", - "@smithy/node-http-handler": "^3.2.4", - "@smithy/property-provider": "^3.1.7", - "@smithy/protocol-http": "^4.1.4", - "@smithy/smithy-client": "^3.3.6", - "@smithy/types": "^3.5.0", - "@smithy/util-stream": "^3.1.9", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.665.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.665.0.tgz", - "integrity": "sha512-CSWBV5GqCkK78TTXq6qx40MWCt90t8rS/O7FIR4nbmoUhG/DysaC1G0om1fSx6k+GWcvIIIsSvD4hdbh8FRWKA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.664.0", - "@aws-sdk/credential-provider-http": "3.664.0", - "@aws-sdk/credential-provider-process": "3.664.0", - "@aws-sdk/credential-provider-sso": "3.665.0", - "@aws-sdk/credential-provider-web-identity": "3.664.0", - "@aws-sdk/types": "3.664.0", - "@smithy/credential-provider-imds": "^3.2.4", - "@smithy/property-provider": "^3.1.7", - "@smithy/shared-ini-file-loader": "^3.1.8", - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.665.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.665.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.665.0.tgz", - "integrity": "sha512-cmJfVi4IM0WaKMQvPXhiS5mdIZyCoa04I3D+IEKpD2GAuVZa6tgwqfPyaApFDLjyedGGNFkC4MRgAjCcCl4WFg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.664.0", - "@aws-sdk/credential-provider-http": "3.664.0", - "@aws-sdk/credential-provider-ini": "3.665.0", - "@aws-sdk/credential-provider-process": "3.664.0", - "@aws-sdk/credential-provider-sso": "3.665.0", - "@aws-sdk/credential-provider-web-identity": "3.664.0", - "@aws-sdk/types": "3.664.0", - "@smithy/credential-provider-imds": "^3.2.4", - "@smithy/property-provider": "^3.1.7", - "@smithy/shared-ini-file-loader": "^3.1.8", - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.664.0.tgz", - "integrity": "sha512-sQicIw/qWTsmMw8EUQNJXdrWV5SXaZc2zGdCQsQxhR6wwNO2/rZ5JmzdcwUADmleBVyPYk3KGLhcofF/qXT2Ng==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@smithy/property-provider": "^3.1.7", - "@smithy/shared-ini-file-loader": "^3.1.8", - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.665.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.665.0.tgz", - "integrity": "sha512-Xe8WW4r70bsetGQG3azFeK/gd+Q4OmNiidtRrG64y/V9TIvIqc7Y/yUZNhEgFkpG19o188VmXg/ulnG3E+MvLg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-sso": "3.665.0", - "@aws-sdk/token-providers": "3.664.0", - "@aws-sdk/types": "3.664.0", - "@smithy/property-provider": "^3.1.7", - "@smithy/shared-ini-file-loader": "^3.1.8", - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.664.0.tgz", - "integrity": "sha512-10ltP1BfSKRJVXd8Yr5oLbo+VSDskWbps0X3szSsxTk0Dju1xvkz7hoIjylWLvtGbvQ+yb2pmsJYKCudW/4DJg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@smithy/property-provider": "^3.1.7", - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.664.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.664.0.tgz", - "integrity": "sha512-4tCXJ+DZWTq38eLmFgnEmO8X4jfWpgPbWoCyVYpRHCPHq6xbrU65gfwS9jGx25L4YdEce641ChI9TKLryuUgRA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@smithy/protocol-http": "^4.1.4", - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/middleware-logger": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.664.0.tgz", - "integrity": "sha512-eNykMqQuv7eg9pAcaLro44fscIe1VkFfhm+gYnlxd+PH6xqapRki1E68VHehnIptnVBdqnWfEqLUSLGm9suqhg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.664.0.tgz", - "integrity": "sha512-jq27WMZhm+dY8BWZ9Ipy3eXtZj0lJzpaKQE3A3tH5AOIlUV/gqrmnJ9CdqVVef4EJsq9Yil4ZzQjKKmPsxveQg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@smithy/protocol-http": "^4.1.4", - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.664.0.tgz", - "integrity": "sha512-Kp5UwXwayO6d472nntiwgrxqay2KS9ozXNmKjQfDrUWbEzvgKI+jgKNMia8MMnjSxYoBGpQ1B8NGh8a6KMEJJg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@aws-sdk/util-endpoints": "3.664.0", - "@smithy/core": "^2.4.7", - "@smithy/protocol-http": "^4.1.4", - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.664.0.tgz", - "integrity": "sha512-o/B8dg8K+9714RGYPgMxZgAChPe/MTSMkf/eHXTUFHNik5i1HgVKfac22njV2iictGy/6GhpFsKa1OWNYAkcUg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@smithy/node-config-provider": "^3.1.8", - "@smithy/types": "^3.5.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.7", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/token-providers": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.664.0.tgz", - "integrity": "sha512-dBAvXW2/6bAxidvKARFxyCY2uCynYBKRFN00NhS1T5ggxm3sUnuTpWw1DTjl02CVPkacBOocZf10h8pQbHSK8w==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@smithy/property-provider": "^3.1.7", - "@smithy/shared-ini-file-loader": "^3.1.8", - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sso-oidc": "^3.664.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/types": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.664.0.tgz", - "integrity": "sha512-+GtXktvVgpreM2b+NJL9OqZGsOzHwlCUrO8jgQUvH/yA6Kd8QO2YFhQCp0C9sSzTteZJVqGBu8E0CQurxJHPbw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/util-endpoints": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.664.0.tgz", - "integrity": "sha512-KrXoHz6zmAahVHkyWMRT+P6xJaxItgmklxEDrT+npsUB4d5C/lhw16Crcp9TDi828fiZK3GYKRAmmNhvmzvBNg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@smithy/types": "^3.5.0", - "@smithy/util-endpoints": "^2.1.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.664.0.tgz", - "integrity": "sha512-c/PV3+f1ss4PpskHbcOxTZ6fntV2oXy/xcDR9nW+kVaz5cM1G702gF0rvGLKPqoBwkj2rWGe6KZvEBeLzynTUQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.664.0", - "@smithy/types": "^3.5.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/client-elasticache/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.664.0.tgz", - "integrity": "sha512-l/m6KkgrTw1p/VTJTk0IoP9I2OnpWp3WbBgzxoNeh9cUcxTufIn++sBxKj5hhDql57LKWsckScG/MhFuH0vZZA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/middleware-user-agent": "3.664.0", - "@aws-sdk/types": "3.664.0", - "@smithy/node-config-provider": "^3.1.8", - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, "node_modules/@aws-sdk/client-secrets-manager": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.654.0.tgz", - "integrity": "sha512-Fua3kW8XCU2+gWcv8vHpsaR5g4ABuE4/tqv2B7vbMThLZ2Aam6Rw9b5dIMhpbje+edhAUBS0x6UyE88zQeHWZQ==", + "version": "3.675.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.675.0.tgz", + "integrity": "sha512-qC9e56BzlAbKOtvAfbRuGCNDkGjFLi856SeYQ1U9kpegd6+yrFNScKUCJHEZ/clX1zfGPaJCpbEwCtiEaayADw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.654.0", - "@aws-sdk/client-sts": "3.654.0", - "@aws-sdk/core": "3.654.0", - "@aws-sdk/credential-provider-node": "3.654.0", - "@aws-sdk/middleware-host-header": "3.654.0", - "@aws-sdk/middleware-logger": "3.654.0", - "@aws-sdk/middleware-recursion-detection": "3.654.0", - "@aws-sdk/middleware-user-agent": "3.654.0", - "@aws-sdk/region-config-resolver": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@aws-sdk/util-endpoints": "3.654.0", - "@aws-sdk/util-user-agent-browser": "3.654.0", - "@aws-sdk/util-user-agent-node": "3.654.0", - "@smithy/config-resolver": "^3.0.8", - "@smithy/core": "^2.4.3", - "@smithy/fetch-http-handler": "^3.2.7", - "@smithy/hash-node": "^3.0.6", - "@smithy/invalid-dependency": "^3.0.6", - "@smithy/middleware-content-length": "^3.0.8", - "@smithy/middleware-endpoint": "^3.1.3", - "@smithy/middleware-retry": "^3.0.18", - "@smithy/middleware-serde": "^3.0.6", - "@smithy/middleware-stack": "^3.0.6", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/node-http-handler": "^3.2.2", - "@smithy/protocol-http": "^4.1.3", - "@smithy/smithy-client": "^3.3.2", - "@smithy/types": "^3.4.2", - "@smithy/url-parser": "^3.0.6", + "@aws-sdk/client-sso-oidc": "3.675.0", + "@aws-sdk/client-sts": "3.675.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-node": "3.675.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.669.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.675.0", + "@aws-sdk/util-user-agent-node": "3.669.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.18", - "@smithy/util-defaults-mode-node": "^3.0.18", - "@smithy/util-endpoints": "^2.1.2", - "@smithy/util-middleware": "^3.0.6", - "@smithy/util-retry": "^3.0.6", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", "@smithy/util-utf8": "^3.0.0", + "@types/uuid": "^9.0.1", "tslib": "^2.6.2", "uuid": "^9.0.1" }, @@ -775,52 +305,52 @@ } }, "node_modules/@aws-sdk/client-ses": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.654.0.tgz", - "integrity": "sha512-DeM1ocK/ct98xDiZ5G4weSVDf4r8y+G2VOcJAiq4BnUYI0VGYB8yYkl1/Dy8hjlu2Ow8UgUz719pzBYhJvD9aQ==", + "version": "3.675.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.675.0.tgz", + "integrity": "sha512-4/OyFFpHMIahDc063vk4viETLtNPjopcUpwmWMtV8rhOns8KjJ2b1tvpvV7lNYT53mUm+g3fhYok9McHFDeeMA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.654.0", - "@aws-sdk/client-sts": "3.654.0", - "@aws-sdk/core": "3.654.0", - "@aws-sdk/credential-provider-node": "3.654.0", - "@aws-sdk/middleware-host-header": "3.654.0", - "@aws-sdk/middleware-logger": "3.654.0", - "@aws-sdk/middleware-recursion-detection": "3.654.0", - "@aws-sdk/middleware-user-agent": "3.654.0", - "@aws-sdk/region-config-resolver": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@aws-sdk/util-endpoints": "3.654.0", - "@aws-sdk/util-user-agent-browser": "3.654.0", - "@aws-sdk/util-user-agent-node": "3.654.0", - "@smithy/config-resolver": "^3.0.8", - "@smithy/core": "^2.4.3", - "@smithy/fetch-http-handler": "^3.2.7", - "@smithy/hash-node": "^3.0.6", - "@smithy/invalid-dependency": "^3.0.6", - "@smithy/middleware-content-length": "^3.0.8", - "@smithy/middleware-endpoint": "^3.1.3", - "@smithy/middleware-retry": "^3.0.18", - "@smithy/middleware-serde": "^3.0.6", - "@smithy/middleware-stack": "^3.0.6", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/node-http-handler": "^3.2.2", - "@smithy/protocol-http": "^4.1.3", - "@smithy/smithy-client": "^3.3.2", - "@smithy/types": "^3.4.2", - "@smithy/url-parser": "^3.0.6", + "@aws-sdk/client-sso-oidc": "3.675.0", + "@aws-sdk/client-sts": "3.675.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-node": "3.675.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.669.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.675.0", + "@aws-sdk/util-user-agent-node": "3.669.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.18", - "@smithy/util-defaults-mode-node": "^3.0.18", - "@smithy/util-endpoints": "^2.1.2", - "@smithy/util-middleware": "^3.0.6", - "@smithy/util-retry": "^3.0.6", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", "@smithy/util-utf8": "^3.0.0", - "@smithy/util-waiter": "^3.1.5", + "@smithy/util-waiter": "^3.1.6", "tslib": "^2.6.2" }, "engines": { @@ -828,47 +358,47 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.654.0.tgz", - "integrity": "sha512-4kBxs2IzCDtj6a6lRXa/lXK5wWpMGzwKtb+HMXf/rJYVM6x7wYRzc1hYrOd3DYkFQ/sR3dUFj+0mTP0os3aAbA==", + "version": "3.675.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.675.0.tgz", + "integrity": "sha512-2goBCEr4acZJ1YJ69eWPTsIfZUbO7enog+lBA5kZShDiwovqzwYSHSlf6OGz4ETs2xT1n7n+QfKY0p+TluTfEw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.654.0", - "@aws-sdk/middleware-host-header": "3.654.0", - "@aws-sdk/middleware-logger": "3.654.0", - "@aws-sdk/middleware-recursion-detection": "3.654.0", - "@aws-sdk/middleware-user-agent": "3.654.0", - "@aws-sdk/region-config-resolver": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@aws-sdk/util-endpoints": "3.654.0", - "@aws-sdk/util-user-agent-browser": "3.654.0", - "@aws-sdk/util-user-agent-node": "3.654.0", - "@smithy/config-resolver": "^3.0.8", - "@smithy/core": "^2.4.3", - "@smithy/fetch-http-handler": "^3.2.7", - "@smithy/hash-node": "^3.0.6", - "@smithy/invalid-dependency": "^3.0.6", - "@smithy/middleware-content-length": "^3.0.8", - "@smithy/middleware-endpoint": "^3.1.3", - "@smithy/middleware-retry": "^3.0.18", - "@smithy/middleware-serde": "^3.0.6", - "@smithy/middleware-stack": "^3.0.6", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/node-http-handler": "^3.2.2", - "@smithy/protocol-http": "^4.1.3", - "@smithy/smithy-client": "^3.3.2", - "@smithy/types": "^3.4.2", - "@smithy/url-parser": "^3.0.6", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.669.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.675.0", + "@aws-sdk/util-user-agent-node": "3.669.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.18", - "@smithy/util-defaults-mode-node": "^3.0.18", - "@smithy/util-endpoints": "^2.1.2", - "@smithy/util-middleware": "^3.0.6", - "@smithy/util-retry": "^3.0.6", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -877,48 +407,48 @@ } }, "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.654.0.tgz", - "integrity": "sha512-gbHrKsEnaAtmkNCVQzLyiqMzpDaThV/bWl/ODEklI+t6stW3Pe3oDMstEHLfJ6JU5g8sYnx4VLuxlnJMtUkvPw==", + "version": "3.675.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.675.0.tgz", + "integrity": "sha512-4kEcaa2P/BFz+xy5tagbtzM08gbjHXyYqW+n6SJuUFK7N6bZNnA4cu1hVgHcqOqk8Dbwv7fiseGT0x3Hhqjwqg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.654.0", - "@aws-sdk/credential-provider-node": "3.654.0", - "@aws-sdk/middleware-host-header": "3.654.0", - "@aws-sdk/middleware-logger": "3.654.0", - "@aws-sdk/middleware-recursion-detection": "3.654.0", - "@aws-sdk/middleware-user-agent": "3.654.0", - "@aws-sdk/region-config-resolver": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@aws-sdk/util-endpoints": "3.654.0", - "@aws-sdk/util-user-agent-browser": "3.654.0", - "@aws-sdk/util-user-agent-node": "3.654.0", - "@smithy/config-resolver": "^3.0.8", - "@smithy/core": "^2.4.3", - "@smithy/fetch-http-handler": "^3.2.7", - "@smithy/hash-node": "^3.0.6", - "@smithy/invalid-dependency": "^3.0.6", - "@smithy/middleware-content-length": "^3.0.8", - "@smithy/middleware-endpoint": "^3.1.3", - "@smithy/middleware-retry": "^3.0.18", - "@smithy/middleware-serde": "^3.0.6", - "@smithy/middleware-stack": "^3.0.6", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/node-http-handler": "^3.2.2", - "@smithy/protocol-http": "^4.1.3", - "@smithy/smithy-client": "^3.3.2", - "@smithy/types": "^3.4.2", - "@smithy/url-parser": "^3.0.6", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-node": "3.675.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.669.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.675.0", + "@aws-sdk/util-user-agent-node": "3.669.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.18", - "@smithy/util-defaults-mode-node": "^3.0.18", - "@smithy/util-endpoints": "^2.1.2", - "@smithy/util-middleware": "^3.0.6", - "@smithy/util-retry": "^3.0.6", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -926,53 +456,53 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.654.0" + "@aws-sdk/client-sts": "^3.675.0" } }, "node_modules/@aws-sdk/client-sts": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.654.0.tgz", - "integrity": "sha512-tyHa8jsBy+/NQZFHm6Q2Q09Vi9p3EH4yPy6PU8yPewpi2klreObtrUd0anJa6nzjS9SSuqnlZWsRic3cQ4QwCg==", + "version": "3.675.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.675.0.tgz", + "integrity": "sha512-zgjyR4GyuONeDGJBKNt9lFJ8HfDX7rpxZZVR7LSXr9lUkjf6vUGgD2k/K4UAoOTWCKKCor6TA562ezGlA8su6Q==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.654.0", - "@aws-sdk/core": "3.654.0", - "@aws-sdk/credential-provider-node": "3.654.0", - "@aws-sdk/middleware-host-header": "3.654.0", - "@aws-sdk/middleware-logger": "3.654.0", - "@aws-sdk/middleware-recursion-detection": "3.654.0", - "@aws-sdk/middleware-user-agent": "3.654.0", - "@aws-sdk/region-config-resolver": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@aws-sdk/util-endpoints": "3.654.0", - "@aws-sdk/util-user-agent-browser": "3.654.0", - "@aws-sdk/util-user-agent-node": "3.654.0", - "@smithy/config-resolver": "^3.0.8", - "@smithy/core": "^2.4.3", - "@smithy/fetch-http-handler": "^3.2.7", - "@smithy/hash-node": "^3.0.6", - "@smithy/invalid-dependency": "^3.0.6", - "@smithy/middleware-content-length": "^3.0.8", - "@smithy/middleware-endpoint": "^3.1.3", - "@smithy/middleware-retry": "^3.0.18", - "@smithy/middleware-serde": "^3.0.6", - "@smithy/middleware-stack": "^3.0.6", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/node-http-handler": "^3.2.2", - "@smithy/protocol-http": "^4.1.3", - "@smithy/smithy-client": "^3.3.2", - "@smithy/types": "^3.4.2", - "@smithy/url-parser": "^3.0.6", + "@aws-sdk/client-sso-oidc": "3.675.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-node": "3.675.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.669.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.675.0", + "@aws-sdk/util-user-agent-node": "3.669.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.18", - "@smithy/util-defaults-mode-node": "^3.0.18", - "@smithy/util-endpoints": "^2.1.2", - "@smithy/util-middleware": "^3.0.6", - "@smithy/util-retry": "^3.0.6", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -981,19 +511,20 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.654.0.tgz", - "integrity": "sha512-4Rwx7BVaNaFqmXBDmnOkMbyuIFFbpZ+ru4lr660p45zY1QoNNSalechfoRffcokLFOZO+VWEJkdcorPUUU993w==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.667.0.tgz", + "integrity": "sha512-pMcDVI7Tmdsc8R3sDv0Omj/4iRParGY+uJtAfF669WnZfDfaBQaix2Mq7+Mu08vdjqO9K3gicFvjk9S1VLmOKA==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^2.4.3", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/property-provider": "^3.1.6", - "@smithy/protocol-http": "^4.1.3", - "@smithy/signature-v4": "^4.1.3", - "@smithy/smithy-client": "^3.3.2", - "@smithy/types": "^3.4.2", - "@smithy/util-middleware": "^3.0.6", + "@aws-sdk/types": "3.667.0", + "@smithy/core": "^2.4.8", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/property-provider": "^3.1.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/signature-v4": "^4.2.0", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/util-middleware": "^3.0.7", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, @@ -1002,14 +533,15 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.654.0.tgz", - "integrity": "sha512-kogsx3Ql81JouHS7DkheCDU9MYAvK0AokxjcshDveGmf7BbgbWCA8Fnb9wjQyNDaOXNvkZu8Z8rgkX91z324/w==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.667.0.tgz", + "integrity": "sha512-zZbrkkaPc54WXm+QAnpuv0LPNfsts0HPPd+oCECGs7IQRaFsGj187cwvPg9RMWDFZqpm64MdBDoA8OQHsqzYCw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/property-provider": "^3.1.6", - "@smithy/types": "^3.4.2", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -1017,19 +549,20 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.654.0.tgz", - "integrity": "sha512-tgmAH4MBi/aDR882lfw48+tDV95ZH3GWc1Eoe6DpNLiM3GN2VfU/cZwuHmi6aq+vAbdIlswBHJ/+va0fOvlyjw==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.667.0.tgz", + "integrity": "sha512-sjtybFfERZWiqTY7fswBxKQLvUkiCucOWyqh3IaPo/4nE1PXRnaZCVG0+kRBPrYIxWqiVwytvZzMJy8sVZcG0A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/fetch-http-handler": "^3.2.7", - "@smithy/node-http-handler": "^3.2.2", - "@smithy/property-provider": "^3.1.6", - "@smithy/protocol-http": "^4.1.3", - "@smithy/smithy-client": "^3.3.2", - "@smithy/types": "^3.4.2", - "@smithy/util-stream": "^3.1.6", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/util-stream": "^3.1.9", "tslib": "^2.6.2" }, "engines": { @@ -1037,47 +570,48 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.654.0.tgz", - "integrity": "sha512-DKSdaNu2hwdmuvnm9KnA0NLqMWxxmxSOLWjSUSoFIm++wGXUjPrRMFYKvMktaXnPuyf5my8gF/yGbwzPZ8wlTg==", + "version": "3.675.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.675.0.tgz", + "integrity": "sha512-kCBlC6grpbpCvgowk9T4JHZxJ88VfN0r77bDZClcadFRAKQ8UHyO02zhgFCfUdnU1lNv1mr3ngEcGN7XzJlYWA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.654.0", - "@aws-sdk/credential-provider-http": "3.654.0", - "@aws-sdk/credential-provider-process": "3.654.0", - "@aws-sdk/credential-provider-sso": "3.654.0", - "@aws-sdk/credential-provider-web-identity": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@smithy/credential-provider-imds": "^3.2.3", - "@smithy/property-provider": "^3.1.6", - "@smithy/shared-ini-file-loader": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-env": "3.667.0", + "@aws-sdk/credential-provider-http": "3.667.0", + "@aws-sdk/credential-provider-process": "3.667.0", + "@aws-sdk/credential-provider-sso": "3.675.0", + "@aws-sdk/credential-provider-web-identity": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/credential-provider-imds": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.654.0" + "@aws-sdk/client-sts": "^3.675.0" } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.654.0.tgz", - "integrity": "sha512-wPV7CNYaXDEc+SS+3R0v8SZwkHRUE1z2k2j1d49tH5QBDT4tb/k2V/biXWkwSk3hbR+IMWXmuhJDv/5lybhIvg==", + "version": "3.675.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.675.0.tgz", + "integrity": "sha512-VO1WVZCDmAYu4sY/6qIBzdm5vJTxLhWKJWvL5kVFfSe8WiNNoHlTqYYUK9vAm/JYpIgFLTefPbIc5W4MK7o6Pg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.654.0", - "@aws-sdk/credential-provider-http": "3.654.0", - "@aws-sdk/credential-provider-ini": "3.654.0", - "@aws-sdk/credential-provider-process": "3.654.0", - "@aws-sdk/credential-provider-sso": "3.654.0", - "@aws-sdk/credential-provider-web-identity": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@smithy/credential-provider-imds": "^3.2.3", - "@smithy/property-provider": "^3.1.6", - "@smithy/shared-ini-file-loader": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/credential-provider-env": "3.667.0", + "@aws-sdk/credential-provider-http": "3.667.0", + "@aws-sdk/credential-provider-ini": "3.675.0", + "@aws-sdk/credential-provider-process": "3.667.0", + "@aws-sdk/credential-provider-sso": "3.675.0", + "@aws-sdk/credential-provider-web-identity": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/credential-provider-imds": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -1085,15 +619,16 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.654.0.tgz", - "integrity": "sha512-PmQoo8sZ9Q2Ow8OMzK++Z9lI7MsRUG7sNq3E72DVA215dhtTICTDQwGlXH2AAmIp7n+G9LLRds+4wo2ehG4mkg==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.667.0.tgz", + "integrity": "sha512-HZHnvop32fKgsNHkdhVaul7UzQ25sEc0j9yqA4bjhtbk0ECl42kj3f1pJ+ZU/YD9ut8lMJs/vVqiOdNThVdeBw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/property-provider": "^3.1.6", - "@smithy/shared-ini-file-loader": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -1101,17 +636,18 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.654.0.tgz", - "integrity": "sha512-7GFme6fWEdA/XYKzZPOAdj/jS6fMBy1NdSIZsDXikS0v9jU+ZzHrAaWt13YLzHyjgxB9Sg9id9ncdY1IiubQXQ==", + "version": "3.675.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.675.0.tgz", + "integrity": "sha512-p/EE2c0ebSgRhg1Fe1OH2+xNl7j1P4DTc7kZy1mX1NJ72fkqnGgBuf1vk5J9RmiRpbauPNMlm+xohjkGS7iodA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.654.0", - "@aws-sdk/token-providers": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@smithy/property-provider": "^3.1.6", - "@smithy/shared-ini-file-loader": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/client-sso": "3.675.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/token-providers": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -1119,32 +655,33 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.654.0.tgz", - "integrity": "sha512-6a2g9gMtZToqSu+CusjNK5zvbLJahQ9di7buO3iXgbizXpLXU1rnawCpWxwslMpT5fLgMSKDnKDrr6wdEk7jSw==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.667.0.tgz", + "integrity": "sha512-t8CFlZMD/1p/8Cli3rvRiTJpjr/8BO64gw166AHgFZYSN2h95L2l1tcW0jpsc3PprA32nLg1iQVKYt4WGM4ugw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/property-provider": "^3.1.6", - "@smithy/types": "^3.4.2", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.654.0" + "@aws-sdk/client-sts": "^3.667.0" } }, "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.654.0.tgz", - "integrity": "sha512-rxGgVHWKp8U2ubMv+t+vlIk7QYUaRCHaVpmUlJv0Wv6Q0KeO9a42T9FxHphjOTlCGQOLcjCreL9CF8Qhtb4mdQ==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.667.0.tgz", + "integrity": "sha512-Z7fIAMQnPegs7JjAQvlOeWXwpMRfegh5eCoIP6VLJIeR6DLfYKbP35JBtt98R6DXslrN2RsbTogjbxPEDQfw1w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/protocol-http": "^4.1.3", - "@smithy/types": "^3.4.2", + "@aws-sdk/types": "3.667.0", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -1152,13 +689,13 @@ } }, "node_modules/@aws-sdk/middleware-logger": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.654.0.tgz", - "integrity": "sha512-OQYb+nWlmASyXfRb989pwkJ9EVUMP1CrKn2eyTk3usl20JZmKo2Vjis6I0tLUkMSxMhnBJJlQKyWkRpD/u1FVg==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.667.0.tgz", + "integrity": "sha512-PtTRNpNm/5c746jRgZCNg4X9xEJIwggkGJrF0GP9AB1ANg4pc/sF2Fvn1NtqPe9wtQ2stunJprnm5WkCHN7QiA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/types": "^3.4.2", + "@aws-sdk/types": "3.667.0", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -1166,14 +703,14 @@ } }, "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.654.0.tgz", - "integrity": "sha512-gKSomgltKVmsT8sC6W7CrADZ4GHwX9epk3GcH6QhebVO3LA9LRbkL3TwOPUXakxxOLLUTYdOZLIOtFf7iH00lg==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.667.0.tgz", + "integrity": "sha512-U5glWD3ehFohzpUpopLtmqAlDurGWo2wRGPNgi4SwhWU7UDt6LS7E/UvJjqC0CUrjlzOw+my2A+Ncf+fisMhxQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/protocol-http": "^4.1.3", - "@smithy/types": "^3.4.2", + "@aws-sdk/types": "3.667.0", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -1181,15 +718,17 @@ } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.654.0.tgz", - "integrity": "sha512-liCcqPAyRsr53cy2tYu4qeH4MMN0eh9g6k56XzI5xd4SghXH5YWh4qOYAlQ8T66ZV4nPMtD8GLtLXGzsH8moFg==", + "version": "3.669.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.669.0.tgz", + "integrity": "sha512-K8ScPi45zjJrj5Y2gRqVsvKKQCQbvQBfYGcBw9ZOx9TTavH80bOCBjWg/GFnvs4f37tqVc1wMN2oGvcTF6HveQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@aws-sdk/util-endpoints": "3.654.0", - "@smithy/protocol-http": "^4.1.3", - "@smithy/types": "^3.4.2", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@smithy/core": "^2.4.8", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -1197,16 +736,16 @@ } }, "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.654.0.tgz", - "integrity": "sha512-ydGOrXJxj3x0sJhsXyTmvJVLAE0xxuTWFJihTl67RtaO7VRNtd82I3P3bwoMMaDn5WpmV5mPo8fEUDRlBm3fPg==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.667.0.tgz", + "integrity": "sha512-iNr+JhhA902JMKHG9IwT9YdaEx6KGl6vjAL5BRNeOjfj4cZYMog6Lz/IlfOAltMtT0w88DAHDEFrBd2uO0l2eg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/types": "3.667.0", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/types": "^3.5.0", "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.6", + "@smithy/util-middleware": "^3.0.7", "tslib": "^2.6.2" }, "engines": { @@ -1214,31 +753,31 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.654.0.tgz", - "integrity": "sha512-D8GeJYmvbfWkQDtTB4owmIobSMexZel0fOoetwvgCQ/7L8VPph3Q2bn1TRRIXvH7wdt6DcDxA3tKMHPBkT3GlA==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.667.0.tgz", + "integrity": "sha512-ZecJlG8p6D4UTYlBHwOWX6nknVtw/OBJ3yPXTSajBjhUlj9lE2xvejI8gl4rqkyLXk7z3bki+KR4tATbMaM9yg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/property-provider": "^3.1.6", - "@smithy/shared-ini-file-loader": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sso-oidc": "^3.654.0" + "@aws-sdk/client-sso-oidc": "^3.667.0" } }, "node_modules/@aws-sdk/types": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.654.0.tgz", - "integrity": "sha512-VWvbED3SV+10QJIcmU/PKjsKilsTV16d1I7/on4bvD/jo1qGeMXqLDBSen3ks/tuvXZF/mFc7ZW/W2DiLVtO7A==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.667.0.tgz", + "integrity": "sha512-gYq0xCsqFfQaSL/yT1Gl1vIUjtsg7d7RhnUfsXaHt8xTxOKRTdH9GjbesBjXOzgOvB0W0vfssfreSNGFlOOMJg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -1246,14 +785,14 @@ } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.654.0.tgz", - "integrity": "sha512-i902fcBknHs0Irgdpi62+QMvzxE+bczvILXigYrlHL4+PiEnlMVpni5L5W1qCkNZXf8AaMrSBuR1NZAGp6UOUw==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.667.0.tgz", + "integrity": "sha512-X22SYDAuQJWnkF1/q17pkX3nGw5XMD9YEUbmt87vUnRq7iyJ3JOpl6UKOBeUBaL838wA5yzdbinmCITJ/VZ1QA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/types": "^3.4.2", - "@smithy/util-endpoints": "^2.1.2", + "@aws-sdk/types": "3.667.0", + "@smithy/types": "^3.5.0", + "@smithy/util-endpoints": "^2.1.3", "tslib": "^2.6.2" }, "engines": { @@ -1272,26 +811,27 @@ } }, "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.654.0.tgz", - "integrity": "sha512-ykYAJqvnxLt7wfrqya28wuH3/7NdrwzfiFd7NqEVQf7dXVxL5RPEpD7DxjcyQo3DsHvvdUvGZVaQhozycn1pzA==", + "version": "3.675.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.675.0.tgz", + "integrity": "sha512-HW4vGfRiX54RLcsYjLuAhcBBJ6lRVEZd7njfGpAwBB9s7BH8t48vrpYbyA5XbbqbTvXfYBnugQCUw9HWjEa1ww==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/types": "^3.4.2", + "@aws-sdk/types": "3.667.0", + "@smithy/types": "^3.5.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.654.0.tgz", - "integrity": "sha512-a0ojjdBN6pqv6gB4H/QPPSfhs7mFtlVwnmKCM/QrTaFzN0U810PJ1BST3lBx5sa23I5jWHGaoFY+5q65C3clLQ==", + "version": "3.669.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.669.0.tgz", + "integrity": "sha512-9jxCYrgggy2xd44ZASqI7AMiRVaSiFp+06Kg8BQSU0ijKpBJlwcsqIS8pDT/n6LxuOw2eV5ipvM2C0r1iKzrGA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/middleware-user-agent": "3.669.0", + "@aws-sdk/types": "3.667.0", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2605,12 +2145,12 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.4.tgz", - "integrity": "sha512-MlWK8eqj0JlpZBnWmjQLqmFp71Ug00P+m72/1xQB3YByXD4zZ+y9N4hYrR0EDmrUCZIkyATWHOXFgtavwGDTzQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.5.tgz", + "integrity": "sha512-hsjtwpIemmCkm3ZV5fd/T0bPIugW1gJXwZ/hpuVubt2hEUApIoUTrf6qIdh9MAWlw0vjMrA1ztJLAwtNaZogvg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.5.0", + "@smithy/types": "^3.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2670,16 +2210,16 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.0.tgz", - "integrity": "sha512-LafbclHNKnsorMgUkKm7Tk7oJ7xizsZ1VwqhGKqoCIrXh4fqDDp73fK99HOEEgcsQbtemmeY/BPv0vTVYYUNEQ==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.1.tgz", + "integrity": "sha512-NsV1jF4EvmO5wqmaSzlnTVetemBS3FZHdyc5CExbDljcyJCEEkJr8ANu2JvtNbVg/9MvKAWV44kTrGS+Pi4INg==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^3.0.0", - "@smithy/protocol-http": "^4.1.4", - "@smithy/types": "^3.5.0", + "@smithy/protocol-http": "^4.1.5", + "@smithy/types": "^3.6.0", "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-middleware": "^3.0.7", + "@smithy/util-middleware": "^3.0.8", "@smithy/util-uri-escape": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" @@ -2706,9 +2246,9 @@ } }, "node_modules/@smithy/types": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.5.0.tgz", - "integrity": "sha512-QN0twHNfe8mNJdH9unwsCK13GURU7oEAZqkBI+rsvpv1jrmserO+WnLE7jidR9W/1dxwZ0u/CB01mV2Gms/K2Q==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.6.0.tgz", + "integrity": "sha512-8VXK/KzOHefoC65yRgCn5vG1cysPJjHnOVt9d0ybFQSmJgQj152vMn4EkYhGuaOmnnZvCPav/KnYyE6/KsNZ2w==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -2845,12 +2385,12 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.7.tgz", - "integrity": "sha512-OVA6fv/3o7TMJTpTgOi1H5OTwnuUa8hzRzhSFDtZyNxi6OZ70L/FHattSmhE212I7b6WSOJAAmbYnvcjTHOJCA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.8.tgz", + "integrity": "sha512-p7iYAPaQjoeM+AKABpYWeDdtwQNxasr4aXQEA/OmbOaug9V0odRVDy3Wx4ci8soljE/JXQo+abV0qZpW8NX0yA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.5.0", + "@smithy/types": "^3.6.0", "tslib": "^2.6.2" }, "engines": { @@ -3160,6 +2700,12 @@ "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "license": "MIT" + }, "node_modules/@xmldom/is-dom-node": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@xmldom/is-dom-node/-/is-dom-node-1.0.1.tgz", @@ -3637,9 +3183,9 @@ } }, "node_modules/chart.js": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.4.tgz", - "integrity": "sha512-emICKGBABnxhMjUjlYRR12PmOXhJ2eJjEHL2/dZlWjxRAZT1D8xplLFq5M0tMQK8ja+wBS/tuVEJB5C6r7VxJA==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.5.tgz", + "integrity": "sha512-CVVjg1RYTJV9OCC8WeJPMx8gsV8K6WIyIEQUE3ui4AR9Hfgls9URri6Ja3hyMVBbTF8Q2KFa19PE815gWcWhng==", "license": "MIT", "dependencies": { "@kurkle/color": "^0.3.0" @@ -3707,9 +3253,9 @@ } }, "node_modules/cloudinary": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-2.5.0.tgz", - "integrity": "sha512-gPkyylFpyBAXiErAnMgZBlpwztHuZoik/OTLQM9oswjlzYHLMtQGoh0oisPBQvVHQxHmBUjcgwsAi393HDedqQ==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-2.5.1.tgz", + "integrity": "sha512-CNg6uU53Hl4FEVynkTGpt5bQEAQWDHi3H+Sm62FzKf5uQHipSN2v7qVqS8GRVqeb0T1WNV+22+75DOJeRXYeSQ==", "license": "MIT", "dependencies": { "lodash": "^4.17.21", @@ -3986,17 +3532,27 @@ } }, "node_modules/cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", "dependencies": { - "cookie": "0.4.1", + "cookie": "0.7.2", "cookie-signature": "1.0.6" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -4611,9 +4167,9 @@ } }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", @@ -4621,7 +4177,7 @@ "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -4653,9 +4209,10 @@ } }, "node_modules/express/node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4830,9 +4387,9 @@ "license": "MIT" }, "node_modules/firebase-admin": { - "version": "12.5.0", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-12.5.0.tgz", - "integrity": "sha512-ad8vnlPcuuZN9scSgY8UnAxPI4mzP2/Q+dsrVLTf+j3h7bIq0FOelDCDGz4StgKJdk244v2kpOxqJjPG3grBHg==", + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-12.6.0.tgz", + "integrity": "sha512-gc0pDiUmxscxBhcjMcttmjvExJmnQdVRb+IIth95CvMm7F9rLdabrQZThW2mK02HR696P+rzd6NqkdUA3URu4w==", "license": "Apache-2.0", "dependencies": { "@fastify/busboy": "^3.0.0", @@ -5762,9 +5319,9 @@ } }, "node_modules/json-2-csv": { - "version": "5.5.5", - "resolved": "https://registry.npmjs.org/json-2-csv/-/json-2-csv-5.5.5.tgz", - "integrity": "sha512-xLeiOE+jtDMX4SMn9JlD6BVI9c5SYVFmtlsNBSelGlq9iUHdVmwlxQ/uUI/BEVQuKDVLlxNrsOfwlI3rfYy1zA==", + "version": "5.5.6", + "resolved": "https://registry.npmjs.org/json-2-csv/-/json-2-csv-5.5.6.tgz", + "integrity": "sha512-N673XbJgHwUq9JreKpk530jSywPF/rEAQ08dV99QQpkluP/4HTwshpoP9hmDz26iSFqu7eNAPgyJfu/77HvPGA==", "license": "MIT", "dependencies": { "deeks": "3.1.0", @@ -6198,9 +5755,10 @@ } }, "node_modules/moment-timezone": { - "version": "0.5.45", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.45.tgz", - "integrity": "sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==", + "version": "0.5.46", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.46.tgz", + "integrity": "sha512-ZXm9b36esbe7OmdABqIWJuBBiLLwAjrN7CE+7sYdCCx82Nabt1wHDj8TVseS59QIlfFPbOoiBPm6ca9BioG4hw==", + "license": "MIT", "dependencies": { "moment": "^2.29.4" }, @@ -6596,9 +6154,9 @@ "license": "MIT" }, "node_modules/phone": { - "version": "3.1.50", - "resolved": "https://registry.npmjs.org/phone/-/phone-3.1.50.tgz", - "integrity": "sha512-TRmb2bX3sX+rrOrc8FRd8hmy4exoH2Lu3vjBP/dLgwwci1lv7DbjJ2iHMe7X4Hm8Pa0rJcfqTbq/O1vjU4NgxQ==", + "version": "3.1.51", + "resolved": "https://registry.npmjs.org/phone/-/phone-3.1.51.tgz", + "integrity": "sha512-ggy58LoEAb6LPZEyz1iXz7dQKbDAwp6V6yQgRQUDSlx4HgKm2YGETA5Ns/39/HQ+QL74+OBR05xzdUhi6TMHLQ==", "license": "MIT", "engines": { "node": ">=12" @@ -7233,9 +6791,9 @@ } }, "node_modules/soap": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/soap/-/soap-1.1.4.tgz", - "integrity": "sha512-9uALgOdm/Dxcr2VWlB4VjsZbJ6k8L+fR1Dp/ICHFWSKXP3cFr9v9rIu+UBntVHmrJsErXwezv+dYsWte6lbzCA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/soap/-/soap-1.1.5.tgz", + "integrity": "sha512-6YJrwY+tXHwlk/wtS7+XSc0jyEWgNw8xJQYvY9m1jZlPaGkc2nzmwKAq98fwGIw51acywhsraaeq/6GFggaNYw==", "license": "MIT", "dependencies": { "axios": "^1.7.7", diff --git a/package.json b/package.json index b170d0045..057c1d1be 100644 --- a/package.json +++ b/package.json @@ -19,10 +19,10 @@ "makeitpretty": "prettier --write \"**/*.{css,js,json,jsx,scss}\"" }, "dependencies": { - "@aws-sdk/client-elasticache": "^3.665.0", - "@aws-sdk/client-secrets-manager": "^3.654.0", - "@aws-sdk/client-ses": "^3.654.0", - "@aws-sdk/credential-provider-node": "^3.654.0", + "@aws-sdk/client-elasticache": "^3.675.0", + "@aws-sdk/client-secrets-manager": "^3.675.0", + "@aws-sdk/client-ses": "^3.675.0", + "@aws-sdk/credential-provider-node": "^3.675.0", "@opensearch-project/opensearch": "^2.12.0", "@socket.io/admin-ui": "^0.5.1", "@socket.io/redis-adapter": "^8.3.0", @@ -32,35 +32,35 @@ "bluebird": "^3.7.2", "body-parser": "^1.20.3", "canvas": "^2.11.2", - "chart.js": "^4.4.4", - "cloudinary": "^2.5.0", + "chart.js": "^4.4.5", + "cloudinary": "^2.5.1", "compression": "^1.7.4", - "cookie-parser": "^1.4.6", + "cookie-parser": "^1.4.7", "cors": "2.8.5", "csrf": "^3.1.0", "dinero.js": "^1.9.1", "dotenv": "^16.4.5", - "express": "^4.21.0", - "firebase-admin": "^12.5.0", + "express": "^4.21.1", + "firebase-admin": "^12.6.0", "graphql": "^16.9.0", "graphql-request": "^6.1.0", "graylog2": "^0.2.1", "inline-css": "^4.0.2", "intuit-oauth": "^4.1.2", "ioredis": "^5.4.1", - "json-2-csv": "^5.5.5", + "json-2-csv": "^5.5.6", "lodash": "^4.17.21", "moment": "^2.30.1", - "moment-timezone": "^0.5.45", + "moment-timezone": "^0.5.46", "multer": "^1.4.5-lts.1", "node-mailjet": "^6.0.6", "node-persist": "^4.0.3", "nodemailer": "^6.9.15", - "phone": "^3.1.50", + "phone": "^3.1.51", "recursive-diff": "^1.0.9", "redis": "^4.7.0", "rimraf": "^6.0.1", - "soap": "^1.1.4", + "soap": "^1.1.5", "socket.io": "^4.8.0", "socket.io-adapter": "^2.5.5", "ssh2-sftp-client": "^10.0.3", From 9233cef23ab9987e1c91ff9d9964c86c177f7fd7 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Wed, 23 Oct 2024 17:02:45 -0700 Subject: [PATCH 35/79] IO-2978 Production not in Production Status Signed-off-by: Allan Carr --- .../production-board-kanban.component.jsx | 16 +- .../production-list-table.component.jsx | 2 +- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 7105 +++++++++-------- client/src/utils/TemplateConstants.js | 8 + 6 files changed, 3573 insertions(+), 3560 deletions(-) diff --git a/client/src/components/production-board-kanban/production-board-kanban.component.jsx b/client/src/components/production-board-kanban/production-board-kanban.component.jsx index ef10f99b9..00333198c 100644 --- a/client/src/components/production-board-kanban/production-board-kanban.component.jsx +++ b/client/src/components/production-board-kanban/production-board-kanban.component.jsx @@ -1,12 +1,14 @@ import { SyncOutlined } from "@ant-design/icons"; -import { useApolloClient } from "@apollo/client"; -import Board from "./trello-board/index"; -import { Button, notification, Skeleton, Space } from "antd"; import { PageHeader } from "@ant-design/pro-layout"; +import { useApolloClient } from "@apollo/client"; +import { Button, notification, Skeleton, Space } from "antd"; +import cloneDeep from "lodash/cloneDeep"; +import isEqual from "lodash/isEqual"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; +import NoteUpsertModal from "../../components/note-upsert-modal/note-upsert-modal.container"; import { logImEXEvent } from "../../firebase/firebase.utils"; import { generate_UPDATE_JOB_KANBAN } from "../../graphql/jobs.queries"; import { insertAuditTrail } from "../../redux/application/application.actions"; @@ -15,14 +17,13 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings"; import IndefiniteLoading from "../indefinite-loading/indefinite-loading.component"; import ProductionBoardFilters from "../production-board-filters/production-board-filters.component"; import ProductionListDetailComponent from "../production-list-detail/production-list-detail.component"; +import ProductionListPrint from "../production-list-table/production-list-print.component.jsx"; import CardColorLegend from "./production-board-kanban-card-color-legend.component.jsx"; import "./production-board-kanban.styles.scss"; import { createBoardData } from "./production-board-kanban.utils.js"; -import ProductionBoardKanbanSettings from "./settings/production-board-kanban.settings.component.jsx"; -import cloneDeep from "lodash/cloneDeep"; -import isEqual from "lodash/isEqual"; import { defaultFilters, mergeWithDefaults } from "./settings/defaultKanbanSettings.js"; -import NoteUpsertModal from "../../components/note-upsert-modal/note-upsert-modal.container"; +import ProductionBoardKanbanSettings from "./settings/production-board-kanban.settings.component.jsx"; +import Board from "./trello-board/index"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop @@ -214,6 +215,7 @@ function ProductionBoardKanbanComponent({ data, bodyshop, refetch, insertAuditTr bodyshop={bodyshop} data={data} /> + } /> diff --git a/client/src/components/production-list-table/production-list-table.component.jsx b/client/src/components/production-list-table/production-list-table.component.jsx index c8763ad13..09e41b5e8 100644 --- a/client/src/components/production-list-table/production-list-table.component.jsx +++ b/client/src/components/production-list-table/production-list-table.component.jsx @@ -77,7 +77,7 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici const matchingColumnConfig = useMemo(() => { return bodyshop?.production_config?.find((p) => p.name === defaultView); - }, [bodyshop.production_config]); + }, [bodyshop.production_config, defaultView]); useEffect(() => { const newColumns = diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index bdc45df6e..7b72e1d61 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -3044,6 +3044,7 @@ "production_by_target_date": "Production by Target Date", "production_by_technician": "Production by Technician", "production_by_technician_one": "Production filtered by Technician", + "production_not_production_status": "Production not in Production Status", "production_over_time": "Production Level over Time", "psr_by_make": "Percent of Sales by Vehicle Make", "purchase_return_ratio_grouped_by_vendor_detail": "Purchase & Return Ratio by Vendor (Detail)", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 66d512cef..b6b7aec07 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -3044,6 +3044,7 @@ "production_by_target_date": "", "production_by_technician": "", "production_by_technician_one": "", + "production_not_production_status": "", "production_over_time": "", "psr_by_make": "", "purchase_return_ratio_grouped_by_vendor_detail": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index c4cdbf53f..854d0e4e8 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -1,2850 +1,2850 @@ { - "translation": { - "allocations": { - "actions": { - "assign": "Attribuer" - }, - "errors": { - "deleting": "", - "saving": "", - "validation": "" - }, - "fields": { - "employee": "Alloué à" - }, - "successes": { - "deleted": "", - "save": "" - } - }, - "appointments": { - "actions": { - "block": "", - "calculate": "", - "cancel": "annuler", - "intake": "Admission", - "new": "Nouveau rendez-vous", - "preview": "", - "reschedule": "Replanifier", - "sendreminder": "", - "unblock": "", - "viewjob": "Voir le travail" - }, - "errors": { - "blocking": "", - "canceling": "Erreur lors de l'annulation du rendez-vous. {{message}}", - "saving": "Erreur lors de la planification du rendez-vous. {{message}}" - }, - "fields": { - "alt_transport": "", - "color": "", - "end": "", - "note": "", - "start": "", - "time": "", - "title": "Titre" - }, - "labels": { - "arrivedon": "Arrivé le:", - "arrivingjobs": "", - "blocked": "", - "cancelledappointment": "Rendez-vous annulé pour:", - "completingjobs": "", - "dataconsistency": "", - "expectedjobs": "", - "expectedprodhrs": "", - "history": "", - "inproduction": "", - "manualevent": "", - "noarrivingjobs": "", - "nocompletingjobs": "", - "nodateselected": "Aucune date n'a été sélectionnée.", - "priorappointments": "Rendez-vous précédents", - "reminder": "", - "scheduledfor": "Rendez-vous prévu pour:", - "severalerrorsfound": "", - "smartscheduling": "", - "smspaymentreminder": "", - "suggesteddates": "" - }, - "successes": { - "canceled": "Rendez-vous annulé avec succès.", - "created": "Rendez-vous planifié avec succès.", - "saved": "" - } - }, - "associations": { - "actions": { - "activate": "Activer" - }, - "fields": { - "active": "Actif?", - "shopname": "nom de la boutique" - }, - "labels": { - "actions": "actes" - } - }, - "audit": { - "fields": { - "cc": "", - "contents": "", - "created": "", - "operation": "", - "status": "", - "subject": "", - "to": "", - "useremail": "", - "values": "" - } - }, - "audit_trail": { - "messages": { - "admin_job_remove_from_ar": "", - "admin_jobmarkexported": "", - "admin_jobmarkforreexport": "", - "admin_jobuninvoice": "", - "admin_jobunvoid": "", - "alerttoggle": "", - "appointmentcancel": "", - "appointmentinsert": "", - "assignedlinehours": "", - "billdeleted": "", - "billposted": "", - "billupdated": "", - "failedpayment": "", - "jobassignmentchange": "", - "jobassignmentremoved": "", - "jobchecklist": "", - "jobclosedwithbypass": "", - "jobconverted": "", - "jobdelivery": "", - "jobexported": "", - "jobfieldchanged": "", - "jobimported": "", - "jobinproductionchange": "", - "jobintake": "", - "jobinvoiced": "", - "jobioucreated": "", - "jobmodifylbradj": "", - "jobnoteadded": "", - "jobnotedeleted": "", - "jobnoteupdated": "", - "jobspartsorder": "", - "jobspartsreturn": "", - "jobstatuschange": "", - "jobsupplement": "", - "jobsuspend": "", - "jobvoid": "", - "tasks_completed": "", - "tasks_created": "", - "tasks_deleted": "", - "tasks_uncompleted": "", - "tasks_undeleted": "", - "tasks_updated": "" - } - }, - "billlines": { - "actions": { - "newline": "" - }, - "fields": { - "actual_cost": "", - "actual_price": "", - "cost_center": "", - "federal_tax_applicable": "", - "jobline": "", - "line_desc": "", - "local_tax_applicable": "", - "location": "", - "quantity": "", - "state_tax_applicable": "" - }, - "labels": { - "deductedfromlbr": "", - "entered": "", - "from": "", - "mod_lbr_adjustment": "", - "other": "", - "reconciled": "", - "unreconciled": "" - }, - "validation": { - "atleastone": "" - } - }, - "bills": { - "actions": { - "deductallhours": "", - "edit": "", - "receive": "", - "return": "" - }, - "errors": { - "creating": "", - "deleting": "", - "existinginventoryline": "", - "exporting": "", - "exporting-partner": "", - "invalidro": "", - "invalidvendor": "", - "validation": "" - }, - "fields": { - "allpartslocation": "", - "date": "", - "exported": "", - "federal_tax_rate": "", - "invoice_number": "", - "is_credit_memo": "", - "is_credit_memo_short": "", - "local_tax_rate": "", - "ro_number": "", - "state_tax_rate": "", - "total": "", - "vendor": "", - "vendorname": "" - }, - "labels": { - "actions": "", - "bill_lines": "", - "bill_total": "", - "billcmtotal": "", - "bills": "", - "calculatedcreditsnotreceived": "", - "creditsnotreceived": "", - "creditsreceived": "", - "dedfromlbr": "", - "deleteconfirm": "", - "discrepancy": "", - "discrepwithcms": "", - "discrepwithlbradj": "", - "editadjwarning": "", - "entered_total": "", - "enteringcreditmemo": "", - "federal_tax": "", - "federal_tax_exempt": "", - "generatepartslabel": "", - "iouexists": "", - "local_tax": "", - "markexported": "", - "markforreexport": "", - "new": "", - "nobilllines": "", - "noneselected": "", - "onlycmforinvoiced": "", - "printlabels": "", - "retailtotal": "", - "returnfrombill": "", - "savewithdiscrepancy": "", - "state_tax": "", - "subtotal": "", - "totalreturns": "" - }, - "successes": { - "created": "", - "deleted": "", - "exported": "", - "markexported": "", - "reexport": "" - }, - "validation": { - "closingperiod": "", - "inventoryquantity": "", - "manualinhouse": "", - "unique_invoice_number": "" - } - }, - "bodyshop": { - "actions": { - "add_task_preset": "", - "addapptcolor": "", - "addbucket": "", - "addpartslocation": "", - "addpartsrule": "", - "addspeedprint": "", - "addtemplate": "", - "newlaborrate": "", - "newsalestaxcode": "", - "newstatus": "", - "testrender": "" - }, - "errors": { - "creatingdefaultview": "", - "loading": "Impossible de charger les détails de la boutique. Veuillez appeler le support technique.", - "saving": "" - }, - "fields": { - "ReceivableCustomField": "", - "address1": "", - "address2": "", - "appt_alt_transport": "", - "appt_colors": { - "color": "", - "label": "" - }, - "appt_length": "", - "attach_pdf_to_email": "", - "batchid": "", - "bill_allow_post_to_closed": "", - "bill_federal_tax_rate": "", - "bill_local_tax_rate": "", - "bill_state_tax_rate": "", - "city": "", - "closingperiod": "", - "companycode": "", - "country": "", - "dailybodytarget": "", - "dailypainttarget": "", - "default_adjustment_rate": "", - "deliver": { - "require_actual_delivery_date": "", - "templates": "" - }, - "dms": { - "apcontrol": "", - "appostingaccount": "", - "cashierid": "", - "default_journal": "", - "disablebillwip": "", - "disablecontactvehiclecreation": "", - "dms_acctnumber": "", - "dms_control_override": "", - "dms_wip_acctnumber": "", - "generic_customer_number": "", - "itc_federal": "", - "itc_local": "", - "itc_state": "", - "mappingname": "", - "sendmaterialscosting": "", - "srcco": "" - }, - "email": "", - "enforce_class": "", - "enforce_conversion_category": "", - "enforce_conversion_csr": "", - "enforce_referral": "", - "federal_tax_id": "", - "ignoreblockeddays": "", - "inhousevendorid": "", - "insurance_vendor_id": "", - "intake": { - "next_contact_hours": "", - "templates": "" - }, - "intellipay_config": { - "cash_discount_percentage": "", - "enable_cash_discount": "" - }, - "invoice_federal_tax_rate": "", - "invoice_local_tax_rate": "", - "invoice_state_tax_rate": "", - "jc_hourly_rates": { - "mapa": "", - "mash": "" - }, - "last_name_first": "", - "lastnumberworkingdays": "", - "localmediaserverhttp": "", - "localmediaservernetwork": "", - "localmediatoken": "", - "logo_img_footer_margin": "", - "logo_img_header_margin": "", - "logo_img_path": "", - "logo_img_path_height": "", - "logo_img_path_width": "", - "md_categories": "", - "md_ccc_rates": "", - "md_classes": "", - "md_ded_notes": "", - "md_email_cc": "", - "md_from_emails": "", - "md_functionality_toggles": { - "parts_queue_toggle": "" - }, - "md_hour_split": { - "paint": "", - "prep": "" - }, - "md_ins_co": { - "city": "", - "name": "", - "private": "", - "state": "", - "street1": "", - "street2": "", - "zip": "" - }, - "md_jobline_presets": "", - "md_lost_sale_reasons": "", - "md_parts_order_comment": "", - "md_parts_scan": { - "expression": "", - "flags": "" - }, - "md_payment_types": "", - "md_referral_sources": "", - "md_ro_guard": { - "enabled": "", - "enforce_ar": "", - "enforce_bills": "", - "enforce_cm": "", - "enforce_labor": "", - "enforce_ppd": "", - "enforce_profit": "", - "enforce_sublet": "", - "masterbypass": "", - "totalgppercent_minimum": "" - }, - "md_tasks_presets": { - "enable_tasks": "", - "hourstype": "", - "memo": "", - "name": "", - "nextstatus": "", - "percent": "", - "use_approvals": "" - }, - "messaginglabel": "", - "messagingtext": "", - "noteslabel": "", - "notestext": "", - "partslocation": "", - "phone": "", - "prodtargethrs": "", - "rbac": { - "accounting": { - "exportlog": "", - "payables": "", - "payments": "", - "receivables": "" - }, - "bills": { - "delete": "", - "enter": "", - "list": "", - "reexport": "", - "view": "" - }, - "contracts": { - "create": "", - "detail": "", - "list": "" - }, - "courtesycar": { - "create": "", - "detail": "", - "list": "" - }, - "csi": { - "export": "", - "page": "" - }, - "employee_teams": { - "page": "" - }, - "employees": { - "page": "" - }, - "inventory": { - "delete": "", - "list": "" - }, - "jobs": { - "admin": "", - "available-list": "", - "checklist-view": "", - "close": "", - "create": "", - "deliver": "", - "detail": "", - "intake": "", - "list-active": "", - "list-all": "", - "list-ready": "", - "partsqueue": "", - "void": "" - }, - "owners": { - "detail": "", - "list": "" - }, - "payments": { - "enter": "", - "list": "" - }, - "phonebook": { - "edit": "", - "view": "" - }, - "production": { - "board": "", - "list": "" - }, - "schedule": { - "view": "" - }, - "scoreboard": { - "view": "" - }, - "shiftclock": { - "view": "" - }, - "shop": { - "config": "", - "dashboard": "", - "rbac": "", - "reportcenter": "", - "templates": "", - "vendors": "" - }, - "temporarydocs": { - "view": "" - }, - "timetickets": { - "edit": "", - "editcommitted": "", - "enter": "", - "list": "", - "shiftedit": "" - }, - "ttapprovals": { - "approve": "", - "view": "" - }, - "users": { - "editaccess": "" - } - }, - "responsibilitycenter": "", - "responsibilitycenter_accountdesc": "", - "responsibilitycenter_accountitem": "", - "responsibilitycenter_accountname": "", - "responsibilitycenter_accountnumber": "", - "responsibilitycenter_rate": "", - "responsibilitycenter_tax_rate": "", - "responsibilitycenter_tax_sur": "", - "responsibilitycenter_tax_thres": "", - "responsibilitycenter_tax_tier": "", - "responsibilitycenter_tax_type": "", - "responsibilitycenters": { - "ap": "", - "ar": "", - "ats": "", - "federal_tax": "", - "federal_tax_itc": "", - "gst_override": "", - "invoiceexemptcode": "", - "itemexemptcode": "", - "la1": "", - "la2": "", - "la3": "", - "la4": "", - "laa": "", - "lab": "", - "lad": "", - "lae": "", - "laf": "", - "lag": "", - "lam": "", - "lar": "", - "las": "", - "lau": "", - "local_tax": "", - "mapa": "", - "mash": "", - "paa": "", - "pac": "", - "pag": "", - "pal": "", - "pam": "", - "pan": "", - "pao": "", - "pap": "", - "par": "", - "pas": "", - "pasl": "", - "refund": "", - "sales_tax_codes": { - "code": "", - "description": "", - "federal": "", - "local": "", - "state": "" - }, - "state_tax": "", - "tow": "" - }, - "schedule_end_time": "", - "schedule_start_time": "", - "shopname": "", - "speedprint": { - "id": "", - "label": "", - "templates": "" - }, - "ss_configuration": { - "dailyhrslimit": "" - }, - "ssbuckets": { - "color": "", - "gte": "", - "id": "", - "label": "", - "lt": "", - "target": "" - }, - "state": "", - "state_tax_id": "", - "status": "", - "statuses": { - "active_statuses": "", - "additional_board_statuses": "", - "color": "", - "default_arrived": "", - "default_bo": "", - "default_canceled": "", - "default_completed": "", - "default_delivered": "", - "default_exported": "", - "default_imported": "", - "default_invoiced": "", - "default_ordered": "", - "default_quote": "", - "default_received": "", - "default_returned": "", - "default_scheduled": "", - "default_void": "", - "open_statuses": "", - "post_production_statuses": "", - "pre_production_statuses": "", - "production_colors": "", - "production_statuses": "", - "ready_statuses": "" - }, - "target_touchtime": "", - "timezone": "", - "tt_allow_post_to_invoiced": "", - "tt_enforce_hours_for_tech_console": "", - "use_fippa": "", - "use_paint_scale_data": "", - "uselocalmediaserver": "", - "website": "", - "zip_post": "" - }, - "labels": { - "2tiername": "", - "2tiersetup": "", - "2tiersource": "", - "accountingsetup": "", - "accountingtiers": "", - "alljobstatuses": "", - "allopenjobstatuses": "", - "apptcolors": "", - "businessinformation": "", - "checklists": "", - "csiq": "", - "customtemplates": "", - "defaultcostsmapping": "", - "defaultprofitsmapping": "", - "deliverchecklist": "", - "dms": { - "cdk": { - "controllist": "", - "payers": "" - }, - "cdk_dealerid": "", - "costsmapping": "", - "dms_allocations": "", - "pbs_serialnumber": "", - "profitsmapping": "", - "title": "" - }, - "emaillater": "", - "employee_teams": "", - "employees": "", - "estimators": "", - "filehandlers": "", - "insurancecos": "", - "intakechecklist": "", - "intellipay": "", - "intellipay_cash_discount": "", - "jobstatuses": "", - "laborrates": "", - "licensing": "", - "md_parts_scan": "", - "md_ro_guard": "", - "md_tasks_presets": "", - "md_to_emails": "", - "md_to_emails_emails": "", - "messagingpresets": "", - "notemplatesavailable": "", - "notespresets": "", - "orderstatuses": "", - "partslocations": "", - "partsscan": "", - "printlater": "", - "qbo": "", - "qbo_departmentid": "", - "qbo_usa": "", - "rbac": "", - "responsibilitycenters": { - "costs": "", - "profits": "", - "sales_tax_codes": "", - "tax_accounts": "", - "title": "" - }, - "roguard": { - "title": "" - }, - "scheduling": "", - "scoreboardsetup": "", - "shopinfo": "", - "speedprint": "", - "ssbuckets": "", - "systemsettings": "", - "task-presets": "", - "workingdays": "" - }, - "successes": { - "areyousure": "", - "defaultviewcreated": "", - "save": "", - "unsavedchanges": "" - }, - "validation": { - "centermustexist": "", - "larsplit": "", - "useremailmustexist": "" - } - }, - "checklist": { - "actions": { - "printall": "" - }, - "errors": { - "complete": "", - "nochecklist": "" - }, - "labels": { - "addtoproduction": "", - "allow_text_message": "", - "checklist": "", - "printpack": "", - "removefromproduction": "" - }, - "successes": { - "completed": "" - } - }, - "contracts": { - "actions": { - "changerate": "", - "convertoro": "", - "decodelicense": "", - "find": "", - "printcontract": "", - "senddltoform": "" - }, - "errors": { - "fetchingjobinfo": "", - "returning": "", - "saving": "", - "selectjobandcar": "" - }, - "fields": { - "actax": "", - "actualreturn": "", - "agreementnumber": "", - "cc_cardholder": "", - "cc_expiry": "", - "cc_num": "", - "cleanupcharge": "", - "coverage": "", - "dailyfreekm": "", - "dailyrate": "", - "damage": "", - "damagewaiver": "", - "driver": "", - "driver_addr1": "", - "driver_addr2": "", - "driver_city": "", - "driver_dlexpiry": "", - "driver_dlnumber": "", - "driver_dlst": "", - "driver_dob": "", - "driver_fn": "", - "driver_ln": "", - "driver_ph1": "", - "driver_state": "", - "driver_zip": "", - "excesskmrate": "", - "federaltax": "", - "fuelin": "", - "fuelout": "", - "kmend": "", - "kmstart": "", - "length": "", - "localtax": "", - "refuelcharge": "", - "scheduledreturn": "", - "start": "", - "statetax": "", - "status": "" - }, - "labels": { - "agreement": "", - "availablecars": "", - "cardueforservice": "", - "convertform": { - "applycleanupcharge": "", - "refuelqty": "" - }, - "correctdataonform": "", - "dateinpast": "", - "dlexpirebeforereturn": "", - "driverinformation": "", - "findcontract": "", - "findermodal": "", - "insuranceexpired": "", - "noteconvertedfrom": "", - "populatefromjob": "", - "rates": "", - "time": "", - "vehicle": "", - "waitingforscan": "" - }, - "status": { - "new": "", - "out": "", - "returned": "" - }, - "successes": { - "saved": "" - } - }, - "courtesycars": { - "actions": { - "new": "", - "return": "" - }, - "errors": { - "saving": "" - }, - "fields": { - "color": "", - "dailycost": "", - "damage": "", - "fleetnumber": "", - "fuel": "", - "insuranceexpires": "", - "leaseenddate": "", - "make": "", - "mileage": "", - "model": "", - "nextservicedate": "", - "nextservicekm": "", - "notes": "", - "plate": "", - "purchasedate": "", - "readiness": "", - "registrationexpires": "", - "serviceenddate": "", - "servicestartdate": "", - "status": "", - "vin": "", - "year": "" - }, - "labels": { - "courtesycar": "", - "fuel": { - "12": "", - "14": "", - "18": "", - "34": "", - "38": "", - "58": "", - "78": "", - "empty": "", - "full": "" - }, - "outwith": "", - "return": "", - "status": "", - "uniquefleet": "", - "usage": "", - "vehicle": "" - }, - "readiness": { - "notready": "", - "ready": "" - }, - "status": { - "in": "", - "inservice": "", - "leasereturn": "", - "out": "", - "sold": "", - "unavailable": "" - }, - "successes": { - "saved": "" - } - }, - "csi": { - "actions": { - "activate": "" - }, - "errors": { - "creating": "", - "notconfigured": "", - "notfoundsubtitle": "", - "notfoundtitle": "", - "surveycompletesubtitle": "", - "surveycompletetitle": "" - }, - "fields": { - "completedon": "", - "created_at": "", - "surveyid": "", - "validuntil": "" - }, - "labels": { - "copyright": "", - "greeting": "", - "intro": "", - "nologgedinuser": "", - "nologgedinuser_sub": "", - "noneselected": "", - "title": "" - }, - "successes": { - "created": "", - "submitted": "", - "submittedsub": "" - } - }, - "dashboard": { - "actions": { - "addcomponent": "" - }, - "errors": { - "refreshrequired": "", - "updatinglayout": "" - }, - "labels": { - "bodyhrs": "", - "dollarsinproduction": "", - "phone": "", - "prodhrs": "", - "refhrs": "" - }, - "titles": { - "joblifecycle": "", - "labhours": "", - "larhours": "", - "monthlyemployeeefficiency": "", - "monthlyjobcosting": "", - "monthlylaborsales": "", - "monthlypartssales": "", - "monthlyrevenuegraph": "", - "prodhrssummary": "", - "productiondollars": "", - "productionhours": "", - "projectedmonthlysales": "", - "scheduledindate": "", - "scheduledintoday": "", - "scheduledoutdate": "", - "scheduledouttoday": "", - "tasks": "" - } - }, - "dms": { - "errors": { - "alreadyexported": "" - }, - "labels": { - "refreshallocations": "" - } - }, - "documents": { - "actions": { - "delete": "", - "download": "", - "reassign": "", - "selectallimages": "", - "selectallotherdocuments": "" - }, - "errors": { - "deletes3": "Erreur lors de la suppression du document du stockage.", - "deleting": "", - "deleting_cloudinary": "", - "getpresignurl": "Erreur lors de l'obtention de l'URL présignée pour le document. {{message}}", - "insert": "Incapable de télécharger le fichier. {{message}}", - "nodocuments": "Il n'y a pas de documents.", - "updating": "" - }, - "labels": { - "confirmdelete": "", - "doctype": "", - "newjobid": "", - "openinexplorer": "", - "optimizedimage": "", - "reassign_limitexceeded": "", - "reassign_limitexceeded_title": "", - "storageexceeded": "", - "storageexceeded_title": "", - "upload": "Télécharger", - "upload_limitexceeded": "", - "upload_limitexceeded_title": "", - "uploading": "", - "usage": "" - }, - "successes": { - "delete": "Le document a bien été supprimé.", - "edituploaded": "", - "insert": "Document téléchargé avec succès.", - "updated": "" - } - }, - "emails": { - "errors": { - "notsent": "Courriel non envoyé. Erreur rencontrée lors de l'envoi de {{message}}" - }, - "fields": { - "cc": "", - "from": "", - "subject": "", - "to": "" - }, - "labels": { - "attachments": "", - "documents": "", - "emailpreview": "", - "generatingemail": "", - "pdfcopywillbeattached": "", - "preview": "" - }, - "successes": { - "sent": "E-mail envoyé avec succès." - } - }, - "employee_teams": { - "actions": { - "new": "", - "newmember": "" - }, - "fields": { - "active": "", - "employeeid": "", - "max_load": "", - "name": "", - "percentage": "" - } - }, - "employees": { - "actions": { - "addvacation": "", - "new": "Nouvel employé", - "newrate": "" - }, - "errors": { - "delete": "Erreur rencontrée lors de la suppression de l'employé. {{message}}", - "save": "Une erreur s'est produite lors de l'enregistrement de l'employé. {{message}}", - "validation": "Veuillez cocher tous les champs.", - "validationtitle": "Impossible d'enregistrer l'employé." - }, - "fields": { - "active": "Actif?", - "base_rate": "Taux de base", - "cost_center": "Centre de coûts", - "employee_number": "Numéro d'employé", - "external_id": "", - "first_name": "Prénom", - "flat_rate": "Taux fixe (désactivé est le temps normal)", - "hire_date": "Date d'embauche", - "last_name": "Nom de famille", - "pin": "", - "rate": "", - "termination_date": "Date de résiliation", - "user_email": "", - "vacation": { - "end": "", - "length": "", - "start": "" - } - }, - "labels": { - "actions": "", - "active": "", - "endmustbeafterstart": "", - "flat_rate": "", - "inactive": "", - "name": "", - "rate_type": "", - "status": "", - "straight_time": "" - }, - "successes": { - "delete": "L'employé a bien été supprimé.", - "save": "L'employé a enregistré avec succès.", - "vacationadded": "" - }, - "validation": { - "unique_employee_number": "" - } - }, - "eula": { - "buttons": { - "accept": "Accept EULA" - }, - "content": { - "never_scrolled": "You must scroll to the bottom of the Terms and Conditions before accepting." - }, - "errors": { - "acceptance": { - "description": "Something went wrong while accepting the EULA. Please try again.", - "message": "Eula Acceptance Error" - } - }, - "labels": { - "accepted_terms": "I accept the terms and conditions of this agreement.", - "address": "Address", - "business_name": "Legal Business Name", - "date_accepted": "Date Accepted", - "first_name": "First Name", - "last_name": "Last Name", - "phone_number": "Phone Number" - }, - "messages": { - "accepted_terms": "Please accept the terms and conditions of this agreement.", - "business_name": "Please enter your legal business name.", - "date_accepted": "Please enter Today's Date.", - "first_name": "Please enter your first name.", - "last_name": "Please enter your last name.", - "phone_number": "Please enter your phone number." - }, - "titles": { - "modal": "Terms and Conditions", - "upper_card": "Acknowledgement" - } - }, - "exportlogs": { - "fields": { - "createdat": "" - }, - "labels": { - "attempts": "", - "priorsuccesfulexport": "" - } - }, - "general": { - "actions": { - "add": "", - "autoupdate": "", - "calculate": "", - "cancel": "", - "clear": "", - "close": "", - "copied": "", - "copylink": "", - "create": "", - "defaults": "", - "delay": "", - "delete": "Effacer", - "deleteall": "", - "deselectall": "", - "download": "", - "edit": "modifier", - "login": "", - "next": "", - "previous": "", - "print": "", - "refresh": "", - "remove": "", - "remove_alert": "", - "reset": " Rétablir l'original.", - "resetpassword": "", - "save": "sauvegarder", - "saveandnew": "", - "saveas": "", - "selectall": "", - "send": "", - "sendbysms": "", - "senderrortosupport": "", - "submit": "", - "tryagain": "", - "view": "", - "viewreleasenotes": "" - }, - "errors": { - "fcm": "", - "notfound": "", - "sizelimit": "" - }, - "itemtypes": { - "contract": "", - "courtesycar": "", - "job": "", - "owner": "", - "vehicle": "" - }, - "labels": { - "actions": "actes", - "areyousure": "", - "barcode": "code à barre", - "cancel": "", - "clear": "", - "confirmpassword": "", - "created_at": "", - "date": "", - "datetime": "", - "email": "", - "errors": "", - "excel": "", - "exceptiontitle": "", - "friday": "", - "globalsearch": "", - "help": "", - "hours": "", - "in": "dans", - "instanceconflictext": "", - "instanceconflictitle": "", - "item": "", - "label": "", - "loading": "Chargement...", - "loadingapp": "Chargement de {{app}}", - "loadingshop": "Chargement des données de la boutique ...", - "loggingin": "Vous connecter ...", - "markedexported": "", - "media": "", - "message": "", - "monday": "", - "na": "N / A", - "newpassword": "", - "no": "", - "nointernet": "", - "nointernet_sub": "", - "none": "", - "out": "En dehors", - "password": "", - "passwordresetsuccess": "", - "passwordresetsuccess_sub": "", - "passwordresetvalidatesuccess": "", - "passwordresetvalidatesuccess_sub": "", - "passwordsdonotmatch": "", - "print": "", - "refresh": "", - "reports": "", - "required": "", - "saturday": "", - "search": "Chercher...", - "searchresults": "", - "selectdate": "", - "sendagain": "", - "sendby": "", - "signin": "", - "sms": "", - "status": "", - "sub_status": { - "expired": "" - }, - "successful": "", - "sunday": "", - "text": "", - "thursday": "", - "total": "", - "totals": "", - "tuesday": "", - "tvmode": "", - "unknown": "Inconnu", - "unsavedchanges": "", - "username": "", - "view": "", - "wednesday": "", - "yes": "" - }, - "languages": { - "english": "Anglais", - "french": "Francais", - "spanish": "Espanol" - }, - "messages": { - "exception": "", - "newversionmessage": "", - "newversiontitle": "", - "noacctfilepath": "", - "nofeatureaccess": "", - "noshop": "", - "notfoundsub": "", - "notfoundtitle": "", - "partnernotrunning": "", - "rbacunauth": "", - "unsavedchanges": "Vous avez des changements non enregistrés.", - "unsavedchangespopup": "" - }, - "validation": { - "invalidemail": "S'il vous plaît entrer un email valide.", - "invalidphone": "", - "required": "Ce champ est requis." - } - }, - "help": { - "actions": { - "connect": "" - }, - "labels": { - "codeplacholder": "", - "rescuedesc": "", - "rescuetitle": "" - } - }, - "intake": { - "labels": { - "printpack": "" - } - }, - "inventory": { - "actions": { - "addtoinventory": "", - "addtoro": "", - "consumefrominventory": "", - "edit": "", - "new": "" - }, - "errors": { - "inserting": "" - }, - "fields": { - "comment": "", - "manualinvoicenumber": "", - "manualvendor": "" - }, - "labels": { - "consumedbyjob": "", - "deleteconfirm": "", - "frombillinvoicenumber": "", - "fromvendor": "", - "inventory": "", - "showall": "", - "showavailable": "" - }, - "successes": { - "deleted": "", - "inserted": "", - "updated": "" - } - }, - "job_lifecycle": { - "columns": { - "duration": "", - "end": "", - "human_readable": "", - "percentage": "", - "relative_end": "", - "relative_start": "", - "start": "", - "status": "", - "status_count": "", - "value": "" - }, - "content": { - "calculated_based_on": "", - "current_status_accumulated_time": "", - "data_unavailable": "", - "jobs_in_since": "", - "legend_title": "", - "loading": "", - "not_available": "", - "previous_status_accumulated_time": "", - "title": "", - "title_durations": "", - "title_loading": "", - "title_transitions": "" - }, - "errors": { - "fetch": "Erreur lors de l'obtention des données du cycle de vie des tâches" - }, - "titles": { - "dashboard": "", - "top_durations": "" - } - }, - "job_payments": { - "buttons": { - "create_short_link": "", - "goback": "", - "proceedtopayment": "", - "refundpayment": "" - }, - "notifications": { - "error": { - "description": "", - "openingip": "", - "title": "" - } - }, - "titles": { - "amount": "", - "dateOfPayment": "", - "descriptions": "", - "hint": "", - "payer": "", - "payername": "", - "paymentid": "", - "paymentnum": "", - "paymenttype": "", - "refundamount": "", - "transactionid": "" - } - }, - "joblines": { - "actions": { - "assign_team": "", - "converttolabor": "", - "dispatchparts": "", - "new": "" - }, - "errors": { - "creating": "", - "updating": "" - }, - "fields": { - "act_price": "Prix actuel", - "act_price_before_ppc": "", - "adjustment": "", - "ah_detail_line": "", - "amount": "", - "assigned_team": "", - "assigned_team_name": "", - "create_ppc": "", - "db_price": "Prix de la base de données", - "lbr_types": { - "LA1": "", - "LA2": "", - "LA3": "", - "LA4": "", - "LAA": "", - "LAB": "", - "LAD": "", - "LAE": "", - "LAF": "", - "LAG": "", - "LAM": "", - "LAR": "", - "LAS": "", - "LAU": "" - }, - "line_desc": "Description de la ligne", - "line_ind": "S#", - "line_no": "", - "location": "", - "mod_lb_hrs": "Heures de travail", - "mod_lbr_ty": "Type de travail", - "notes": "", - "oem_partno": "Pièce OEM #", - "op_code_desc": "", - "part_qty": "", - "part_type": "Type de pièce", - "part_types": { - "CCC": "", - "CCD": "", - "CCDR": "", - "CCF": "", - "CCM": "", - "PAA": "", - "PAC": "", - "PAE": "", - "PAG": "", - "PAL": "", - "PAM": "", - "PAN": "", - "PAO": "", - "PAP": "", - "PAR": "", - "PAS": "", - "PASL": "" - }, - "profitcenter_labor": "", - "profitcenter_part": "", - "prt_dsmk_m": "", - "prt_dsmk_p": "", - "status": "Statut", - "tax_part": "", - "total": "", - "unq_seq": "Seq #" - }, - "labels": { - "adjustmenttobeadded": "", - "billref": "", - "convertedtolabor": "", - "edit": "Ligne d'édition", - "ioucreated": "", - "new": "Nouvelle ligne", - "nostatus": "", - "presets": "" - }, - "successes": { - "created": "", - "saved": "", - "updated": "" - }, - "validations": { - "ahdetailonlyonuserdefinedtypes": "", - "hrsrequirediflbrtyp": "", - "requiredifparttype": "", - "zeropriceexistingpart": "" - } - }, - "jobs": { - "actions": { - "addDocuments": "Ajouter des documents de travail", - "addNote": "Ajouter une note", - "addtopartsqueue": "", - "addtoproduction": "", - "addtoscoreboard": "", - "allocate": "", - "autoallocate": "", - "changefilehandler": "", - "changelaborrate": "", - "changestatus": "Changer le statut", - "changestimator": "", - "convert": "Convertir", - "createiou": "", - "deliver": "", - "dms": { - "addpayer": "", - "createnewcustomer": "", - "findmakemodelcode": "", - "getmakes": "", - "labels": { - "refreshallocations": "" - }, - "post": "", - "refetchmakesmodels": "", - "usegeneric": "", - "useselected": "" - }, - "dmsautoallocate": "", - "export": "", - "exportcustdata": "", - "exportselected": "", - "filterpartsonly": "", - "generatecsi": "", - "gotojob": "", - "intake": "", - "manualnew": "", - "mark": "", - "markasexported": "", - "markpstexempt": "", - "markpstexemptconfirm": "", - "postbills": "Poster des factures", - "printCenter": "Centre d'impression", - "recalculate": "", - "reconcile": "", - "removefromproduction": "", - "schedule": "Programme", - "sendcsi": "", - "sendpartspricechange": "", - "sendtodms": "", - "sync": "", - "taxprofileoverride": "", - "taxprofileoverride_confirm": "", - "uninvoice": "", - "unvoid": "", - "viewchecklist": "", - "viewdetail": "" - }, - "errors": { - "addingtoproduction": "", - "cannotintake": "", - "closing": "", - "creating": "", - "deleted": "Erreur lors de la suppression du travail.", - "exporting": "", - "exporting-partner": "", - "invoicing": "", - "noaccess": "Ce travail n'existe pas ou vous n'y avez pas accès.", - "nodamage": "", - "nodates": "Aucune date spécifiée pour ce travail.", - "nofinancial": "", - "nojobselected": "Aucun travail n'est sélectionné.", - "noowner": "Aucun propriétaire associé.", - "novehicle": "Aucun véhicule associé.", - "partspricechange": "", - "saving": "Erreur rencontrée lors de la sauvegarde de l'enregistrement.", - "scanimport": "", - "totalscalc": "", - "updating": "", - "validation": "Veuillez vous assurer que tous les champs sont correctement entrés.", - "validationtitle": "Erreur de validation", - "voiding": "" - }, - "fields": { - "active_tasks": "", - "actual_completion": "Achèvement réel", - "actual_delivery": "Livraison réelle", - "actual_in": "En réel", - "adjustment_bottom_line": "Ajustements", - "adjustmenthours": "", - "alt_transport": "", - "area_of_damage_impact": { - "10": "", - "11": "", - "12": "", - "13": "", - "14": "", - "15": "", - "16": "", - "25": "", - "26": "", - "27": "", - "28": "", - "34": "", - "01": "", - "02": "", - "03": "", - "04": "", - "05": "", - "06": "", - "07": "", - "08": "", - "09": "" - }, - "auto_add_ats": "", - "ca_bc_pvrt": "", - "ca_customer_gst": "", - "ca_gst_registrant": "", - "category": "", - "ccc": "", - "ccd": "", - "ccdr": "", - "ccf": "", - "ccm": "", - "cieca_id": "CIECA ID", - "cieca_pfl": { - "lbr_adjp": "", - "lbr_tax_in": "", - "lbr_taxp": "", - "lbr_tx_in1": "", - "lbr_tx_in2": "", - "lbr_tx_in3": "", - "lbr_tx_in4": "", - "lbr_tx_in5": "" - }, - "cieca_pfo": { - "stor_t_in1": "", - "stor_t_in2": "", - "stor_t_in3": "", - "stor_t_in4": "", - "stor_t_in5": "", - "tow_t_in1": "", - "tow_t_in2": "", - "tow_t_in3": "", - "tow_t_in4": "", - "tow_t_in5": "" - }, - "claim_total": "Total réclamation", - "class": "", - "clm_no": "Prétendre #", - "clm_total": "Total réclamation", - "comment": "", - "customerowing": "Client propriétaire", - "date_estimated": "Date estimée", - "date_exported": "Exportés", - "date_invoiced": "Facturé", - "date_last_contacted": "", - "date_lost_sale": "", - "date_next_contact": "", - "date_open": "Ouvrir", - "date_rentalresp": "", - "date_repairstarted": "", - "date_scheduled": "Prévu", - "date_towin": "", - "date_void": "", - "ded_amt": "Déductible", - "ded_note": "", - "ded_status": "Statut de franchise", - "depreciation_taxes": "Amortissement / taxes", - "dms": { - "address": "", - "amount": "", - "center": "", - "control_type": { - "account_number": "" - }, - "cost": "", - "cost_dms_acctnumber": "", - "dms_make": "", - "dms_model": "", - "dms_model_override": "", - "dms_unsold": "", - "dms_wip_acctnumber": "", - "id": "", - "inservicedate": "", - "journal": "", - "lines": "", - "name1": "", - "payer": { - "amount": "", - "control_type": "", - "controlnumber": "", - "dms_acctnumber": "", - "name": "" - }, - "sale": "", - "sale_dms_acctnumber": "", - "story": "", - "vinowner": "" - }, - "dms_allocation": "", - "driveable": "", - "employee_body": "", - "employee_csr": "représentant du service à la clientèle", - "employee_csr_writer": "", - "employee_prep": "", - "employee_refinish": "", - "est_addr1": "Adresse de l'évaluateur", - "est_co_nm": "Expert", - "est_ct_fn": "Prénom de l'évaluateur", - "est_ct_ln": "Nom de l'évaluateur", - "est_ea": "Courriel de l'évaluateur", - "est_ph1": "Numéro de téléphone de l'évaluateur", - "federal_tax_payable": "Impôt fédéral à payer", - "federal_tax_rate": "", - "ins_addr1": "Adresse Insurance Co.", - "ins_city": "Insurance City", - "ins_co_id": "ID de la compagnie d'assurance", - "ins_co_nm": "Nom de la compagnie d'assurance", - "ins_co_nm_short": "", - "ins_ct_fn": "Prénom du gestionnaire de fichiers", - "ins_ct_ln": "Nom du gestionnaire de fichiers", - "ins_ea": "Courriel du gestionnaire de fichiers", - "ins_ph1": "Numéro de téléphone du gestionnaire de fichiers", - "intake": { - "label": "", - "max": "", - "min": "", - "name": "", - "required": "", - "type": "" - }, - "invoice_final_note": "", - "kmin": "Kilométrage en", - "kmout": "Kilométrage hors", - "la1": "", - "la2": "", - "la3": "", - "la4": "", - "laa": "", - "lab": "", - "labor_rate_desc": "Nom du taux de main-d'œuvre", - "lad": "", - "lae": "", - "laf": "", - "lag": "", - "lam": "", - "lar": "", - "las": "", - "lau": "", - "local_tax_rate": "", - "loss_date": "Date de perte", - "loss_desc": "", - "loss_of_use": "", - "lost_sale_reason": "", - "ma2s": "", - "ma3s": "", - "mabl": "", - "macs": "", - "mahw": "", - "mapa": "", - "mash": "", - "matd": "", - "materials": { - "MAPA": "", - "MASH": "", - "cal_maxdlr": "", - "cal_opcode": "", - "mat_adjp": "", - "mat_taxp": "", - "mat_tx_in1": "", - "mat_tx_in2": "", - "mat_tx_in3": "", - "mat_tx_in4": "", - "mat_tx_in5": "", - "materials": "", - "tax_ind": "" - }, - "other_amount_payable": "Autre montant à payer", - "owner": "Propriétaire", - "owner_owing": "Cust. Owes", - "ownr_ea": "Email", - "ownr_ph1": "Téléphone 1", - "ownr_ph2": "", - "paa": "", - "pac": "", - "pae": "", - "pag": "", - "pal": "", - "pam": "", - "pan": "", - "pao": "", - "pap": "", - "par": "", - "parts_tax_rates": { - "prt_discp": "", - "prt_mktyp": "", - "prt_mkupp": "", - "prt_tax_in": "", - "prt_tax_rt": "", - "prt_tx_in1": "", - "prt_tx_in2": "", - "prt_tx_in3": "", - "prt_tx_in4": "", - "prt_tx_in5": "", - "prt_tx_ty1": "", - "prt_type": "" - }, - "partsstatus": "", - "pas": "", - "pay_date": "Date d'Pay", - "phoneshort": "PH", - "po_number": "", - "policy_no": "Politique #", - "ponumber": "Numéro de bon de commande", - "production_vars": { - "note": "" - }, - "qb_multiple_payers": { - "amount": "", - "name": "" - }, - "queued_for_parts": "", - "rate_ats": "", - "rate_la1": "Taux LA1", - "rate_la2": "Taux LA2", - "rate_la3": "Taux LA3", - "rate_la4": "Taux LA4", - "rate_laa": "Taux d'aluminium", - "rate_lab": "Taux de la main-d'œuvre", - "rate_lad": "Taux de diagnostic", - "rate_lae": "Tarif électrique", - "rate_laf": "Taux de trame", - "rate_lag": "Taux de verre", - "rate_lam": "Taux mécanique", - "rate_lar": "Taux de finition", - "rate_las": "", - "rate_lau": "Taux d'aluminium", - "rate_ma2s": "Taux de peinture en 2 étapes", - "rate_ma3s": "Taux de peinture en 3 étapes", - "rate_mabl": "MABL ??", - "rate_macs": "MACS ??", - "rate_mahw": "Taux de déchets dangereux", - "rate_mapa": "Taux de matériaux de peinture", - "rate_mash": "Tarif du matériel de la boutique", - "rate_matd": "Taux d'élimination des pneus", - "referral_source_extra": "", - "referral_source_other": "", - "referralsource": "Source de référence", - "regie_number": "Enregistrement #", - "repairtotal": "Réparation totale", - "ro_number": "RO #", - "scheduled_completion": "Achèvement planifié", - "scheduled_delivery": "Livraison programmée", - "scheduled_in": "Planifié dans", - "selling_dealer": "Revendeur vendeur", - "selling_dealer_contact": "Contacter le revendeur", - "servicecar": "Voiture de service", - "servicing_dealer": "Concessionnaire", - "servicing_dealer_contact": "Contacter le concessionnaire", - "special_coverage_policy": "Politique de couverture spéciale", - "specialcoveragepolicy": "Politique de couverture spéciale", - "state_tax_rate": "", - "status": "Statut de l'emploi", - "storage_payable": "Stockage", - "tax_lbr_rt": "", - "tax_levies_rt": "", - "tax_paint_mat_rt": "", - "tax_registration_number": "", - "tax_shop_mat_rt": "", - "tax_str_rt": "", - "tax_sub_rt": "", - "tax_tow_rt": "", - "towin": "", - "towing_payable": "Remorquage à payer", - "unitnumber": "Unité #", - "updated_at": "Mis à jour à", - "uploaded_by": "Telechargé par", - "vehicle": "Véhicule" - }, - "forms": { - "admindates": "", - "appraiserinfo": "", - "claiminfo": "", - "estdates": "", - "laborrates": "", - "lossinfo": "", - "other": "", - "repairdates": "", - "scheddates": "" - }, - "labels": { - "accountsreceivable": "", - "act_price_ppc": "", - "actual_completion_inferred": "", - "actual_delivery_inferred": "", - "actual_in_inferred": "", - "additionalpayeroverallocation": "", - "additionaltotal": "", - "adjustmentrate": "", - "adjustments": "", - "adminwarning": "", - "allocations": "", - "alreadyaddedtoscoreboard": "", - "alreadyclosed": "", - "appointmentconfirmation": "Envoyer une confirmation au client?", - "associationwarning": "", - "audit": "", - "available": "", - "availablejobs": "", - "ca_bc_pvrt": { - "days": "", - "rate": "" - }, - "ca_gst_all_if_null": "", - "calc_repair_days": "", - "calc_repair_days_tt": "", - "calc_scheuled_completion": "", - "cards": { - "customer": "Informations client", - "damage": "Zone de dommages", - "dates": "Rendez-vous", - "documents": "Documents récents", - "estimator": "Estimateur", - "filehandler": "Gestionnaire de fichiers", - "insurance": "Détails de l'assurance", - "more": "Plus", - "notes": "Remarques", - "parts": "les pièces", - "totals": "Totaux", - "vehicle": "Véhicule" - }, - "changeclass": "", - "checklistcompletedby": "", - "checklistdocuments": "", - "checklists": "", - "cieca_pfl": "", - "cieca_pfo": "", - "cieca_pft": "", - "closeconfirm": "", - "closejob": "", - "closingperiod": "", - "contracts": "", - "convertedtolabor": "", - "cost": "", - "cost_Additional": "", - "cost_labor": "", - "cost_parts": "", - "cost_sublet": "", - "costs": "", - "create": { - "jobinfo": "", - "newowner": "", - "newvehicle": "", - "novehicle": "", - "ownerinfo": "", - "vehicleinfo": "" - }, - "createiouwarning": "", - "creating_new_job": "Création d'un nouvel emploi ...", - "deductible": { - "stands": "", - "waived": "" - }, - "deleteconfirm": "", - "deletedelivery": "", - "deleteintake": "", - "deliverchecklist": "", - "difference": "", - "diskscan": "", - "dms": { - "apexported": "", - "damageto": "", - "defaultstory": "", - "disablebillwip": "", - "invoicedatefuture": "", - "kmoutnotgreaterthankmin": "", - "logs": "", - "notallocated": "", - "postingform": "", - "totalallocated": "" - }, - "documents": "Les documents", - "documents-images": "", - "documents-other": "", - "duplicateconfirm": "", - "emailaudit": "", - "employeeassignments": "", - "estimatelines": "", - "estimator": "", - "existing_jobs": "Emplois existants", - "federal_tax_amt": "", - "gpdollars": "", - "gppercent": "", - "hrs_claimed": "", - "hrs_total": "", - "importnote": "", - "inproduction": "", - "intakechecklist": "", - "iou": "", - "job": "", - "jobcosting": "", - "jobtotals": "", - "labor_hrs": "", - "labor_rates_subtotal": "", - "laborallocations": "", - "labortotals": "", - "lines": "Estimer les lignes", - "local_tax_amt": "", - "mapa": "", - "markforreexport": "", - "mash": "", - "masterbypass": "", - "materials": { - "mapa": "" - }, - "missingprofileinfo": "", - "multipayers": "", - "net_repairs": "", - "notes": "Remarques", - "othertotal": "", - "outstanding_ar": "", - "outstanding_credit_memos": "", - "outstanding_ppd": "", - "outstanding_reconciliation_discrep": "", - "outstanding_sublets": "", - "outstandinghours": "", - "override_header": "Remplacer l'en-tête d'estimation à l'importation?", - "ownerassociation": "", - "parts": "les pièces", - "parts_lines": "", - "parts_received": "", - "parts_tax_rates": "", - "partsfilter": "", - "partssubletstotal": "", - "partstotal": "", - "performance": "", - "pimraryamountpayable": "", - "plitooltips": { - "billtotal": "", - "calculatedcreditsnotreceived": "", - "creditmemos": "", - "creditsnotreceived": "", - "discrep1": "", - "discrep2": "", - "discrep3": "", - "laboradj": "", - "partstotal": "", - "totalreturns": "" - }, - "ppc": "", - "ppdnotexported": "", - "profileadjustments": "", - "profitbypassrequired": "", - "profits": "", - "prt_dsmk_total": "", - "rates": "Les taux", - "rates_subtotal": "", - "reconciliation": { - "billlinestotal": "", - "byassoc": "", - "byprice": "", - "clear": "", - "discrepancy": "", - "joblinestotal": "", - "multipleactprices": "", - "multiplebilllines": "", - "multiplebillsforactprice": "", - "removedpartsstrikethrough": "" - }, - "reconciliationheader": "", - "relatedros": "", - "remove_from_ar": "", - "returntotals": "", - "ro_guard": { - "enforce_ar": "", - "enforce_bills": "", - "enforce_cm": "", - "enforce_labor": "", - "enforce_ppd": "", - "enforce_profit": "", - "enforce_sublet": "", - "enforce_validation": "", - "enforced": "" - }, - "roguard": "", - "roguardwarnings": "", - "rosaletotal": "", - "sale_additional": "", - "sale_labor": "", - "sale_parts": "", - "sale_sublet": "", - "sales": "", - "savebeforeconversion": "", - "scheduledinchange": "", - "specialcoveragepolicy": "", - "state_tax_amt": "", - "subletsnotcompleted": "", - "subletstotal": "", - "subtotal": "", - "supplementnote": "", - "suspended": "", - "suspense": "", - "tasks": "", - "threshhold": "", - "total_cost": "", - "total_cust_payable": "", - "total_repairs": "", - "total_sales": "", - "total_sales_tax": "", - "totals": "", - "unvoidnote": "", - "update_scheduled_completion": "", - "vehicle_info": "Véhicule", - "vehicleassociation": "", - "viewallocations": "", - "voidjob": "", - "voidnote": "" - }, - "successes": { - "addedtoproduction": "", - "all_deleted": "{{count}} travaux supprimés avec succès.", - "closed": "", - "converted": "Travail converti avec succès.", - "created": "Le travail a été créé avec succès. Clique pour voir.", - "creatednoclick": "", - "delete": "", - "deleted": "Le travail a bien été supprimé.", - "duplicated": "", - "exported": "", - "invoiced": "", - "ioucreated": "", - "partsqueue": "", - "save": "Le travail a été enregistré avec succès.", - "savetitle": "Enregistrement enregistré avec succès.", - "supplemented": "Travail complété avec succès.", - "updated": "", - "voided": "" - } - }, - "landing": { - "bigfeature": { - "subtitle": "", - "title": "" - }, - "footer": { - "company": { - "about": "", - "contact": "", - "disclaimers": "", - "name": "", - "privacypolicy": "" - }, - "io": { - "help": "", - "name": "", - "status": "" - }, - "slogan": "" - }, - "hero": { - "button": "", - "title": "" - }, - "labels": { - "features": "", - "managemyshop": "", - "pricing": "" - }, - "pricing": { - "basic": { - "name": "", - "sub": "" - }, - "essentials": { - "name": "", - "sub": "" - }, - "pricingtitle": "", - "pro": { - "name": "", - "sub": "" - }, - "title": "", - "unlimited": { - "name": "", - "sub": "" - } - } - }, - "menus": { - "currentuser": { - "languageselector": "La langue", - "profile": "Profil" - }, - "header": { - "accounting": "", - "accounting-payables": "", - "accounting-payments": "", - "accounting-receivables": "", - "activejobs": "Emplois actifs", - "all_tasks": "", - "alljobs": "", - "allpayments": "", - "availablejobs": "Emplois disponibles", - "bills": "", - "courtesycars": "", - "courtesycars-all": "", - "courtesycars-contracts": "", - "courtesycars-newcontract": "", - "create_task": "", - "customers": "Les clients", - "dashboard": "", - "enterbills": "", - "entercardpayment": "", - "enterpayment": "", - "entertimeticket": "", - "export": "", - "export-logs": "", - "help": "", - "home": "Accueil", - "inventory": "", - "jobs": "Emplois", - "my_tasks": "", - "newjob": "", - "owners": "Propriétaires", - "parts-queue": "", - "phonebook": "", - "productionboard": "", - "productionlist": "", - "readyjobs": "", - "recent": "", - "reportcenter": "", - "rescueme": "", - "schedule": "Programme", - "scoreboard": "", - "search": { - "bills": "", - "jobs": "", - "owners": "", - "payments": "", - "phonebook": "", - "vehicles": "" - }, - "shiftclock": "", - "shop": "Mon magasin", - "shop_config": "Configuration", - "shop_csi": "", - "shop_templates": "", - "shop_vendors": "Vendeurs", - "tasks": "", - "temporarydocs": "", - "timetickets": "", - "ttapprovals": "", - "vehicles": "Véhicules" - }, - "jobsactions": { - "admin": "", - "cancelallappointments": "", - "closejob": "", - "deletejob": "", - "duplicate": "", - "duplicatenolines": "", - "newcccontract": "", - "void": "" - }, - "jobsdetail": { - "claimdetail": "Détails de la réclamation", - "dates": "Rendez-vous", - "financials": "", - "general": "", - "insurance": "", - "labor": "La main d'oeuvre", - "lifecycle": "", - "parts": "", - "partssublet": "Pièces / Sous-location", - "rates": "", - "repairdata": "Données de réparation", - "totals": "" - }, - "profilesidebar": { - "profile": "Mon profil", - "shops": "Mes boutiques" - }, - "tech": { - "assignedjobs": "", - "claimtask": "", - "dispatchedparts": "", - "home": "", - "jobclockin": "", - "jobclockout": "", - "joblookup": "", - "login": "", - "logout": "", - "productionboard": "", - "productionlist": "", - "shiftclockin": "" - } - }, - "messaging": { - "actions": { - "link": "", - "new": "" - }, - "errors": { - "invalidphone": "", - "noattachedjobs": "", - "updatinglabel": "" - }, - "labels": { - "addlabel": "", - "archive": "", - "maxtenimages": "", - "messaging": "Messagerie", - "noallowtxt": "", - "nojobs": "", - "nopush": "", - "phonenumber": "", - "presets": "", - "recentonly": "", - "selectmedia": "", - "sentby": "", - "typeamessage": "Envoyer un message...", - "unarchive": "" - }, - "render": { - "conversation_list": "" - } - }, - "notes": { - "actions": { - "actions": "actes", - "deletenote": "Supprimer la note", - "edit": "Note éditée", - "new": "Nouvelle note", - "savetojobnotes": "" - }, - "errors": { - "inserting": "" - }, - "fields": { - "createdby": "Créé par", - "critical": "Critique", - "private": "privé", - "text": "Contenu", - "type": "", - "types": { - "customer": "", - "general": "", - "office": "", - "paint": "", - "parts": "", - "shop": "", - "supplement": "" - }, - "updatedat": "Mis à jour à" - }, - "labels": { - "addtorelatedro": "", - "newnoteplaceholder": "Ajouter une note...", - "notetoadd": "", - "systemnotes": "", - "usernotes": "" - }, - "successes": { - "create": "Remarque créée avec succès.", - "deleted": "Remarque supprimée avec succès.", - "updated": "Remarque mise à jour avec succès." - } - }, - "owner": { - "labels": { - "noownerinfo": "" - } - }, - "owners": { - "actions": { - "update": "" - }, - "errors": { - "deleting": "", - "noaccess": "L'enregistrement n'existe pas ou vous n'y avez pas accès.", - "saving": "", - "selectexistingornew": "" - }, - "fields": { - "address": "Adresse", - "allow_text_message": "Autorisation de texte?", - "name": "Prénom", - "note": "", - "ownr_addr1": "Adresse", - "ownr_addr2": "Adresse 2 ", - "ownr_city": "Ville", - "ownr_co_nm": "", - "ownr_ctry": "Pays", - "ownr_ea": "Email", - "ownr_fn": "Prénom", - "ownr_ln": "Nom de famille", - "ownr_ph1": "Téléphone 1", - "ownr_ph2": "", - "ownr_st": "Etat / Province", - "ownr_title": "Titre", - "ownr_zip": "Zip / code postal", - "preferred_contact": "Méthode de contact préférée", - "tax_number": "" - }, - "forms": { - "address": "", - "contact": "", - "name": "" - }, - "labels": { - "create_new": "Créez un nouvel enregistrement de propriétaire.", - "deleteconfirm": "", - "existing_owners": "Propriétaires existants", - "fromclaim": "", - "fromowner": "", - "relatedjobs": "", - "updateowner": "" - }, - "successes": { - "delete": "", - "save": "Le propriétaire a bien enregistré." - } - }, - "parts": { - "actions": { - "order": "Commander des pièces", - "orderinhouse": "" - } - }, - "parts_dispatch": { - "actions": { - "accept": "" - }, - "errors": { - "accepting": "", - "creating": "" - }, - "fields": { - "number": "", - "percent_accepted": "" - }, - "labels": { - "notyetdispatched": "", - "parts_dispatch": "" - } - }, - "parts_dispatch_lines": { - "fields": { - "accepted_at": "" - } - }, - "parts_orders": { - "actions": { - "backordered": "", - "receive": "", - "receivebill": "" - }, - "errors": { - "associatedbills": "", - "backordering": "", - "creating": "Erreur rencontrée lors de la création de la commande de pièces.", - "oec": "", - "saving": "", - "updating": "" - }, - "fields": { - "act_price": "", - "backordered_eta": "", - "backordered_on": "", - "cm_received": "", - "comments": "", - "cost": "", - "db_price": "", - "deliver_by": "", - "job_line_id": "", - "line_desc": "", - "line_remarks": "", - "lineremarks": "Remarques sur la ligne", - "oem_partno": "", - "order_date": "", - "order_number": "", - "orderedby": "", - "part_type": "", - "quantity": "", - "return": "", - "status": "" - }, - "labels": { - "allpartsto": "", - "confirmdelete": "", - "custompercent": "", - "discount": "", - "email": "Envoyé par email", - "inthisorder": "Pièces dans cette commande", - "is_quote": "", - "mark_as_received": "", - "newpartsorder": "", - "notyetordered": "", - "oec": "", - "order_type": "", - "orderhistory": "Historique des commandes", - "parts_order": "", - "parts_orders": "", - "print": "Afficher le formulaire imprimé", - "receive": "", - "removefrompartsqueue": "", - "returnpartsorder": "", - "sublet_order": "" - }, - "successes": { - "created": "Commande de pièces créée avec succès.", - "line_updated": "", - "received": "", - "return_created": "" - } - }, - "payments": { - "actions": { - "generatepaymentlink": "" - }, - "errors": { - "exporting": "", - "exporting-partner": "", - "inserting": "" - }, - "fields": { - "amount": "", - "created_at": "", - "date": "", - "exportedat": "", - "memo": "", - "payer": "", - "paymentnum": "", - "stripeid": "", - "transactionid": "", - "type": "" - }, - "labels": { - "balance": "", - "ca_bc_etf_table": "", - "customer": "", - "edit": "", - "electronicpayment": "", - "external": "", - "findermodal": "", - "insurance": "", - "markexported": "", - "markforreexport": "", - "new": "", - "signup": "", - "smspaymentreminder": "", - "title": "", - "totalpayments": "" - }, - "successes": { - "exported": "", - "markexported": "", - "markreexported": "", - "payment": "", - "paymentupdate": "", - "stripe": "" - } - }, - "phonebook": { - "actions": { - "new": "" - }, - "errors": { - "adding": "", - "saving": "" - }, - "fields": { - "address1": "", - "address2": "", - "category": "", - "city": "", - "company": "", - "country": "", - "email": "", - "fax": "", - "firstname": "", - "lastname": "", - "phone1": "", - "phone2": "", - "state": "" - }, - "labels": { - "noneselected": "", - "onenamerequired": "", - "vendorcategory": "" - }, - "successes": { - "added": "", - "deleted": "", - "saved": "" - } - }, - "printcenter": { - "appointments": { - "appointment_confirmation": "" - }, - "bills": { - "inhouse_invoice": "" - }, - "courtesycarcontract": { - "courtesy_car_contract": "", - "courtesy_car_impound": "", - "courtesy_car_inventory": "", - "courtesy_car_terms": "" - }, - "errors": { - "nocontexttype": "" - }, - "jobs": { - "3rdpartyfields": { - "addr1": "", - "addr2": "", - "addr3": "", - "attn": "", - "city": "", - "custgst": "", - "ded_amt": "", - "depreciation": "", - "other": "", - "ponumber": "", - "refnumber": "", - "sendtype": "", - "state": "", - "zip": "" - }, - "3rdpartypayer": "", - "ab_proof_of_loss": "", - "appointment_confirmation": "", - "appointment_reminder": "", - "casl_authorization": "", - "committed_timetickets_ro": "", - "coversheet_landscape": "", - "coversheet_portrait": "", - "csi_invitation": "", - "csi_invitation_action": "", - "diagnostic_authorization": "", - "dms_posting_sheet": "", - "envelope_return_address": "", - "estimate": "", - "estimate_detail": "", - "estimate_followup": "", - "express_repair_checklist": "", - "filing_coversheet_landscape": "", - "filing_coversheet_portrait": "", - "final_invoice": "", - "fippa_authorization": "", - "folder_label_multiple": "", - "glass_express_checklist": "", - "guarantee": "", - "individual_job_note": "", - "invoice_customer_payable": "", - "invoice_total_payable": "", - "iou_form": "", - "job_costing_ro": "", - "job_lifecycle_ro": "", - "job_notes": "", - "job_tasks": "", - "key_tag": "", - "labels": { - "count": "", - "labels": "", - "position": "" - }, - "lag_time_ro": "", - "mechanical_authorization": "", - "mpi_animal_checklist": "", - "mpi_eglass_auth": "", - "mpi_final_acct_sheet": "", - "mpi_final_repair_acct_sheet": "", - "paint_grid": "", - "parts_dispatch": "", - "parts_invoice_label_single": "", - "parts_label_multiple": "", - "parts_label_single": "", - "parts_list": "", - "parts_order": "", - "parts_order_confirmation": "", - "parts_order_history": "", - "parts_return_slip": "", - "payment_receipt": "", - "payment_request": "", - "payments_by_job": "", - "purchases_by_ro_detail": "", - "purchases_by_ro_summary": "", - "qc_sheet": "", - "rental_reservation": "", - "ro_totals": "", - "ro_with_description": "", - "sgi_certificate_of_repairs": "", - "sgi_windshield_auth": "", - "stolen_recovery_checklist": "", - "sublet_order": "", - "supplement_request": "", - "thank_you_ro": "", - "thirdpartypayer": "", - "timetickets_ro": "", - "vehicle_check_in": "", - "vehicle_delivery_check": "", - "window_tag": "", - "window_tag_sublet": "", - "work_authorization": "", - "worksheet_by_line_number": "", - "worksheet_sorted_by_operation": "", - "worksheet_sorted_by_operation_no_hours": "", - "worksheet_sorted_by_operation_part_type": "", - "worksheet_sorted_by_operation_type": "", - "worksheet_sorted_by_team": "" - }, - "labels": { - "groups": { - "authorization": "", - "financial": "", - "post": "", - "pre": "", - "ro": "", - "worksheet": "" - }, - "misc": "", - "repairorder": "", - "reportcentermodal": "", - "speedprint": "", - "title": "" - }, - "payments": { - "ca_bc_etf_table": "", - "exported_payroll": "" - }, - "special": { - "attendance_detail_csv": "" - }, - "subjects": { - "jobs": { - "individual_job_note": "", - "parts_dispatch": "", - "parts_order": "", - "parts_return_slip": "", - "sublet_order": "" - } - }, - "vendors": { - "purchases_by_vendor_detailed": "", - "purchases_by_vendor_summary": "" - } - }, - "production": { - "actions": { - "addcolumns": "", - "bodypriority-clear": "", - "bodypriority-set": "", - "detailpriority-clear": "", - "detailpriority-set": "", - "paintpriority-clear": "", - "paintpriority-set": "", - "remove": "", - "removecolumn": "", - "saveconfig": "", - "suspend": "", - "unsuspend": "" - }, - "constants": { - "main_profile": "" - }, - "errors": { - "boardupdate": "", - "name_exists": "", - "name_required": "", - "removing": "", - "settings": "" - }, - "labels": { - "actual_in": "", - "addnewprofile": "", - "alert": "", - "alertoff": "", - "alerton": "", - "alerts": "", - "ats": "", - "bodyhours": "", - "bodypriority": "", - "bodyshop": { - "labels": { - "qbo_departmentid": "", - "qbo_usa": "" - } - }, - "card_size": "", - "cardcolor": "", - "cardsettings": "", - "clm_no": "", - "comment": "", - "compact": "", - "detailpriority": "", - "employeeassignments": "", - "employeesearch": "", - "estimator": "", - "horizontal": "", - "ins_co_nm": "", - "jobdetail": "", - "kiosk_mode": "", - "laborhrs": "", - "legend": "", - "model_info": "", - "note": "", - "off": "", - "on": "", - "orientation": "", - "ownr_nm": "", - "paintpriority": "", - "partsstatus": "", - "production_note": "", - "refinishhours": "", - "scheduled_completion": "", - "selectview": "", - "stickyheader": "", - "sublets": "", - "subtotal": "", - "tall": "", - "tasks": "", - "totalhours": "", - "touchtime": "", - "vertical": "", - "viewname": "", - "wide": "" - }, - "options": { - "horizontal": "", - "large": "", - "medium": "", - "small": "", - "vertical": "" - }, - "settings": { - "board_settings": "", - "filters": { - "md_estimators": "", - "md_ins_cos": "" - }, - "filters_title": "", - "information": "", - "layout": "", + "translation": { + "allocations": { + "actions": { + "assign": "Attribuer" + }, + "errors": { + "deleting": "", + "saving": "", + "validation": "" + }, + "fields": { + "employee": "Alloué à" + }, + "successes": { + "deleted": "", + "save": "" + } + }, + "appointments": { + "actions": { + "block": "", + "calculate": "", + "cancel": "annuler", + "intake": "Admission", + "new": "Nouveau rendez-vous", + "preview": "", + "reschedule": "Replanifier", + "sendreminder": "", + "unblock": "", + "viewjob": "Voir le travail" + }, + "errors": { + "blocking": "", + "canceling": "Erreur lors de l'annulation du rendez-vous. {{message}}", + "saving": "Erreur lors de la planification du rendez-vous. {{message}}" + }, + "fields": { + "alt_transport": "", + "color": "", + "end": "", + "note": "", + "start": "", + "time": "", + "title": "Titre" + }, + "labels": { + "arrivedon": "Arrivé le:", + "arrivingjobs": "", + "blocked": "", + "cancelledappointment": "Rendez-vous annulé pour:", + "completingjobs": "", + "dataconsistency": "", + "expectedjobs": "", + "expectedprodhrs": "", + "history": "", + "inproduction": "", + "manualevent": "", + "noarrivingjobs": "", + "nocompletingjobs": "", + "nodateselected": "Aucune date n'a été sélectionnée.", + "priorappointments": "Rendez-vous précédents", + "reminder": "", + "scheduledfor": "Rendez-vous prévu pour:", + "severalerrorsfound": "", + "smartscheduling": "", + "smspaymentreminder": "", + "suggesteddates": "" + }, + "successes": { + "canceled": "Rendez-vous annulé avec succès.", + "created": "Rendez-vous planifié avec succès.", + "saved": "" + } + }, + "associations": { + "actions": { + "activate": "Activer" + }, + "fields": { + "active": "Actif?", + "shopname": "nom de la boutique" + }, + "labels": { + "actions": "actes" + } + }, + "audit": { + "fields": { + "cc": "", + "contents": "", + "created": "", + "operation": "", + "status": "", + "subject": "", + "to": "", + "useremail": "", + "values": "" + } + }, + "audit_trail": { + "messages": { + "admin_job_remove_from_ar": "", + "admin_jobmarkexported": "", + "admin_jobmarkforreexport": "", + "admin_jobuninvoice": "", + "admin_jobunvoid": "", + "alerttoggle": "", + "appointmentcancel": "", + "appointmentinsert": "", + "assignedlinehours": "", + "billdeleted": "", + "billposted": "", + "billupdated": "", + "failedpayment": "", + "jobassignmentchange": "", + "jobassignmentremoved": "", + "jobchecklist": "", + "jobclosedwithbypass": "", + "jobconverted": "", + "jobdelivery": "", + "jobexported": "", + "jobfieldchanged": "", + "jobimported": "", + "jobinproductionchange": "", + "jobintake": "", + "jobinvoiced": "", + "jobioucreated": "", + "jobmodifylbradj": "", + "jobnoteadded": "", + "jobnotedeleted": "", + "jobnoteupdated": "", + "jobspartsorder": "", + "jobspartsreturn": "", + "jobstatuschange": "", + "jobsupplement": "", + "jobsuspend": "", + "jobvoid": "", + "tasks_completed": "", + "tasks_created": "", + "tasks_deleted": "", + "tasks_uncompleted": "", + "tasks_undeleted": "", + "tasks_updated": "" + } + }, + "billlines": { + "actions": { + "newline": "" + }, + "fields": { + "actual_cost": "", + "actual_price": "", + "cost_center": "", + "federal_tax_applicable": "", + "jobline": "", + "line_desc": "", + "local_tax_applicable": "", + "location": "", + "quantity": "", + "state_tax_applicable": "" + }, + "labels": { + "deductedfromlbr": "", + "entered": "", + "from": "", + "mod_lbr_adjustment": "", + "other": "", + "reconciled": "", + "unreconciled": "" + }, + "validation": { + "atleastone": "" + } + }, + "bills": { + "actions": { + "deductallhours": "", + "edit": "", + "receive": "", + "return": "" + }, + "errors": { + "creating": "", + "deleting": "", + "existinginventoryline": "", + "exporting": "", + "exporting-partner": "", + "invalidro": "", + "invalidvendor": "", + "validation": "" + }, + "fields": { + "allpartslocation": "", + "date": "", + "exported": "", + "federal_tax_rate": "", + "invoice_number": "", + "is_credit_memo": "", + "is_credit_memo_short": "", + "local_tax_rate": "", + "ro_number": "", + "state_tax_rate": "", + "total": "", + "vendor": "", + "vendorname": "" + }, + "labels": { + "actions": "", + "bill_lines": "", + "bill_total": "", + "billcmtotal": "", + "bills": "", + "calculatedcreditsnotreceived": "", + "creditsnotreceived": "", + "creditsreceived": "", + "dedfromlbr": "", + "deleteconfirm": "", + "discrepancy": "", + "discrepwithcms": "", + "discrepwithlbradj": "", + "editadjwarning": "", + "entered_total": "", + "enteringcreditmemo": "", + "federal_tax": "", + "federal_tax_exempt": "", + "generatepartslabel": "", + "iouexists": "", + "local_tax": "", + "markexported": "", + "markforreexport": "", + "new": "", + "nobilllines": "", + "noneselected": "", + "onlycmforinvoiced": "", + "printlabels": "", + "retailtotal": "", + "returnfrombill": "", + "savewithdiscrepancy": "", + "state_tax": "", + "subtotal": "", + "totalreturns": "" + }, + "successes": { + "created": "", + "deleted": "", + "exported": "", + "markexported": "", + "reexport": "" + }, + "validation": { + "closingperiod": "", + "inventoryquantity": "", + "manualinhouse": "", + "unique_invoice_number": "" + } + }, + "bodyshop": { + "actions": { + "add_task_preset": "", + "addapptcolor": "", + "addbucket": "", + "addpartslocation": "", + "addpartsrule": "", + "addspeedprint": "", + "addtemplate": "", + "newlaborrate": "", + "newsalestaxcode": "", + "newstatus": "", + "testrender": "" + }, + "errors": { + "creatingdefaultview": "", + "loading": "Impossible de charger les détails de la boutique. Veuillez appeler le support technique.", + "saving": "" + }, + "fields": { + "ReceivableCustomField": "", + "address1": "", + "address2": "", + "appt_alt_transport": "", + "appt_colors": { + "color": "", + "label": "" + }, + "appt_length": "", + "attach_pdf_to_email": "", + "batchid": "", + "bill_allow_post_to_closed": "", + "bill_federal_tax_rate": "", + "bill_local_tax_rate": "", + "bill_state_tax_rate": "", + "city": "", + "closingperiod": "", + "companycode": "", + "country": "", + "dailybodytarget": "", + "dailypainttarget": "", + "default_adjustment_rate": "", + "deliver": { + "require_actual_delivery_date": "", + "templates": "" + }, + "dms": { + "apcontrol": "", + "appostingaccount": "", + "cashierid": "", + "default_journal": "", + "disablebillwip": "", + "disablecontactvehiclecreation": "", + "dms_acctnumber": "", + "dms_control_override": "", + "dms_wip_acctnumber": "", + "generic_customer_number": "", + "itc_federal": "", + "itc_local": "", + "itc_state": "", + "mappingname": "", + "sendmaterialscosting": "", + "srcco": "" + }, + "email": "", + "enforce_class": "", + "enforce_conversion_category": "", + "enforce_conversion_csr": "", + "enforce_referral": "", + "federal_tax_id": "", + "ignoreblockeddays": "", + "inhousevendorid": "", + "insurance_vendor_id": "", + "intake": { + "next_contact_hours": "", + "templates": "" + }, + "intellipay_config": { + "cash_discount_percentage": "", + "enable_cash_discount": "" + }, + "invoice_federal_tax_rate": "", + "invoice_local_tax_rate": "", + "invoice_state_tax_rate": "", + "jc_hourly_rates": { + "mapa": "", + "mash": "" + }, + "last_name_first": "", + "lastnumberworkingdays": "", + "localmediaserverhttp": "", + "localmediaservernetwork": "", + "localmediatoken": "", + "logo_img_footer_margin": "", + "logo_img_header_margin": "", + "logo_img_path": "", + "logo_img_path_height": "", + "logo_img_path_width": "", + "md_categories": "", + "md_ccc_rates": "", + "md_classes": "", + "md_ded_notes": "", + "md_email_cc": "", + "md_from_emails": "", + "md_functionality_toggles": { + "parts_queue_toggle": "" + }, + "md_hour_split": { + "paint": "", + "prep": "" + }, + "md_ins_co": { + "city": "", + "name": "", + "private": "", + "state": "", + "street1": "", + "street2": "", + "zip": "" + }, + "md_jobline_presets": "", + "md_lost_sale_reasons": "", + "md_parts_order_comment": "", + "md_parts_scan": { + "expression": "", + "flags": "" + }, + "md_payment_types": "", + "md_referral_sources": "", + "md_ro_guard": { + "enabled": "", + "enforce_ar": "", + "enforce_bills": "", + "enforce_cm": "", + "enforce_labor": "", + "enforce_ppd": "", + "enforce_profit": "", + "enforce_sublet": "", + "masterbypass": "", + "totalgppercent_minimum": "" + }, + "md_tasks_presets": { + "enable_tasks": "", + "hourstype": "", + "memo": "", + "name": "", + "nextstatus": "", + "percent": "", + "use_approvals": "" + }, + "messaginglabel": "", + "messagingtext": "", + "noteslabel": "", + "notestext": "", + "partslocation": "", + "phone": "", + "prodtargethrs": "", + "rbac": { + "accounting": { + "exportlog": "", + "payables": "", + "payments": "", + "receivables": "" + }, + "bills": { + "delete": "", + "enter": "", + "list": "", + "reexport": "", + "view": "" + }, + "contracts": { + "create": "", + "detail": "", + "list": "" + }, + "courtesycar": { + "create": "", + "detail": "", + "list": "" + }, + "csi": { + "export": "", + "page": "" + }, + "employee_teams": { + "page": "" + }, + "employees": { + "page": "" + }, + "inventory": { + "delete": "", + "list": "" + }, + "jobs": { + "admin": "", + "available-list": "", + "checklist-view": "", + "close": "", + "create": "", + "deliver": "", + "detail": "", + "intake": "", + "list-active": "", + "list-all": "", + "list-ready": "", + "partsqueue": "", + "void": "" + }, + "owners": { + "detail": "", + "list": "" + }, + "payments": { + "enter": "", + "list": "" + }, + "phonebook": { + "edit": "", + "view": "" + }, + "production": { + "board": "", + "list": "" + }, + "schedule": { + "view": "" + }, + "scoreboard": { + "view": "" + }, + "shiftclock": { + "view": "" + }, + "shop": { + "config": "", + "dashboard": "", + "rbac": "", + "reportcenter": "", + "templates": "", + "vendors": "" + }, + "temporarydocs": { + "view": "" + }, + "timetickets": { + "edit": "", + "editcommitted": "", + "enter": "", + "list": "", + "shiftedit": "" + }, + "ttapprovals": { + "approve": "", + "view": "" + }, + "users": { + "editaccess": "" + } + }, + "responsibilitycenter": "", + "responsibilitycenter_accountdesc": "", + "responsibilitycenter_accountitem": "", + "responsibilitycenter_accountname": "", + "responsibilitycenter_accountnumber": "", + "responsibilitycenter_rate": "", + "responsibilitycenter_tax_rate": "", + "responsibilitycenter_tax_sur": "", + "responsibilitycenter_tax_thres": "", + "responsibilitycenter_tax_tier": "", + "responsibilitycenter_tax_type": "", + "responsibilitycenters": { + "ap": "", + "ar": "", + "ats": "", + "federal_tax": "", + "federal_tax_itc": "", + "gst_override": "", + "invoiceexemptcode": "", + "itemexemptcode": "", + "la1": "", + "la2": "", + "la3": "", + "la4": "", + "laa": "", + "lab": "", + "lad": "", + "lae": "", + "laf": "", + "lag": "", + "lam": "", + "lar": "", + "las": "", + "lau": "", + "local_tax": "", + "mapa": "", + "mash": "", + "paa": "", + "pac": "", + "pag": "", + "pal": "", + "pam": "", + "pan": "", + "pao": "", + "pap": "", + "par": "", + "pas": "", + "pasl": "", + "refund": "", + "sales_tax_codes": { + "code": "", + "description": "", + "federal": "", + "local": "", + "state": "" + }, + "state_tax": "", + "tow": "" + }, + "schedule_end_time": "", + "schedule_start_time": "", + "shopname": "", + "speedprint": { + "id": "", + "label": "", + "templates": "" + }, + "ss_configuration": { + "dailyhrslimit": "" + }, + "ssbuckets": { + "color": "", + "gte": "", + "id": "", + "label": "", + "lt": "", + "target": "" + }, + "state": "", + "state_tax_id": "", + "status": "", + "statuses": { + "active_statuses": "", + "additional_board_statuses": "", + "color": "", + "default_arrived": "", + "default_bo": "", + "default_canceled": "", + "default_completed": "", + "default_delivered": "", + "default_exported": "", + "default_imported": "", + "default_invoiced": "", + "default_ordered": "", + "default_quote": "", + "default_received": "", + "default_returned": "", + "default_scheduled": "", + "default_void": "", + "open_statuses": "", + "post_production_statuses": "", + "pre_production_statuses": "", + "production_colors": "", + "production_statuses": "", + "ready_statuses": "" + }, + "target_touchtime": "", + "timezone": "", + "tt_allow_post_to_invoiced": "", + "tt_enforce_hours_for_tech_console": "", + "use_fippa": "", + "use_paint_scale_data": "", + "uselocalmediaserver": "", + "website": "", + "zip_post": "" + }, + "labels": { + "2tiername": "", + "2tiersetup": "", + "2tiersource": "", + "accountingsetup": "", + "accountingtiers": "", + "alljobstatuses": "", + "allopenjobstatuses": "", + "apptcolors": "", + "businessinformation": "", + "checklists": "", + "csiq": "", + "customtemplates": "", + "defaultcostsmapping": "", + "defaultprofitsmapping": "", + "deliverchecklist": "", + "dms": { + "cdk": { + "controllist": "", + "payers": "" + }, + "cdk_dealerid": "", + "costsmapping": "", + "dms_allocations": "", + "pbs_serialnumber": "", + "profitsmapping": "", + "title": "" + }, + "emaillater": "", + "employee_teams": "", + "employees": "", + "estimators": "", + "filehandlers": "", + "insurancecos": "", + "intakechecklist": "", + "intellipay": "", + "intellipay_cash_discount": "", + "jobstatuses": "", + "laborrates": "", + "licensing": "", + "md_parts_scan": "", + "md_ro_guard": "", + "md_tasks_presets": "", + "md_to_emails": "", + "md_to_emails_emails": "", + "messagingpresets": "", + "notemplatesavailable": "", + "notespresets": "", + "orderstatuses": "", + "partslocations": "", + "partsscan": "", + "printlater": "", + "qbo": "", + "qbo_departmentid": "", + "qbo_usa": "", + "rbac": "", + "responsibilitycenters": { + "costs": "", + "profits": "", + "sales_tax_codes": "", + "tax_accounts": "", + "title": "" + }, + "roguard": { + "title": "" + }, + "scheduling": "", + "scoreboardsetup": "", + "shopinfo": "", + "speedprint": "", + "ssbuckets": "", + "systemsettings": "", + "task-presets": "", + "workingdays": "" + }, + "successes": { + "areyousure": "", + "defaultviewcreated": "", + "save": "", + "unsavedchanges": "" + }, + "validation": { + "centermustexist": "", + "larsplit": "", + "useremailmustexist": "" + } + }, + "checklist": { + "actions": { + "printall": "" + }, + "errors": { + "complete": "", + "nochecklist": "" + }, + "labels": { + "addtoproduction": "", + "allow_text_message": "", + "checklist": "", + "printpack": "", + "removefromproduction": "" + }, + "successes": { + "completed": "" + } + }, + "contracts": { + "actions": { + "changerate": "", + "convertoro": "", + "decodelicense": "", + "find": "", + "printcontract": "", + "senddltoform": "" + }, + "errors": { + "fetchingjobinfo": "", + "returning": "", + "saving": "", + "selectjobandcar": "" + }, + "fields": { + "actax": "", + "actualreturn": "", + "agreementnumber": "", + "cc_cardholder": "", + "cc_expiry": "", + "cc_num": "", + "cleanupcharge": "", + "coverage": "", + "dailyfreekm": "", + "dailyrate": "", + "damage": "", + "damagewaiver": "", + "driver": "", + "driver_addr1": "", + "driver_addr2": "", + "driver_city": "", + "driver_dlexpiry": "", + "driver_dlnumber": "", + "driver_dlst": "", + "driver_dob": "", + "driver_fn": "", + "driver_ln": "", + "driver_ph1": "", + "driver_state": "", + "driver_zip": "", + "excesskmrate": "", + "federaltax": "", + "fuelin": "", + "fuelout": "", + "kmend": "", + "kmstart": "", + "length": "", + "localtax": "", + "refuelcharge": "", + "scheduledreturn": "", + "start": "", + "statetax": "", + "status": "" + }, + "labels": { + "agreement": "", + "availablecars": "", + "cardueforservice": "", + "convertform": { + "applycleanupcharge": "", + "refuelqty": "" + }, + "correctdataonform": "", + "dateinpast": "", + "dlexpirebeforereturn": "", + "driverinformation": "", + "findcontract": "", + "findermodal": "", + "insuranceexpired": "", + "noteconvertedfrom": "", + "populatefromjob": "", + "rates": "", + "time": "", + "vehicle": "", + "waitingforscan": "" + }, + "status": { + "new": "", + "out": "", + "returned": "" + }, + "successes": { + "saved": "" + } + }, + "courtesycars": { + "actions": { + "new": "", + "return": "" + }, + "errors": { + "saving": "" + }, + "fields": { + "color": "", + "dailycost": "", + "damage": "", + "fleetnumber": "", + "fuel": "", + "insuranceexpires": "", + "leaseenddate": "", + "make": "", + "mileage": "", + "model": "", + "nextservicedate": "", + "nextservicekm": "", + "notes": "", + "plate": "", + "purchasedate": "", + "readiness": "", + "registrationexpires": "", + "serviceenddate": "", + "servicestartdate": "", + "status": "", + "vin": "", + "year": "" + }, + "labels": { + "courtesycar": "", + "fuel": { + "12": "", + "14": "", + "18": "", + "34": "", + "38": "", + "58": "", + "78": "", + "empty": "", + "full": "" + }, + "outwith": "", + "return": "", + "status": "", + "uniquefleet": "", + "usage": "", + "vehicle": "" + }, + "readiness": { + "notready": "", + "ready": "" + }, + "status": { + "in": "", + "inservice": "", + "leasereturn": "", + "out": "", + "sold": "", + "unavailable": "" + }, + "successes": { + "saved": "" + } + }, + "csi": { + "actions": { + "activate": "" + }, + "errors": { + "creating": "", + "notconfigured": "", + "notfoundsubtitle": "", + "notfoundtitle": "", + "surveycompletesubtitle": "", + "surveycompletetitle": "" + }, + "fields": { + "completedon": "", + "created_at": "", + "surveyid": "", + "validuntil": "" + }, + "labels": { + "copyright": "", + "greeting": "", + "intro": "", + "nologgedinuser": "", + "nologgedinuser_sub": "", + "noneselected": "", + "title": "" + }, + "successes": { + "created": "", + "submitted": "", + "submittedsub": "" + } + }, + "dashboard": { + "actions": { + "addcomponent": "" + }, + "errors": { + "refreshrequired": "", + "updatinglayout": "" + }, + "labels": { + "bodyhrs": "", + "dollarsinproduction": "", + "phone": "", + "prodhrs": "", + "refhrs": "" + }, + "titles": { + "joblifecycle": "", + "labhours": "", + "larhours": "", + "monthlyemployeeefficiency": "", + "monthlyjobcosting": "", + "monthlylaborsales": "", + "monthlypartssales": "", + "monthlyrevenuegraph": "", + "prodhrssummary": "", + "productiondollars": "", + "productionhours": "", + "projectedmonthlysales": "", + "scheduledindate": "", + "scheduledintoday": "", + "scheduledoutdate": "", + "scheduledouttoday": "", + "tasks": "" + } + }, + "dms": { + "errors": { + "alreadyexported": "" + }, + "labels": { + "refreshallocations": "" + } + }, + "documents": { + "actions": { + "delete": "", + "download": "", + "reassign": "", + "selectallimages": "", + "selectallotherdocuments": "" + }, + "errors": { + "deletes3": "Erreur lors de la suppression du document du stockage.", + "deleting": "", + "deleting_cloudinary": "", + "getpresignurl": "Erreur lors de l'obtention de l'URL présignée pour le document. {{message}}", + "insert": "Incapable de télécharger le fichier. {{message}}", + "nodocuments": "Il n'y a pas de documents.", + "updating": "" + }, + "labels": { + "confirmdelete": "", + "doctype": "", + "newjobid": "", + "openinexplorer": "", + "optimizedimage": "", + "reassign_limitexceeded": "", + "reassign_limitexceeded_title": "", + "storageexceeded": "", + "storageexceeded_title": "", + "upload": "Télécharger", + "upload_limitexceeded": "", + "upload_limitexceeded_title": "", + "uploading": "", + "usage": "" + }, + "successes": { + "delete": "Le document a bien été supprimé.", + "edituploaded": "", + "insert": "Document téléchargé avec succès.", + "updated": "" + } + }, + "emails": { + "errors": { + "notsent": "Courriel non envoyé. Erreur rencontrée lors de l'envoi de {{message}}" + }, + "fields": { + "cc": "", + "from": "", + "subject": "", + "to": "" + }, + "labels": { + "attachments": "", + "documents": "", + "emailpreview": "", + "generatingemail": "", + "pdfcopywillbeattached": "", + "preview": "" + }, + "successes": { + "sent": "E-mail envoyé avec succès." + } + }, + "employee_teams": { + "actions": { + "new": "", + "newmember": "" + }, + "fields": { + "active": "", + "employeeid": "", + "max_load": "", + "name": "", + "percentage": "" + } + }, + "employees": { + "actions": { + "addvacation": "", + "new": "Nouvel employé", + "newrate": "" + }, + "errors": { + "delete": "Erreur rencontrée lors de la suppression de l'employé. {{message}}", + "save": "Une erreur s'est produite lors de l'enregistrement de l'employé. {{message}}", + "validation": "Veuillez cocher tous les champs.", + "validationtitle": "Impossible d'enregistrer l'employé." + }, + "fields": { + "active": "Actif?", + "base_rate": "Taux de base", + "cost_center": "Centre de coûts", + "employee_number": "Numéro d'employé", + "external_id": "", + "first_name": "Prénom", + "flat_rate": "Taux fixe (désactivé est le temps normal)", + "hire_date": "Date d'embauche", + "last_name": "Nom de famille", + "pin": "", + "rate": "", + "termination_date": "Date de résiliation", + "user_email": "", + "vacation": { + "end": "", + "length": "", + "start": "" + } + }, + "labels": { + "actions": "", + "active": "", + "endmustbeafterstart": "", + "flat_rate": "", + "inactive": "", + "name": "", + "rate_type": "", + "status": "", + "straight_time": "" + }, + "successes": { + "delete": "L'employé a bien été supprimé.", + "save": "L'employé a enregistré avec succès.", + "vacationadded": "" + }, + "validation": { + "unique_employee_number": "" + } + }, + "eula": { + "buttons": { + "accept": "Accept EULA" + }, + "content": { + "never_scrolled": "You must scroll to the bottom of the Terms and Conditions before accepting." + }, + "errors": { + "acceptance": { + "description": "Something went wrong while accepting the EULA. Please try again.", + "message": "Eula Acceptance Error" + } + }, + "labels": { + "accepted_terms": "I accept the terms and conditions of this agreement.", + "address": "Address", + "business_name": "Legal Business Name", + "date_accepted": "Date Accepted", + "first_name": "First Name", + "last_name": "Last Name", + "phone_number": "Phone Number" + }, + "messages": { + "accepted_terms": "Please accept the terms and conditions of this agreement.", + "business_name": "Please enter your legal business name.", + "date_accepted": "Please enter Today's Date.", + "first_name": "Please enter your first name.", + "last_name": "Please enter your last name.", + "phone_number": "Please enter your phone number." + }, + "titles": { + "modal": "Terms and Conditions", + "upper_card": "Acknowledgement" + } + }, + "exportlogs": { + "fields": { + "createdat": "" + }, + "labels": { + "attempts": "", + "priorsuccesfulexport": "" + } + }, + "general": { + "actions": { + "add": "", + "autoupdate": "", + "calculate": "", + "cancel": "", + "clear": "", + "close": "", + "copied": "", + "copylink": "", + "create": "", + "defaults": "", + "delay": "", + "delete": "Effacer", + "deleteall": "", + "deselectall": "", + "download": "", + "edit": "modifier", + "login": "", + "next": "", + "previous": "", + "print": "", + "refresh": "", + "remove": "", + "remove_alert": "", + "reset": " Rétablir l'original.", + "resetpassword": "", + "save": "sauvegarder", + "saveandnew": "", + "saveas": "", + "selectall": "", + "send": "", + "sendbysms": "", + "senderrortosupport": "", + "submit": "", + "tryagain": "", + "view": "", + "viewreleasenotes": "" + }, + "errors": { + "fcm": "", + "notfound": "", + "sizelimit": "" + }, + "itemtypes": { + "contract": "", + "courtesycar": "", + "job": "", + "owner": "", + "vehicle": "" + }, + "labels": { + "actions": "actes", + "areyousure": "", + "barcode": "code à barre", + "cancel": "", + "clear": "", + "confirmpassword": "", + "created_at": "", + "date": "", + "datetime": "", + "email": "", + "errors": "", + "excel": "", + "exceptiontitle": "", + "friday": "", + "globalsearch": "", + "help": "", + "hours": "", + "in": "dans", + "instanceconflictext": "", + "instanceconflictitle": "", + "item": "", + "label": "", + "loading": "Chargement...", + "loadingapp": "Chargement de {{app}}", + "loadingshop": "Chargement des données de la boutique ...", + "loggingin": "Vous connecter ...", + "markedexported": "", + "media": "", + "message": "", + "monday": "", + "na": "N / A", + "newpassword": "", + "no": "", + "nointernet": "", + "nointernet_sub": "", + "none": "", + "out": "En dehors", + "password": "", + "passwordresetsuccess": "", + "passwordresetsuccess_sub": "", + "passwordresetvalidatesuccess": "", + "passwordresetvalidatesuccess_sub": "", + "passwordsdonotmatch": "", + "print": "", + "refresh": "", + "reports": "", + "required": "", + "saturday": "", + "search": "Chercher...", + "searchresults": "", + "selectdate": "", + "sendagain": "", + "sendby": "", + "signin": "", + "sms": "", + "status": "", + "sub_status": { + "expired": "" + }, + "successful": "", + "sunday": "", + "text": "", + "thursday": "", + "total": "", + "totals": "", + "tuesday": "", + "tvmode": "", + "unknown": "Inconnu", + "unsavedchanges": "", + "username": "", + "view": "", + "wednesday": "", + "yes": "" + }, + "languages": { + "english": "Anglais", + "french": "Francais", + "spanish": "Espanol" + }, + "messages": { + "exception": "", + "newversionmessage": "", + "newversiontitle": "", + "noacctfilepath": "", + "nofeatureaccess": "", + "noshop": "", + "notfoundsub": "", + "notfoundtitle": "", + "partnernotrunning": "", + "rbacunauth": "", + "unsavedchanges": "Vous avez des changements non enregistrés.", + "unsavedchangespopup": "" + }, + "validation": { + "invalidemail": "S'il vous plaît entrer un email valide.", + "invalidphone": "", + "required": "Ce champ est requis." + } + }, + "help": { + "actions": { + "connect": "" + }, + "labels": { + "codeplacholder": "", + "rescuedesc": "", + "rescuetitle": "" + } + }, + "intake": { + "labels": { + "printpack": "" + } + }, + "inventory": { + "actions": { + "addtoinventory": "", + "addtoro": "", + "consumefrominventory": "", + "edit": "", + "new": "" + }, + "errors": { + "inserting": "" + }, + "fields": { + "comment": "", + "manualinvoicenumber": "", + "manualvendor": "" + }, + "labels": { + "consumedbyjob": "", + "deleteconfirm": "", + "frombillinvoicenumber": "", + "fromvendor": "", + "inventory": "", + "showall": "", + "showavailable": "" + }, + "successes": { + "deleted": "", + "inserted": "", + "updated": "" + } + }, + "job_lifecycle": { + "columns": { + "duration": "", + "end": "", + "human_readable": "", + "percentage": "", + "relative_end": "", + "relative_start": "", + "start": "", + "status": "", + "status_count": "", + "value": "" + }, + "content": { + "calculated_based_on": "", + "current_status_accumulated_time": "", + "data_unavailable": "", + "jobs_in_since": "", + "legend_title": "", + "loading": "", + "not_available": "", + "previous_status_accumulated_time": "", + "title": "", + "title_durations": "", + "title_loading": "", + "title_transitions": "" + }, + "errors": { + "fetch": "Erreur lors de l'obtention des données du cycle de vie des tâches" + }, + "titles": { + "dashboard": "", + "top_durations": "" + } + }, + "job_payments": { + "buttons": { + "create_short_link": "", + "goback": "", + "proceedtopayment": "", + "refundpayment": "" + }, + "notifications": { + "error": { + "description": "", + "openingip": "", + "title": "" + } + }, + "titles": { + "amount": "", + "dateOfPayment": "", + "descriptions": "", + "hint": "", + "payer": "", + "payername": "", + "paymentid": "", + "paymentnum": "", + "paymenttype": "", + "refundamount": "", + "transactionid": "" + } + }, + "joblines": { + "actions": { + "assign_team": "", + "converttolabor": "", + "dispatchparts": "", + "new": "" + }, + "errors": { + "creating": "", + "updating": "" + }, + "fields": { + "act_price": "Prix actuel", + "act_price_before_ppc": "", + "adjustment": "", + "ah_detail_line": "", + "amount": "", + "assigned_team": "", + "assigned_team_name": "", + "create_ppc": "", + "db_price": "Prix de la base de données", + "lbr_types": { + "LA1": "", + "LA2": "", + "LA3": "", + "LA4": "", + "LAA": "", + "LAB": "", + "LAD": "", + "LAE": "", + "LAF": "", + "LAG": "", + "LAM": "", + "LAR": "", + "LAS": "", + "LAU": "" + }, + "line_desc": "Description de la ligne", + "line_ind": "S#", + "line_no": "", + "location": "", + "mod_lb_hrs": "Heures de travail", + "mod_lbr_ty": "Type de travail", + "notes": "", + "oem_partno": "Pièce OEM #", + "op_code_desc": "", + "part_qty": "", + "part_type": "Type de pièce", + "part_types": { + "CCC": "", + "CCD": "", + "CCDR": "", + "CCF": "", + "CCM": "", + "PAA": "", + "PAC": "", + "PAE": "", + "PAG": "", + "PAL": "", + "PAM": "", + "PAN": "", + "PAO": "", + "PAP": "", + "PAR": "", + "PAS": "", + "PASL": "" + }, + "profitcenter_labor": "", + "profitcenter_part": "", + "prt_dsmk_m": "", + "prt_dsmk_p": "", + "status": "Statut", + "tax_part": "", + "total": "", + "unq_seq": "Seq #" + }, + "labels": { + "adjustmenttobeadded": "", + "billref": "", + "convertedtolabor": "", + "edit": "Ligne d'édition", + "ioucreated": "", + "new": "Nouvelle ligne", + "nostatus": "", + "presets": "" + }, + "successes": { + "created": "", + "saved": "", + "updated": "" + }, + "validations": { + "ahdetailonlyonuserdefinedtypes": "", + "hrsrequirediflbrtyp": "", + "requiredifparttype": "", + "zeropriceexistingpart": "" + } + }, + "jobs": { + "actions": { + "addDocuments": "Ajouter des documents de travail", + "addNote": "Ajouter une note", + "addtopartsqueue": "", + "addtoproduction": "", + "addtoscoreboard": "", + "allocate": "", + "autoallocate": "", + "changefilehandler": "", + "changelaborrate": "", + "changestatus": "Changer le statut", + "changestimator": "", + "convert": "Convertir", + "createiou": "", + "deliver": "", + "dms": { + "addpayer": "", + "createnewcustomer": "", + "findmakemodelcode": "", + "getmakes": "", + "labels": { + "refreshallocations": "" + }, + "post": "", + "refetchmakesmodels": "", + "usegeneric": "", + "useselected": "" + }, + "dmsautoallocate": "", + "export": "", + "exportcustdata": "", + "exportselected": "", + "filterpartsonly": "", + "generatecsi": "", + "gotojob": "", + "intake": "", + "manualnew": "", + "mark": "", + "markasexported": "", + "markpstexempt": "", + "markpstexemptconfirm": "", + "postbills": "Poster des factures", + "printCenter": "Centre d'impression", + "recalculate": "", + "reconcile": "", + "removefromproduction": "", + "schedule": "Programme", + "sendcsi": "", + "sendpartspricechange": "", + "sendtodms": "", + "sync": "", + "taxprofileoverride": "", + "taxprofileoverride_confirm": "", + "uninvoice": "", + "unvoid": "", + "viewchecklist": "", + "viewdetail": "" + }, + "errors": { + "addingtoproduction": "", + "cannotintake": "", + "closing": "", + "creating": "", + "deleted": "Erreur lors de la suppression du travail.", + "exporting": "", + "exporting-partner": "", + "invoicing": "", + "noaccess": "Ce travail n'existe pas ou vous n'y avez pas accès.", + "nodamage": "", + "nodates": "Aucune date spécifiée pour ce travail.", + "nofinancial": "", + "nojobselected": "Aucun travail n'est sélectionné.", + "noowner": "Aucun propriétaire associé.", + "novehicle": "Aucun véhicule associé.", + "partspricechange": "", + "saving": "Erreur rencontrée lors de la sauvegarde de l'enregistrement.", + "scanimport": "", + "totalscalc": "", + "updating": "", + "validation": "Veuillez vous assurer que tous les champs sont correctement entrés.", + "validationtitle": "Erreur de validation", + "voiding": "" + }, + "fields": { + "active_tasks": "", + "actual_completion": "Achèvement réel", + "actual_delivery": "Livraison réelle", + "actual_in": "En réel", + "adjustment_bottom_line": "Ajustements", + "adjustmenthours": "", + "alt_transport": "", + "area_of_damage_impact": { + "10": "", + "11": "", + "12": "", + "13": "", + "14": "", + "15": "", + "16": "", + "25": "", + "26": "", + "27": "", + "28": "", + "34": "", + "01": "", + "02": "", + "03": "", + "04": "", + "05": "", + "06": "", + "07": "", + "08": "", + "09": "" + }, + "auto_add_ats": "", + "ca_bc_pvrt": "", + "ca_customer_gst": "", + "ca_gst_registrant": "", + "category": "", + "ccc": "", + "ccd": "", + "ccdr": "", + "ccf": "", + "ccm": "", + "cieca_id": "CIECA ID", + "cieca_pfl": { + "lbr_adjp": "", + "lbr_tax_in": "", + "lbr_taxp": "", + "lbr_tx_in1": "", + "lbr_tx_in2": "", + "lbr_tx_in3": "", + "lbr_tx_in4": "", + "lbr_tx_in5": "" + }, + "cieca_pfo": { + "stor_t_in1": "", + "stor_t_in2": "", + "stor_t_in3": "", + "stor_t_in4": "", + "stor_t_in5": "", + "tow_t_in1": "", + "tow_t_in2": "", + "tow_t_in3": "", + "tow_t_in4": "", + "tow_t_in5": "" + }, + "claim_total": "Total réclamation", + "class": "", + "clm_no": "Prétendre #", + "clm_total": "Total réclamation", + "comment": "", + "customerowing": "Client propriétaire", + "date_estimated": "Date estimée", + "date_exported": "Exportés", + "date_invoiced": "Facturé", + "date_last_contacted": "", + "date_lost_sale": "", + "date_next_contact": "", + "date_open": "Ouvrir", + "date_rentalresp": "", + "date_repairstarted": "", + "date_scheduled": "Prévu", + "date_towin": "", + "date_void": "", + "ded_amt": "Déductible", + "ded_note": "", + "ded_status": "Statut de franchise", + "depreciation_taxes": "Amortissement / taxes", + "dms": { + "address": "", + "amount": "", + "center": "", + "control_type": { + "account_number": "" + }, + "cost": "", + "cost_dms_acctnumber": "", + "dms_make": "", + "dms_model": "", + "dms_model_override": "", + "dms_unsold": "", + "dms_wip_acctnumber": "", + "id": "", + "inservicedate": "", + "journal": "", + "lines": "", + "name1": "", + "payer": { + "amount": "", + "control_type": "", + "controlnumber": "", + "dms_acctnumber": "", + "name": "" + }, + "sale": "", + "sale_dms_acctnumber": "", + "story": "", + "vinowner": "" + }, + "dms_allocation": "", + "driveable": "", + "employee_body": "", + "employee_csr": "représentant du service à la clientèle", + "employee_csr_writer": "", + "employee_prep": "", + "employee_refinish": "", + "est_addr1": "Adresse de l'évaluateur", + "est_co_nm": "Expert", + "est_ct_fn": "Prénom de l'évaluateur", + "est_ct_ln": "Nom de l'évaluateur", + "est_ea": "Courriel de l'évaluateur", + "est_ph1": "Numéro de téléphone de l'évaluateur", + "federal_tax_payable": "Impôt fédéral à payer", + "federal_tax_rate": "", + "ins_addr1": "Adresse Insurance Co.", + "ins_city": "Insurance City", + "ins_co_id": "ID de la compagnie d'assurance", + "ins_co_nm": "Nom de la compagnie d'assurance", + "ins_co_nm_short": "", + "ins_ct_fn": "Prénom du gestionnaire de fichiers", + "ins_ct_ln": "Nom du gestionnaire de fichiers", + "ins_ea": "Courriel du gestionnaire de fichiers", + "ins_ph1": "Numéro de téléphone du gestionnaire de fichiers", + "intake": { + "label": "", + "max": "", + "min": "", + "name": "", + "required": "", + "type": "" + }, + "invoice_final_note": "", + "kmin": "Kilométrage en", + "kmout": "Kilométrage hors", + "la1": "", + "la2": "", + "la3": "", + "la4": "", + "laa": "", + "lab": "", + "labor_rate_desc": "Nom du taux de main-d'œuvre", + "lad": "", + "lae": "", + "laf": "", + "lag": "", + "lam": "", + "lar": "", + "las": "", + "lau": "", + "local_tax_rate": "", + "loss_date": "Date de perte", + "loss_desc": "", + "loss_of_use": "", + "lost_sale_reason": "", + "ma2s": "", + "ma3s": "", + "mabl": "", + "macs": "", + "mahw": "", + "mapa": "", + "mash": "", + "matd": "", + "materials": { + "MAPA": "", + "MASH": "", + "cal_maxdlr": "", + "cal_opcode": "", + "mat_adjp": "", + "mat_taxp": "", + "mat_tx_in1": "", + "mat_tx_in2": "", + "mat_tx_in3": "", + "mat_tx_in4": "", + "mat_tx_in5": "", + "materials": "", + "tax_ind": "" + }, + "other_amount_payable": "Autre montant à payer", + "owner": "Propriétaire", + "owner_owing": "Cust. Owes", + "ownr_ea": "Email", + "ownr_ph1": "Téléphone 1", + "ownr_ph2": "", + "paa": "", + "pac": "", + "pae": "", + "pag": "", + "pal": "", + "pam": "", + "pan": "", + "pao": "", + "pap": "", + "par": "", + "parts_tax_rates": { + "prt_discp": "", + "prt_mktyp": "", + "prt_mkupp": "", + "prt_tax_in": "", + "prt_tax_rt": "", + "prt_tx_in1": "", + "prt_tx_in2": "", + "prt_tx_in3": "", + "prt_tx_in4": "", + "prt_tx_in5": "", + "prt_tx_ty1": "", + "prt_type": "" + }, + "partsstatus": "", + "pas": "", + "pay_date": "Date d'Pay", + "phoneshort": "PH", + "po_number": "", + "policy_no": "Politique #", + "ponumber": "Numéro de bon de commande", + "production_vars": { + "note": "" + }, + "qb_multiple_payers": { + "amount": "", + "name": "" + }, + "queued_for_parts": "", + "rate_ats": "", + "rate_la1": "Taux LA1", + "rate_la2": "Taux LA2", + "rate_la3": "Taux LA3", + "rate_la4": "Taux LA4", + "rate_laa": "Taux d'aluminium", + "rate_lab": "Taux de la main-d'œuvre", + "rate_lad": "Taux de diagnostic", + "rate_lae": "Tarif électrique", + "rate_laf": "Taux de trame", + "rate_lag": "Taux de verre", + "rate_lam": "Taux mécanique", + "rate_lar": "Taux de finition", + "rate_las": "", + "rate_lau": "Taux d'aluminium", + "rate_ma2s": "Taux de peinture en 2 étapes", + "rate_ma3s": "Taux de peinture en 3 étapes", + "rate_mabl": "MABL ??", + "rate_macs": "MACS ??", + "rate_mahw": "Taux de déchets dangereux", + "rate_mapa": "Taux de matériaux de peinture", + "rate_mash": "Tarif du matériel de la boutique", + "rate_matd": "Taux d'élimination des pneus", + "referral_source_extra": "", + "referral_source_other": "", + "referralsource": "Source de référence", + "regie_number": "Enregistrement #", + "repairtotal": "Réparation totale", + "ro_number": "RO #", + "scheduled_completion": "Achèvement planifié", + "scheduled_delivery": "Livraison programmée", + "scheduled_in": "Planifié dans", + "selling_dealer": "Revendeur vendeur", + "selling_dealer_contact": "Contacter le revendeur", + "servicecar": "Voiture de service", + "servicing_dealer": "Concessionnaire", + "servicing_dealer_contact": "Contacter le concessionnaire", + "special_coverage_policy": "Politique de couverture spéciale", + "specialcoveragepolicy": "Politique de couverture spéciale", + "state_tax_rate": "", + "status": "Statut de l'emploi", + "storage_payable": "Stockage", + "tax_lbr_rt": "", + "tax_levies_rt": "", + "tax_paint_mat_rt": "", + "tax_registration_number": "", + "tax_shop_mat_rt": "", + "tax_str_rt": "", + "tax_sub_rt": "", + "tax_tow_rt": "", + "towin": "", + "towing_payable": "Remorquage à payer", + "unitnumber": "Unité #", + "updated_at": "Mis à jour à", + "uploaded_by": "Telechargé par", + "vehicle": "Véhicule" + }, + "forms": { + "admindates": "", + "appraiserinfo": "", + "claiminfo": "", + "estdates": "", + "laborrates": "", + "lossinfo": "", + "other": "", + "repairdates": "", + "scheddates": "" + }, + "labels": { + "accountsreceivable": "", + "act_price_ppc": "", + "actual_completion_inferred": "", + "actual_delivery_inferred": "", + "actual_in_inferred": "", + "additionalpayeroverallocation": "", + "additionaltotal": "", + "adjustmentrate": "", + "adjustments": "", + "adminwarning": "", + "allocations": "", + "alreadyaddedtoscoreboard": "", + "alreadyclosed": "", + "appointmentconfirmation": "Envoyer une confirmation au client?", + "associationwarning": "", + "audit": "", + "available": "", + "availablejobs": "", + "ca_bc_pvrt": { + "days": "", + "rate": "" + }, + "ca_gst_all_if_null": "", + "calc_repair_days": "", + "calc_repair_days_tt": "", + "calc_scheuled_completion": "", + "cards": { + "customer": "Informations client", + "damage": "Zone de dommages", + "dates": "Rendez-vous", + "documents": "Documents récents", + "estimator": "Estimateur", + "filehandler": "Gestionnaire de fichiers", + "insurance": "Détails de l'assurance", + "more": "Plus", + "notes": "Remarques", + "parts": "les pièces", + "totals": "Totaux", + "vehicle": "Véhicule" + }, + "changeclass": "", + "checklistcompletedby": "", + "checklistdocuments": "", + "checklists": "", + "cieca_pfl": "", + "cieca_pfo": "", + "cieca_pft": "", + "closeconfirm": "", + "closejob": "", + "closingperiod": "", + "contracts": "", + "convertedtolabor": "", + "cost": "", + "cost_Additional": "", + "cost_labor": "", + "cost_parts": "", + "cost_sublet": "", + "costs": "", + "create": { + "jobinfo": "", + "newowner": "", + "newvehicle": "", + "novehicle": "", + "ownerinfo": "", + "vehicleinfo": "" + }, + "createiouwarning": "", + "creating_new_job": "Création d'un nouvel emploi ...", + "deductible": { + "stands": "", + "waived": "" + }, + "deleteconfirm": "", + "deletedelivery": "", + "deleteintake": "", + "deliverchecklist": "", + "difference": "", + "diskscan": "", + "dms": { + "apexported": "", + "damageto": "", + "defaultstory": "", + "disablebillwip": "", + "invoicedatefuture": "", + "kmoutnotgreaterthankmin": "", + "logs": "", + "notallocated": "", + "postingform": "", + "totalallocated": "" + }, + "documents": "Les documents", + "documents-images": "", + "documents-other": "", + "duplicateconfirm": "", + "emailaudit": "", + "employeeassignments": "", + "estimatelines": "", + "estimator": "", + "existing_jobs": "Emplois existants", + "federal_tax_amt": "", + "gpdollars": "", + "gppercent": "", + "hrs_claimed": "", + "hrs_total": "", + "importnote": "", + "inproduction": "", + "intakechecklist": "", + "iou": "", + "job": "", + "jobcosting": "", + "jobtotals": "", + "labor_hrs": "", + "labor_rates_subtotal": "", + "laborallocations": "", + "labortotals": "", + "lines": "Estimer les lignes", + "local_tax_amt": "", + "mapa": "", + "markforreexport": "", + "mash": "", + "masterbypass": "", + "materials": { + "mapa": "" + }, + "missingprofileinfo": "", + "multipayers": "", + "net_repairs": "", + "notes": "Remarques", + "othertotal": "", + "outstanding_ar": "", + "outstanding_credit_memos": "", + "outstanding_ppd": "", + "outstanding_reconciliation_discrep": "", + "outstanding_sublets": "", + "outstandinghours": "", + "override_header": "Remplacer l'en-tête d'estimation à l'importation?", + "ownerassociation": "", + "parts": "les pièces", + "parts_lines": "", + "parts_received": "", + "parts_tax_rates": "", + "partsfilter": "", + "partssubletstotal": "", + "partstotal": "", + "performance": "", + "pimraryamountpayable": "", + "plitooltips": { + "billtotal": "", + "calculatedcreditsnotreceived": "", + "creditmemos": "", + "creditsnotreceived": "", + "discrep1": "", + "discrep2": "", + "discrep3": "", + "laboradj": "", + "partstotal": "", + "totalreturns": "" + }, + "ppc": "", + "ppdnotexported": "", + "profileadjustments": "", + "profitbypassrequired": "", + "profits": "", + "prt_dsmk_total": "", + "rates": "Les taux", + "rates_subtotal": "", + "reconciliation": { + "billlinestotal": "", + "byassoc": "", + "byprice": "", + "clear": "", + "discrepancy": "", + "joblinestotal": "", + "multipleactprices": "", + "multiplebilllines": "", + "multiplebillsforactprice": "", + "removedpartsstrikethrough": "" + }, + "reconciliationheader": "", + "relatedros": "", + "remove_from_ar": "", + "returntotals": "", + "ro_guard": { + "enforce_ar": "", + "enforce_bills": "", + "enforce_cm": "", + "enforce_labor": "", + "enforce_ppd": "", + "enforce_profit": "", + "enforce_sublet": "", + "enforce_validation": "", + "enforced": "" + }, + "roguard": "", + "roguardwarnings": "", + "rosaletotal": "", + "sale_additional": "", + "sale_labor": "", + "sale_parts": "", + "sale_sublet": "", + "sales": "", + "savebeforeconversion": "", + "scheduledinchange": "", + "specialcoveragepolicy": "", + "state_tax_amt": "", + "subletsnotcompleted": "", + "subletstotal": "", + "subtotal": "", + "supplementnote": "", + "suspended": "", + "suspense": "", + "tasks": "", + "threshhold": "", + "total_cost": "", + "total_cust_payable": "", + "total_repairs": "", + "total_sales": "", + "total_sales_tax": "", + "totals": "", + "unvoidnote": "", + "update_scheduled_completion": "", + "vehicle_info": "Véhicule", + "vehicleassociation": "", + "viewallocations": "", + "voidjob": "", + "voidnote": "" + }, + "successes": { + "addedtoproduction": "", + "all_deleted": "{{count}} travaux supprimés avec succès.", + "closed": "", + "converted": "Travail converti avec succès.", + "created": "Le travail a été créé avec succès. Clique pour voir.", + "creatednoclick": "", + "delete": "", + "deleted": "Le travail a bien été supprimé.", + "duplicated": "", + "exported": "", + "invoiced": "", + "ioucreated": "", + "partsqueue": "", + "save": "Le travail a été enregistré avec succès.", + "savetitle": "Enregistrement enregistré avec succès.", + "supplemented": "Travail complété avec succès.", + "updated": "", + "voided": "" + } + }, + "landing": { + "bigfeature": { + "subtitle": "", + "title": "" + }, + "footer": { + "company": { + "about": "", + "contact": "", + "disclaimers": "", + "name": "", + "privacypolicy": "" + }, + "io": { + "help": "", + "name": "", + "status": "" + }, + "slogan": "" + }, + "hero": { + "button": "", + "title": "" + }, + "labels": { + "features": "", + "managemyshop": "", + "pricing": "" + }, + "pricing": { + "basic": { + "name": "", + "sub": "" + }, + "essentials": { + "name": "", + "sub": "" + }, + "pricingtitle": "", + "pro": { + "name": "", + "sub": "" + }, + "title": "", + "unlimited": { + "name": "", + "sub": "" + } + } + }, + "menus": { + "currentuser": { + "languageselector": "La langue", + "profile": "Profil" + }, + "header": { + "accounting": "", + "accounting-payables": "", + "accounting-payments": "", + "accounting-receivables": "", + "activejobs": "Emplois actifs", + "all_tasks": "", + "alljobs": "", + "allpayments": "", + "availablejobs": "Emplois disponibles", + "bills": "", + "courtesycars": "", + "courtesycars-all": "", + "courtesycars-contracts": "", + "courtesycars-newcontract": "", + "create_task": "", + "customers": "Les clients", + "dashboard": "", + "enterbills": "", + "entercardpayment": "", + "enterpayment": "", + "entertimeticket": "", + "export": "", + "export-logs": "", + "help": "", + "home": "Accueil", + "inventory": "", + "jobs": "Emplois", + "my_tasks": "", + "newjob": "", + "owners": "Propriétaires", + "parts-queue": "", + "phonebook": "", + "productionboard": "", + "productionlist": "", + "readyjobs": "", + "recent": "", + "reportcenter": "", + "rescueme": "", + "schedule": "Programme", + "scoreboard": "", + "search": { + "bills": "", + "jobs": "", + "owners": "", + "payments": "", + "phonebook": "", + "vehicles": "" + }, + "shiftclock": "", + "shop": "Mon magasin", + "shop_config": "Configuration", + "shop_csi": "", + "shop_templates": "", + "shop_vendors": "Vendeurs", + "tasks": "", + "temporarydocs": "", + "timetickets": "", + "ttapprovals": "", + "vehicles": "Véhicules" + }, + "jobsactions": { + "admin": "", + "cancelallappointments": "", + "closejob": "", + "deletejob": "", + "duplicate": "", + "duplicatenolines": "", + "newcccontract": "", + "void": "" + }, + "jobsdetail": { + "claimdetail": "Détails de la réclamation", + "dates": "Rendez-vous", + "financials": "", + "general": "", + "insurance": "", + "labor": "La main d'oeuvre", + "lifecycle": "", + "parts": "", + "partssublet": "Pièces / Sous-location", + "rates": "", + "repairdata": "Données de réparation", + "totals": "" + }, + "profilesidebar": { + "profile": "Mon profil", + "shops": "Mes boutiques" + }, + "tech": { + "assignedjobs": "", + "claimtask": "", + "dispatchedparts": "", + "home": "", + "jobclockin": "", + "jobclockout": "", + "joblookup": "", + "login": "", + "logout": "", + "productionboard": "", + "productionlist": "", + "shiftclockin": "" + } + }, + "messaging": { + "actions": { + "link": "", + "new": "" + }, + "errors": { + "invalidphone": "", + "noattachedjobs": "", + "updatinglabel": "" + }, + "labels": { + "addlabel": "", + "archive": "", + "maxtenimages": "", + "messaging": "Messagerie", + "noallowtxt": "", + "nojobs": "", + "nopush": "", + "phonenumber": "", + "presets": "", + "recentonly": "", + "selectmedia": "", + "sentby": "", + "typeamessage": "Envoyer un message...", + "unarchive": "" + }, + "render": { + "conversation_list": "" + } + }, + "notes": { + "actions": { + "actions": "actes", + "deletenote": "Supprimer la note", + "edit": "Note éditée", + "new": "Nouvelle note", + "savetojobnotes": "" + }, + "errors": { + "inserting": "" + }, + "fields": { + "createdby": "Créé par", + "critical": "Critique", + "private": "privé", + "text": "Contenu", + "type": "", + "types": { + "customer": "", + "general": "", + "office": "", + "paint": "", + "parts": "", + "shop": "", + "supplement": "" + }, + "updatedat": "Mis à jour à" + }, + "labels": { + "addtorelatedro": "", + "newnoteplaceholder": "Ajouter une note...", + "notetoadd": "", + "systemnotes": "", + "usernotes": "" + }, + "successes": { + "create": "Remarque créée avec succès.", + "deleted": "Remarque supprimée avec succès.", + "updated": "Remarque mise à jour avec succès." + } + }, + "owner": { + "labels": { + "noownerinfo": "" + } + }, + "owners": { + "actions": { + "update": "" + }, + "errors": { + "deleting": "", + "noaccess": "L'enregistrement n'existe pas ou vous n'y avez pas accès.", + "saving": "", + "selectexistingornew": "" + }, + "fields": { + "address": "Adresse", + "allow_text_message": "Autorisation de texte?", + "name": "Prénom", + "note": "", + "ownr_addr1": "Adresse", + "ownr_addr2": "Adresse 2 ", + "ownr_city": "Ville", + "ownr_co_nm": "", + "ownr_ctry": "Pays", + "ownr_ea": "Email", + "ownr_fn": "Prénom", + "ownr_ln": "Nom de famille", + "ownr_ph1": "Téléphone 1", + "ownr_ph2": "", + "ownr_st": "Etat / Province", + "ownr_title": "Titre", + "ownr_zip": "Zip / code postal", + "preferred_contact": "Méthode de contact préférée", + "tax_number": "" + }, + "forms": { + "address": "", + "contact": "", + "name": "" + }, + "labels": { + "create_new": "Créez un nouvel enregistrement de propriétaire.", + "deleteconfirm": "", + "existing_owners": "Propriétaires existants", + "fromclaim": "", + "fromowner": "", + "relatedjobs": "", + "updateowner": "" + }, + "successes": { + "delete": "", + "save": "Le propriétaire a bien enregistré." + } + }, + "parts": { + "actions": { + "order": "Commander des pièces", + "orderinhouse": "" + } + }, + "parts_dispatch": { + "actions": { + "accept": "" + }, + "errors": { + "accepting": "", + "creating": "" + }, + "fields": { + "number": "", + "percent_accepted": "" + }, + "labels": { + "notyetdispatched": "", + "parts_dispatch": "" + } + }, + "parts_dispatch_lines": { + "fields": { + "accepted_at": "" + } + }, + "parts_orders": { + "actions": { + "backordered": "", + "receive": "", + "receivebill": "" + }, + "errors": { + "associatedbills": "", + "backordering": "", + "creating": "Erreur rencontrée lors de la création de la commande de pièces.", + "oec": "", + "saving": "", + "updating": "" + }, + "fields": { + "act_price": "", + "backordered_eta": "", + "backordered_on": "", + "cm_received": "", + "comments": "", + "cost": "", + "db_price": "", + "deliver_by": "", + "job_line_id": "", + "line_desc": "", + "line_remarks": "", + "lineremarks": "Remarques sur la ligne", + "oem_partno": "", + "order_date": "", + "order_number": "", + "orderedby": "", + "part_type": "", + "quantity": "", + "return": "", + "status": "" + }, + "labels": { + "allpartsto": "", + "confirmdelete": "", + "custompercent": "", + "discount": "", + "email": "Envoyé par email", + "inthisorder": "Pièces dans cette commande", + "is_quote": "", + "mark_as_received": "", + "newpartsorder": "", + "notyetordered": "", + "oec": "", + "order_type": "", + "orderhistory": "Historique des commandes", + "parts_order": "", + "parts_orders": "", + "print": "Afficher le formulaire imprimé", + "receive": "", + "removefrompartsqueue": "", + "returnpartsorder": "", + "sublet_order": "" + }, + "successes": { + "created": "Commande de pièces créée avec succès.", + "line_updated": "", + "received": "", + "return_created": "" + } + }, + "payments": { + "actions": { + "generatepaymentlink": "" + }, + "errors": { + "exporting": "", + "exporting-partner": "", + "inserting": "" + }, + "fields": { + "amount": "", + "created_at": "", + "date": "", + "exportedat": "", + "memo": "", + "payer": "", + "paymentnum": "", + "stripeid": "", + "transactionid": "", + "type": "" + }, + "labels": { + "balance": "", + "ca_bc_etf_table": "", + "customer": "", + "edit": "", + "electronicpayment": "", + "external": "", + "findermodal": "", + "insurance": "", + "markexported": "", + "markforreexport": "", + "new": "", + "signup": "", + "smspaymentreminder": "", + "title": "", + "totalpayments": "" + }, + "successes": { + "exported": "", + "markexported": "", + "markreexported": "", + "payment": "", + "paymentupdate": "", + "stripe": "" + } + }, + "phonebook": { + "actions": { + "new": "" + }, + "errors": { + "adding": "", + "saving": "" + }, + "fields": { + "address1": "", + "address2": "", + "category": "", + "city": "", + "company": "", + "country": "", + "email": "", + "fax": "", + "firstname": "", + "lastname": "", + "phone1": "", + "phone2": "", + "state": "" + }, + "labels": { + "noneselected": "", + "onenamerequired": "", + "vendorcategory": "" + }, + "successes": { + "added": "", + "deleted": "", + "saved": "" + } + }, + "printcenter": { + "appointments": { + "appointment_confirmation": "" + }, + "bills": { + "inhouse_invoice": "" + }, + "courtesycarcontract": { + "courtesy_car_contract": "", + "courtesy_car_impound": "", + "courtesy_car_inventory": "", + "courtesy_car_terms": "" + }, + "errors": { + "nocontexttype": "" + }, + "jobs": { + "3rdpartyfields": { + "addr1": "", + "addr2": "", + "addr3": "", + "attn": "", + "city": "", + "custgst": "", + "ded_amt": "", + "depreciation": "", + "other": "", + "ponumber": "", + "refnumber": "", + "sendtype": "", + "state": "", + "zip": "" + }, + "3rdpartypayer": "", + "ab_proof_of_loss": "", + "appointment_confirmation": "", + "appointment_reminder": "", + "casl_authorization": "", + "committed_timetickets_ro": "", + "coversheet_landscape": "", + "coversheet_portrait": "", + "csi_invitation": "", + "csi_invitation_action": "", + "diagnostic_authorization": "", + "dms_posting_sheet": "", + "envelope_return_address": "", + "estimate": "", + "estimate_detail": "", + "estimate_followup": "", + "express_repair_checklist": "", + "filing_coversheet_landscape": "", + "filing_coversheet_portrait": "", + "final_invoice": "", + "fippa_authorization": "", + "folder_label_multiple": "", + "glass_express_checklist": "", + "guarantee": "", + "individual_job_note": "", + "invoice_customer_payable": "", + "invoice_total_payable": "", + "iou_form": "", + "job_costing_ro": "", + "job_lifecycle_ro": "", + "job_notes": "", + "job_tasks": "", + "key_tag": "", + "labels": { + "count": "", + "labels": "", + "position": "" + }, + "lag_time_ro": "", + "mechanical_authorization": "", + "mpi_animal_checklist": "", + "mpi_eglass_auth": "", + "mpi_final_acct_sheet": "", + "mpi_final_repair_acct_sheet": "", + "paint_grid": "", + "parts_dispatch": "", + "parts_invoice_label_single": "", + "parts_label_multiple": "", + "parts_label_single": "", + "parts_list": "", + "parts_order": "", + "parts_order_confirmation": "", + "parts_order_history": "", + "parts_return_slip": "", + "payment_receipt": "", + "payment_request": "", + "payments_by_job": "", + "purchases_by_ro_detail": "", + "purchases_by_ro_summary": "", + "qc_sheet": "", + "rental_reservation": "", + "ro_totals": "", + "ro_with_description": "", + "sgi_certificate_of_repairs": "", + "sgi_windshield_auth": "", + "stolen_recovery_checklist": "", + "sublet_order": "", + "supplement_request": "", + "thank_you_ro": "", + "thirdpartypayer": "", + "timetickets_ro": "", + "vehicle_check_in": "", + "vehicle_delivery_check": "", + "window_tag": "", + "window_tag_sublet": "", + "work_authorization": "", + "worksheet_by_line_number": "", + "worksheet_sorted_by_operation": "", + "worksheet_sorted_by_operation_no_hours": "", + "worksheet_sorted_by_operation_part_type": "", + "worksheet_sorted_by_operation_type": "", + "worksheet_sorted_by_team": "" + }, + "labels": { + "groups": { + "authorization": "", + "financial": "", + "post": "", + "pre": "", + "ro": "", + "worksheet": "" + }, + "misc": "", + "repairorder": "", + "reportcentermodal": "", + "speedprint": "", + "title": "" + }, + "payments": { + "ca_bc_etf_table": "", + "exported_payroll": "" + }, + "special": { + "attendance_detail_csv": "" + }, + "subjects": { + "jobs": { + "individual_job_note": "", + "parts_dispatch": "", + "parts_order": "", + "parts_return_slip": "", + "sublet_order": "" + } + }, + "vendors": { + "purchases_by_vendor_detailed": "", + "purchases_by_vendor_summary": "" + } + }, + "production": { + "actions": { + "addcolumns": "", + "bodypriority-clear": "", + "bodypriority-set": "", + "detailpriority-clear": "", + "detailpriority-set": "", + "paintpriority-clear": "", + "paintpriority-set": "", + "remove": "", + "removecolumn": "", + "saveconfig": "", + "suspend": "", + "unsuspend": "" + }, + "constants": { + "main_profile": "" + }, + "errors": { + "boardupdate": "", + "name_exists": "", + "name_required": "", + "removing": "", + "settings": "" + }, + "labels": { + "actual_in": "", + "addnewprofile": "", + "alert": "", + "alertoff": "", + "alerton": "", + "alerts": "", + "ats": "", + "bodyhours": "", + "bodypriority": "", + "bodyshop": { + "labels": { + "qbo_departmentid": "", + "qbo_usa": "" + } + }, + "card_size": "", + "cardcolor": "", + "cardsettings": "", + "clm_no": "", + "comment": "", + "compact": "", + "detailpriority": "", + "employeeassignments": "", + "employeesearch": "", + "estimator": "", + "horizontal": "", + "ins_co_nm": "", + "jobdetail": "", + "kiosk_mode": "", + "laborhrs": "", + "legend": "", + "model_info": "", + "note": "", + "off": "", + "on": "", + "orientation": "", + "ownr_nm": "", + "paintpriority": "", + "partsstatus": "", + "production_note": "", + "refinishhours": "", + "scheduled_completion": "", + "selectview": "", + "stickyheader": "", + "sublets": "", + "subtotal": "", + "tall": "", + "tasks": "", + "totalhours": "", + "touchtime": "", + "vertical": "", + "viewname": "", + "wide": "" + }, + "options": { + "horizontal": "", + "large": "", + "medium": "", + "small": "", + "vertical": "" + }, + "settings": { + "board_settings": "", + "filters": { + "md_estimators": "", + "md_ins_cos": "" + }, + "filters_title": "", + "information": "", + "layout": "", "statistics": { "jobs_in_production": "", "tasks_in_production": "", @@ -2865,8 +2865,8 @@ "total_lar_on_board": "", "total_lar_in_view": "" }, - "statistics_title": "" - }, + "statistics_title": "" + }, "statistics": { "currency_symbol": "", "hours": "", @@ -2891,708 +2891,709 @@ "total_lar_on_board": "", "total_lar_in_view": "" }, - "successes": { - "removed": "" - } - }, - "profile": { - "errors": { - "state": "Erreur lors de la lecture de l'état de la page. Rafraichissez, s'il vous plait." - }, - "labels": { - "activeshop": "" - }, - "successes": { - "updated": "" - } - }, - "reportcenter": { - "actions": { - "generate": "" - }, - "labels": { - "advanced_filters": "", - "advanced_filters_false": "", - "advanced_filters_filter_field": "", - "advanced_filters_filter_operator": "", - "advanced_filters_filter_value": "", - "advanced_filters_filters": "", - "advanced_filters_hide": "", - "advanced_filters_show": "", - "advanced_filters_sorter_direction": "", - "advanced_filters_sorter_field": "", - "advanced_filters_sorters": "", - "advanced_filters_true": "", - "dates": "", - "employee": "", - "filterson": "", - "generateasemail": "", - "groups": { - "customers": "", - "jobs": "", - "payroll": "", - "purchases": "", - "sales": "" - }, - "key": "", - "objects": { - "appointments": "", - "bills": "", - "csi": "", - "exportlogs": "", - "jobs": "", - "parts_orders": "", - "payments": "", - "scoreboard": "", - "tasks": "", - "timetickets": "" - }, - "vendor": "" - }, - "templates": { - "adp_payroll_flat": "", - "adp_payroll_straight": "", - "anticipated_revenue": "", - "ar_aging": "", - "attendance_detail": "", - "attendance_employee": "", - "attendance_summary": "", - "committed_timetickets": "", - "committed_timetickets_employee": "", - "committed_timetickets_summary": "", - "credits_not_received_date": "", - "credits_not_received_date_vendorid": "", - "csi": "", - "customer_list": "", - "cycle_time_analysis": "", - "estimates_written_converted": "", - "estimator_detail": "", - "estimator_summary": "", - "export_payables": "", - "export_payments": "", - "export_receivables": "", - "exported_gsr_by_ro": "", - "exported_gsr_by_ro_labor": "", - "gsr_by_atp": "", - "gsr_by_ats": "", - "gsr_by_category": "", - "gsr_by_csr": "", - "gsr_by_delivery_date": "", - "gsr_by_estimator": "", - "gsr_by_exported_date": "", - "gsr_by_ins_co": "", - "gsr_by_make": "", - "gsr_by_referral": "", - "gsr_by_ro": "", - "gsr_labor_only": "", - "hours_sold_detail_closed": "", - "hours_sold_detail_closed_csr": "", - "hours_sold_detail_closed_estimator": "", - "hours_sold_detail_closed_ins_co": "", - "hours_sold_detail_closed_status": "", - "hours_sold_detail_open": "", - "hours_sold_detail_open_csr": "", - "hours_sold_detail_open_estimator": "", - "hours_sold_detail_open_ins_co": "", - "hours_sold_detail_open_status": "", - "hours_sold_summary_closed": "", - "hours_sold_summary_closed_csr": "", - "hours_sold_summary_closed_estimator": "", - "hours_sold_summary_closed_ins_co": "", - "hours_sold_summary_closed_status": "", - "hours_sold_summary_open": "", - "hours_sold_summary_open_csr": "", - "hours_sold_summary_open_estimator": "", - "hours_sold_summary_open_ins_co": "", - "hours_sold_summary_open_status": "", - "job_costing_ro_csr": "", - "job_costing_ro_date_detail": "", - "job_costing_ro_date_summary": "", - "job_costing_ro_estimator": "", - "job_costing_ro_ins_co": "", - "job_lifecycle_date_detail": "", - "job_lifecycle_date_summary": "", - "jobs_completed_not_invoiced": "", - "jobs_invoiced_not_exported": "", - "jobs_reconcile": "", - "jobs_scheduled_completion": "", - "lag_time": "", - "load_level": "", - "lost_sales": "", - "open_orders": "", - "open_orders_csr": "", - "open_orders_estimator": "", - "open_orders_excel": "", - "open_orders_ins_co": "", - "open_orders_referral": "", - "open_orders_specific_csr": "", - "open_orders_status": "", - "parts_backorder": "", - "parts_not_recieved": "", - "parts_not_recieved_vendor": "", - "parts_received_not_scheduled": "", - "payments_by_date": "", - "payments_by_date_payment": "", - "payments_by_date_type": "", - "production_by_category": "", - "production_by_category_one": "", - "production_by_csr": "", - "production_by_last_name": "", - "production_by_repair_status": "", - "production_by_repair_status_one": "", - "production_by_ro": "", - "production_by_target_date": "", - "production_by_technician": "", - "production_by_technician_one": "", - "production_over_time": "", - "psr_by_make": "", - "purchase_return_ratio_grouped_by_vendor_detail": "", - "purchase_return_ratio_grouped_by_vendor_summary": "", - "purchases_by_cost_center_detail": "", - "purchases_by_cost_center_summary": "", - "purchases_by_date_range_detail": "", - "purchases_by_date_range_summary": "", - "purchases_by_ro_detail_date": "", - "purchases_by_ro_summary_date": "", - "purchases_by_vendor_detailed_date_range": "", - "purchases_by_vendor_summary_date_range": "", - "purchases_grouped_by_vendor_detailed": "", - "purchases_grouped_by_vendor_summary": "", - "returns_grouped_by_vendor_detailed": "", - "returns_grouped_by_vendor_summary": "", - "schedule": "", - "scheduled_parts_list": "", - "scoreboard_detail": "", - "scoreboard_summary": "", - "supplement_ratio_ins_co": "", - "tasks_date": "", - "tasks_date_employee": "", - "thank_you_date": "", - "timetickets": "", - "timetickets_employee": "", - "timetickets_summary": "", - "unclaimed_hrs": "", - "void_ros": "", - "work_in_progress_committed_labour": "", - "work_in_progress_jobs": "", - "work_in_progress_labour": "", - "work_in_progress_payables": "" - } - }, - "schedule": { - "labels": { - "atssummary": "", - "employeevacation": "", - "estimators": "", - "ins_co_nm_filter": "", - "intake": "", - "manual": "", - "manualevent": "" - } - }, - "scoreboard": { - "actions": { - "edit": "" - }, - "errors": { - "adding": "", - "removing": "", - "updating": "" - }, - "fields": { - "bodyhrs": "", - "date": "", - "painthrs": "" - }, - "labels": { - "allemployeetimetickets": "", - "asoftodaytarget": "", - "body": "", - "bodyabbrev": "", - "bodycharttitle": "", - "calendarperiod": "", - "combinedcharttitle": "", - "dailyactual": "", - "dailytarget": "", - "efficiencyoverperiod": "", - "entries": "", - "jobs": "", - "jobscompletednotinvoiced": "", - "lastmonth": "", - "lastweek": "", - "monthlytarget": "", - "priorweek": "", - "productivestatistics": "", - "productivetimeticketsoverdate": "", - "refinish": "", - "refinishabbrev": "", - "refinishcharttitle": "", - "targets": "", - "thismonth": "", - "thisweek": "", - "timetickets": "", - "timeticketsemployee": "", - "todateactual": "", - "total": "", - "totalhrs": "", - "totaloverperiod": "", - "weeklyactual": "", - "weeklytarget": "", - "workingdays": "" - }, - "successes": { - "added": "", - "removed": "", - "updated": "" - } - }, - "tasks": { - "actions": { - "edit": "", - "new": "" - }, - "buttons": { - "allTasks": "", - "complete": "", - "create": "", - "delete": "", - "edit": "", - "myTasks": "", - "refresh": "" - }, - "date_presets": { - "completion": "", - "day": "", - "days": "", - "delivery": "", - "next_week": "", - "one_month": "", - "three_months": "", - "three_weeks": "", - "today": "", - "tomorrow": "", - "two_weeks": "" - }, - "failures": { - "completed": "", - "created": "", - "deleted": "", - "updated": "" - }, - "fields": { - "actions": "", - "assigned_to": "", - "bill": "", - "billid": "", - "completed": "", - "created_at": "", - "description": "", - "due_date": "", - "job": { - "ro_number": "" - }, - "jobid": "", - "jobline": "", - "joblineid": "", - "parts_order": "", - "partsorderid": "", - "priorities": { - "high": "", - "low": "", - "medium": "" - }, - "priority": "", - "remind_at": "", - "title": "" - }, - "placeholders": { - "assigned_to": "", - "billid": "", - "description": "", - "jobid": "", - "joblineid": "", - "partsorderid": "" - }, - "successes": { - "completed": "", - "created": "", - "deleted": "", - "updated": "" - }, - "titles": { - "all_tasks": "", - "completed": "", - "deleted": "", - "job_tasks": "", - "mine": "", - "my_tasks": "" - }, - "validation": { - "due_at_error_message": "", - "remind_at_error_message": "" - } - }, - "tech": { - "fields": { - "employeeid": "", - "pin": "" - }, - "labels": { - "loggedin": "", - "notloggedin": "" - } - }, - "templates": { - "errors": { - "updating": "" - }, - "successes": { - "updated": "" - } - }, - "timetickets": { - "actions": { - "claimtasks": "", - "clockin": "", - "clockout": "", - "commit": "", - "commitone": "", - "enter": "", - "payall": "", - "printemployee": "", - "uncommit": "" - }, - "errors": { - "clockingin": "", - "clockingout": "", - "creating": "", - "deleting": "", - "noemployeeforuser": "", - "noemployeeforuser_sub": "", - "payall": "", - "shiftalreadyclockedon": "" - }, - "fields": { - "actualhrs": "", - "ciecacode": "", - "clockhours": "", - "clockoff": "", - "clockon": "", - "committed": "", - "committed_at": "", - "cost_center": "", - "created_by": "", - "date": "", - "efficiency": "", - "employee": "", - "employee_team": "", - "flat_rate": "", - "memo": "", - "productivehrs": "", - "ro_number": "", - "task_name": "" - }, - "labels": { - "alreadyclockedon": "", - "ambreak": "", - "amshift": "", - "claimtaskpreview": "", - "clockhours": "", - "clockintojob": "", - "deleteconfirm": "", - "edit": "", - "efficiency": "", - "flat_rate": "", - "jobhours": "", - "lunch": "", - "new": "", - "payrollclaimedtasks": "", - "pmbreak": "", - "pmshift": "", - "shift": "", - "shiftalreadyclockedon": "", - "straight_time": "", - "task": "", - "timetickets": "", - "unassigned": "", - "zeroactualnegativeprod": "" - }, - "successes": { - "clockedin": "", - "clockedout": "", - "committed": "", - "created": "", - "deleted": "", - "payall": "" - }, - "validation": { - "clockoffmustbeafterclockon": "", - "clockoffwithoutclockon": "", - "hoursenteredmorethanavailable": "", - "unassignedlines": "" - } - }, - "titles": { - "accounting-payables": "", - "accounting-payments": "", - "accounting-receivables": "", - "all_tasks": "", - "app": "", - "bc": { - "accounting-payables": "", - "accounting-payments": "", - "accounting-receivables": "", - "all_tasks": "", - "availablejobs": "", - "bills-list": "", - "contracts": "", - "contracts-create": "", - "contracts-detail": "", - "courtesycars": "", - "courtesycars-detail": "", - "courtesycars-new": "", - "dashboard": "", - "dms": "", - "export-logs": "", - "inventory": "", - "jobs": "", - "jobs-active": "", - "jobs-admin": "", - "jobs-all": "", - "jobs-checklist": "", - "jobs-close": "", - "jobs-deliver": "", - "jobs-detail": "", - "jobs-intake": "", - "jobs-new": "", - "jobs-ready": "", - "my_tasks": "", - "owner-detail": "", - "owners": "", - "parts-queue": "", - "payments-all": "", - "phonebook": "", - "productionboard": "", - "productionlist": "", - "profile": "", - "schedule": "", - "scoreboard": "", - "shop": "", - "shop-csi": "", - "shop-templates": "", - "shop-vendors": "", - "tasks": "", - "temporarydocs": "", - "timetickets": "", - "ttapprovals": "", - "vehicle-details": "", - "vehicles": "" - }, - "bills-list": "", - "contracts": "", - "contracts-create": "", - "contracts-detail": "", - "courtesycars": "", - "courtesycars-create": "", - "courtesycars-detail": "", - "dashboard": "", - "dms": "", - "export-logs": "", - "imexonline": "", - "inventory": "", - "jobs": "Tous les emplois | {{app}}", - "jobs-admin": "", - "jobs-all": "", - "jobs-checklist": "", - "jobs-close": "", - "jobs-create": "", - "jobs-deliver": "", - "jobs-intake": "", - "jobsavailable": "Emplois disponibles | {{app}}", - "jobsdetail": "Travail {{ro_number}} | {{app}}", - "jobsdocuments": "Documents de travail {{ro_number}} | {{app}}", - "manageroot": "Accueil | {{app}}", - "my_tasks": "", - "owners": "Tous les propriétaires | {{app}}", - "owners-detail": "", - "parts-queue": "", - "payments-all": "", - "phonebook": "", - "productionboard": "", - "productionlist": "", - "profile": "Mon profil | {{app}}", - "promanager": "", - "readyjobs": "", - "resetpassword": "", - "resetpasswordvalidate": "", - "romeonline": "", - "schedule": "Horaire | {{app}}", - "scoreboard": "", - "shop": "Mon magasin | {{app}}", - "shop-csi": "", - "shop-templates": "", - "shop_vendors": "Vendeurs | {{app}}", - "tasks": "", - "techconsole": "{{app}}", - "techjobclock": "{{app}}", - "techjoblookup": "{{app}}", - "techshiftclock": "{{app}}", - "temporarydocs": "", - "timetickets": "", - "ttapprovals": "", - "vehicledetail": "Détails du véhicule {{vehicle} | {{app}}", - "vehicles": "Tous les véhicules | {{app}}" - }, - "trello": { - "labels": { - "add_card": "", - "add_lane": "", - "cancel": "", - "delete_lane": "", - "description": "", - "label": "", - "lane_actions": "", - "title": "" - } - }, - "tt_approvals": { - "actions": { - "approveselected": "" - }, - "labels": { - "approval_queue_in_use": "", - "calculate": "" - } - }, - "user": { - "actions": { - "changepassword": "", - "signout": "Déconnexion", - "updateprofile": "Mettre à jour le profil" - }, - "errors": { - "updating": "" - }, - "fields": { - "authlevel": "", - "displayname": "Afficher un nom", - "email": "", - "photourl": "URL de l'avatar" - }, - "labels": { - "actions": "", - "changepassword": "", - "profileinfo": "" - }, - "successess": { - "passwordchanged": "" - } - }, - "users": { - "errors": { - "signinerror": { - "auth/user-disabled": "", - "auth/user-not-found": "", - "auth/wrong-password": "" - } - } - }, - "vehicles": { - "errors": { - "deleting": "", - "noaccess": "Le véhicule n'existe pas ou vous n'y avez pas accès.", - "selectexistingornew": "", - "validation": "Veuillez vous assurer que tous les champs sont correctement entrés.", - "validationtitle": "Erreur de validation" - }, - "fields": { - "description": "Description du véhicule", - "notes": "", - "plate_no": "Plaque d'immatriculation", - "plate_st": "Juridiction de la plaque", - "trim_color": "Couleur de garniture", - "v_bstyle": "Style corporel", - "v_color": "Couleur", - "v_cond": "Etat", - "v_engine": "moteur", - "v_make_desc": "Faire", - "v_makecode": "Faire du code", - "v_mldgcode": "Code de moulage", - "v_model_desc": "Modèle", - "v_model_yr": "année", - "v_options": "Les options", - "v_paint_codes": "Codes de peinture", - "v_prod_dt": "Date de production", - "v_stage": "Étape", - "v_tone": "ton", - "v_trimcode": "Code de coupe", - "v_type": "Type", - "v_vin": "V.I.N." - }, - "forms": { - "detail": "", - "misc": "", - "registration": "" - }, - "labels": { - "deleteconfirm": "", - "fromvehicle": "", - "novehinfo": "", - "relatedjobs": "", - "updatevehicle": "" - }, - "successes": { - "delete": "", - "save": "Le véhicule a été enregistré avec succès." - } - }, - "vendors": { - "actions": { - "addtophonebook": "", - "new": "Nouveau vendeur", - "newpreferredmake": "" - }, - "errors": { - "deleting": "Erreur rencontrée lors de la suppression du fournisseur.", - "saving": "Erreur rencontrée lors de l'enregistrement du fournisseur." - }, - "fields": { - "active": "", - "am": "", - "city": "Ville", - "cost_center": "Centre de coûts", - "country": "Pays", - "discount": "Remise %", - "display_name": "Afficher un nom", - "dmsid": "", - "due_date": "Date limite de paiement", - "email": "Email du contact", - "favorite": "Préféré?", - "lkq": "", - "make": "", - "name": "Nom du vendeur", - "oem": "", - "phone": "", - "prompt_discount": "Remise rapide%", - "state": "Etat / Province", - "street1": "rue", - "street2": "Adresse 2 ", - "taxid": "Identifiant de taxe", - "terms": "Modalités de paiement", - "zip": "Zip / code postal" - }, - "labels": { - "noneselected": "Aucun fournisseur n'est sélectionné.", - "preferredmakes": "", - "search": "Tapez le nom d'un vendeur" - }, - "successes": { - "deleted": "Le fournisseur a bien été supprimé.", - "saved": "Le fournisseur a bien enregistré." - }, - "validation": { - "unique_vendor_name": "" - } - } - } + "successes": { + "removed": "" + } + }, + "profile": { + "errors": { + "state": "Erreur lors de la lecture de l'état de la page. Rafraichissez, s'il vous plait." + }, + "labels": { + "activeshop": "" + }, + "successes": { + "updated": "" + } + }, + "reportcenter": { + "actions": { + "generate": "" + }, + "labels": { + "advanced_filters": "", + "advanced_filters_false": "", + "advanced_filters_filter_field": "", + "advanced_filters_filter_operator": "", + "advanced_filters_filter_value": "", + "advanced_filters_filters": "", + "advanced_filters_hide": "", + "advanced_filters_show": "", + "advanced_filters_sorter_direction": "", + "advanced_filters_sorter_field": "", + "advanced_filters_sorters": "", + "advanced_filters_true": "", + "dates": "", + "employee": "", + "filterson": "", + "generateasemail": "", + "groups": { + "customers": "", + "jobs": "", + "payroll": "", + "purchases": "", + "sales": "" + }, + "key": "", + "objects": { + "appointments": "", + "bills": "", + "csi": "", + "exportlogs": "", + "jobs": "", + "parts_orders": "", + "payments": "", + "scoreboard": "", + "tasks": "", + "timetickets": "" + }, + "vendor": "" + }, + "templates": { + "adp_payroll_flat": "", + "adp_payroll_straight": "", + "anticipated_revenue": "", + "ar_aging": "", + "attendance_detail": "", + "attendance_employee": "", + "attendance_summary": "", + "committed_timetickets": "", + "committed_timetickets_employee": "", + "committed_timetickets_summary": "", + "credits_not_received_date": "", + "credits_not_received_date_vendorid": "", + "csi": "", + "customer_list": "", + "cycle_time_analysis": "", + "estimates_written_converted": "", + "estimator_detail": "", + "estimator_summary": "", + "export_payables": "", + "export_payments": "", + "export_receivables": "", + "exported_gsr_by_ro": "", + "exported_gsr_by_ro_labor": "", + "gsr_by_atp": "", + "gsr_by_ats": "", + "gsr_by_category": "", + "gsr_by_csr": "", + "gsr_by_delivery_date": "", + "gsr_by_estimator": "", + "gsr_by_exported_date": "", + "gsr_by_ins_co": "", + "gsr_by_make": "", + "gsr_by_referral": "", + "gsr_by_ro": "", + "gsr_labor_only": "", + "hours_sold_detail_closed": "", + "hours_sold_detail_closed_csr": "", + "hours_sold_detail_closed_estimator": "", + "hours_sold_detail_closed_ins_co": "", + "hours_sold_detail_closed_status": "", + "hours_sold_detail_open": "", + "hours_sold_detail_open_csr": "", + "hours_sold_detail_open_estimator": "", + "hours_sold_detail_open_ins_co": "", + "hours_sold_detail_open_status": "", + "hours_sold_summary_closed": "", + "hours_sold_summary_closed_csr": "", + "hours_sold_summary_closed_estimator": "", + "hours_sold_summary_closed_ins_co": "", + "hours_sold_summary_closed_status": "", + "hours_sold_summary_open": "", + "hours_sold_summary_open_csr": "", + "hours_sold_summary_open_estimator": "", + "hours_sold_summary_open_ins_co": "", + "hours_sold_summary_open_status": "", + "job_costing_ro_csr": "", + "job_costing_ro_date_detail": "", + "job_costing_ro_date_summary": "", + "job_costing_ro_estimator": "", + "job_costing_ro_ins_co": "", + "job_lifecycle_date_detail": "", + "job_lifecycle_date_summary": "", + "jobs_completed_not_invoiced": "", + "jobs_invoiced_not_exported": "", + "jobs_reconcile": "", + "jobs_scheduled_completion": "", + "lag_time": "", + "load_level": "", + "lost_sales": "", + "open_orders": "", + "open_orders_csr": "", + "open_orders_estimator": "", + "open_orders_excel": "", + "open_orders_ins_co": "", + "open_orders_referral": "", + "open_orders_specific_csr": "", + "open_orders_status": "", + "parts_backorder": "", + "parts_not_recieved": "", + "parts_not_recieved_vendor": "", + "parts_received_not_scheduled": "", + "payments_by_date": "", + "payments_by_date_payment": "", + "payments_by_date_type": "", + "production_by_category": "", + "production_by_category_one": "", + "production_by_csr": "", + "production_by_last_name": "", + "production_by_repair_status": "", + "production_by_repair_status_one": "", + "production_by_ro": "", + "production_by_target_date": "", + "production_by_technician": "", + "production_by_technician_one": "", + "production_not_production_status": "", + "production_over_time": "", + "psr_by_make": "", + "purchase_return_ratio_grouped_by_vendor_detail": "", + "purchase_return_ratio_grouped_by_vendor_summary": "", + "purchases_by_cost_center_detail": "", + "purchases_by_cost_center_summary": "", + "purchases_by_date_range_detail": "", + "purchases_by_date_range_summary": "", + "purchases_by_ro_detail_date": "", + "purchases_by_ro_summary_date": "", + "purchases_by_vendor_detailed_date_range": "", + "purchases_by_vendor_summary_date_range": "", + "purchases_grouped_by_vendor_detailed": "", + "purchases_grouped_by_vendor_summary": "", + "returns_grouped_by_vendor_detailed": "", + "returns_grouped_by_vendor_summary": "", + "schedule": "", + "scheduled_parts_list": "", + "scoreboard_detail": "", + "scoreboard_summary": "", + "supplement_ratio_ins_co": "", + "tasks_date": "", + "tasks_date_employee": "", + "thank_you_date": "", + "timetickets": "", + "timetickets_employee": "", + "timetickets_summary": "", + "unclaimed_hrs": "", + "void_ros": "", + "work_in_progress_committed_labour": "", + "work_in_progress_jobs": "", + "work_in_progress_labour": "", + "work_in_progress_payables": "" + } + }, + "schedule": { + "labels": { + "atssummary": "", + "employeevacation": "", + "estimators": "", + "ins_co_nm_filter": "", + "intake": "", + "manual": "", + "manualevent": "" + } + }, + "scoreboard": { + "actions": { + "edit": "" + }, + "errors": { + "adding": "", + "removing": "", + "updating": "" + }, + "fields": { + "bodyhrs": "", + "date": "", + "painthrs": "" + }, + "labels": { + "allemployeetimetickets": "", + "asoftodaytarget": "", + "body": "", + "bodyabbrev": "", + "bodycharttitle": "", + "calendarperiod": "", + "combinedcharttitle": "", + "dailyactual": "", + "dailytarget": "", + "efficiencyoverperiod": "", + "entries": "", + "jobs": "", + "jobscompletednotinvoiced": "", + "lastmonth": "", + "lastweek": "", + "monthlytarget": "", + "priorweek": "", + "productivestatistics": "", + "productivetimeticketsoverdate": "", + "refinish": "", + "refinishabbrev": "", + "refinishcharttitle": "", + "targets": "", + "thismonth": "", + "thisweek": "", + "timetickets": "", + "timeticketsemployee": "", + "todateactual": "", + "total": "", + "totalhrs": "", + "totaloverperiod": "", + "weeklyactual": "", + "weeklytarget": "", + "workingdays": "" + }, + "successes": { + "added": "", + "removed": "", + "updated": "" + } + }, + "tasks": { + "actions": { + "edit": "", + "new": "" + }, + "buttons": { + "allTasks": "", + "complete": "", + "create": "", + "delete": "", + "edit": "", + "myTasks": "", + "refresh": "" + }, + "date_presets": { + "completion": "", + "day": "", + "days": "", + "delivery": "", + "next_week": "", + "one_month": "", + "three_months": "", + "three_weeks": "", + "today": "", + "tomorrow": "", + "two_weeks": "" + }, + "failures": { + "completed": "", + "created": "", + "deleted": "", + "updated": "" + }, + "fields": { + "actions": "", + "assigned_to": "", + "bill": "", + "billid": "", + "completed": "", + "created_at": "", + "description": "", + "due_date": "", + "job": { + "ro_number": "" + }, + "jobid": "", + "jobline": "", + "joblineid": "", + "parts_order": "", + "partsorderid": "", + "priorities": { + "high": "", + "low": "", + "medium": "" + }, + "priority": "", + "remind_at": "", + "title": "" + }, + "placeholders": { + "assigned_to": "", + "billid": "", + "description": "", + "jobid": "", + "joblineid": "", + "partsorderid": "" + }, + "successes": { + "completed": "", + "created": "", + "deleted": "", + "updated": "" + }, + "titles": { + "all_tasks": "", + "completed": "", + "deleted": "", + "job_tasks": "", + "mine": "", + "my_tasks": "" + }, + "validation": { + "due_at_error_message": "", + "remind_at_error_message": "" + } + }, + "tech": { + "fields": { + "employeeid": "", + "pin": "" + }, + "labels": { + "loggedin": "", + "notloggedin": "" + } + }, + "templates": { + "errors": { + "updating": "" + }, + "successes": { + "updated": "" + } + }, + "timetickets": { + "actions": { + "claimtasks": "", + "clockin": "", + "clockout": "", + "commit": "", + "commitone": "", + "enter": "", + "payall": "", + "printemployee": "", + "uncommit": "" + }, + "errors": { + "clockingin": "", + "clockingout": "", + "creating": "", + "deleting": "", + "noemployeeforuser": "", + "noemployeeforuser_sub": "", + "payall": "", + "shiftalreadyclockedon": "" + }, + "fields": { + "actualhrs": "", + "ciecacode": "", + "clockhours": "", + "clockoff": "", + "clockon": "", + "committed": "", + "committed_at": "", + "cost_center": "", + "created_by": "", + "date": "", + "efficiency": "", + "employee": "", + "employee_team": "", + "flat_rate": "", + "memo": "", + "productivehrs": "", + "ro_number": "", + "task_name": "" + }, + "labels": { + "alreadyclockedon": "", + "ambreak": "", + "amshift": "", + "claimtaskpreview": "", + "clockhours": "", + "clockintojob": "", + "deleteconfirm": "", + "edit": "", + "efficiency": "", + "flat_rate": "", + "jobhours": "", + "lunch": "", + "new": "", + "payrollclaimedtasks": "", + "pmbreak": "", + "pmshift": "", + "shift": "", + "shiftalreadyclockedon": "", + "straight_time": "", + "task": "", + "timetickets": "", + "unassigned": "", + "zeroactualnegativeprod": "" + }, + "successes": { + "clockedin": "", + "clockedout": "", + "committed": "", + "created": "", + "deleted": "", + "payall": "" + }, + "validation": { + "clockoffmustbeafterclockon": "", + "clockoffwithoutclockon": "", + "hoursenteredmorethanavailable": "", + "unassignedlines": "" + } + }, + "titles": { + "accounting-payables": "", + "accounting-payments": "", + "accounting-receivables": "", + "all_tasks": "", + "app": "", + "bc": { + "accounting-payables": "", + "accounting-payments": "", + "accounting-receivables": "", + "all_tasks": "", + "availablejobs": "", + "bills-list": "", + "contracts": "", + "contracts-create": "", + "contracts-detail": "", + "courtesycars": "", + "courtesycars-detail": "", + "courtesycars-new": "", + "dashboard": "", + "dms": "", + "export-logs": "", + "inventory": "", + "jobs": "", + "jobs-active": "", + "jobs-admin": "", + "jobs-all": "", + "jobs-checklist": "", + "jobs-close": "", + "jobs-deliver": "", + "jobs-detail": "", + "jobs-intake": "", + "jobs-new": "", + "jobs-ready": "", + "my_tasks": "", + "owner-detail": "", + "owners": "", + "parts-queue": "", + "payments-all": "", + "phonebook": "", + "productionboard": "", + "productionlist": "", + "profile": "", + "schedule": "", + "scoreboard": "", + "shop": "", + "shop-csi": "", + "shop-templates": "", + "shop-vendors": "", + "tasks": "", + "temporarydocs": "", + "timetickets": "", + "ttapprovals": "", + "vehicle-details": "", + "vehicles": "" + }, + "bills-list": "", + "contracts": "", + "contracts-create": "", + "contracts-detail": "", + "courtesycars": "", + "courtesycars-create": "", + "courtesycars-detail": "", + "dashboard": "", + "dms": "", + "export-logs": "", + "imexonline": "", + "inventory": "", + "jobs": "Tous les emplois | {{app}}", + "jobs-admin": "", + "jobs-all": "", + "jobs-checklist": "", + "jobs-close": "", + "jobs-create": "", + "jobs-deliver": "", + "jobs-intake": "", + "jobsavailable": "Emplois disponibles | {{app}}", + "jobsdetail": "Travail {{ro_number}} | {{app}}", + "jobsdocuments": "Documents de travail {{ro_number}} | {{app}}", + "manageroot": "Accueil | {{app}}", + "my_tasks": "", + "owners": "Tous les propriétaires | {{app}}", + "owners-detail": "", + "parts-queue": "", + "payments-all": "", + "phonebook": "", + "productionboard": "", + "productionlist": "", + "profile": "Mon profil | {{app}}", + "promanager": "", + "readyjobs": "", + "resetpassword": "", + "resetpasswordvalidate": "", + "romeonline": "", + "schedule": "Horaire | {{app}}", + "scoreboard": "", + "shop": "Mon magasin | {{app}}", + "shop-csi": "", + "shop-templates": "", + "shop_vendors": "Vendeurs | {{app}}", + "tasks": "", + "techconsole": "{{app}}", + "techjobclock": "{{app}}", + "techjoblookup": "{{app}}", + "techshiftclock": "{{app}}", + "temporarydocs": "", + "timetickets": "", + "ttapprovals": "", + "vehicledetail": "Détails du véhicule {{vehicle} | {{app}}", + "vehicles": "Tous les véhicules | {{app}}" + }, + "trello": { + "labels": { + "add_card": "", + "add_lane": "", + "cancel": "", + "delete_lane": "", + "description": "", + "label": "", + "lane_actions": "", + "title": "" + } + }, + "tt_approvals": { + "actions": { + "approveselected": "" + }, + "labels": { + "approval_queue_in_use": "", + "calculate": "" + } + }, + "user": { + "actions": { + "changepassword": "", + "signout": "Déconnexion", + "updateprofile": "Mettre à jour le profil" + }, + "errors": { + "updating": "" + }, + "fields": { + "authlevel": "", + "displayname": "Afficher un nom", + "email": "", + "photourl": "URL de l'avatar" + }, + "labels": { + "actions": "", + "changepassword": "", + "profileinfo": "" + }, + "successess": { + "passwordchanged": "" + } + }, + "users": { + "errors": { + "signinerror": { + "auth/user-disabled": "", + "auth/user-not-found": "", + "auth/wrong-password": "" + } + } + }, + "vehicles": { + "errors": { + "deleting": "", + "noaccess": "Le véhicule n'existe pas ou vous n'y avez pas accès.", + "selectexistingornew": "", + "validation": "Veuillez vous assurer que tous les champs sont correctement entrés.", + "validationtitle": "Erreur de validation" + }, + "fields": { + "description": "Description du véhicule", + "notes": "", + "plate_no": "Plaque d'immatriculation", + "plate_st": "Juridiction de la plaque", + "trim_color": "Couleur de garniture", + "v_bstyle": "Style corporel", + "v_color": "Couleur", + "v_cond": "Etat", + "v_engine": "moteur", + "v_make_desc": "Faire", + "v_makecode": "Faire du code", + "v_mldgcode": "Code de moulage", + "v_model_desc": "Modèle", + "v_model_yr": "année", + "v_options": "Les options", + "v_paint_codes": "Codes de peinture", + "v_prod_dt": "Date de production", + "v_stage": "Étape", + "v_tone": "ton", + "v_trimcode": "Code de coupe", + "v_type": "Type", + "v_vin": "V.I.N." + }, + "forms": { + "detail": "", + "misc": "", + "registration": "" + }, + "labels": { + "deleteconfirm": "", + "fromvehicle": "", + "novehinfo": "", + "relatedjobs": "", + "updatevehicle": "" + }, + "successes": { + "delete": "", + "save": "Le véhicule a été enregistré avec succès." + } + }, + "vendors": { + "actions": { + "addtophonebook": "", + "new": "Nouveau vendeur", + "newpreferredmake": "" + }, + "errors": { + "deleting": "Erreur rencontrée lors de la suppression du fournisseur.", + "saving": "Erreur rencontrée lors de l'enregistrement du fournisseur." + }, + "fields": { + "active": "", + "am": "", + "city": "Ville", + "cost_center": "Centre de coûts", + "country": "Pays", + "discount": "Remise %", + "display_name": "Afficher un nom", + "dmsid": "", + "due_date": "Date limite de paiement", + "email": "Email du contact", + "favorite": "Préféré?", + "lkq": "", + "make": "", + "name": "Nom du vendeur", + "oem": "", + "phone": "", + "prompt_discount": "Remise rapide%", + "state": "Etat / Province", + "street1": "rue", + "street2": "Adresse 2 ", + "taxid": "Identifiant de taxe", + "terms": "Modalités de paiement", + "zip": "Zip / code postal" + }, + "labels": { + "noneselected": "Aucun fournisseur n'est sélectionné.", + "preferredmakes": "", + "search": "Tapez le nom d'un vendeur" + }, + "successes": { + "deleted": "Le fournisseur a bien été supprimé.", + "saved": "Le fournisseur a bien enregistré." + }, + "validation": { + "unique_vendor_name": "" + } + } + } } diff --git a/client/src/utils/TemplateConstants.js b/client/src/utils/TemplateConstants.js index 4fdcf6e3e..9f80986d2 100644 --- a/client/src/utils/TemplateConstants.js +++ b/client/src/utils/TemplateConstants.js @@ -2333,6 +2333,14 @@ export const TemplateList = (type, context) => { key: "production_by_technician", //idtype: "vendor", disabled: false + }, + production_not_production_status: { + title: i18n.t("reportcenter.templates.production_not_production_status"), + description: "", + subject: i18n.t("reportcenter.templates.production_not_production_status"), + key: "production_not_production_status", + //idtype: "vendor", + disabled: false } } : {}), From 2d3c13c587ac5633802f99358f13829aa77ea3b6 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Thu, 24 Oct 2024 11:50:54 -0700 Subject: [PATCH 36/79] IO-2998 Add winston and replace logger.js --- package-lock.json | 177 +++++++++++++++++--- package.json | 2 + server/accounting/pbs/pbs-ap-allocations.js | 4 +- server/accounting/pbs/pbs-job-export.js | 4 +- server/accounting/qb-receivables-lines.js | 10 +- server/accounting/qbo/qbo-payables.js | 2 +- server/accounting/qbo/qbo-payments.js | 2 +- server/accounting/qbo/qbo-receivables.js | 2 +- server/admin/adminops.js | 8 +- server/cdk/cdk-calculate-allocations.js | 8 +- server/data/arms.js | 7 +- server/data/autohouse.js | 3 - server/firebase/firebase-handler.js | 16 +- server/utils/logger.js | 69 ++++++-- server/web-sockets/web-socket.js | 2 +- 15 files changed, 242 insertions(+), 74 deletions(-) diff --git a/package-lock.json b/package-lock.json index 822bb487e..1b282208a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,6 +56,8 @@ "ssh2-sftp-client": "^10.0.3", "twilio": "^4.23.0", "uuid": "^10.0.0", + "winston": "^3.15.0", + "winston-cloudwatch": "^6.3.0", "xml2js": "^0.6.2", "xmlbuilder2": "^3.1.1" }, @@ -1705,6 +1707,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", "engines": { "node": ">=0.1.90" } @@ -3158,7 +3161,8 @@ "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" }, "node_modules/@xmldom/is-dom-node": { "version": "1.0.1", @@ -3185,7 +3189,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "optional": true, "dependencies": { "event-target-shim": "^5.0.0" }, @@ -3398,8 +3401,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "optional": true + ] }, "node_modules/base64id": { "version": "2.0.0", @@ -3537,6 +3539,30 @@ "node": ">= 0.4.0" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -3612,7 +3638,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3628,7 +3653,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -4605,11 +4629,19 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "optional": true, "engines": { "node": ">=6" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/express": { "version": "4.21.0", "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", @@ -4769,7 +4801,8 @@ "node_modules/fecha": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" }, "node_modules/file-uri-to-path": { "version": "2.0.0", @@ -5345,7 +5378,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -5501,6 +5533,26 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -5911,6 +5963,12 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", + "license": "MIT" + }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -5928,6 +5986,12 @@ "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "license": "MIT" }, + "node_modules/lodash.find": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz", + "integrity": "sha512-yaRZoAV3Xq28F1iafWN1+a0rflOej93l1DQUejs3SZ41h2O9UJBoS9aueGjPDgAl4B6tPC0NuuchLKaDQQ3Isg==", + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -5944,6 +6008,18 @@ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" }, + "node_modules/lodash.isempty": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", + "integrity": "sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg==", + "license": "MIT" + }, + "node_modules/lodash.iserror": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.iserror/-/lodash.iserror-3.1.1.tgz", + "integrity": "sha512-eT/VeNns9hS7vAj1NKW/rRX6b+C3UX3/IAAqEE7aC4Oo2C0iD82NaP5IS4bSlQsammTii4qBJ8G1zd1LTL8hCw==", + "license": "MIT" + }, "node_modules/lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", @@ -5970,9 +6046,10 @@ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", + "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", + "license": "MIT", "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -6635,6 +6712,15 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -6978,9 +7064,10 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", "engines": { "node": ">=10" } @@ -7952,6 +8039,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", "engines": { "node": ">= 14.0.0" } @@ -8191,39 +8279,76 @@ } }, "node_modules/winston": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", - "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.15.0.tgz", + "integrity": "sha512-RhruH2Cj0bV0WgNL+lOfoUBI4DVfdUNjVnJGVovWZmrcKtrFTTRzgXYK2O9cymSGjrERCtaAeHwMNnUWXlwZow==", + "license": "MIT", "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", - "logform": "^2.4.0", + "logform": "^2.6.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", - "winston-transport": "^4.5.0" + "winston-transport": "^4.7.0" }, "engines": { "node": ">= 12.0.0" } }, - "node_modules/winston-transport": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", - "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", + "node_modules/winston-cloudwatch": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/winston-cloudwatch/-/winston-cloudwatch-6.3.0.tgz", + "integrity": "sha512-ffLMBUtas4qCpAyNfA6yUjZUQPepl6XduwHjukxRtI8hSWE4dKmy1k1lcLpyYiglrsgZop+OQYAV/iJJ+7Z94g==", + "license": "MIT", "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", + "async": "^3.1.0", + "chalk": "^4.0.0", + "fast-safe-stringify": "^2.0.7", + "lodash.assign": "^4.2.0", + "lodash.find": "^4.6.0", + "lodash.isempty": "^4.4.0", + "lodash.iserror": "^3.1.1" + }, + "peerDependencies": { + "@aws-sdk/client-cloudwatch-logs": "^3.0.0", + "winston": "^3.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.8.0.tgz", + "integrity": "sha512-qxSTKswC6llEMZKgCQdaWgDuMJQnhuvF5f2Nk3SNXc4byfQ+voo2mX1Px9dkNOuR8p0KAjfPG29PuYUSIb+vSA==", + "license": "MIT", + "dependencies": { + "logform": "^2.6.1", + "readable-stream": "^4.5.2", "triple-beam": "^1.3.0" }, "engines": { "node": ">= 12.0.0" } }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index b170d0045..c8c5c38b4 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,8 @@ "ssh2-sftp-client": "^10.0.3", "twilio": "^4.23.0", "uuid": "^10.0.0", + "winston": "^3.15.0", + "winston-cloudwatch": "^6.3.0", "xml2js": "^0.6.2", "xmlbuilder2": "^3.1.1" }, diff --git a/server/accounting/pbs/pbs-ap-allocations.js b/server/accounting/pbs/pbs-ap-allocations.js index 3b8a20996..269e22c4f 100644 --- a/server/accounting/pbs/pbs-ap-allocations.js +++ b/server/accounting/pbs/pbs-ap-allocations.js @@ -24,7 +24,7 @@ axios.interceptors.request.use((x) => { const printable = `${new Date()} | Request: ${x.method.toUpperCase()} | ${ x.url } | ${JSON.stringify(x.data)} | ${JSON.stringify(headers)}`; - console.log(printable); + //console.log(printable); CdkBase.createJsonEvent(socket, "TRACE", `Raw Request: ${printable}`, x.data); @@ -35,7 +35,7 @@ axios.interceptors.response.use((x) => { const socket = x.config.socket; const printable = `${new Date()} | Response: ${x.status} | ${JSON.stringify(x.data)}`; - console.log(printable); + //console.log(printable); CdkBase.createJsonEvent(socket, "TRACE", `Raw Response: ${printable}`, x.data); return x; diff --git a/server/accounting/pbs/pbs-job-export.js b/server/accounting/pbs/pbs-job-export.js index b43aa0e3b..34db63a17 100644 --- a/server/accounting/pbs/pbs-job-export.js +++ b/server/accounting/pbs/pbs-job-export.js @@ -26,7 +26,7 @@ axios.interceptors.request.use((x) => { const printable = `${new Date()} | Request: ${x.method.toUpperCase()} | ${ x.url } | ${JSON.stringify(x.data)} | ${JSON.stringify(headers)}`; - console.log(printable); + //console.log(printable); CdkBase.createJsonEvent(socket, "TRACE", `Raw Request: ${printable}`, x.data); @@ -37,7 +37,7 @@ axios.interceptors.response.use((x) => { const socket = x.config.socket; const printable = `${new Date()} | Response: ${x.status} | ${JSON.stringify(x.data)}`; - console.log(printable); + //console.log(printable); CdkBase.createJsonEvent(socket, "TRACE", `Raw Response: ${printable}`, x.data); return x; diff --git a/server/accounting/qb-receivables-lines.js b/server/accounting/qb-receivables-lines.js index 0dedb4472..8476ce6d4 100644 --- a/server/accounting/qb-receivables-lines.js +++ b/server/accounting/qb-receivables-lines.js @@ -207,7 +207,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes }); if (!hasMapaLine && jobs_by_pk.job_totals.rates.mapa.total.amount > 0) { - // console.log("Adding MAPA Line Manually."); + // //console.log("Adding MAPA Line Manually."); const mapaAccountName = responsibilityCenters.defaults.profits.MAPA; const mapaAccount = responsibilityCenters.profits.find((c) => c.name === mapaAccountName); @@ -272,12 +272,12 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes }); } } else { - //console.log("NO MAPA ACCOUNT FOUND!!"); + ////console.log("NO MAPA ACCOUNT FOUND!!"); } } if (!hasMashLine && jobs_by_pk.job_totals.rates.mash.total.amount > 0) { - // console.log("Adding MASH Line Manually."); + // //console.log("Adding MASH Line Manually."); const mashAccountName = responsibilityCenters.defaults.profits.MASH; @@ -341,7 +341,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes }); } } else { - // console.log("NO MASH ACCOUNT FOUND!!"); + // //console.log("NO MASH ACCOUNT FOUND!!"); } } @@ -795,7 +795,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes : taxCodes[taxAccountCode]; for (let tyCounter = 1; tyCounter <= 5; tyCounter++) { const taxAmount = Dinero(job_totals.totals.us_sales_tax_breakdown[`ty${tyCounter}Tax`]); - console.log(`Tax ${tyCounter}`, taxAmount.toFormat()); + //console.log(`Tax ${tyCounter}`, taxAmount.toFormat()); if (taxAmount.getAmount() > 0) { if (qbo) { InvoiceLineAdd.push({ diff --git a/server/accounting/qbo/qbo-payables.js b/server/accounting/qbo/qbo-payables.js index c0673cbc5..9b5cf2558 100644 --- a/server/accounting/qbo/qbo-payables.js +++ b/server/accounting/qbo/qbo-payables.js @@ -121,7 +121,7 @@ exports.default = async (req, res) => { res.status(200).json(ret); } catch (error) { - console.log(error); + //console.log(error); logger.log("qbo-payable-create-error", "ERROR", req.user.email, { error: error.message, stack: error.stack diff --git a/server/accounting/qbo/qbo-payments.js b/server/accounting/qbo/qbo-payments.js index 436efca71..b5d884f02 100644 --- a/server/accounting/qbo/qbo-payments.js +++ b/server/accounting/qbo/qbo-payments.js @@ -182,7 +182,7 @@ exports.default = async (req, res) => { res.status(200).json(ret); } catch (error) { - console.log(error); + //console.log(error); logger.log("qbo-payment-create-error", "ERROR", req.user.email, { error: error.message, stack: error.stack diff --git a/server/accounting/qbo/qbo-receivables.js b/server/accounting/qbo/qbo-receivables.js index 51aeade0f..38edd0af9 100644 --- a/server/accounting/qbo/qbo-receivables.js +++ b/server/accounting/qbo/qbo-receivables.js @@ -185,7 +185,7 @@ exports.default = async (req, res) => { error?.response?.data || error?.message }); - console.log(error); + //console.log(error); logger.log("qbo-receivable-create-error", "ERROR", req.user.email, { error: error.message, stack: error.stack diff --git a/server/admin/adminops.js b/server/admin/adminops.js index 7e8b1c676..d134bdcba 100644 --- a/server/admin/adminops.js +++ b/server/admin/adminops.js @@ -9,7 +9,7 @@ require("dotenv").config({ const client = require("../graphql-client/graphql-client").client; exports.createAssociation = async (req, res) => { - logger.log("admin-create-association", "ADMIN", req.user.email, null, { + logger.log("admin-create-association", "debug", req.user.email, null, { request: req.body, ioadmin: true }); @@ -31,7 +31,7 @@ exports.createAssociation = async (req, res) => { res.json(result); }; exports.createShop = async (req, res) => { - logger.log("admin-create-shop", "ADMIN", req.user.email, null, { + logger.log("admin-create-shop", "debug", req.user.email, null, { request: req.body, ioadmin: true }); @@ -64,7 +64,7 @@ exports.createShop = async (req, res) => { } }; exports.updateCounter = async (req, res) => { - logger.log("admin-update-counter", "ADMIN", req.user.email, null, { + logger.log("admin-update-counter", "debug", req.user.email, null, { request: req.body, ioadmin: true }); @@ -91,7 +91,7 @@ exports.updateCounter = async (req, res) => { } }; exports.updateShop = async (req, res) => { - logger.log("admin-update-shop", "ADMIN", req.user.email, null, { + logger.log("admin-update-shop", "debug", req.user.email, null, { request: req.body, ioadmin: true }); diff --git a/server/cdk/cdk-calculate-allocations.js b/server/cdk/cdk-calculate-allocations.js index ddac4ee4c..afe9549ea 100644 --- a/server/cdk/cdk-calculate-allocations.js +++ b/server/cdk/cdk-calculate-allocations.js @@ -22,7 +22,7 @@ exports.defaultRoute = async function (req, res) { const jobData = await QueryJobData(req, req.BearerToken, req.body.jobid); return res.status(200).json({ data: calculateAllocations(req, jobData) }); } catch (error) { - console.log(error); + ////console.log(error); CdkBase.createLogEvent(req, "ERROR", `Error encountered in CdkCalculateAllocations. ${error}`); res.status(500).json({ error: `Error encountered in CdkCalculateAllocations. ${error}` }); } @@ -33,7 +33,7 @@ exports.default = async function (socket, jobid) { const jobData = await QueryJobData(socket, "Bearer " + socket.handshake.auth.token, jobid); return calculateAllocations(socket, jobData); } catch (error) { - console.log(error); + ////console.log(error); CdkBase.createLogEvent(socket, "ERROR", `Error encountered in CdkCalculateAllocations. ${error}`); } }; @@ -212,7 +212,7 @@ function calculateAllocations(connectionData, job) { }); if (!hasMapaLine && job.job_totals.rates.mapa.total.amount > 0) { - // console.log("Adding MAPA Line Manually."); + // //console.log("Adding MAPA Line Manually."); const mapaAccountName = selectedDmsAllocationConfig.profits.MAPA; const mapaAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mapaAccountName); @@ -224,7 +224,7 @@ function calculateAllocations(connectionData, job) { Dinero(job.job_totals.rates.mapa.total) ); } else { - //console.log("NO MAPA ACCOUNT FOUND!!"); + ////console.log("NO MAPA ACCOUNT FOUND!!"); } } diff --git a/server/data/arms.js b/server/data/arms.js index ec3d026e8..70ad3be5e 100644 --- a/server/data/arms.js +++ b/server/data/arms.js @@ -820,7 +820,7 @@ exports.default = async (req, res) => { job: JSON.stringify({ id: job.id, ro_number: job.ro_number }), error: error.message || JSON.stringify(error) }); - console.log(error); + //console.log(error); } } catch (error) { logger.log("arms-failed-job", "ERROR", "api", job.shopid, { @@ -886,7 +886,10 @@ exports.default = async (req, res) => { const [result, rawResponse, , rawRequest] = entegralResponse; } catch (error) { fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml); - console.log(error); + //console.log(error); + logger.log("arms-error-shop", "ERROR", "api", bodyshop.id, { + error + }); } } catch (error) { //Error at the shop level. diff --git a/server/data/autohouse.js b/server/data/autohouse.js index fa52679df..9b6494e67 100644 --- a/server/data/autohouse.js +++ b/server/data/autohouse.js @@ -206,9 +206,6 @@ const CreateRepairOrderTag = (job, errorCallback) => { const repairCosts = CreateCosts(job); - if (job.ro_number === "QBD209") { - console.log("Stop here"); - } //Calculate detail only lines. const detailAdjustments = job.joblines .filter((jl) => jl.ah_detail_line && jl.mod_lbr_ty) diff --git a/server/firebase/firebase-handler.js b/server/firebase/firebase-handler.js index 2590e6f57..ec20114f9 100644 --- a/server/firebase/firebase-handler.js +++ b/server/firebase/firebase-handler.js @@ -16,7 +16,7 @@ admin.initializeApp({ }); const createUser = async (req, res) => { - logger.log("admin-create-user", "ADMIN", req.user.email, null, { + logger.log("admin-create-user", "debug", req.user.email, null, { request: req.body, ioadmin: true }); @@ -97,7 +97,7 @@ const sendPromanagerWelcomeEmail = (req, res) => { // Validate email before proceeding if (!dbUser.validemail) { - logger.log("admin-send-welcome-email-skip", "ADMIN", req.user.email, null, { + logger.log("admin-send-welcome-email-skip", "debug", req.user.email, null, { message: "User email is not valid, skipping email.", email }); @@ -107,7 +107,7 @@ const sendPromanagerWelcomeEmail = (req, res) => { // Check if the user's company is ProManager const convenientCompany = dbUser.associations?.[0]?.bodyshop?.convenient_company; if (convenientCompany !== "promanager") { - logger.log("admin-send-welcome-email-skip", "ADMIN", req.user.email, null, { + logger.log("admin-send-welcome-email-skip", "debug", req.user.email, null, { message: 'convenient_company is not "promanager", skipping email.', convenientCompany }); @@ -141,7 +141,7 @@ const sendPromanagerWelcomeEmail = (req, res) => { }) .then(() => { // Log success and return response - logger.log("admin-send-welcome-email", "ADMIN", req.user.email, null, { + logger.log("admin-send-welcome-email", "debug", req.user.email, null, { request: req.body, ioadmin: true, emailSentTo: email @@ -161,7 +161,7 @@ const sendPromanagerWelcomeEmail = (req, res) => { }; const updateUser = (req, res) => { - logger.log("admin-update-user", "ADMIN", req.user.email, null, { + logger.log("admin-update-user", "debug", req.user.email, null, { request: req.body, ioadmin: true }); @@ -184,7 +184,7 @@ const updateUser = (req, res) => { .then((userRecord) => { // See the UserRecord reference doc for the contents of userRecord. - logger.log("admin-update-user-success", "ADMIN", req.user.email, null, { + logger.log("admin-update-user-success", "debug", req.user.email, null, { userRecord, ioadmin: true }); @@ -199,7 +199,7 @@ const updateUser = (req, res) => { }; const getUser = (req, res) => { - logger.log("admin-get-user", "ADMIN", req.user.email, null, { + logger.log("admin-get-user", "debug", req.user.email, null, { request: req.body, ioadmin: true }); @@ -321,7 +321,7 @@ module.exports = { // admin.auth().setCustomUserClaims(uid, { // ioadmin: true, // "https://hasura.io/jwt/claims": { -// "x-hasura-default-role": "admin", +// "x-hasura-default-role": "debug", // "x-hasura-allowed-roles": ["admin"], // "x-hasura-user-id": uid, // }, diff --git a/server/utils/logger.js b/server/utils/logger.js index 357dcba3d..0b7b9b0e4 100644 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -1,25 +1,66 @@ const graylog2 = require("graylog2"); +const InstanceManager = require("../utils/instanceMgr").default; const logger = new graylog2.graylog({ servers: [{ host: "logs.bodyshop.app", port: 12201 }] }); +const winston = require("winston"); +const WinstonCloudWatch = require("winston-cloudwatch"); + +const region = InstanceManager({ + imex: "ca-central-1", + rome: "us-east-2" +}); + +const logGroupName = process.env.CLOUDWATCH_LOG_GROUP; + +const winstonLogger = winston.createLogger({ + //level: "debug", + format: winston.format.json(), + transports: [ + ...(process.env.NODE_ENV !== "production" ? [new winston.transports.Console({ level: "silly" })] : []), + new WinstonCloudWatch({ + level: "error", + logGroupName: logGroupName, + logStreamName: "errors", + awsRegion: region, + jsonMessage: true + }), + new WinstonCloudWatch({ + level: "warn", + logGroupName: logGroupName, + logStreamName: "warn", + awsRegion: region, + jsonMessage: true + }), + new WinstonCloudWatch({ + level: "debug", + logGroupName: logGroupName, + logStreamName: "debug", + awsRegion: region, + jsonMessage: true + }) + ] +}); + function log(message, type, user, record, object) { - if (type !== "ioevent") - console.log(message, { - type, - env: process.env.NODE_ENV || "development", - user, - record, - ...object - }); - logger.log(message, message, { - type, - env: process.env.NODE_ENV || "development", - user, - record, - ...object + // winstonLogger.debug(message, user, record, object); + + winstonLogger.log({ + level: type.toLowerCase(), + message: message, + user: user, + record: record, + object: object }); + // logger.log(message, message, { + // type, + // env: process.env.NODE_ENV || "development", + // user, + // record, + // ...object + // }); } module.exports = { log }; diff --git a/server/web-sockets/web-socket.js b/server/web-sockets/web-socket.js index c19f77dcb..ef6e6dc13 100644 --- a/server/web-sockets/web-socket.js +++ b/server/web-sockets/web-socket.js @@ -122,7 +122,7 @@ io.on("connection", (socket) => { function createLogEvent(socket, level, message) { if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy(level)) { - console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`); + // console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`); socket.emit("log-event", { timestamp: new Date(), level, From 8dc1f7e08f6d94035025bc04933de2254e4b41d1 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Thu, 24 Oct 2024 12:18:39 -0700 Subject: [PATCH 37/79] IO-2998 remove graylog and additional erroneous console logs. --- package-lock.json | 9 --- package.json | 1 - server/accounting/qbo/qbo-receivables.js | 2 +- server/intellipay/intellipay.js | 6 +- server/ioevent/ioevent.js | 8 +-- server/job/job-totals-USA.js | 12 ++-- server/job/job-totals.js | 2 +- server/opensearch/os-handler.js | 4 +- server/render/canvas-handler.js | 7 ++- server/sms/receive.js | 13 +++- server/utils/logger.js | 79 +++++++++++++----------- server/web-sockets/redisSocketEvents.js | 4 +- server/web-sockets/web-socket.js | 4 +- 13 files changed, 78 insertions(+), 73 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1b282208a..f419a5f3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,6 @@ "firebase-admin": "^12.5.0", "graphql": "^16.9.0", "graphql-request": "^6.1.0", - "graylog2": "^0.2.1", "inline-css": "^4.0.2", "intuit-oauth": "^4.1.2", "ioredis": "^5.4.1", @@ -5338,14 +5337,6 @@ "graphql": "14 - 16" } }, - "node_modules/graylog2": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/graylog2/-/graylog2-0.2.1.tgz", - "integrity": "sha512-vjysakwOhrAqMeIvSK0WZcmzKvkpxY6pCfT9QqtdSVAidPFIynuin7adqbdFp9MCCTbTE402WIxvg8cph5OWTA==", - "engines": { - "node": ">=0.6.11" - } - }, "node_modules/gtoken": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.0.1.tgz", diff --git a/package.json b/package.json index c8c5c38b4..589b49295 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "firebase-admin": "^12.5.0", "graphql": "^16.9.0", "graphql-request": "^6.1.0", - "graylog2": "^0.2.1", "inline-css": "^4.0.2", "intuit-oauth": "^4.1.2", "ioredis": "^5.4.1", diff --git a/server/accounting/qbo/qbo-receivables.js b/server/accounting/qbo/qbo-receivables.js index 38edd0af9..f57c6711a 100644 --- a/server/accounting/qbo/qbo-receivables.js +++ b/server/accounting/qbo/qbo-receivables.js @@ -211,7 +211,7 @@ exports.default = async (req, res) => { res.status(200).json(ret); } catch (error) { - console.log(error); + //console.log(error); logger.log("qbo-receivable-create-error", "ERROR", req.user.email, { error: error.message, stack: error.stack diff --git a/server/intellipay/intellipay.js b/server/intellipay/intellipay.js index 3c6289b9b..c231f8261 100644 --- a/server/intellipay/intellipay.js +++ b/server/intellipay/intellipay.js @@ -78,7 +78,7 @@ exports.lightbox_credentials = async (req, res) => { res.send(response.data); } catch (error) { - console.log(error); + //console.log(error); logger.log("intellipay-lightbox-credentials-error", "ERROR", req.user?.email, null, { error: JSON.stringify(error) }); @@ -109,7 +109,7 @@ exports.payment_refund = async (req, res) => { res.send(response.data); } catch (error) { - console.log(error); + //console.log(error); logger.log("intellipay-refund-error", "ERROR", req.user?.email, null, { error: JSON.stringify(error) }); @@ -143,7 +143,7 @@ exports.generate_payment_url = async (req, res) => { res.send(response.data); } catch (error) { - console.log(error); + //console.log(error); logger.log("intellipay-payment-url-error", "ERROR", req.user?.email, null, { error: JSON.stringify(error) }); diff --git a/server/ioevent/ioevent.js b/server/ioevent/ioevent.js index a657e31d8..5d4223f73 100644 --- a/server/ioevent/ioevent.js +++ b/server/ioevent/ioevent.js @@ -28,10 +28,10 @@ exports.default = async (req, res) => { // } // }); - ioRedis.to(getBodyshopRoom(bodyshopid)).emit("bodyshop-message", { - operationName, - useremail - }); + // ioRedis.to(getBodyshopRoom(bodyshopid)).emit("bodyshop-message", { + // operationName, + // useremail + // }); res.sendStatus(200); } catch (error) { diff --git a/server/job/job-totals-USA.js b/server/job/job-totals-USA.js index ca9a74bca..4e123850e 100644 --- a/server/job/job-totals-USA.js +++ b/server/job/job-totals-USA.js @@ -866,8 +866,8 @@ function CalculateTaxesTotals(job, otherTotals) { } }); - console.log("*** Taxable Amounts***"); - console.table(JSON.parse(JSON.stringify(taxableAmounts))); + // console.log("*** Taxable Amounts***"); + // console.table(JSON.parse(JSON.stringify(taxableAmounts))); //For the taxable amounts, figure out which tax type applies. //Then sum up the total of that tax type and then calculate the thresholds. @@ -979,8 +979,8 @@ function CalculateTaxesTotals(job, otherTotals) { } const remainingTaxableAmounts = taxableAmountsByTier; - console.log("*** Taxable Amounts by Tier***"); - console.table(JSON.parse(JSON.stringify(taxableAmountsByTier))); + // console.log("*** Taxable Amounts by Tier***"); + // console.table(JSON.parse(JSON.stringify(taxableAmountsByTier))); Object.keys(taxableAmountsByTier).forEach((taxTierKey) => { try { @@ -1030,8 +1030,8 @@ function CalculateTaxesTotals(job, otherTotals) { } }); - console.log("*** Total Tax by Tier Amounts***"); - console.table(JSON.parse(JSON.stringify(totalTaxByTier))); + // console.log("*** Total Tax by Tier Amounts***"); + // console.table(JSON.parse(JSON.stringify(totalTaxByTier))); stateTax = stateTax .add(totalTaxByTier.ty1Tax) diff --git a/server/job/job-totals.js b/server/job/job-totals.js index 079f54cba..4cd45e13c 100644 --- a/server/job/job-totals.js +++ b/server/job/job-totals.js @@ -182,7 +182,7 @@ async function AutoAddAtsIfRequired({ job, client }) { job.joblines[atsLineIndex].act_price = atsAmount; } - console.log(job.jobLines); + //console.log(job.jobLines); } } diff --git a/server/opensearch/os-handler.js b/server/opensearch/os-handler.js index ba35eebd9..930933373 100644 --- a/server/opensearch/os-handler.js +++ b/server/opensearch/os-handler.js @@ -148,7 +148,7 @@ async function OpenSearchUpdateHandler(req, res) { }; const response = await osClient.index(payload); - console.log(response.body); + //console.log(response.body); res.status(200).json(response.body); } } catch (error) { @@ -255,7 +255,7 @@ async function OpenSearchSearchHandler(req, res) { res.json(body); } catch (error) { - console.log(error); + //console.log(error); logger.log("os-search-error", "ERROR", req.user.email, null, { error: JSON.stringify(error) }); diff --git a/server/render/canvas-handler.js b/server/render/canvas-handler.js index 010a3bec3..0af2a7f53 100644 --- a/server/render/canvas-handler.js +++ b/server/render/canvas-handler.js @@ -1,18 +1,19 @@ const { createCanvas } = require("canvas"); const Chart = require("chart.js/auto"); +const logger = require("../utils/logger"); const { backgroundColors, borderColors } = require("./canvas-colors"); const { isObject, defaultsDeep, isNumber } = require("lodash"); exports.canvastest = function (req, res) { - console.log("Incoming test request.", req); + //console.log("Incoming test request.", req); res.status(200).send("OK"); }; exports.canvas = function (req, res) { const { w, h, values, keys, override } = req.body; - console.log("Incoming Canvas Request:", w, h, values, keys, override); - + //console.log("Incoming Canvas Request:", w, h, values, keys, override); + logger.log("inbound-canvas-creation", "debug", "jsr", null, { w, h, values, keys, override }); // Gate required values if (!values || !keys) { res.status(400).send("Missing required data"); diff --git a/server/sms/receive.js b/server/sms/receive.js index ad9291a7f..c34147833 100644 --- a/server/sms/receive.js +++ b/server/sms/receive.js @@ -47,7 +47,7 @@ exports.receive = async (req, res) => { //Found a bodyshop - should always happen. if (response.bodyshops[0].conversations.length === 0) { //No conversation Found, create one. - console.log("[SMS Receive] No conversation found. Creating one."); + //console.log("[SMS Receive] No conversation found. Creating one."); newMessage.conversation = { data: { bodyshopid: response.bodyshops[0].id, @@ -56,7 +56,7 @@ exports.receive = async (req, res) => { }; } else if (response.bodyshops[0].conversations.length === 1) { //Just add it to the conversation - console.log("[SMS Receive] Conversation found. Added ID."); + //console.log("[SMS Receive] Conversation found. Added ID."); newMessage.conversationid = response.bodyshops[0].conversations[0].id; } else { //We should never get here. @@ -123,7 +123,14 @@ exports.receive = async (req, res) => { } } } catch (e1) { - console.log("e1", e1); + logger.log("sms-inbound-error", "ERROR", "api", null, { + msid: req.body.SmsMessageSid, + text: req.body.Body, + image: !!req.body.MediaUrl0, + image_path: generateMediaArray(req.body), + messagingServiceSid: req.body.MessagingServiceSid, + error: e1 + }); res.sendStatus(500).json(e1); } } diff --git a/server/utils/logger.js b/server/utils/logger.js index 0b7b9b0e4..183442dc6 100644 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -1,10 +1,4 @@ -const graylog2 = require("graylog2"); const InstanceManager = require("../utils/instanceMgr").default; - -const logger = new graylog2.graylog({ - servers: [{ host: "logs.bodyshop.app", port: 12201 }] -}); - const winston = require("winston"); const WinstonCloudWatch = require("winston-cloudwatch"); @@ -19,28 +13,47 @@ const winstonLogger = winston.createLogger({ //level: "debug", format: winston.format.json(), transports: [ - ...(process.env.NODE_ENV !== "production" ? [new winston.transports.Console({ level: "silly" })] : []), - new WinstonCloudWatch({ - level: "error", - logGroupName: logGroupName, - logStreamName: "errors", - awsRegion: region, - jsonMessage: true - }), - new WinstonCloudWatch({ - level: "warn", - logGroupName: logGroupName, - logStreamName: "warn", - awsRegion: region, - jsonMessage: true - }), - new WinstonCloudWatch({ - level: "debug", - logGroupName: logGroupName, - logStreamName: "debug", - awsRegion: region, - jsonMessage: true - }) + ...(process.env.NODE_ENV !== "production" + ? [ + new winston.transports.Console({ + level: "silly", + format: winston.format.combine( + winston.format.colorize(), // Colorize the output + winston.format.timestamp(), // Add timestamps + winston.format.printf(({ level, message, timestamp, user, record, object }) => { + // Format the log message for pretty printing + return `${timestamp} [${level}]: ${message} ${ + user ? `| user: ${JSON.stringify(user)}` : "" + } ${record ? `| record: ${JSON.stringify(record)}` : ""} ${ + object ? `| object: ${JSON.stringify(object, null, 2)}` : "" + }`; + }) + ) + }) + ] + : [ + new WinstonCloudWatch({ + level: "error", + logGroupName: logGroupName, + logStreamName: "errors", + awsRegion: region, + jsonMessage: true + }), + new WinstonCloudWatch({ + level: "warn", + logGroupName: logGroupName, + logStreamName: "warn", + awsRegion: region, + jsonMessage: true + }), + new WinstonCloudWatch({ + level: "debug", + logGroupName: logGroupName, + logStreamName: "debug", + awsRegion: region, + jsonMessage: true + }) + ]) ] }); @@ -52,15 +65,9 @@ function log(message, type, user, record, object) { message: message, user: user, record: record, - object: object + meta: object }); - // logger.log(message, message, { - // type, - // env: process.env.NODE_ENV || "development", - // user, - // record, - // ...object - // }); + } module.exports = { log }; diff --git a/server/web-sockets/redisSocketEvents.js b/server/web-sockets/redisSocketEvents.js index f0c028d17..a19953311 100644 --- a/server/web-sockets/redisSocketEvents.js +++ b/server/web-sockets/redisSocketEvents.js @@ -8,7 +8,7 @@ const redisSocketEvents = ({ }) => { // Logging helper functions const createLogEvent = (socket, level, message) => { - console.log(`[IOREDIS LOG EVENT] - ${socket?.user?.email} - ${socket.id} - ${message}`); + //console.log(`[IOREDIS LOG EVENT] - ${socket?.user?.email} - ${socket.id} - ${message}`); logger.log("ioredis-log-event", level, socket?.user?.email, null, { wsmessage: message }); }; @@ -33,7 +33,7 @@ const redisSocketEvents = ({ next(new Error("Authentication error - no authorization token.")); } } catch (error) { - console.log("Uncaught connection error:::", error); + //console.log("Uncaught connection error:::", error); logger.log("websocket-connection-error", "error", null, null, { ...error }); diff --git a/server/web-sockets/web-socket.js b/server/web-sockets/web-socket.js index ef6e6dc13..3140c2e87 100644 --- a/server/web-sockets/web-socket.js +++ b/server/web-sockets/web-socket.js @@ -31,7 +31,7 @@ io.use(function (socket, next) { next(new Error("Authentication error - no authorization token.")); } } catch (error) { - console.log("Uncaught connection error:::", error); + //console.log("Uncaught connection error:::", error); logger.log("websocket-connection-error", "error", null, null, { token: socket.handshake.auth.token, ...error @@ -148,7 +148,7 @@ function createLogEvent(socket, level, message) { function createJsonEvent(socket, level, message, json) { if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy(level)) { - console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`); + //console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`); socket.emit("log-event", { timestamp: new Date(), level, From cd2a7cad7f5b4ea19f6b4a66d2c546ac3ddaedd2 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 24 Oct 2024 14:21:35 -0700 Subject: [PATCH 38/79] feature/IO-2998-enhanced-api-logging - Finish Signed-off-by: Dave Richer --- docker-compose.yml | 3 +- server/utils/logger.js | 140 ++++++++++++++++++++++------------------- 2 files changed, 79 insertions(+), 64 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 933eb022d..503d874b3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -74,7 +74,7 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock environment: - - SERVICES=ses,secretsmanager + - SERVICES=ses,secretsmanager,cloudwatch,logs - DEBUG=0 - AWS_ACCESS_KEY_ID=test - AWS_SECRET_ACCESS_KEY=test @@ -115,6 +115,7 @@ services: aws --endpoint-url=http://localstack:4566 ses verify-domain-identity --domain imex.online --region ca-central-1 aws --endpoint-url=http://localstack:4566 ses verify-email-identity --email-address noreply@imex.online --region ca-central-1 aws --endpoint-url=http://localstack:4566 secretsmanager create-secret --name CHATTER_PRIVATE_KEY --secret-string file:///tmp/certs/id_rsa + aws --endpoint-url=http://localstack:4566 logs create-log-group --log-group-name development --region ca-central-1 " # Node App: The Main IMEX API node-app: diff --git a/server/utils/logger.js b/server/utils/logger.js index 183442dc6..6768b6821 100644 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -1,73 +1,87 @@ const InstanceManager = require("../utils/instanceMgr").default; const winston = require("winston"); const WinstonCloudWatch = require("winston-cloudwatch"); +const { isString, isEmpty } = require("lodash"); -const region = InstanceManager({ - imex: "ca-central-1", - rome: "us-east-2" -}); +const createLogger = () => { + try { + const region = InstanceManager({ + imex: "ca-central-1", + rome: "us-east-2" + }); -const logGroupName = process.env.CLOUDWATCH_LOG_GROUP; + const isLocal = isString(process.env?.LOCALSTACK_HOSTNAME) && !isEmpty(process.env?.LOCALSTACK_HOSTNAME); -const winstonLogger = winston.createLogger({ - //level: "debug", - format: winston.format.json(), - transports: [ - ...(process.env.NODE_ENV !== "production" - ? [ - new winston.transports.Console({ - level: "silly", - format: winston.format.combine( - winston.format.colorize(), // Colorize the output - winston.format.timestamp(), // Add timestamps - winston.format.printf(({ level, message, timestamp, user, record, object }) => { - // Format the log message for pretty printing - return `${timestamp} [${level}]: ${message} ${ - user ? `| user: ${JSON.stringify(user)}` : "" - } ${record ? `| record: ${JSON.stringify(record)}` : ""} ${ - object ? `| object: ${JSON.stringify(object, null, 2)}` : "" - }`; - }) - ) + const logGroupName = isLocal ? "development" : process.env.CLOUDWATCH_LOG_GROUP; + + const winstonCloudwatchTransportDefaults = { + logGroupName: logGroupName, + awsOptions: { + region + }, + jsonMessage: true + }; + + if (isLocal) { + winstonCloudwatchTransportDefaults.awsOptions.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`; + console.log(`Winston Transports set to LocalStack end point: ${winstonCloudwatchTransportDefaults.endpoint}`); + } + + const developmentTransports = [ + new winston.transports.Console({ + level: "silly", + format: winston.format.combine( + winston.format.colorize(), // Colorize the output + winston.format.timestamp(), // Add timestamps + winston.format.printf(({ level, message, timestamp, user, record, object }) => { + // Format the log message for pretty printing + return `${timestamp} [${level}]: ${message} ${ + user ? `| user: ${JSON.stringify(user)}` : "" + } ${record ? `| record: ${JSON.stringify(record)}` : ""} ${ + object ? `| object: ${JSON.stringify(object, null, 2)}` : "" + }`; }) - ] - : [ - new WinstonCloudWatch({ - level: "error", - logGroupName: logGroupName, - logStreamName: "errors", - awsRegion: region, - jsonMessage: true - }), - new WinstonCloudWatch({ - level: "warn", - logGroupName: logGroupName, - logStreamName: "warn", - awsRegion: region, - jsonMessage: true - }), - new WinstonCloudWatch({ - level: "debug", - logGroupName: logGroupName, - logStreamName: "debug", - awsRegion: region, - jsonMessage: true - }) - ]) - ] -}); + ) + }) + ]; + const productionTransports = [ + new WinstonCloudWatch({ + level: "error", + logStreamName: "errors", + ...winstonCloudwatchTransportDefaults + }), + new WinstonCloudWatch({ + level: "warn", + logStreamName: "warn", + ...winstonCloudwatchTransportDefaults + }), + new WinstonCloudWatch({ + level: "debug", + logStreamName: "debug", + ...winstonCloudwatchTransportDefaults + }) + ]; -function log(message, type, user, record, object) { - // winstonLogger.debug(message, user, record, object); + const winstonLogger = winston.createLogger({ + format: winston.format.json(), + transports: + process.env.NODE_ENV !== "production" + ? productionTransports + : [...developmentTransports, ...productionTransports] + }); - winstonLogger.log({ - level: type.toLowerCase(), - message: message, - user: user, - record: record, - meta: object - }); + return (message, type, user, record, object) => { + winstonLogger.log({ + level: type.toLowerCase(), + message: message, + user: user, + record: record, + meta: object + }); + }; + } catch (e) { + return console.log; + } +}; -} - -module.exports = { log }; +module.exports = { log: createLogger() }; From 1ca8b2a78dcc6d190cd843c3100e9b3df75a343c Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 24 Oct 2024 14:36:35 -0700 Subject: [PATCH 39/79] feature/IO-2998-enhanced-api-logging - Finish Signed-off-by: Dave Richer --- server/utils/logger.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/server/utils/logger.js b/server/utils/logger.js index 6768b6821..46167cab4 100644 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -24,17 +24,18 @@ const createLogger = () => { if (isLocal) { winstonCloudwatchTransportDefaults.awsOptions.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`; - console.log(`Winston Transports set to LocalStack end point: ${winstonCloudwatchTransportDefaults.endpoint}`); + console.log( + `Winston Transports set to LocalStack end point: ${winstonCloudwatchTransportDefaults.awsOptions.endpoint}` + ); } - const developmentTransports = [ + const getDevelopmentTransports = () => [ new winston.transports.Console({ level: "silly", format: winston.format.combine( - winston.format.colorize(), // Colorize the output - winston.format.timestamp(), // Add timestamps + winston.format.colorize(), + winston.format.timestamp(), winston.format.printf(({ level, message, timestamp, user, record, object }) => { - // Format the log message for pretty printing return `${timestamp} [${level}]: ${message} ${ user ? `| user: ${JSON.stringify(user)}` : "" } ${record ? `| record: ${JSON.stringify(record)}` : ""} ${ @@ -44,7 +45,8 @@ const createLogger = () => { ) }) ]; - const productionTransports = [ + + const getProductionTransports = () => [ new WinstonCloudWatch({ level: "error", logStreamName: "errors", @@ -65,9 +67,9 @@ const createLogger = () => { const winstonLogger = winston.createLogger({ format: winston.format.json(), transports: - process.env.NODE_ENV !== "production" - ? productionTransports - : [...developmentTransports, ...productionTransports] + process.env.NODE_ENV === "production" + ? getProductionTransports() + : [...getDevelopmentTransports(), ...getProductionTransports()] }); return (message, type, user, record, object) => { @@ -80,7 +82,8 @@ const createLogger = () => { }); }; } catch (e) { - return console.log; + console.error("Logger setup failed", e); + return () => {}; // Return a no-op function in case of failure } }; From 111f2806741524e8b64e86d0db57fbf2a329e068 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 25 Oct 2024 08:11:33 -0700 Subject: [PATCH 40/79] feature/IO-2998-enhanced-api-logging - Finish Signed-off-by: Dave Richer --- server.js | 2 +- server/utils/logger.js | 73 +++++++++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/server.js b/server.js index d84aa907e..8b0d780ff 100644 --- a/server.js +++ b/server.js @@ -174,7 +174,7 @@ const connectToRedisCluster = async () => { Math.min(CLUSTER_RETRY_BASE_DELAY + times * 50, CLUSTER_RETRY_MAX_DELAY) + Math.random() * CLUSTER_RETRY_JITTER; logger.log( `[${process.env.NODE_ENV}] Redis cluster not yet ready. Retrying in ${delay.toFixed(2)}ms`, - "ERROR", + "WARN", "redis", "api" ); diff --git a/server/utils/logger.js b/server/utils/logger.js index 46167cab4..8f3f1a47a 100644 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -5,19 +5,16 @@ const { isString, isEmpty } = require("lodash"); const createLogger = () => { try { - const region = InstanceManager({ - imex: "ca-central-1", - rome: "us-east-2" - }); - const isLocal = isString(process.env?.LOCALSTACK_HOSTNAME) && !isEmpty(process.env?.LOCALSTACK_HOSTNAME); - const logGroupName = isLocal ? "development" : process.env.CLOUDWATCH_LOG_GROUP; const winstonCloudwatchTransportDefaults = { logGroupName: logGroupName, awsOptions: { - region + region: InstanceManager({ + imex: "ca-central-1", + rome: "us-east-2" + }) }, jsonMessage: true }; @@ -29,6 +26,25 @@ const createLogger = () => { ); } + const levelFilter = (levels) => { + return winston.format((info) => { + if (Array.isArray(levels)) { + return levels.includes(info.level) ? info : false; + } else { + return info.level === levels ? info : false; + } + })(); + }; + + const createProductionTransport = (level, logStreamName, filters) => { + return new WinstonCloudWatch({ + level, + logStreamName: logStreamName || level, + format: levelFilter(filters || level), + ...winstonCloudwatchTransportDefaults + }); + }; + const getDevelopmentTransports = () => [ new winston.transports.Console({ level: "silly", @@ -47,21 +63,10 @@ const createLogger = () => { ]; const getProductionTransports = () => [ - new WinstonCloudWatch({ - level: "error", - logStreamName: "errors", - ...winstonCloudwatchTransportDefaults - }), - new WinstonCloudWatch({ - level: "warn", - logStreamName: "warn", - ...winstonCloudwatchTransportDefaults - }), - new WinstonCloudWatch({ - level: "debug", - logStreamName: "debug", - ...winstonCloudwatchTransportDefaults - }) + createProductionTransport("error"), + createProductionTransport("warn"), + createProductionTransport("info"), + createProductionTransport("silly", "debug", ["http", "verbose", "debug", "silly"]) ]; const winstonLogger = winston.createLogger({ @@ -72,19 +77,27 @@ const createLogger = () => { : [...getDevelopmentTransports(), ...getProductionTransports()] }); - return (message, type, user, record, object) => { + const log = (message, type, user, record, meta) => { winstonLogger.log({ level: type.toLowerCase(), - message: message, - user: user, - record: record, - meta: object + message, + user, + record, + meta }); }; + + return { + log, + logger: winstonLogger + }; } catch (e) { - console.error("Logger setup failed", e); - return () => {}; // Return a no-op function in case of failure + console.error("Error setting up enhanced Logger, defaulting to console.: " + e?.message || ""); + return { + log: console.log, + logger: console.log + }; } }; -module.exports = { log: createLogger() }; +module.exports = createLogger(); From 1cd64ab6f12cc240ac88e19f43ed6fda9192e769 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 25 Oct 2024 08:29:51 -0700 Subject: [PATCH 41/79] feature/IO-2998-enhanced-api-logging - Missing package Signed-off-by: Dave Richer --- package-lock.json | 630 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 631 insertions(+) diff --git a/package-lock.json b/package-lock.json index 47fd2ec73..2f0edfad5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.2.0", "license": "UNLICENSED", "dependencies": { + "@aws-sdk/client-cloudwatch-logs": "^3.679.0", "@aws-sdk/client-elasticache": "^3.675.0", "@aws-sdk/client-secrets-manager": "^3.675.0", "@aws-sdk/client-ses": "^3.675.0", @@ -71,6 +72,20 @@ "npm": ">=8.0.0" } }, + "node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-crypto/sha256-browser": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", @@ -186,6 +201,554 @@ "node": ">=14.0.0" } }, + "node_modules/@aws-sdk/client-cloudwatch-logs": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.679.0.tgz", + "integrity": "sha512-A1qTVNX8KdpqvXgULd4Suo88uuNWPa8DiuBL8Qkw/WefYT7TSWsOpwuVK0oFkMpCfB0rQN9fXZh2DBiaz8YmZg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.679.0", + "@aws-sdk/client-sts": "3.679.0", + "@aws-sdk/core": "3.679.0", + "@aws-sdk/credential-provider-node": "3.679.0", + "@aws-sdk/middleware-host-header": "3.679.0", + "@aws-sdk/middleware-logger": "3.679.0", + "@aws-sdk/middleware-recursion-detection": "3.679.0", + "@aws-sdk/middleware-user-agent": "3.679.0", + "@aws-sdk/region-config-resolver": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@aws-sdk/util-endpoints": "3.679.0", + "@aws-sdk/util-user-agent-browser": "3.679.0", + "@aws-sdk/util-user-agent-node": "3.679.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/eventstream-serde-browser": "^3.0.10", + "@smithy/eventstream-serde-config-resolver": "^3.0.7", + "@smithy/eventstream-serde-node": "^3.0.9", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", + "@smithy/util-utf8": "^3.0.0", + "@types/uuid": "^9.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/client-sso": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.679.0.tgz", + "integrity": "sha512-/0cAvYnpOZTo/Y961F1kx2fhDDLUYZ0SQQ5/75gh3xVImLj7Zw+vp74ieqFbqWLYGMaq8z1Arr9A8zG95mbLdg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.679.0", + "@aws-sdk/middleware-host-header": "3.679.0", + "@aws-sdk/middleware-logger": "3.679.0", + "@aws-sdk/middleware-recursion-detection": "3.679.0", + "@aws-sdk/middleware-user-agent": "3.679.0", + "@aws-sdk/region-config-resolver": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@aws-sdk/util-endpoints": "3.679.0", + "@aws-sdk/util-user-agent-browser": "3.679.0", + "@aws-sdk/util-user-agent-node": "3.679.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.679.0.tgz", + "integrity": "sha512-/dBYWcCwbA/id4sFCIVZvf0UsvzHCC68SryxeNQk/PDkY9N4n5yRcMUkZDaEyQCjowc3kY4JOXp2AdUP037nhA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.679.0", + "@aws-sdk/credential-provider-node": "3.679.0", + "@aws-sdk/middleware-host-header": "3.679.0", + "@aws-sdk/middleware-logger": "3.679.0", + "@aws-sdk/middleware-recursion-detection": "3.679.0", + "@aws-sdk/middleware-user-agent": "3.679.0", + "@aws-sdk/region-config-resolver": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@aws-sdk/util-endpoints": "3.679.0", + "@aws-sdk/util-user-agent-browser": "3.679.0", + "@aws-sdk/util-user-agent-node": "3.679.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.679.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/client-sts": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.679.0.tgz", + "integrity": "sha512-3CvrT8w1RjFu1g8vKA5Azfr5V83r2/b68Ock43WE003Bq/5Y38mwmYX7vk0fPHzC3qejt4YMAWk/C3fSKOy25g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.679.0", + "@aws-sdk/core": "3.679.0", + "@aws-sdk/credential-provider-node": "3.679.0", + "@aws-sdk/middleware-host-header": "3.679.0", + "@aws-sdk/middleware-logger": "3.679.0", + "@aws-sdk/middleware-recursion-detection": "3.679.0", + "@aws-sdk/middleware-user-agent": "3.679.0", + "@aws-sdk/region-config-resolver": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@aws-sdk/util-endpoints": "3.679.0", + "@aws-sdk/util-user-agent-browser": "3.679.0", + "@aws-sdk/util-user-agent-node": "3.679.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/core": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.679.0.tgz", + "integrity": "sha512-CS6PWGX8l4v/xyvX8RtXnBisdCa5+URzKd0L6GvHChype9qKUVxO/Gg6N/y43Hvg7MNWJt9FBPNWIxUB+byJwg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.679.0", + "@smithy/core": "^2.4.8", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/property-provider": "^3.1.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/signature-v4": "^4.2.0", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/util-middleware": "^3.0.7", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.679.0.tgz", + "integrity": "sha512-EdlTYbzMm3G7VUNAMxr9S1nC1qUNqhKlAxFU8E7cKsAe8Bp29CD5HAs3POc56AVo9GC4yRIS+/mtlZSmrckzUA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.679.0.tgz", + "integrity": "sha512-ZoKLubW5DqqV1/2a3TSn+9sSKg0T8SsYMt1JeirnuLJF0mCoYFUaWMyvxxKuxPoqvUsaycxKru4GkpJ10ltNBw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/util-stream": "^3.1.9", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.679.0.tgz", + "integrity": "sha512-Rg7t8RwUzKcumpipG4neZqaeJ6DF+Bco1+FHn5BZB68jpvwvjBjcQUuWkxj18B6ctYHr1fkunnzeKEn/+vy7+w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.679.0", + "@aws-sdk/credential-provider-env": "3.679.0", + "@aws-sdk/credential-provider-http": "3.679.0", + "@aws-sdk/credential-provider-process": "3.679.0", + "@aws-sdk/credential-provider-sso": "3.679.0", + "@aws-sdk/credential-provider-web-identity": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@smithy/credential-provider-imds": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.679.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.679.0.tgz", + "integrity": "sha512-E3lBtaqCte8tWs6Rkssc8sLzvGoJ10TLGvpkijOlz43wPd6xCRh1YLwg6zolf9fVFtEyUs/GsgymiASOyxhFtw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.679.0", + "@aws-sdk/credential-provider-http": "3.679.0", + "@aws-sdk/credential-provider-ini": "3.679.0", + "@aws-sdk/credential-provider-process": "3.679.0", + "@aws-sdk/credential-provider-sso": "3.679.0", + "@aws-sdk/credential-provider-web-identity": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@smithy/credential-provider-imds": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.679.0.tgz", + "integrity": "sha512-u/p4TV8kQ0zJWDdZD4+vdQFTMhkDEJFws040Gm113VHa/Xo1SYOjbpvqeuFoz6VmM0bLvoOWjxB9MxnSQbwKpQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.679.0.tgz", + "integrity": "sha512-SAtWonhi9asxn0ukEbcE81jkyanKgqpsrtskvYPpO9Z9KOednM4Cqt6h1bfcS9zaHjN2zu815Gv8O7WiV+F/DQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.679.0", + "@aws-sdk/core": "3.679.0", + "@aws-sdk/token-providers": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.679.0.tgz", + "integrity": "sha512-a74tLccVznXCaBefWPSysUcLXYJiSkeUmQGtalNgJ1vGkE36W5l/8czFiiowdWdKWz7+x6xf0w+Kjkjlj42Ung==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.679.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.679.0.tgz", + "integrity": "sha512-y176HuQ8JRY3hGX8rQzHDSbCl9P5Ny9l16z4xmaiLo+Qfte7ee4Yr3yaAKd7GFoJ3/Mhud2XZ37fR015MfYl2w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.679.0", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/middleware-logger": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.679.0.tgz", + "integrity": "sha512-0vet8InEj7nvIvGKk+ch7bEF5SyZ7Us9U7YTEgXPrBNStKeRUsgwRm0ijPWWd0a3oz2okaEwXsFl7G/vI0XiEA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.679.0", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.679.0.tgz", + "integrity": "sha512-sQoAZFsQiW/LL3DfKMYwBoGjYDEnMbA9WslWN8xneCmBAwKo6IcSksvYs23PP8XMIoBGe2I2J9BSr654XWygTQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.679.0", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.679.0.tgz", + "integrity": "sha512-4hdeXhPDURPqQLPd9jCpUEo9fQITXl3NM3W1MwcJpE0gdUM36uXkQOYsTPeeU/IRCLVjK8Htlh2oCaM9iJrLCA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@aws-sdk/util-endpoints": "3.679.0", + "@smithy/core": "^2.4.8", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.679.0.tgz", + "integrity": "sha512-Ybx54P8Tg6KKq5ck7uwdjiKif7n/8g1x+V0V9uTjBjRWqaIgiqzXwKWoPj6NCNkE7tJNtqI4JrNxp/3S3HvmRw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.679.0", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/types": "^3.5.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/token-providers": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.679.0.tgz", + "integrity": "sha512-1/+Zso/x2jqgutKixYFQEGli0FELTgah6bm7aB+m2FAWH4Hz7+iMUsazg6nSWm714sG9G3h5u42Dmpvi9X6/hA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.679.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.679.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/types": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.679.0.tgz", + "integrity": "sha512-NwVq8YvInxQdJ47+zz4fH3BRRLC6lL+WLkvr242PVBbUOLRyK/lkwHlfiKUoeVIMyK5NF+up6TRg71t/8Bny6Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/util-endpoints": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.679.0.tgz", + "integrity": "sha512-YL6s4Y/1zC45OvddvgE139fjeWSKKPgLlnfrvhVL7alNyY9n7beR4uhoDpNrt5mI6sn9qiBF17790o+xLAXjjg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.679.0", + "@smithy/types": "^3.5.0", + "@smithy/util-endpoints": "^2.1.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.679.0.tgz", + "integrity": "sha512-CusSm2bTBG1kFypcsqU8COhnYc6zltobsqs3nRrvYqYaOqtMnuE46K4XTWpnzKgwDejgZGOE+WYyprtAxrPvmQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.679.0", + "@smithy/types": "^3.5.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.679.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.679.0.tgz", + "integrity": "sha512-Bw4uXZ+NU5ed6TNfo4tBbhBSW+2eQxXYjYBGl5gLUNUpg2pDFToQAP6rXBFiwcG52V2ny5oLGiD82SoYuYkAVg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.679.0", + "@aws-sdk/types": "3.679.0", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@aws-sdk/client-elasticache": { "version": "3.675.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-elasticache/-/client-elasticache-3.675.0.tgz", @@ -1962,6 +2525,73 @@ "node": ">=16.0.0" } }, + "node_modules/@smithy/eventstream-codec": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.7.tgz", + "integrity": "sha512-kVSXScIiRN7q+s1x7BrQtZ1Aa9hvvP9FeCqCdBxv37GimIHgBCOnZ5Ip80HLt0DhnAKpiobFdGqTFgbaJNrazA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^3.6.0", + "@smithy/util-hex-encoding": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/eventstream-serde-browser": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.11.tgz", + "integrity": "sha512-Pd1Wnq3CQ/v2SxRifDUihvpXzirJYbbtXfEnnLV/z0OGCTx/btVX74P86IgrZkjOydOASBGXdPpupYQI+iO/6A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^3.0.10", + "@smithy/types": "^3.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.8.tgz", + "integrity": "sha512-zkFIG2i1BLbfoGQnf1qEeMqX0h5qAznzaZmMVNnvPZz9J5AWBPkOMckZWPedGUPcVITacwIdQXoPcdIQq5FRcg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.10.tgz", + "integrity": "sha512-hjpU1tIsJ9qpcoZq9zGHBJPBOeBGYt+n8vfhDwnITPhEre6APrvqq/y3XMDEGUT2cWQ4ramNqBPRbx3qn55rhw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^3.0.10", + "@smithy/types": "^3.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.10.tgz", + "integrity": "sha512-ewG1GHbbqsFZ4asaq40KmxCmXO+AFSM1b+DcO2C03dyJj/ZH71CiTg853FSE/3SHK9q3jiYQIFjlGSwfxQ9kww==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-codec": "^3.1.7", + "@smithy/types": "^3.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@smithy/fetch-http-handler": { "version": "3.2.9", "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.9.tgz", diff --git a/package.json b/package.json index 8531ae19a..2a3c24ded 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "makeitpretty": "prettier --write \"**/*.{css,js,json,jsx,scss}\"" }, "dependencies": { + "@aws-sdk/client-cloudwatch-logs": "^3.679.0", "@aws-sdk/client-elasticache": "^3.675.0", "@aws-sdk/client-secrets-manager": "^3.675.0", "@aws-sdk/client-ses": "^3.675.0", From d085a9c7c9908d88fb5c9d6a4666e6a9ecae02f0 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Fri, 25 Oct 2024 08:33:17 -0700 Subject: [PATCH 42/79] IO-2974 add comment to schedule. --- .../components/job-at-change/schedule-event.component.jsx | 5 +++++ client/src/graphql/appointments.queries.js | 1 + 2 files changed, 6 insertions(+) diff --git a/client/src/components/job-at-change/schedule-event.component.jsx b/client/src/components/job-at-change/schedule-event.component.jsx index b34e90668..e7f70ff65 100644 --- a/client/src/components/job-at-change/schedule-event.component.jsx +++ b/client/src/components/job-at-change/schedule-event.component.jsx @@ -23,6 +23,7 @@ import ScheduleEventColor from "./schedule-event.color.component"; import ScheduleEventNote from "./schedule-event.note.component"; import { useMutation } from "@apollo/client"; import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries"; +import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop @@ -127,6 +128,9 @@ export function ScheduleEventComponent({ {(event.job && event.job.alt_transport) || ""} + + + ) : ( @@ -316,6 +320,7 @@ export function ScheduleEventComponent({ })`} {event.job && event.job.alt_transport &&
    {event.job.alt_transport}
    } + {event?.job?.comment && `C: ${event.job.comment}`} ) : (
    Date: Fri, 25 Oct 2024 08:37:56 -0700 Subject: [PATCH 43/79] feature/IO-2998-enhanced-api-logging - Missing package Signed-off-by: Dave Richer --- server.js | 12 ++++++------ server/utils/logger.js | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index 8b0d780ff..8acba572a 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,10 @@ -const cors = require("cors"); +// Load environment variables THIS MUST BE AT THE TOP const path = require("path"); +require("dotenv").config({ + path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) +}); + +const cors = require("cors"); const http = require("http"); const Redis = require("ioredis"); const express = require("express"); @@ -18,11 +23,6 @@ const { redisSocketEvents } = require("./server/web-sockets/redisSocketEvents"); const { ElastiCacheClient, DescribeCacheClustersCommand } = require("@aws-sdk/client-elasticache"); const { default: InstanceManager } = require("./server/utils/instanceMgr"); -// Load environment variables -require("dotenv").config({ - path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) -}); - const CLUSTER_RETRY_BASE_DELAY = 100; const CLUSTER_RETRY_MAX_DELAY = 5000; const CLUSTER_RETRY_JITTER = 100; diff --git a/server/utils/logger.js b/server/utils/logger.js index 8f3f1a47a..3a1742432 100644 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -1,3 +1,9 @@ +// Load environment variables THIS MUST BE AT THE TOP +const path = require("path"); +require("dotenv").config({ + path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) +}); + const InstanceManager = require("../utils/instanceMgr").default; const winston = require("winston"); const WinstonCloudWatch = require("winston-cloudwatch"); From 23659fc41298c263a6f8fb2ae39ee05c18c6c09b Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 25 Oct 2024 11:19:40 -0700 Subject: [PATCH 44/79] IO-2973 Created By Tasks Signed-off-by: Allan Carr --- .../task-list/task-list.component.jsx | 27 +- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 7105 +++++++++-------- server/email/tasksEmails.js | 7 +- 5 files changed, 3579 insertions(+), 3562 deletions(-) diff --git a/client/src/components/task-list/task-list.component.jsx b/client/src/components/task-list/task-list.component.jsx index 57e145761..0c01ef6a8 100644 --- a/client/src/components/task-list/task-list.component.jsx +++ b/client/src/components/task-list/task-list.component.jsx @@ -1,10 +1,3 @@ -import { Button, Card, Space, Switch, Table } from "antd"; -import queryString from "query-string"; -import React, { useCallback, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { Link, useLocation, useNavigate } from "react-router-dom"; -import { pageLimit } from "../../utils/config"; -import dayjs from "../../utils/day"; import { CheckCircleFilled, CheckCircleOutlined, @@ -15,9 +8,16 @@ import { PlusCircleFilled, SyncOutlined } from "@ant-design/icons"; -import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter.jsx"; +import { Button, Card, Space, Switch, Table } from "antd"; +import queryString from "query-string"; +import React, { useCallback, useEffect } from "react"; +import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; +import { Link, useLocation, useNavigate } from "react-router-dom"; import { setModalContext } from "../../redux/modals/modals.actions"; +import { pageLimit } from "../../utils/config"; +import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter.jsx"; +import dayjs from "../../utils/day"; /** * Task List Component @@ -140,6 +140,17 @@ function TaskListComponent({ render: (text, record) => {record.created_at} }); + columns.push({ + title: t("tasks.fields.created_by"), + dataIndex: "created_by", + key: "created_by", + width: "10%", + defaultSortOrder: "descend", + sorter: true, + sortOrder: sortcolumn === "created_by" && sortorder, + render: (text, record) => record.created_by + }); + if (!onlyMine) { columns.push({ title: t("tasks.fields.assigned_to"), diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index bdc45df6e..d311ce552 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -3186,6 +3186,7 @@ "billid": "Bill", "completed": "Completed", "created_at": "Created At", + "created_by": "Created By", "description": "Description", "due_date": "Due Date", "job": { diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 66d512cef..795fd7304 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -3186,6 +3186,7 @@ "billid": "", "completed": "", "created_at": "", + "created_by": "", "description": "", "due_date": "", "job": { diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index c4cdbf53f..73f70bc82 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -1,2850 +1,2850 @@ { - "translation": { - "allocations": { - "actions": { - "assign": "Attribuer" - }, - "errors": { - "deleting": "", - "saving": "", - "validation": "" - }, - "fields": { - "employee": "Alloué à" - }, - "successes": { - "deleted": "", - "save": "" - } - }, - "appointments": { - "actions": { - "block": "", - "calculate": "", - "cancel": "annuler", - "intake": "Admission", - "new": "Nouveau rendez-vous", - "preview": "", - "reschedule": "Replanifier", - "sendreminder": "", - "unblock": "", - "viewjob": "Voir le travail" - }, - "errors": { - "blocking": "", - "canceling": "Erreur lors de l'annulation du rendez-vous. {{message}}", - "saving": "Erreur lors de la planification du rendez-vous. {{message}}" - }, - "fields": { - "alt_transport": "", - "color": "", - "end": "", - "note": "", - "start": "", - "time": "", - "title": "Titre" - }, - "labels": { - "arrivedon": "Arrivé le:", - "arrivingjobs": "", - "blocked": "", - "cancelledappointment": "Rendez-vous annulé pour:", - "completingjobs": "", - "dataconsistency": "", - "expectedjobs": "", - "expectedprodhrs": "", - "history": "", - "inproduction": "", - "manualevent": "", - "noarrivingjobs": "", - "nocompletingjobs": "", - "nodateselected": "Aucune date n'a été sélectionnée.", - "priorappointments": "Rendez-vous précédents", - "reminder": "", - "scheduledfor": "Rendez-vous prévu pour:", - "severalerrorsfound": "", - "smartscheduling": "", - "smspaymentreminder": "", - "suggesteddates": "" - }, - "successes": { - "canceled": "Rendez-vous annulé avec succès.", - "created": "Rendez-vous planifié avec succès.", - "saved": "" - } - }, - "associations": { - "actions": { - "activate": "Activer" - }, - "fields": { - "active": "Actif?", - "shopname": "nom de la boutique" - }, - "labels": { - "actions": "actes" - } - }, - "audit": { - "fields": { - "cc": "", - "contents": "", - "created": "", - "operation": "", - "status": "", - "subject": "", - "to": "", - "useremail": "", - "values": "" - } - }, - "audit_trail": { - "messages": { - "admin_job_remove_from_ar": "", - "admin_jobmarkexported": "", - "admin_jobmarkforreexport": "", - "admin_jobuninvoice": "", - "admin_jobunvoid": "", - "alerttoggle": "", - "appointmentcancel": "", - "appointmentinsert": "", - "assignedlinehours": "", - "billdeleted": "", - "billposted": "", - "billupdated": "", - "failedpayment": "", - "jobassignmentchange": "", - "jobassignmentremoved": "", - "jobchecklist": "", - "jobclosedwithbypass": "", - "jobconverted": "", - "jobdelivery": "", - "jobexported": "", - "jobfieldchanged": "", - "jobimported": "", - "jobinproductionchange": "", - "jobintake": "", - "jobinvoiced": "", - "jobioucreated": "", - "jobmodifylbradj": "", - "jobnoteadded": "", - "jobnotedeleted": "", - "jobnoteupdated": "", - "jobspartsorder": "", - "jobspartsreturn": "", - "jobstatuschange": "", - "jobsupplement": "", - "jobsuspend": "", - "jobvoid": "", - "tasks_completed": "", - "tasks_created": "", - "tasks_deleted": "", - "tasks_uncompleted": "", - "tasks_undeleted": "", - "tasks_updated": "" - } - }, - "billlines": { - "actions": { - "newline": "" - }, - "fields": { - "actual_cost": "", - "actual_price": "", - "cost_center": "", - "federal_tax_applicable": "", - "jobline": "", - "line_desc": "", - "local_tax_applicable": "", - "location": "", - "quantity": "", - "state_tax_applicable": "" - }, - "labels": { - "deductedfromlbr": "", - "entered": "", - "from": "", - "mod_lbr_adjustment": "", - "other": "", - "reconciled": "", - "unreconciled": "" - }, - "validation": { - "atleastone": "" - } - }, - "bills": { - "actions": { - "deductallhours": "", - "edit": "", - "receive": "", - "return": "" - }, - "errors": { - "creating": "", - "deleting": "", - "existinginventoryline": "", - "exporting": "", - "exporting-partner": "", - "invalidro": "", - "invalidvendor": "", - "validation": "" - }, - "fields": { - "allpartslocation": "", - "date": "", - "exported": "", - "federal_tax_rate": "", - "invoice_number": "", - "is_credit_memo": "", - "is_credit_memo_short": "", - "local_tax_rate": "", - "ro_number": "", - "state_tax_rate": "", - "total": "", - "vendor": "", - "vendorname": "" - }, - "labels": { - "actions": "", - "bill_lines": "", - "bill_total": "", - "billcmtotal": "", - "bills": "", - "calculatedcreditsnotreceived": "", - "creditsnotreceived": "", - "creditsreceived": "", - "dedfromlbr": "", - "deleteconfirm": "", - "discrepancy": "", - "discrepwithcms": "", - "discrepwithlbradj": "", - "editadjwarning": "", - "entered_total": "", - "enteringcreditmemo": "", - "federal_tax": "", - "federal_tax_exempt": "", - "generatepartslabel": "", - "iouexists": "", - "local_tax": "", - "markexported": "", - "markforreexport": "", - "new": "", - "nobilllines": "", - "noneselected": "", - "onlycmforinvoiced": "", - "printlabels": "", - "retailtotal": "", - "returnfrombill": "", - "savewithdiscrepancy": "", - "state_tax": "", - "subtotal": "", - "totalreturns": "" - }, - "successes": { - "created": "", - "deleted": "", - "exported": "", - "markexported": "", - "reexport": "" - }, - "validation": { - "closingperiod": "", - "inventoryquantity": "", - "manualinhouse": "", - "unique_invoice_number": "" - } - }, - "bodyshop": { - "actions": { - "add_task_preset": "", - "addapptcolor": "", - "addbucket": "", - "addpartslocation": "", - "addpartsrule": "", - "addspeedprint": "", - "addtemplate": "", - "newlaborrate": "", - "newsalestaxcode": "", - "newstatus": "", - "testrender": "" - }, - "errors": { - "creatingdefaultview": "", - "loading": "Impossible de charger les détails de la boutique. Veuillez appeler le support technique.", - "saving": "" - }, - "fields": { - "ReceivableCustomField": "", - "address1": "", - "address2": "", - "appt_alt_transport": "", - "appt_colors": { - "color": "", - "label": "" - }, - "appt_length": "", - "attach_pdf_to_email": "", - "batchid": "", - "bill_allow_post_to_closed": "", - "bill_federal_tax_rate": "", - "bill_local_tax_rate": "", - "bill_state_tax_rate": "", - "city": "", - "closingperiod": "", - "companycode": "", - "country": "", - "dailybodytarget": "", - "dailypainttarget": "", - "default_adjustment_rate": "", - "deliver": { - "require_actual_delivery_date": "", - "templates": "" - }, - "dms": { - "apcontrol": "", - "appostingaccount": "", - "cashierid": "", - "default_journal": "", - "disablebillwip": "", - "disablecontactvehiclecreation": "", - "dms_acctnumber": "", - "dms_control_override": "", - "dms_wip_acctnumber": "", - "generic_customer_number": "", - "itc_federal": "", - "itc_local": "", - "itc_state": "", - "mappingname": "", - "sendmaterialscosting": "", - "srcco": "" - }, - "email": "", - "enforce_class": "", - "enforce_conversion_category": "", - "enforce_conversion_csr": "", - "enforce_referral": "", - "federal_tax_id": "", - "ignoreblockeddays": "", - "inhousevendorid": "", - "insurance_vendor_id": "", - "intake": { - "next_contact_hours": "", - "templates": "" - }, - "intellipay_config": { - "cash_discount_percentage": "", - "enable_cash_discount": "" - }, - "invoice_federal_tax_rate": "", - "invoice_local_tax_rate": "", - "invoice_state_tax_rate": "", - "jc_hourly_rates": { - "mapa": "", - "mash": "" - }, - "last_name_first": "", - "lastnumberworkingdays": "", - "localmediaserverhttp": "", - "localmediaservernetwork": "", - "localmediatoken": "", - "logo_img_footer_margin": "", - "logo_img_header_margin": "", - "logo_img_path": "", - "logo_img_path_height": "", - "logo_img_path_width": "", - "md_categories": "", - "md_ccc_rates": "", - "md_classes": "", - "md_ded_notes": "", - "md_email_cc": "", - "md_from_emails": "", - "md_functionality_toggles": { - "parts_queue_toggle": "" - }, - "md_hour_split": { - "paint": "", - "prep": "" - }, - "md_ins_co": { - "city": "", - "name": "", - "private": "", - "state": "", - "street1": "", - "street2": "", - "zip": "" - }, - "md_jobline_presets": "", - "md_lost_sale_reasons": "", - "md_parts_order_comment": "", - "md_parts_scan": { - "expression": "", - "flags": "" - }, - "md_payment_types": "", - "md_referral_sources": "", - "md_ro_guard": { - "enabled": "", - "enforce_ar": "", - "enforce_bills": "", - "enforce_cm": "", - "enforce_labor": "", - "enforce_ppd": "", - "enforce_profit": "", - "enforce_sublet": "", - "masterbypass": "", - "totalgppercent_minimum": "" - }, - "md_tasks_presets": { - "enable_tasks": "", - "hourstype": "", - "memo": "", - "name": "", - "nextstatus": "", - "percent": "", - "use_approvals": "" - }, - "messaginglabel": "", - "messagingtext": "", - "noteslabel": "", - "notestext": "", - "partslocation": "", - "phone": "", - "prodtargethrs": "", - "rbac": { - "accounting": { - "exportlog": "", - "payables": "", - "payments": "", - "receivables": "" - }, - "bills": { - "delete": "", - "enter": "", - "list": "", - "reexport": "", - "view": "" - }, - "contracts": { - "create": "", - "detail": "", - "list": "" - }, - "courtesycar": { - "create": "", - "detail": "", - "list": "" - }, - "csi": { - "export": "", - "page": "" - }, - "employee_teams": { - "page": "" - }, - "employees": { - "page": "" - }, - "inventory": { - "delete": "", - "list": "" - }, - "jobs": { - "admin": "", - "available-list": "", - "checklist-view": "", - "close": "", - "create": "", - "deliver": "", - "detail": "", - "intake": "", - "list-active": "", - "list-all": "", - "list-ready": "", - "partsqueue": "", - "void": "" - }, - "owners": { - "detail": "", - "list": "" - }, - "payments": { - "enter": "", - "list": "" - }, - "phonebook": { - "edit": "", - "view": "" - }, - "production": { - "board": "", - "list": "" - }, - "schedule": { - "view": "" - }, - "scoreboard": { - "view": "" - }, - "shiftclock": { - "view": "" - }, - "shop": { - "config": "", - "dashboard": "", - "rbac": "", - "reportcenter": "", - "templates": "", - "vendors": "" - }, - "temporarydocs": { - "view": "" - }, - "timetickets": { - "edit": "", - "editcommitted": "", - "enter": "", - "list": "", - "shiftedit": "" - }, - "ttapprovals": { - "approve": "", - "view": "" - }, - "users": { - "editaccess": "" - } - }, - "responsibilitycenter": "", - "responsibilitycenter_accountdesc": "", - "responsibilitycenter_accountitem": "", - "responsibilitycenter_accountname": "", - "responsibilitycenter_accountnumber": "", - "responsibilitycenter_rate": "", - "responsibilitycenter_tax_rate": "", - "responsibilitycenter_tax_sur": "", - "responsibilitycenter_tax_thres": "", - "responsibilitycenter_tax_tier": "", - "responsibilitycenter_tax_type": "", - "responsibilitycenters": { - "ap": "", - "ar": "", - "ats": "", - "federal_tax": "", - "federal_tax_itc": "", - "gst_override": "", - "invoiceexemptcode": "", - "itemexemptcode": "", - "la1": "", - "la2": "", - "la3": "", - "la4": "", - "laa": "", - "lab": "", - "lad": "", - "lae": "", - "laf": "", - "lag": "", - "lam": "", - "lar": "", - "las": "", - "lau": "", - "local_tax": "", - "mapa": "", - "mash": "", - "paa": "", - "pac": "", - "pag": "", - "pal": "", - "pam": "", - "pan": "", - "pao": "", - "pap": "", - "par": "", - "pas": "", - "pasl": "", - "refund": "", - "sales_tax_codes": { - "code": "", - "description": "", - "federal": "", - "local": "", - "state": "" - }, - "state_tax": "", - "tow": "" - }, - "schedule_end_time": "", - "schedule_start_time": "", - "shopname": "", - "speedprint": { - "id": "", - "label": "", - "templates": "" - }, - "ss_configuration": { - "dailyhrslimit": "" - }, - "ssbuckets": { - "color": "", - "gte": "", - "id": "", - "label": "", - "lt": "", - "target": "" - }, - "state": "", - "state_tax_id": "", - "status": "", - "statuses": { - "active_statuses": "", - "additional_board_statuses": "", - "color": "", - "default_arrived": "", - "default_bo": "", - "default_canceled": "", - "default_completed": "", - "default_delivered": "", - "default_exported": "", - "default_imported": "", - "default_invoiced": "", - "default_ordered": "", - "default_quote": "", - "default_received": "", - "default_returned": "", - "default_scheduled": "", - "default_void": "", - "open_statuses": "", - "post_production_statuses": "", - "pre_production_statuses": "", - "production_colors": "", - "production_statuses": "", - "ready_statuses": "" - }, - "target_touchtime": "", - "timezone": "", - "tt_allow_post_to_invoiced": "", - "tt_enforce_hours_for_tech_console": "", - "use_fippa": "", - "use_paint_scale_data": "", - "uselocalmediaserver": "", - "website": "", - "zip_post": "" - }, - "labels": { - "2tiername": "", - "2tiersetup": "", - "2tiersource": "", - "accountingsetup": "", - "accountingtiers": "", - "alljobstatuses": "", - "allopenjobstatuses": "", - "apptcolors": "", - "businessinformation": "", - "checklists": "", - "csiq": "", - "customtemplates": "", - "defaultcostsmapping": "", - "defaultprofitsmapping": "", - "deliverchecklist": "", - "dms": { - "cdk": { - "controllist": "", - "payers": "" - }, - "cdk_dealerid": "", - "costsmapping": "", - "dms_allocations": "", - "pbs_serialnumber": "", - "profitsmapping": "", - "title": "" - }, - "emaillater": "", - "employee_teams": "", - "employees": "", - "estimators": "", - "filehandlers": "", - "insurancecos": "", - "intakechecklist": "", - "intellipay": "", - "intellipay_cash_discount": "", - "jobstatuses": "", - "laborrates": "", - "licensing": "", - "md_parts_scan": "", - "md_ro_guard": "", - "md_tasks_presets": "", - "md_to_emails": "", - "md_to_emails_emails": "", - "messagingpresets": "", - "notemplatesavailable": "", - "notespresets": "", - "orderstatuses": "", - "partslocations": "", - "partsscan": "", - "printlater": "", - "qbo": "", - "qbo_departmentid": "", - "qbo_usa": "", - "rbac": "", - "responsibilitycenters": { - "costs": "", - "profits": "", - "sales_tax_codes": "", - "tax_accounts": "", - "title": "" - }, - "roguard": { - "title": "" - }, - "scheduling": "", - "scoreboardsetup": "", - "shopinfo": "", - "speedprint": "", - "ssbuckets": "", - "systemsettings": "", - "task-presets": "", - "workingdays": "" - }, - "successes": { - "areyousure": "", - "defaultviewcreated": "", - "save": "", - "unsavedchanges": "" - }, - "validation": { - "centermustexist": "", - "larsplit": "", - "useremailmustexist": "" - } - }, - "checklist": { - "actions": { - "printall": "" - }, - "errors": { - "complete": "", - "nochecklist": "" - }, - "labels": { - "addtoproduction": "", - "allow_text_message": "", - "checklist": "", - "printpack": "", - "removefromproduction": "" - }, - "successes": { - "completed": "" - } - }, - "contracts": { - "actions": { - "changerate": "", - "convertoro": "", - "decodelicense": "", - "find": "", - "printcontract": "", - "senddltoform": "" - }, - "errors": { - "fetchingjobinfo": "", - "returning": "", - "saving": "", - "selectjobandcar": "" - }, - "fields": { - "actax": "", - "actualreturn": "", - "agreementnumber": "", - "cc_cardholder": "", - "cc_expiry": "", - "cc_num": "", - "cleanupcharge": "", - "coverage": "", - "dailyfreekm": "", - "dailyrate": "", - "damage": "", - "damagewaiver": "", - "driver": "", - "driver_addr1": "", - "driver_addr2": "", - "driver_city": "", - "driver_dlexpiry": "", - "driver_dlnumber": "", - "driver_dlst": "", - "driver_dob": "", - "driver_fn": "", - "driver_ln": "", - "driver_ph1": "", - "driver_state": "", - "driver_zip": "", - "excesskmrate": "", - "federaltax": "", - "fuelin": "", - "fuelout": "", - "kmend": "", - "kmstart": "", - "length": "", - "localtax": "", - "refuelcharge": "", - "scheduledreturn": "", - "start": "", - "statetax": "", - "status": "" - }, - "labels": { - "agreement": "", - "availablecars": "", - "cardueforservice": "", - "convertform": { - "applycleanupcharge": "", - "refuelqty": "" - }, - "correctdataonform": "", - "dateinpast": "", - "dlexpirebeforereturn": "", - "driverinformation": "", - "findcontract": "", - "findermodal": "", - "insuranceexpired": "", - "noteconvertedfrom": "", - "populatefromjob": "", - "rates": "", - "time": "", - "vehicle": "", - "waitingforscan": "" - }, - "status": { - "new": "", - "out": "", - "returned": "" - }, - "successes": { - "saved": "" - } - }, - "courtesycars": { - "actions": { - "new": "", - "return": "" - }, - "errors": { - "saving": "" - }, - "fields": { - "color": "", - "dailycost": "", - "damage": "", - "fleetnumber": "", - "fuel": "", - "insuranceexpires": "", - "leaseenddate": "", - "make": "", - "mileage": "", - "model": "", - "nextservicedate": "", - "nextservicekm": "", - "notes": "", - "plate": "", - "purchasedate": "", - "readiness": "", - "registrationexpires": "", - "serviceenddate": "", - "servicestartdate": "", - "status": "", - "vin": "", - "year": "" - }, - "labels": { - "courtesycar": "", - "fuel": { - "12": "", - "14": "", - "18": "", - "34": "", - "38": "", - "58": "", - "78": "", - "empty": "", - "full": "" - }, - "outwith": "", - "return": "", - "status": "", - "uniquefleet": "", - "usage": "", - "vehicle": "" - }, - "readiness": { - "notready": "", - "ready": "" - }, - "status": { - "in": "", - "inservice": "", - "leasereturn": "", - "out": "", - "sold": "", - "unavailable": "" - }, - "successes": { - "saved": "" - } - }, - "csi": { - "actions": { - "activate": "" - }, - "errors": { - "creating": "", - "notconfigured": "", - "notfoundsubtitle": "", - "notfoundtitle": "", - "surveycompletesubtitle": "", - "surveycompletetitle": "" - }, - "fields": { - "completedon": "", - "created_at": "", - "surveyid": "", - "validuntil": "" - }, - "labels": { - "copyright": "", - "greeting": "", - "intro": "", - "nologgedinuser": "", - "nologgedinuser_sub": "", - "noneselected": "", - "title": "" - }, - "successes": { - "created": "", - "submitted": "", - "submittedsub": "" - } - }, - "dashboard": { - "actions": { - "addcomponent": "" - }, - "errors": { - "refreshrequired": "", - "updatinglayout": "" - }, - "labels": { - "bodyhrs": "", - "dollarsinproduction": "", - "phone": "", - "prodhrs": "", - "refhrs": "" - }, - "titles": { - "joblifecycle": "", - "labhours": "", - "larhours": "", - "monthlyemployeeefficiency": "", - "monthlyjobcosting": "", - "monthlylaborsales": "", - "monthlypartssales": "", - "monthlyrevenuegraph": "", - "prodhrssummary": "", - "productiondollars": "", - "productionhours": "", - "projectedmonthlysales": "", - "scheduledindate": "", - "scheduledintoday": "", - "scheduledoutdate": "", - "scheduledouttoday": "", - "tasks": "" - } - }, - "dms": { - "errors": { - "alreadyexported": "" - }, - "labels": { - "refreshallocations": "" - } - }, - "documents": { - "actions": { - "delete": "", - "download": "", - "reassign": "", - "selectallimages": "", - "selectallotherdocuments": "" - }, - "errors": { - "deletes3": "Erreur lors de la suppression du document du stockage.", - "deleting": "", - "deleting_cloudinary": "", - "getpresignurl": "Erreur lors de l'obtention de l'URL présignée pour le document. {{message}}", - "insert": "Incapable de télécharger le fichier. {{message}}", - "nodocuments": "Il n'y a pas de documents.", - "updating": "" - }, - "labels": { - "confirmdelete": "", - "doctype": "", - "newjobid": "", - "openinexplorer": "", - "optimizedimage": "", - "reassign_limitexceeded": "", - "reassign_limitexceeded_title": "", - "storageexceeded": "", - "storageexceeded_title": "", - "upload": "Télécharger", - "upload_limitexceeded": "", - "upload_limitexceeded_title": "", - "uploading": "", - "usage": "" - }, - "successes": { - "delete": "Le document a bien été supprimé.", - "edituploaded": "", - "insert": "Document téléchargé avec succès.", - "updated": "" - } - }, - "emails": { - "errors": { - "notsent": "Courriel non envoyé. Erreur rencontrée lors de l'envoi de {{message}}" - }, - "fields": { - "cc": "", - "from": "", - "subject": "", - "to": "" - }, - "labels": { - "attachments": "", - "documents": "", - "emailpreview": "", - "generatingemail": "", - "pdfcopywillbeattached": "", - "preview": "" - }, - "successes": { - "sent": "E-mail envoyé avec succès." - } - }, - "employee_teams": { - "actions": { - "new": "", - "newmember": "" - }, - "fields": { - "active": "", - "employeeid": "", - "max_load": "", - "name": "", - "percentage": "" - } - }, - "employees": { - "actions": { - "addvacation": "", - "new": "Nouvel employé", - "newrate": "" - }, - "errors": { - "delete": "Erreur rencontrée lors de la suppression de l'employé. {{message}}", - "save": "Une erreur s'est produite lors de l'enregistrement de l'employé. {{message}}", - "validation": "Veuillez cocher tous les champs.", - "validationtitle": "Impossible d'enregistrer l'employé." - }, - "fields": { - "active": "Actif?", - "base_rate": "Taux de base", - "cost_center": "Centre de coûts", - "employee_number": "Numéro d'employé", - "external_id": "", - "first_name": "Prénom", - "flat_rate": "Taux fixe (désactivé est le temps normal)", - "hire_date": "Date d'embauche", - "last_name": "Nom de famille", - "pin": "", - "rate": "", - "termination_date": "Date de résiliation", - "user_email": "", - "vacation": { - "end": "", - "length": "", - "start": "" - } - }, - "labels": { - "actions": "", - "active": "", - "endmustbeafterstart": "", - "flat_rate": "", - "inactive": "", - "name": "", - "rate_type": "", - "status": "", - "straight_time": "" - }, - "successes": { - "delete": "L'employé a bien été supprimé.", - "save": "L'employé a enregistré avec succès.", - "vacationadded": "" - }, - "validation": { - "unique_employee_number": "" - } - }, - "eula": { - "buttons": { - "accept": "Accept EULA" - }, - "content": { - "never_scrolled": "You must scroll to the bottom of the Terms and Conditions before accepting." - }, - "errors": { - "acceptance": { - "description": "Something went wrong while accepting the EULA. Please try again.", - "message": "Eula Acceptance Error" - } - }, - "labels": { - "accepted_terms": "I accept the terms and conditions of this agreement.", - "address": "Address", - "business_name": "Legal Business Name", - "date_accepted": "Date Accepted", - "first_name": "First Name", - "last_name": "Last Name", - "phone_number": "Phone Number" - }, - "messages": { - "accepted_terms": "Please accept the terms and conditions of this agreement.", - "business_name": "Please enter your legal business name.", - "date_accepted": "Please enter Today's Date.", - "first_name": "Please enter your first name.", - "last_name": "Please enter your last name.", - "phone_number": "Please enter your phone number." - }, - "titles": { - "modal": "Terms and Conditions", - "upper_card": "Acknowledgement" - } - }, - "exportlogs": { - "fields": { - "createdat": "" - }, - "labels": { - "attempts": "", - "priorsuccesfulexport": "" - } - }, - "general": { - "actions": { - "add": "", - "autoupdate": "", - "calculate": "", - "cancel": "", - "clear": "", - "close": "", - "copied": "", - "copylink": "", - "create": "", - "defaults": "", - "delay": "", - "delete": "Effacer", - "deleteall": "", - "deselectall": "", - "download": "", - "edit": "modifier", - "login": "", - "next": "", - "previous": "", - "print": "", - "refresh": "", - "remove": "", - "remove_alert": "", - "reset": " Rétablir l'original.", - "resetpassword": "", - "save": "sauvegarder", - "saveandnew": "", - "saveas": "", - "selectall": "", - "send": "", - "sendbysms": "", - "senderrortosupport": "", - "submit": "", - "tryagain": "", - "view": "", - "viewreleasenotes": "" - }, - "errors": { - "fcm": "", - "notfound": "", - "sizelimit": "" - }, - "itemtypes": { - "contract": "", - "courtesycar": "", - "job": "", - "owner": "", - "vehicle": "" - }, - "labels": { - "actions": "actes", - "areyousure": "", - "barcode": "code à barre", - "cancel": "", - "clear": "", - "confirmpassword": "", - "created_at": "", - "date": "", - "datetime": "", - "email": "", - "errors": "", - "excel": "", - "exceptiontitle": "", - "friday": "", - "globalsearch": "", - "help": "", - "hours": "", - "in": "dans", - "instanceconflictext": "", - "instanceconflictitle": "", - "item": "", - "label": "", - "loading": "Chargement...", - "loadingapp": "Chargement de {{app}}", - "loadingshop": "Chargement des données de la boutique ...", - "loggingin": "Vous connecter ...", - "markedexported": "", - "media": "", - "message": "", - "monday": "", - "na": "N / A", - "newpassword": "", - "no": "", - "nointernet": "", - "nointernet_sub": "", - "none": "", - "out": "En dehors", - "password": "", - "passwordresetsuccess": "", - "passwordresetsuccess_sub": "", - "passwordresetvalidatesuccess": "", - "passwordresetvalidatesuccess_sub": "", - "passwordsdonotmatch": "", - "print": "", - "refresh": "", - "reports": "", - "required": "", - "saturday": "", - "search": "Chercher...", - "searchresults": "", - "selectdate": "", - "sendagain": "", - "sendby": "", - "signin": "", - "sms": "", - "status": "", - "sub_status": { - "expired": "" - }, - "successful": "", - "sunday": "", - "text": "", - "thursday": "", - "total": "", - "totals": "", - "tuesday": "", - "tvmode": "", - "unknown": "Inconnu", - "unsavedchanges": "", - "username": "", - "view": "", - "wednesday": "", - "yes": "" - }, - "languages": { - "english": "Anglais", - "french": "Francais", - "spanish": "Espanol" - }, - "messages": { - "exception": "", - "newversionmessage": "", - "newversiontitle": "", - "noacctfilepath": "", - "nofeatureaccess": "", - "noshop": "", - "notfoundsub": "", - "notfoundtitle": "", - "partnernotrunning": "", - "rbacunauth": "", - "unsavedchanges": "Vous avez des changements non enregistrés.", - "unsavedchangespopup": "" - }, - "validation": { - "invalidemail": "S'il vous plaît entrer un email valide.", - "invalidphone": "", - "required": "Ce champ est requis." - } - }, - "help": { - "actions": { - "connect": "" - }, - "labels": { - "codeplacholder": "", - "rescuedesc": "", - "rescuetitle": "" - } - }, - "intake": { - "labels": { - "printpack": "" - } - }, - "inventory": { - "actions": { - "addtoinventory": "", - "addtoro": "", - "consumefrominventory": "", - "edit": "", - "new": "" - }, - "errors": { - "inserting": "" - }, - "fields": { - "comment": "", - "manualinvoicenumber": "", - "manualvendor": "" - }, - "labels": { - "consumedbyjob": "", - "deleteconfirm": "", - "frombillinvoicenumber": "", - "fromvendor": "", - "inventory": "", - "showall": "", - "showavailable": "" - }, - "successes": { - "deleted": "", - "inserted": "", - "updated": "" - } - }, - "job_lifecycle": { - "columns": { - "duration": "", - "end": "", - "human_readable": "", - "percentage": "", - "relative_end": "", - "relative_start": "", - "start": "", - "status": "", - "status_count": "", - "value": "" - }, - "content": { - "calculated_based_on": "", - "current_status_accumulated_time": "", - "data_unavailable": "", - "jobs_in_since": "", - "legend_title": "", - "loading": "", - "not_available": "", - "previous_status_accumulated_time": "", - "title": "", - "title_durations": "", - "title_loading": "", - "title_transitions": "" - }, - "errors": { - "fetch": "Erreur lors de l'obtention des données du cycle de vie des tâches" - }, - "titles": { - "dashboard": "", - "top_durations": "" - } - }, - "job_payments": { - "buttons": { - "create_short_link": "", - "goback": "", - "proceedtopayment": "", - "refundpayment": "" - }, - "notifications": { - "error": { - "description": "", - "openingip": "", - "title": "" - } - }, - "titles": { - "amount": "", - "dateOfPayment": "", - "descriptions": "", - "hint": "", - "payer": "", - "payername": "", - "paymentid": "", - "paymentnum": "", - "paymenttype": "", - "refundamount": "", - "transactionid": "" - } - }, - "joblines": { - "actions": { - "assign_team": "", - "converttolabor": "", - "dispatchparts": "", - "new": "" - }, - "errors": { - "creating": "", - "updating": "" - }, - "fields": { - "act_price": "Prix actuel", - "act_price_before_ppc": "", - "adjustment": "", - "ah_detail_line": "", - "amount": "", - "assigned_team": "", - "assigned_team_name": "", - "create_ppc": "", - "db_price": "Prix de la base de données", - "lbr_types": { - "LA1": "", - "LA2": "", - "LA3": "", - "LA4": "", - "LAA": "", - "LAB": "", - "LAD": "", - "LAE": "", - "LAF": "", - "LAG": "", - "LAM": "", - "LAR": "", - "LAS": "", - "LAU": "" - }, - "line_desc": "Description de la ligne", - "line_ind": "S#", - "line_no": "", - "location": "", - "mod_lb_hrs": "Heures de travail", - "mod_lbr_ty": "Type de travail", - "notes": "", - "oem_partno": "Pièce OEM #", - "op_code_desc": "", - "part_qty": "", - "part_type": "Type de pièce", - "part_types": { - "CCC": "", - "CCD": "", - "CCDR": "", - "CCF": "", - "CCM": "", - "PAA": "", - "PAC": "", - "PAE": "", - "PAG": "", - "PAL": "", - "PAM": "", - "PAN": "", - "PAO": "", - "PAP": "", - "PAR": "", - "PAS": "", - "PASL": "" - }, - "profitcenter_labor": "", - "profitcenter_part": "", - "prt_dsmk_m": "", - "prt_dsmk_p": "", - "status": "Statut", - "tax_part": "", - "total": "", - "unq_seq": "Seq #" - }, - "labels": { - "adjustmenttobeadded": "", - "billref": "", - "convertedtolabor": "", - "edit": "Ligne d'édition", - "ioucreated": "", - "new": "Nouvelle ligne", - "nostatus": "", - "presets": "" - }, - "successes": { - "created": "", - "saved": "", - "updated": "" - }, - "validations": { - "ahdetailonlyonuserdefinedtypes": "", - "hrsrequirediflbrtyp": "", - "requiredifparttype": "", - "zeropriceexistingpart": "" - } - }, - "jobs": { - "actions": { - "addDocuments": "Ajouter des documents de travail", - "addNote": "Ajouter une note", - "addtopartsqueue": "", - "addtoproduction": "", - "addtoscoreboard": "", - "allocate": "", - "autoallocate": "", - "changefilehandler": "", - "changelaborrate": "", - "changestatus": "Changer le statut", - "changestimator": "", - "convert": "Convertir", - "createiou": "", - "deliver": "", - "dms": { - "addpayer": "", - "createnewcustomer": "", - "findmakemodelcode": "", - "getmakes": "", - "labels": { - "refreshallocations": "" - }, - "post": "", - "refetchmakesmodels": "", - "usegeneric": "", - "useselected": "" - }, - "dmsautoallocate": "", - "export": "", - "exportcustdata": "", - "exportselected": "", - "filterpartsonly": "", - "generatecsi": "", - "gotojob": "", - "intake": "", - "manualnew": "", - "mark": "", - "markasexported": "", - "markpstexempt": "", - "markpstexemptconfirm": "", - "postbills": "Poster des factures", - "printCenter": "Centre d'impression", - "recalculate": "", - "reconcile": "", - "removefromproduction": "", - "schedule": "Programme", - "sendcsi": "", - "sendpartspricechange": "", - "sendtodms": "", - "sync": "", - "taxprofileoverride": "", - "taxprofileoverride_confirm": "", - "uninvoice": "", - "unvoid": "", - "viewchecklist": "", - "viewdetail": "" - }, - "errors": { - "addingtoproduction": "", - "cannotintake": "", - "closing": "", - "creating": "", - "deleted": "Erreur lors de la suppression du travail.", - "exporting": "", - "exporting-partner": "", - "invoicing": "", - "noaccess": "Ce travail n'existe pas ou vous n'y avez pas accès.", - "nodamage": "", - "nodates": "Aucune date spécifiée pour ce travail.", - "nofinancial": "", - "nojobselected": "Aucun travail n'est sélectionné.", - "noowner": "Aucun propriétaire associé.", - "novehicle": "Aucun véhicule associé.", - "partspricechange": "", - "saving": "Erreur rencontrée lors de la sauvegarde de l'enregistrement.", - "scanimport": "", - "totalscalc": "", - "updating": "", - "validation": "Veuillez vous assurer que tous les champs sont correctement entrés.", - "validationtitle": "Erreur de validation", - "voiding": "" - }, - "fields": { - "active_tasks": "", - "actual_completion": "Achèvement réel", - "actual_delivery": "Livraison réelle", - "actual_in": "En réel", - "adjustment_bottom_line": "Ajustements", - "adjustmenthours": "", - "alt_transport": "", - "area_of_damage_impact": { - "10": "", - "11": "", - "12": "", - "13": "", - "14": "", - "15": "", - "16": "", - "25": "", - "26": "", - "27": "", - "28": "", - "34": "", - "01": "", - "02": "", - "03": "", - "04": "", - "05": "", - "06": "", - "07": "", - "08": "", - "09": "" - }, - "auto_add_ats": "", - "ca_bc_pvrt": "", - "ca_customer_gst": "", - "ca_gst_registrant": "", - "category": "", - "ccc": "", - "ccd": "", - "ccdr": "", - "ccf": "", - "ccm": "", - "cieca_id": "CIECA ID", - "cieca_pfl": { - "lbr_adjp": "", - "lbr_tax_in": "", - "lbr_taxp": "", - "lbr_tx_in1": "", - "lbr_tx_in2": "", - "lbr_tx_in3": "", - "lbr_tx_in4": "", - "lbr_tx_in5": "" - }, - "cieca_pfo": { - "stor_t_in1": "", - "stor_t_in2": "", - "stor_t_in3": "", - "stor_t_in4": "", - "stor_t_in5": "", - "tow_t_in1": "", - "tow_t_in2": "", - "tow_t_in3": "", - "tow_t_in4": "", - "tow_t_in5": "" - }, - "claim_total": "Total réclamation", - "class": "", - "clm_no": "Prétendre #", - "clm_total": "Total réclamation", - "comment": "", - "customerowing": "Client propriétaire", - "date_estimated": "Date estimée", - "date_exported": "Exportés", - "date_invoiced": "Facturé", - "date_last_contacted": "", - "date_lost_sale": "", - "date_next_contact": "", - "date_open": "Ouvrir", - "date_rentalresp": "", - "date_repairstarted": "", - "date_scheduled": "Prévu", - "date_towin": "", - "date_void": "", - "ded_amt": "Déductible", - "ded_note": "", - "ded_status": "Statut de franchise", - "depreciation_taxes": "Amortissement / taxes", - "dms": { - "address": "", - "amount": "", - "center": "", - "control_type": { - "account_number": "" - }, - "cost": "", - "cost_dms_acctnumber": "", - "dms_make": "", - "dms_model": "", - "dms_model_override": "", - "dms_unsold": "", - "dms_wip_acctnumber": "", - "id": "", - "inservicedate": "", - "journal": "", - "lines": "", - "name1": "", - "payer": { - "amount": "", - "control_type": "", - "controlnumber": "", - "dms_acctnumber": "", - "name": "" - }, - "sale": "", - "sale_dms_acctnumber": "", - "story": "", - "vinowner": "" - }, - "dms_allocation": "", - "driveable": "", - "employee_body": "", - "employee_csr": "représentant du service à la clientèle", - "employee_csr_writer": "", - "employee_prep": "", - "employee_refinish": "", - "est_addr1": "Adresse de l'évaluateur", - "est_co_nm": "Expert", - "est_ct_fn": "Prénom de l'évaluateur", - "est_ct_ln": "Nom de l'évaluateur", - "est_ea": "Courriel de l'évaluateur", - "est_ph1": "Numéro de téléphone de l'évaluateur", - "federal_tax_payable": "Impôt fédéral à payer", - "federal_tax_rate": "", - "ins_addr1": "Adresse Insurance Co.", - "ins_city": "Insurance City", - "ins_co_id": "ID de la compagnie d'assurance", - "ins_co_nm": "Nom de la compagnie d'assurance", - "ins_co_nm_short": "", - "ins_ct_fn": "Prénom du gestionnaire de fichiers", - "ins_ct_ln": "Nom du gestionnaire de fichiers", - "ins_ea": "Courriel du gestionnaire de fichiers", - "ins_ph1": "Numéro de téléphone du gestionnaire de fichiers", - "intake": { - "label": "", - "max": "", - "min": "", - "name": "", - "required": "", - "type": "" - }, - "invoice_final_note": "", - "kmin": "Kilométrage en", - "kmout": "Kilométrage hors", - "la1": "", - "la2": "", - "la3": "", - "la4": "", - "laa": "", - "lab": "", - "labor_rate_desc": "Nom du taux de main-d'œuvre", - "lad": "", - "lae": "", - "laf": "", - "lag": "", - "lam": "", - "lar": "", - "las": "", - "lau": "", - "local_tax_rate": "", - "loss_date": "Date de perte", - "loss_desc": "", - "loss_of_use": "", - "lost_sale_reason": "", - "ma2s": "", - "ma3s": "", - "mabl": "", - "macs": "", - "mahw": "", - "mapa": "", - "mash": "", - "matd": "", - "materials": { - "MAPA": "", - "MASH": "", - "cal_maxdlr": "", - "cal_opcode": "", - "mat_adjp": "", - "mat_taxp": "", - "mat_tx_in1": "", - "mat_tx_in2": "", - "mat_tx_in3": "", - "mat_tx_in4": "", - "mat_tx_in5": "", - "materials": "", - "tax_ind": "" - }, - "other_amount_payable": "Autre montant à payer", - "owner": "Propriétaire", - "owner_owing": "Cust. Owes", - "ownr_ea": "Email", - "ownr_ph1": "Téléphone 1", - "ownr_ph2": "", - "paa": "", - "pac": "", - "pae": "", - "pag": "", - "pal": "", - "pam": "", - "pan": "", - "pao": "", - "pap": "", - "par": "", - "parts_tax_rates": { - "prt_discp": "", - "prt_mktyp": "", - "prt_mkupp": "", - "prt_tax_in": "", - "prt_tax_rt": "", - "prt_tx_in1": "", - "prt_tx_in2": "", - "prt_tx_in3": "", - "prt_tx_in4": "", - "prt_tx_in5": "", - "prt_tx_ty1": "", - "prt_type": "" - }, - "partsstatus": "", - "pas": "", - "pay_date": "Date d'Pay", - "phoneshort": "PH", - "po_number": "", - "policy_no": "Politique #", - "ponumber": "Numéro de bon de commande", - "production_vars": { - "note": "" - }, - "qb_multiple_payers": { - "amount": "", - "name": "" - }, - "queued_for_parts": "", - "rate_ats": "", - "rate_la1": "Taux LA1", - "rate_la2": "Taux LA2", - "rate_la3": "Taux LA3", - "rate_la4": "Taux LA4", - "rate_laa": "Taux d'aluminium", - "rate_lab": "Taux de la main-d'œuvre", - "rate_lad": "Taux de diagnostic", - "rate_lae": "Tarif électrique", - "rate_laf": "Taux de trame", - "rate_lag": "Taux de verre", - "rate_lam": "Taux mécanique", - "rate_lar": "Taux de finition", - "rate_las": "", - "rate_lau": "Taux d'aluminium", - "rate_ma2s": "Taux de peinture en 2 étapes", - "rate_ma3s": "Taux de peinture en 3 étapes", - "rate_mabl": "MABL ??", - "rate_macs": "MACS ??", - "rate_mahw": "Taux de déchets dangereux", - "rate_mapa": "Taux de matériaux de peinture", - "rate_mash": "Tarif du matériel de la boutique", - "rate_matd": "Taux d'élimination des pneus", - "referral_source_extra": "", - "referral_source_other": "", - "referralsource": "Source de référence", - "regie_number": "Enregistrement #", - "repairtotal": "Réparation totale", - "ro_number": "RO #", - "scheduled_completion": "Achèvement planifié", - "scheduled_delivery": "Livraison programmée", - "scheduled_in": "Planifié dans", - "selling_dealer": "Revendeur vendeur", - "selling_dealer_contact": "Contacter le revendeur", - "servicecar": "Voiture de service", - "servicing_dealer": "Concessionnaire", - "servicing_dealer_contact": "Contacter le concessionnaire", - "special_coverage_policy": "Politique de couverture spéciale", - "specialcoveragepolicy": "Politique de couverture spéciale", - "state_tax_rate": "", - "status": "Statut de l'emploi", - "storage_payable": "Stockage", - "tax_lbr_rt": "", - "tax_levies_rt": "", - "tax_paint_mat_rt": "", - "tax_registration_number": "", - "tax_shop_mat_rt": "", - "tax_str_rt": "", - "tax_sub_rt": "", - "tax_tow_rt": "", - "towin": "", - "towing_payable": "Remorquage à payer", - "unitnumber": "Unité #", - "updated_at": "Mis à jour à", - "uploaded_by": "Telechargé par", - "vehicle": "Véhicule" - }, - "forms": { - "admindates": "", - "appraiserinfo": "", - "claiminfo": "", - "estdates": "", - "laborrates": "", - "lossinfo": "", - "other": "", - "repairdates": "", - "scheddates": "" - }, - "labels": { - "accountsreceivable": "", - "act_price_ppc": "", - "actual_completion_inferred": "", - "actual_delivery_inferred": "", - "actual_in_inferred": "", - "additionalpayeroverallocation": "", - "additionaltotal": "", - "adjustmentrate": "", - "adjustments": "", - "adminwarning": "", - "allocations": "", - "alreadyaddedtoscoreboard": "", - "alreadyclosed": "", - "appointmentconfirmation": "Envoyer une confirmation au client?", - "associationwarning": "", - "audit": "", - "available": "", - "availablejobs": "", - "ca_bc_pvrt": { - "days": "", - "rate": "" - }, - "ca_gst_all_if_null": "", - "calc_repair_days": "", - "calc_repair_days_tt": "", - "calc_scheuled_completion": "", - "cards": { - "customer": "Informations client", - "damage": "Zone de dommages", - "dates": "Rendez-vous", - "documents": "Documents récents", - "estimator": "Estimateur", - "filehandler": "Gestionnaire de fichiers", - "insurance": "Détails de l'assurance", - "more": "Plus", - "notes": "Remarques", - "parts": "les pièces", - "totals": "Totaux", - "vehicle": "Véhicule" - }, - "changeclass": "", - "checklistcompletedby": "", - "checklistdocuments": "", - "checklists": "", - "cieca_pfl": "", - "cieca_pfo": "", - "cieca_pft": "", - "closeconfirm": "", - "closejob": "", - "closingperiod": "", - "contracts": "", - "convertedtolabor": "", - "cost": "", - "cost_Additional": "", - "cost_labor": "", - "cost_parts": "", - "cost_sublet": "", - "costs": "", - "create": { - "jobinfo": "", - "newowner": "", - "newvehicle": "", - "novehicle": "", - "ownerinfo": "", - "vehicleinfo": "" - }, - "createiouwarning": "", - "creating_new_job": "Création d'un nouvel emploi ...", - "deductible": { - "stands": "", - "waived": "" - }, - "deleteconfirm": "", - "deletedelivery": "", - "deleteintake": "", - "deliverchecklist": "", - "difference": "", - "diskscan": "", - "dms": { - "apexported": "", - "damageto": "", - "defaultstory": "", - "disablebillwip": "", - "invoicedatefuture": "", - "kmoutnotgreaterthankmin": "", - "logs": "", - "notallocated": "", - "postingform": "", - "totalallocated": "" - }, - "documents": "Les documents", - "documents-images": "", - "documents-other": "", - "duplicateconfirm": "", - "emailaudit": "", - "employeeassignments": "", - "estimatelines": "", - "estimator": "", - "existing_jobs": "Emplois existants", - "federal_tax_amt": "", - "gpdollars": "", - "gppercent": "", - "hrs_claimed": "", - "hrs_total": "", - "importnote": "", - "inproduction": "", - "intakechecklist": "", - "iou": "", - "job": "", - "jobcosting": "", - "jobtotals": "", - "labor_hrs": "", - "labor_rates_subtotal": "", - "laborallocations": "", - "labortotals": "", - "lines": "Estimer les lignes", - "local_tax_amt": "", - "mapa": "", - "markforreexport": "", - "mash": "", - "masterbypass": "", - "materials": { - "mapa": "" - }, - "missingprofileinfo": "", - "multipayers": "", - "net_repairs": "", - "notes": "Remarques", - "othertotal": "", - "outstanding_ar": "", - "outstanding_credit_memos": "", - "outstanding_ppd": "", - "outstanding_reconciliation_discrep": "", - "outstanding_sublets": "", - "outstandinghours": "", - "override_header": "Remplacer l'en-tête d'estimation à l'importation?", - "ownerassociation": "", - "parts": "les pièces", - "parts_lines": "", - "parts_received": "", - "parts_tax_rates": "", - "partsfilter": "", - "partssubletstotal": "", - "partstotal": "", - "performance": "", - "pimraryamountpayable": "", - "plitooltips": { - "billtotal": "", - "calculatedcreditsnotreceived": "", - "creditmemos": "", - "creditsnotreceived": "", - "discrep1": "", - "discrep2": "", - "discrep3": "", - "laboradj": "", - "partstotal": "", - "totalreturns": "" - }, - "ppc": "", - "ppdnotexported": "", - "profileadjustments": "", - "profitbypassrequired": "", - "profits": "", - "prt_dsmk_total": "", - "rates": "Les taux", - "rates_subtotal": "", - "reconciliation": { - "billlinestotal": "", - "byassoc": "", - "byprice": "", - "clear": "", - "discrepancy": "", - "joblinestotal": "", - "multipleactprices": "", - "multiplebilllines": "", - "multiplebillsforactprice": "", - "removedpartsstrikethrough": "" - }, - "reconciliationheader": "", - "relatedros": "", - "remove_from_ar": "", - "returntotals": "", - "ro_guard": { - "enforce_ar": "", - "enforce_bills": "", - "enforce_cm": "", - "enforce_labor": "", - "enforce_ppd": "", - "enforce_profit": "", - "enforce_sublet": "", - "enforce_validation": "", - "enforced": "" - }, - "roguard": "", - "roguardwarnings": "", - "rosaletotal": "", - "sale_additional": "", - "sale_labor": "", - "sale_parts": "", - "sale_sublet": "", - "sales": "", - "savebeforeconversion": "", - "scheduledinchange": "", - "specialcoveragepolicy": "", - "state_tax_amt": "", - "subletsnotcompleted": "", - "subletstotal": "", - "subtotal": "", - "supplementnote": "", - "suspended": "", - "suspense": "", - "tasks": "", - "threshhold": "", - "total_cost": "", - "total_cust_payable": "", - "total_repairs": "", - "total_sales": "", - "total_sales_tax": "", - "totals": "", - "unvoidnote": "", - "update_scheduled_completion": "", - "vehicle_info": "Véhicule", - "vehicleassociation": "", - "viewallocations": "", - "voidjob": "", - "voidnote": "" - }, - "successes": { - "addedtoproduction": "", - "all_deleted": "{{count}} travaux supprimés avec succès.", - "closed": "", - "converted": "Travail converti avec succès.", - "created": "Le travail a été créé avec succès. Clique pour voir.", - "creatednoclick": "", - "delete": "", - "deleted": "Le travail a bien été supprimé.", - "duplicated": "", - "exported": "", - "invoiced": "", - "ioucreated": "", - "partsqueue": "", - "save": "Le travail a été enregistré avec succès.", - "savetitle": "Enregistrement enregistré avec succès.", - "supplemented": "Travail complété avec succès.", - "updated": "", - "voided": "" - } - }, - "landing": { - "bigfeature": { - "subtitle": "", - "title": "" - }, - "footer": { - "company": { - "about": "", - "contact": "", - "disclaimers": "", - "name": "", - "privacypolicy": "" - }, - "io": { - "help": "", - "name": "", - "status": "" - }, - "slogan": "" - }, - "hero": { - "button": "", - "title": "" - }, - "labels": { - "features": "", - "managemyshop": "", - "pricing": "" - }, - "pricing": { - "basic": { - "name": "", - "sub": "" - }, - "essentials": { - "name": "", - "sub": "" - }, - "pricingtitle": "", - "pro": { - "name": "", - "sub": "" - }, - "title": "", - "unlimited": { - "name": "", - "sub": "" - } - } - }, - "menus": { - "currentuser": { - "languageselector": "La langue", - "profile": "Profil" - }, - "header": { - "accounting": "", - "accounting-payables": "", - "accounting-payments": "", - "accounting-receivables": "", - "activejobs": "Emplois actifs", - "all_tasks": "", - "alljobs": "", - "allpayments": "", - "availablejobs": "Emplois disponibles", - "bills": "", - "courtesycars": "", - "courtesycars-all": "", - "courtesycars-contracts": "", - "courtesycars-newcontract": "", - "create_task": "", - "customers": "Les clients", - "dashboard": "", - "enterbills": "", - "entercardpayment": "", - "enterpayment": "", - "entertimeticket": "", - "export": "", - "export-logs": "", - "help": "", - "home": "Accueil", - "inventory": "", - "jobs": "Emplois", - "my_tasks": "", - "newjob": "", - "owners": "Propriétaires", - "parts-queue": "", - "phonebook": "", - "productionboard": "", - "productionlist": "", - "readyjobs": "", - "recent": "", - "reportcenter": "", - "rescueme": "", - "schedule": "Programme", - "scoreboard": "", - "search": { - "bills": "", - "jobs": "", - "owners": "", - "payments": "", - "phonebook": "", - "vehicles": "" - }, - "shiftclock": "", - "shop": "Mon magasin", - "shop_config": "Configuration", - "shop_csi": "", - "shop_templates": "", - "shop_vendors": "Vendeurs", - "tasks": "", - "temporarydocs": "", - "timetickets": "", - "ttapprovals": "", - "vehicles": "Véhicules" - }, - "jobsactions": { - "admin": "", - "cancelallappointments": "", - "closejob": "", - "deletejob": "", - "duplicate": "", - "duplicatenolines": "", - "newcccontract": "", - "void": "" - }, - "jobsdetail": { - "claimdetail": "Détails de la réclamation", - "dates": "Rendez-vous", - "financials": "", - "general": "", - "insurance": "", - "labor": "La main d'oeuvre", - "lifecycle": "", - "parts": "", - "partssublet": "Pièces / Sous-location", - "rates": "", - "repairdata": "Données de réparation", - "totals": "" - }, - "profilesidebar": { - "profile": "Mon profil", - "shops": "Mes boutiques" - }, - "tech": { - "assignedjobs": "", - "claimtask": "", - "dispatchedparts": "", - "home": "", - "jobclockin": "", - "jobclockout": "", - "joblookup": "", - "login": "", - "logout": "", - "productionboard": "", - "productionlist": "", - "shiftclockin": "" - } - }, - "messaging": { - "actions": { - "link": "", - "new": "" - }, - "errors": { - "invalidphone": "", - "noattachedjobs": "", - "updatinglabel": "" - }, - "labels": { - "addlabel": "", - "archive": "", - "maxtenimages": "", - "messaging": "Messagerie", - "noallowtxt": "", - "nojobs": "", - "nopush": "", - "phonenumber": "", - "presets": "", - "recentonly": "", - "selectmedia": "", - "sentby": "", - "typeamessage": "Envoyer un message...", - "unarchive": "" - }, - "render": { - "conversation_list": "" - } - }, - "notes": { - "actions": { - "actions": "actes", - "deletenote": "Supprimer la note", - "edit": "Note éditée", - "new": "Nouvelle note", - "savetojobnotes": "" - }, - "errors": { - "inserting": "" - }, - "fields": { - "createdby": "Créé par", - "critical": "Critique", - "private": "privé", - "text": "Contenu", - "type": "", - "types": { - "customer": "", - "general": "", - "office": "", - "paint": "", - "parts": "", - "shop": "", - "supplement": "" - }, - "updatedat": "Mis à jour à" - }, - "labels": { - "addtorelatedro": "", - "newnoteplaceholder": "Ajouter une note...", - "notetoadd": "", - "systemnotes": "", - "usernotes": "" - }, - "successes": { - "create": "Remarque créée avec succès.", - "deleted": "Remarque supprimée avec succès.", - "updated": "Remarque mise à jour avec succès." - } - }, - "owner": { - "labels": { - "noownerinfo": "" - } - }, - "owners": { - "actions": { - "update": "" - }, - "errors": { - "deleting": "", - "noaccess": "L'enregistrement n'existe pas ou vous n'y avez pas accès.", - "saving": "", - "selectexistingornew": "" - }, - "fields": { - "address": "Adresse", - "allow_text_message": "Autorisation de texte?", - "name": "Prénom", - "note": "", - "ownr_addr1": "Adresse", - "ownr_addr2": "Adresse 2 ", - "ownr_city": "Ville", - "ownr_co_nm": "", - "ownr_ctry": "Pays", - "ownr_ea": "Email", - "ownr_fn": "Prénom", - "ownr_ln": "Nom de famille", - "ownr_ph1": "Téléphone 1", - "ownr_ph2": "", - "ownr_st": "Etat / Province", - "ownr_title": "Titre", - "ownr_zip": "Zip / code postal", - "preferred_contact": "Méthode de contact préférée", - "tax_number": "" - }, - "forms": { - "address": "", - "contact": "", - "name": "" - }, - "labels": { - "create_new": "Créez un nouvel enregistrement de propriétaire.", - "deleteconfirm": "", - "existing_owners": "Propriétaires existants", - "fromclaim": "", - "fromowner": "", - "relatedjobs": "", - "updateowner": "" - }, - "successes": { - "delete": "", - "save": "Le propriétaire a bien enregistré." - } - }, - "parts": { - "actions": { - "order": "Commander des pièces", - "orderinhouse": "" - } - }, - "parts_dispatch": { - "actions": { - "accept": "" - }, - "errors": { - "accepting": "", - "creating": "" - }, - "fields": { - "number": "", - "percent_accepted": "" - }, - "labels": { - "notyetdispatched": "", - "parts_dispatch": "" - } - }, - "parts_dispatch_lines": { - "fields": { - "accepted_at": "" - } - }, - "parts_orders": { - "actions": { - "backordered": "", - "receive": "", - "receivebill": "" - }, - "errors": { - "associatedbills": "", - "backordering": "", - "creating": "Erreur rencontrée lors de la création de la commande de pièces.", - "oec": "", - "saving": "", - "updating": "" - }, - "fields": { - "act_price": "", - "backordered_eta": "", - "backordered_on": "", - "cm_received": "", - "comments": "", - "cost": "", - "db_price": "", - "deliver_by": "", - "job_line_id": "", - "line_desc": "", - "line_remarks": "", - "lineremarks": "Remarques sur la ligne", - "oem_partno": "", - "order_date": "", - "order_number": "", - "orderedby": "", - "part_type": "", - "quantity": "", - "return": "", - "status": "" - }, - "labels": { - "allpartsto": "", - "confirmdelete": "", - "custompercent": "", - "discount": "", - "email": "Envoyé par email", - "inthisorder": "Pièces dans cette commande", - "is_quote": "", - "mark_as_received": "", - "newpartsorder": "", - "notyetordered": "", - "oec": "", - "order_type": "", - "orderhistory": "Historique des commandes", - "parts_order": "", - "parts_orders": "", - "print": "Afficher le formulaire imprimé", - "receive": "", - "removefrompartsqueue": "", - "returnpartsorder": "", - "sublet_order": "" - }, - "successes": { - "created": "Commande de pièces créée avec succès.", - "line_updated": "", - "received": "", - "return_created": "" - } - }, - "payments": { - "actions": { - "generatepaymentlink": "" - }, - "errors": { - "exporting": "", - "exporting-partner": "", - "inserting": "" - }, - "fields": { - "amount": "", - "created_at": "", - "date": "", - "exportedat": "", - "memo": "", - "payer": "", - "paymentnum": "", - "stripeid": "", - "transactionid": "", - "type": "" - }, - "labels": { - "balance": "", - "ca_bc_etf_table": "", - "customer": "", - "edit": "", - "electronicpayment": "", - "external": "", - "findermodal": "", - "insurance": "", - "markexported": "", - "markforreexport": "", - "new": "", - "signup": "", - "smspaymentreminder": "", - "title": "", - "totalpayments": "" - }, - "successes": { - "exported": "", - "markexported": "", - "markreexported": "", - "payment": "", - "paymentupdate": "", - "stripe": "" - } - }, - "phonebook": { - "actions": { - "new": "" - }, - "errors": { - "adding": "", - "saving": "" - }, - "fields": { - "address1": "", - "address2": "", - "category": "", - "city": "", - "company": "", - "country": "", - "email": "", - "fax": "", - "firstname": "", - "lastname": "", - "phone1": "", - "phone2": "", - "state": "" - }, - "labels": { - "noneselected": "", - "onenamerequired": "", - "vendorcategory": "" - }, - "successes": { - "added": "", - "deleted": "", - "saved": "" - } - }, - "printcenter": { - "appointments": { - "appointment_confirmation": "" - }, - "bills": { - "inhouse_invoice": "" - }, - "courtesycarcontract": { - "courtesy_car_contract": "", - "courtesy_car_impound": "", - "courtesy_car_inventory": "", - "courtesy_car_terms": "" - }, - "errors": { - "nocontexttype": "" - }, - "jobs": { - "3rdpartyfields": { - "addr1": "", - "addr2": "", - "addr3": "", - "attn": "", - "city": "", - "custgst": "", - "ded_amt": "", - "depreciation": "", - "other": "", - "ponumber": "", - "refnumber": "", - "sendtype": "", - "state": "", - "zip": "" - }, - "3rdpartypayer": "", - "ab_proof_of_loss": "", - "appointment_confirmation": "", - "appointment_reminder": "", - "casl_authorization": "", - "committed_timetickets_ro": "", - "coversheet_landscape": "", - "coversheet_portrait": "", - "csi_invitation": "", - "csi_invitation_action": "", - "diagnostic_authorization": "", - "dms_posting_sheet": "", - "envelope_return_address": "", - "estimate": "", - "estimate_detail": "", - "estimate_followup": "", - "express_repair_checklist": "", - "filing_coversheet_landscape": "", - "filing_coversheet_portrait": "", - "final_invoice": "", - "fippa_authorization": "", - "folder_label_multiple": "", - "glass_express_checklist": "", - "guarantee": "", - "individual_job_note": "", - "invoice_customer_payable": "", - "invoice_total_payable": "", - "iou_form": "", - "job_costing_ro": "", - "job_lifecycle_ro": "", - "job_notes": "", - "job_tasks": "", - "key_tag": "", - "labels": { - "count": "", - "labels": "", - "position": "" - }, - "lag_time_ro": "", - "mechanical_authorization": "", - "mpi_animal_checklist": "", - "mpi_eglass_auth": "", - "mpi_final_acct_sheet": "", - "mpi_final_repair_acct_sheet": "", - "paint_grid": "", - "parts_dispatch": "", - "parts_invoice_label_single": "", - "parts_label_multiple": "", - "parts_label_single": "", - "parts_list": "", - "parts_order": "", - "parts_order_confirmation": "", - "parts_order_history": "", - "parts_return_slip": "", - "payment_receipt": "", - "payment_request": "", - "payments_by_job": "", - "purchases_by_ro_detail": "", - "purchases_by_ro_summary": "", - "qc_sheet": "", - "rental_reservation": "", - "ro_totals": "", - "ro_with_description": "", - "sgi_certificate_of_repairs": "", - "sgi_windshield_auth": "", - "stolen_recovery_checklist": "", - "sublet_order": "", - "supplement_request": "", - "thank_you_ro": "", - "thirdpartypayer": "", - "timetickets_ro": "", - "vehicle_check_in": "", - "vehicle_delivery_check": "", - "window_tag": "", - "window_tag_sublet": "", - "work_authorization": "", - "worksheet_by_line_number": "", - "worksheet_sorted_by_operation": "", - "worksheet_sorted_by_operation_no_hours": "", - "worksheet_sorted_by_operation_part_type": "", - "worksheet_sorted_by_operation_type": "", - "worksheet_sorted_by_team": "" - }, - "labels": { - "groups": { - "authorization": "", - "financial": "", - "post": "", - "pre": "", - "ro": "", - "worksheet": "" - }, - "misc": "", - "repairorder": "", - "reportcentermodal": "", - "speedprint": "", - "title": "" - }, - "payments": { - "ca_bc_etf_table": "", - "exported_payroll": "" - }, - "special": { - "attendance_detail_csv": "" - }, - "subjects": { - "jobs": { - "individual_job_note": "", - "parts_dispatch": "", - "parts_order": "", - "parts_return_slip": "", - "sublet_order": "" - } - }, - "vendors": { - "purchases_by_vendor_detailed": "", - "purchases_by_vendor_summary": "" - } - }, - "production": { - "actions": { - "addcolumns": "", - "bodypriority-clear": "", - "bodypriority-set": "", - "detailpriority-clear": "", - "detailpriority-set": "", - "paintpriority-clear": "", - "paintpriority-set": "", - "remove": "", - "removecolumn": "", - "saveconfig": "", - "suspend": "", - "unsuspend": "" - }, - "constants": { - "main_profile": "" - }, - "errors": { - "boardupdate": "", - "name_exists": "", - "name_required": "", - "removing": "", - "settings": "" - }, - "labels": { - "actual_in": "", - "addnewprofile": "", - "alert": "", - "alertoff": "", - "alerton": "", - "alerts": "", - "ats": "", - "bodyhours": "", - "bodypriority": "", - "bodyshop": { - "labels": { - "qbo_departmentid": "", - "qbo_usa": "" - } - }, - "card_size": "", - "cardcolor": "", - "cardsettings": "", - "clm_no": "", - "comment": "", - "compact": "", - "detailpriority": "", - "employeeassignments": "", - "employeesearch": "", - "estimator": "", - "horizontal": "", - "ins_co_nm": "", - "jobdetail": "", - "kiosk_mode": "", - "laborhrs": "", - "legend": "", - "model_info": "", - "note": "", - "off": "", - "on": "", - "orientation": "", - "ownr_nm": "", - "paintpriority": "", - "partsstatus": "", - "production_note": "", - "refinishhours": "", - "scheduled_completion": "", - "selectview": "", - "stickyheader": "", - "sublets": "", - "subtotal": "", - "tall": "", - "tasks": "", - "totalhours": "", - "touchtime": "", - "vertical": "", - "viewname": "", - "wide": "" - }, - "options": { - "horizontal": "", - "large": "", - "medium": "", - "small": "", - "vertical": "" - }, - "settings": { - "board_settings": "", - "filters": { - "md_estimators": "", - "md_ins_cos": "" - }, - "filters_title": "", - "information": "", - "layout": "", + "translation": { + "allocations": { + "actions": { + "assign": "Attribuer" + }, + "errors": { + "deleting": "", + "saving": "", + "validation": "" + }, + "fields": { + "employee": "Alloué à" + }, + "successes": { + "deleted": "", + "save": "" + } + }, + "appointments": { + "actions": { + "block": "", + "calculate": "", + "cancel": "annuler", + "intake": "Admission", + "new": "Nouveau rendez-vous", + "preview": "", + "reschedule": "Replanifier", + "sendreminder": "", + "unblock": "", + "viewjob": "Voir le travail" + }, + "errors": { + "blocking": "", + "canceling": "Erreur lors de l'annulation du rendez-vous. {{message}}", + "saving": "Erreur lors de la planification du rendez-vous. {{message}}" + }, + "fields": { + "alt_transport": "", + "color": "", + "end": "", + "note": "", + "start": "", + "time": "", + "title": "Titre" + }, + "labels": { + "arrivedon": "Arrivé le:", + "arrivingjobs": "", + "blocked": "", + "cancelledappointment": "Rendez-vous annulé pour:", + "completingjobs": "", + "dataconsistency": "", + "expectedjobs": "", + "expectedprodhrs": "", + "history": "", + "inproduction": "", + "manualevent": "", + "noarrivingjobs": "", + "nocompletingjobs": "", + "nodateselected": "Aucune date n'a été sélectionnée.", + "priorappointments": "Rendez-vous précédents", + "reminder": "", + "scheduledfor": "Rendez-vous prévu pour:", + "severalerrorsfound": "", + "smartscheduling": "", + "smspaymentreminder": "", + "suggesteddates": "" + }, + "successes": { + "canceled": "Rendez-vous annulé avec succès.", + "created": "Rendez-vous planifié avec succès.", + "saved": "" + } + }, + "associations": { + "actions": { + "activate": "Activer" + }, + "fields": { + "active": "Actif?", + "shopname": "nom de la boutique" + }, + "labels": { + "actions": "actes" + } + }, + "audit": { + "fields": { + "cc": "", + "contents": "", + "created": "", + "operation": "", + "status": "", + "subject": "", + "to": "", + "useremail": "", + "values": "" + } + }, + "audit_trail": { + "messages": { + "admin_job_remove_from_ar": "", + "admin_jobmarkexported": "", + "admin_jobmarkforreexport": "", + "admin_jobuninvoice": "", + "admin_jobunvoid": "", + "alerttoggle": "", + "appointmentcancel": "", + "appointmentinsert": "", + "assignedlinehours": "", + "billdeleted": "", + "billposted": "", + "billupdated": "", + "failedpayment": "", + "jobassignmentchange": "", + "jobassignmentremoved": "", + "jobchecklist": "", + "jobclosedwithbypass": "", + "jobconverted": "", + "jobdelivery": "", + "jobexported": "", + "jobfieldchanged": "", + "jobimported": "", + "jobinproductionchange": "", + "jobintake": "", + "jobinvoiced": "", + "jobioucreated": "", + "jobmodifylbradj": "", + "jobnoteadded": "", + "jobnotedeleted": "", + "jobnoteupdated": "", + "jobspartsorder": "", + "jobspartsreturn": "", + "jobstatuschange": "", + "jobsupplement": "", + "jobsuspend": "", + "jobvoid": "", + "tasks_completed": "", + "tasks_created": "", + "tasks_deleted": "", + "tasks_uncompleted": "", + "tasks_undeleted": "", + "tasks_updated": "" + } + }, + "billlines": { + "actions": { + "newline": "" + }, + "fields": { + "actual_cost": "", + "actual_price": "", + "cost_center": "", + "federal_tax_applicable": "", + "jobline": "", + "line_desc": "", + "local_tax_applicable": "", + "location": "", + "quantity": "", + "state_tax_applicable": "" + }, + "labels": { + "deductedfromlbr": "", + "entered": "", + "from": "", + "mod_lbr_adjustment": "", + "other": "", + "reconciled": "", + "unreconciled": "" + }, + "validation": { + "atleastone": "" + } + }, + "bills": { + "actions": { + "deductallhours": "", + "edit": "", + "receive": "", + "return": "" + }, + "errors": { + "creating": "", + "deleting": "", + "existinginventoryline": "", + "exporting": "", + "exporting-partner": "", + "invalidro": "", + "invalidvendor": "", + "validation": "" + }, + "fields": { + "allpartslocation": "", + "date": "", + "exported": "", + "federal_tax_rate": "", + "invoice_number": "", + "is_credit_memo": "", + "is_credit_memo_short": "", + "local_tax_rate": "", + "ro_number": "", + "state_tax_rate": "", + "total": "", + "vendor": "", + "vendorname": "" + }, + "labels": { + "actions": "", + "bill_lines": "", + "bill_total": "", + "billcmtotal": "", + "bills": "", + "calculatedcreditsnotreceived": "", + "creditsnotreceived": "", + "creditsreceived": "", + "dedfromlbr": "", + "deleteconfirm": "", + "discrepancy": "", + "discrepwithcms": "", + "discrepwithlbradj": "", + "editadjwarning": "", + "entered_total": "", + "enteringcreditmemo": "", + "federal_tax": "", + "federal_tax_exempt": "", + "generatepartslabel": "", + "iouexists": "", + "local_tax": "", + "markexported": "", + "markforreexport": "", + "new": "", + "nobilllines": "", + "noneselected": "", + "onlycmforinvoiced": "", + "printlabels": "", + "retailtotal": "", + "returnfrombill": "", + "savewithdiscrepancy": "", + "state_tax": "", + "subtotal": "", + "totalreturns": "" + }, + "successes": { + "created": "", + "deleted": "", + "exported": "", + "markexported": "", + "reexport": "" + }, + "validation": { + "closingperiod": "", + "inventoryquantity": "", + "manualinhouse": "", + "unique_invoice_number": "" + } + }, + "bodyshop": { + "actions": { + "add_task_preset": "", + "addapptcolor": "", + "addbucket": "", + "addpartslocation": "", + "addpartsrule": "", + "addspeedprint": "", + "addtemplate": "", + "newlaborrate": "", + "newsalestaxcode": "", + "newstatus": "", + "testrender": "" + }, + "errors": { + "creatingdefaultview": "", + "loading": "Impossible de charger les détails de la boutique. Veuillez appeler le support technique.", + "saving": "" + }, + "fields": { + "ReceivableCustomField": "", + "address1": "", + "address2": "", + "appt_alt_transport": "", + "appt_colors": { + "color": "", + "label": "" + }, + "appt_length": "", + "attach_pdf_to_email": "", + "batchid": "", + "bill_allow_post_to_closed": "", + "bill_federal_tax_rate": "", + "bill_local_tax_rate": "", + "bill_state_tax_rate": "", + "city": "", + "closingperiod": "", + "companycode": "", + "country": "", + "dailybodytarget": "", + "dailypainttarget": "", + "default_adjustment_rate": "", + "deliver": { + "require_actual_delivery_date": "", + "templates": "" + }, + "dms": { + "apcontrol": "", + "appostingaccount": "", + "cashierid": "", + "default_journal": "", + "disablebillwip": "", + "disablecontactvehiclecreation": "", + "dms_acctnumber": "", + "dms_control_override": "", + "dms_wip_acctnumber": "", + "generic_customer_number": "", + "itc_federal": "", + "itc_local": "", + "itc_state": "", + "mappingname": "", + "sendmaterialscosting": "", + "srcco": "" + }, + "email": "", + "enforce_class": "", + "enforce_conversion_category": "", + "enforce_conversion_csr": "", + "enforce_referral": "", + "federal_tax_id": "", + "ignoreblockeddays": "", + "inhousevendorid": "", + "insurance_vendor_id": "", + "intake": { + "next_contact_hours": "", + "templates": "" + }, + "intellipay_config": { + "cash_discount_percentage": "", + "enable_cash_discount": "" + }, + "invoice_federal_tax_rate": "", + "invoice_local_tax_rate": "", + "invoice_state_tax_rate": "", + "jc_hourly_rates": { + "mapa": "", + "mash": "" + }, + "last_name_first": "", + "lastnumberworkingdays": "", + "localmediaserverhttp": "", + "localmediaservernetwork": "", + "localmediatoken": "", + "logo_img_footer_margin": "", + "logo_img_header_margin": "", + "logo_img_path": "", + "logo_img_path_height": "", + "logo_img_path_width": "", + "md_categories": "", + "md_ccc_rates": "", + "md_classes": "", + "md_ded_notes": "", + "md_email_cc": "", + "md_from_emails": "", + "md_functionality_toggles": { + "parts_queue_toggle": "" + }, + "md_hour_split": { + "paint": "", + "prep": "" + }, + "md_ins_co": { + "city": "", + "name": "", + "private": "", + "state": "", + "street1": "", + "street2": "", + "zip": "" + }, + "md_jobline_presets": "", + "md_lost_sale_reasons": "", + "md_parts_order_comment": "", + "md_parts_scan": { + "expression": "", + "flags": "" + }, + "md_payment_types": "", + "md_referral_sources": "", + "md_ro_guard": { + "enabled": "", + "enforce_ar": "", + "enforce_bills": "", + "enforce_cm": "", + "enforce_labor": "", + "enforce_ppd": "", + "enforce_profit": "", + "enforce_sublet": "", + "masterbypass": "", + "totalgppercent_minimum": "" + }, + "md_tasks_presets": { + "enable_tasks": "", + "hourstype": "", + "memo": "", + "name": "", + "nextstatus": "", + "percent": "", + "use_approvals": "" + }, + "messaginglabel": "", + "messagingtext": "", + "noteslabel": "", + "notestext": "", + "partslocation": "", + "phone": "", + "prodtargethrs": "", + "rbac": { + "accounting": { + "exportlog": "", + "payables": "", + "payments": "", + "receivables": "" + }, + "bills": { + "delete": "", + "enter": "", + "list": "", + "reexport": "", + "view": "" + }, + "contracts": { + "create": "", + "detail": "", + "list": "" + }, + "courtesycar": { + "create": "", + "detail": "", + "list": "" + }, + "csi": { + "export": "", + "page": "" + }, + "employee_teams": { + "page": "" + }, + "employees": { + "page": "" + }, + "inventory": { + "delete": "", + "list": "" + }, + "jobs": { + "admin": "", + "available-list": "", + "checklist-view": "", + "close": "", + "create": "", + "deliver": "", + "detail": "", + "intake": "", + "list-active": "", + "list-all": "", + "list-ready": "", + "partsqueue": "", + "void": "" + }, + "owners": { + "detail": "", + "list": "" + }, + "payments": { + "enter": "", + "list": "" + }, + "phonebook": { + "edit": "", + "view": "" + }, + "production": { + "board": "", + "list": "" + }, + "schedule": { + "view": "" + }, + "scoreboard": { + "view": "" + }, + "shiftclock": { + "view": "" + }, + "shop": { + "config": "", + "dashboard": "", + "rbac": "", + "reportcenter": "", + "templates": "", + "vendors": "" + }, + "temporarydocs": { + "view": "" + }, + "timetickets": { + "edit": "", + "editcommitted": "", + "enter": "", + "list": "", + "shiftedit": "" + }, + "ttapprovals": { + "approve": "", + "view": "" + }, + "users": { + "editaccess": "" + } + }, + "responsibilitycenter": "", + "responsibilitycenter_accountdesc": "", + "responsibilitycenter_accountitem": "", + "responsibilitycenter_accountname": "", + "responsibilitycenter_accountnumber": "", + "responsibilitycenter_rate": "", + "responsibilitycenter_tax_rate": "", + "responsibilitycenter_tax_sur": "", + "responsibilitycenter_tax_thres": "", + "responsibilitycenter_tax_tier": "", + "responsibilitycenter_tax_type": "", + "responsibilitycenters": { + "ap": "", + "ar": "", + "ats": "", + "federal_tax": "", + "federal_tax_itc": "", + "gst_override": "", + "invoiceexemptcode": "", + "itemexemptcode": "", + "la1": "", + "la2": "", + "la3": "", + "la4": "", + "laa": "", + "lab": "", + "lad": "", + "lae": "", + "laf": "", + "lag": "", + "lam": "", + "lar": "", + "las": "", + "lau": "", + "local_tax": "", + "mapa": "", + "mash": "", + "paa": "", + "pac": "", + "pag": "", + "pal": "", + "pam": "", + "pan": "", + "pao": "", + "pap": "", + "par": "", + "pas": "", + "pasl": "", + "refund": "", + "sales_tax_codes": { + "code": "", + "description": "", + "federal": "", + "local": "", + "state": "" + }, + "state_tax": "", + "tow": "" + }, + "schedule_end_time": "", + "schedule_start_time": "", + "shopname": "", + "speedprint": { + "id": "", + "label": "", + "templates": "" + }, + "ss_configuration": { + "dailyhrslimit": "" + }, + "ssbuckets": { + "color": "", + "gte": "", + "id": "", + "label": "", + "lt": "", + "target": "" + }, + "state": "", + "state_tax_id": "", + "status": "", + "statuses": { + "active_statuses": "", + "additional_board_statuses": "", + "color": "", + "default_arrived": "", + "default_bo": "", + "default_canceled": "", + "default_completed": "", + "default_delivered": "", + "default_exported": "", + "default_imported": "", + "default_invoiced": "", + "default_ordered": "", + "default_quote": "", + "default_received": "", + "default_returned": "", + "default_scheduled": "", + "default_void": "", + "open_statuses": "", + "post_production_statuses": "", + "pre_production_statuses": "", + "production_colors": "", + "production_statuses": "", + "ready_statuses": "" + }, + "target_touchtime": "", + "timezone": "", + "tt_allow_post_to_invoiced": "", + "tt_enforce_hours_for_tech_console": "", + "use_fippa": "", + "use_paint_scale_data": "", + "uselocalmediaserver": "", + "website": "", + "zip_post": "" + }, + "labels": { + "2tiername": "", + "2tiersetup": "", + "2tiersource": "", + "accountingsetup": "", + "accountingtiers": "", + "alljobstatuses": "", + "allopenjobstatuses": "", + "apptcolors": "", + "businessinformation": "", + "checklists": "", + "csiq": "", + "customtemplates": "", + "defaultcostsmapping": "", + "defaultprofitsmapping": "", + "deliverchecklist": "", + "dms": { + "cdk": { + "controllist": "", + "payers": "" + }, + "cdk_dealerid": "", + "costsmapping": "", + "dms_allocations": "", + "pbs_serialnumber": "", + "profitsmapping": "", + "title": "" + }, + "emaillater": "", + "employee_teams": "", + "employees": "", + "estimators": "", + "filehandlers": "", + "insurancecos": "", + "intakechecklist": "", + "intellipay": "", + "intellipay_cash_discount": "", + "jobstatuses": "", + "laborrates": "", + "licensing": "", + "md_parts_scan": "", + "md_ro_guard": "", + "md_tasks_presets": "", + "md_to_emails": "", + "md_to_emails_emails": "", + "messagingpresets": "", + "notemplatesavailable": "", + "notespresets": "", + "orderstatuses": "", + "partslocations": "", + "partsscan": "", + "printlater": "", + "qbo": "", + "qbo_departmentid": "", + "qbo_usa": "", + "rbac": "", + "responsibilitycenters": { + "costs": "", + "profits": "", + "sales_tax_codes": "", + "tax_accounts": "", + "title": "" + }, + "roguard": { + "title": "" + }, + "scheduling": "", + "scoreboardsetup": "", + "shopinfo": "", + "speedprint": "", + "ssbuckets": "", + "systemsettings": "", + "task-presets": "", + "workingdays": "" + }, + "successes": { + "areyousure": "", + "defaultviewcreated": "", + "save": "", + "unsavedchanges": "" + }, + "validation": { + "centermustexist": "", + "larsplit": "", + "useremailmustexist": "" + } + }, + "checklist": { + "actions": { + "printall": "" + }, + "errors": { + "complete": "", + "nochecklist": "" + }, + "labels": { + "addtoproduction": "", + "allow_text_message": "", + "checklist": "", + "printpack": "", + "removefromproduction": "" + }, + "successes": { + "completed": "" + } + }, + "contracts": { + "actions": { + "changerate": "", + "convertoro": "", + "decodelicense": "", + "find": "", + "printcontract": "", + "senddltoform": "" + }, + "errors": { + "fetchingjobinfo": "", + "returning": "", + "saving": "", + "selectjobandcar": "" + }, + "fields": { + "actax": "", + "actualreturn": "", + "agreementnumber": "", + "cc_cardholder": "", + "cc_expiry": "", + "cc_num": "", + "cleanupcharge": "", + "coverage": "", + "dailyfreekm": "", + "dailyrate": "", + "damage": "", + "damagewaiver": "", + "driver": "", + "driver_addr1": "", + "driver_addr2": "", + "driver_city": "", + "driver_dlexpiry": "", + "driver_dlnumber": "", + "driver_dlst": "", + "driver_dob": "", + "driver_fn": "", + "driver_ln": "", + "driver_ph1": "", + "driver_state": "", + "driver_zip": "", + "excesskmrate": "", + "federaltax": "", + "fuelin": "", + "fuelout": "", + "kmend": "", + "kmstart": "", + "length": "", + "localtax": "", + "refuelcharge": "", + "scheduledreturn": "", + "start": "", + "statetax": "", + "status": "" + }, + "labels": { + "agreement": "", + "availablecars": "", + "cardueforservice": "", + "convertform": { + "applycleanupcharge": "", + "refuelqty": "" + }, + "correctdataonform": "", + "dateinpast": "", + "dlexpirebeforereturn": "", + "driverinformation": "", + "findcontract": "", + "findermodal": "", + "insuranceexpired": "", + "noteconvertedfrom": "", + "populatefromjob": "", + "rates": "", + "time": "", + "vehicle": "", + "waitingforscan": "" + }, + "status": { + "new": "", + "out": "", + "returned": "" + }, + "successes": { + "saved": "" + } + }, + "courtesycars": { + "actions": { + "new": "", + "return": "" + }, + "errors": { + "saving": "" + }, + "fields": { + "color": "", + "dailycost": "", + "damage": "", + "fleetnumber": "", + "fuel": "", + "insuranceexpires": "", + "leaseenddate": "", + "make": "", + "mileage": "", + "model": "", + "nextservicedate": "", + "nextservicekm": "", + "notes": "", + "plate": "", + "purchasedate": "", + "readiness": "", + "registrationexpires": "", + "serviceenddate": "", + "servicestartdate": "", + "status": "", + "vin": "", + "year": "" + }, + "labels": { + "courtesycar": "", + "fuel": { + "12": "", + "14": "", + "18": "", + "34": "", + "38": "", + "58": "", + "78": "", + "empty": "", + "full": "" + }, + "outwith": "", + "return": "", + "status": "", + "uniquefleet": "", + "usage": "", + "vehicle": "" + }, + "readiness": { + "notready": "", + "ready": "" + }, + "status": { + "in": "", + "inservice": "", + "leasereturn": "", + "out": "", + "sold": "", + "unavailable": "" + }, + "successes": { + "saved": "" + } + }, + "csi": { + "actions": { + "activate": "" + }, + "errors": { + "creating": "", + "notconfigured": "", + "notfoundsubtitle": "", + "notfoundtitle": "", + "surveycompletesubtitle": "", + "surveycompletetitle": "" + }, + "fields": { + "completedon": "", + "created_at": "", + "surveyid": "", + "validuntil": "" + }, + "labels": { + "copyright": "", + "greeting": "", + "intro": "", + "nologgedinuser": "", + "nologgedinuser_sub": "", + "noneselected": "", + "title": "" + }, + "successes": { + "created": "", + "submitted": "", + "submittedsub": "" + } + }, + "dashboard": { + "actions": { + "addcomponent": "" + }, + "errors": { + "refreshrequired": "", + "updatinglayout": "" + }, + "labels": { + "bodyhrs": "", + "dollarsinproduction": "", + "phone": "", + "prodhrs": "", + "refhrs": "" + }, + "titles": { + "joblifecycle": "", + "labhours": "", + "larhours": "", + "monthlyemployeeefficiency": "", + "monthlyjobcosting": "", + "monthlylaborsales": "", + "monthlypartssales": "", + "monthlyrevenuegraph": "", + "prodhrssummary": "", + "productiondollars": "", + "productionhours": "", + "projectedmonthlysales": "", + "scheduledindate": "", + "scheduledintoday": "", + "scheduledoutdate": "", + "scheduledouttoday": "", + "tasks": "" + } + }, + "dms": { + "errors": { + "alreadyexported": "" + }, + "labels": { + "refreshallocations": "" + } + }, + "documents": { + "actions": { + "delete": "", + "download": "", + "reassign": "", + "selectallimages": "", + "selectallotherdocuments": "" + }, + "errors": { + "deletes3": "Erreur lors de la suppression du document du stockage.", + "deleting": "", + "deleting_cloudinary": "", + "getpresignurl": "Erreur lors de l'obtention de l'URL présignée pour le document. {{message}}", + "insert": "Incapable de télécharger le fichier. {{message}}", + "nodocuments": "Il n'y a pas de documents.", + "updating": "" + }, + "labels": { + "confirmdelete": "", + "doctype": "", + "newjobid": "", + "openinexplorer": "", + "optimizedimage": "", + "reassign_limitexceeded": "", + "reassign_limitexceeded_title": "", + "storageexceeded": "", + "storageexceeded_title": "", + "upload": "Télécharger", + "upload_limitexceeded": "", + "upload_limitexceeded_title": "", + "uploading": "", + "usage": "" + }, + "successes": { + "delete": "Le document a bien été supprimé.", + "edituploaded": "", + "insert": "Document téléchargé avec succès.", + "updated": "" + } + }, + "emails": { + "errors": { + "notsent": "Courriel non envoyé. Erreur rencontrée lors de l'envoi de {{message}}" + }, + "fields": { + "cc": "", + "from": "", + "subject": "", + "to": "" + }, + "labels": { + "attachments": "", + "documents": "", + "emailpreview": "", + "generatingemail": "", + "pdfcopywillbeattached": "", + "preview": "" + }, + "successes": { + "sent": "E-mail envoyé avec succès." + } + }, + "employee_teams": { + "actions": { + "new": "", + "newmember": "" + }, + "fields": { + "active": "", + "employeeid": "", + "max_load": "", + "name": "", + "percentage": "" + } + }, + "employees": { + "actions": { + "addvacation": "", + "new": "Nouvel employé", + "newrate": "" + }, + "errors": { + "delete": "Erreur rencontrée lors de la suppression de l'employé. {{message}}", + "save": "Une erreur s'est produite lors de l'enregistrement de l'employé. {{message}}", + "validation": "Veuillez cocher tous les champs.", + "validationtitle": "Impossible d'enregistrer l'employé." + }, + "fields": { + "active": "Actif?", + "base_rate": "Taux de base", + "cost_center": "Centre de coûts", + "employee_number": "Numéro d'employé", + "external_id": "", + "first_name": "Prénom", + "flat_rate": "Taux fixe (désactivé est le temps normal)", + "hire_date": "Date d'embauche", + "last_name": "Nom de famille", + "pin": "", + "rate": "", + "termination_date": "Date de résiliation", + "user_email": "", + "vacation": { + "end": "", + "length": "", + "start": "" + } + }, + "labels": { + "actions": "", + "active": "", + "endmustbeafterstart": "", + "flat_rate": "", + "inactive": "", + "name": "", + "rate_type": "", + "status": "", + "straight_time": "" + }, + "successes": { + "delete": "L'employé a bien été supprimé.", + "save": "L'employé a enregistré avec succès.", + "vacationadded": "" + }, + "validation": { + "unique_employee_number": "" + } + }, + "eula": { + "buttons": { + "accept": "Accept EULA" + }, + "content": { + "never_scrolled": "You must scroll to the bottom of the Terms and Conditions before accepting." + }, + "errors": { + "acceptance": { + "description": "Something went wrong while accepting the EULA. Please try again.", + "message": "Eula Acceptance Error" + } + }, + "labels": { + "accepted_terms": "I accept the terms and conditions of this agreement.", + "address": "Address", + "business_name": "Legal Business Name", + "date_accepted": "Date Accepted", + "first_name": "First Name", + "last_name": "Last Name", + "phone_number": "Phone Number" + }, + "messages": { + "accepted_terms": "Please accept the terms and conditions of this agreement.", + "business_name": "Please enter your legal business name.", + "date_accepted": "Please enter Today's Date.", + "first_name": "Please enter your first name.", + "last_name": "Please enter your last name.", + "phone_number": "Please enter your phone number." + }, + "titles": { + "modal": "Terms and Conditions", + "upper_card": "Acknowledgement" + } + }, + "exportlogs": { + "fields": { + "createdat": "" + }, + "labels": { + "attempts": "", + "priorsuccesfulexport": "" + } + }, + "general": { + "actions": { + "add": "", + "autoupdate": "", + "calculate": "", + "cancel": "", + "clear": "", + "close": "", + "copied": "", + "copylink": "", + "create": "", + "defaults": "", + "delay": "", + "delete": "Effacer", + "deleteall": "", + "deselectall": "", + "download": "", + "edit": "modifier", + "login": "", + "next": "", + "previous": "", + "print": "", + "refresh": "", + "remove": "", + "remove_alert": "", + "reset": " Rétablir l'original.", + "resetpassword": "", + "save": "sauvegarder", + "saveandnew": "", + "saveas": "", + "selectall": "", + "send": "", + "sendbysms": "", + "senderrortosupport": "", + "submit": "", + "tryagain": "", + "view": "", + "viewreleasenotes": "" + }, + "errors": { + "fcm": "", + "notfound": "", + "sizelimit": "" + }, + "itemtypes": { + "contract": "", + "courtesycar": "", + "job": "", + "owner": "", + "vehicle": "" + }, + "labels": { + "actions": "actes", + "areyousure": "", + "barcode": "code à barre", + "cancel": "", + "clear": "", + "confirmpassword": "", + "created_at": "", + "date": "", + "datetime": "", + "email": "", + "errors": "", + "excel": "", + "exceptiontitle": "", + "friday": "", + "globalsearch": "", + "help": "", + "hours": "", + "in": "dans", + "instanceconflictext": "", + "instanceconflictitle": "", + "item": "", + "label": "", + "loading": "Chargement...", + "loadingapp": "Chargement de {{app}}", + "loadingshop": "Chargement des données de la boutique ...", + "loggingin": "Vous connecter ...", + "markedexported": "", + "media": "", + "message": "", + "monday": "", + "na": "N / A", + "newpassword": "", + "no": "", + "nointernet": "", + "nointernet_sub": "", + "none": "", + "out": "En dehors", + "password": "", + "passwordresetsuccess": "", + "passwordresetsuccess_sub": "", + "passwordresetvalidatesuccess": "", + "passwordresetvalidatesuccess_sub": "", + "passwordsdonotmatch": "", + "print": "", + "refresh": "", + "reports": "", + "required": "", + "saturday": "", + "search": "Chercher...", + "searchresults": "", + "selectdate": "", + "sendagain": "", + "sendby": "", + "signin": "", + "sms": "", + "status": "", + "sub_status": { + "expired": "" + }, + "successful": "", + "sunday": "", + "text": "", + "thursday": "", + "total": "", + "totals": "", + "tuesday": "", + "tvmode": "", + "unknown": "Inconnu", + "unsavedchanges": "", + "username": "", + "view": "", + "wednesday": "", + "yes": "" + }, + "languages": { + "english": "Anglais", + "french": "Francais", + "spanish": "Espanol" + }, + "messages": { + "exception": "", + "newversionmessage": "", + "newversiontitle": "", + "noacctfilepath": "", + "nofeatureaccess": "", + "noshop": "", + "notfoundsub": "", + "notfoundtitle": "", + "partnernotrunning": "", + "rbacunauth": "", + "unsavedchanges": "Vous avez des changements non enregistrés.", + "unsavedchangespopup": "" + }, + "validation": { + "invalidemail": "S'il vous plaît entrer un email valide.", + "invalidphone": "", + "required": "Ce champ est requis." + } + }, + "help": { + "actions": { + "connect": "" + }, + "labels": { + "codeplacholder": "", + "rescuedesc": "", + "rescuetitle": "" + } + }, + "intake": { + "labels": { + "printpack": "" + } + }, + "inventory": { + "actions": { + "addtoinventory": "", + "addtoro": "", + "consumefrominventory": "", + "edit": "", + "new": "" + }, + "errors": { + "inserting": "" + }, + "fields": { + "comment": "", + "manualinvoicenumber": "", + "manualvendor": "" + }, + "labels": { + "consumedbyjob": "", + "deleteconfirm": "", + "frombillinvoicenumber": "", + "fromvendor": "", + "inventory": "", + "showall": "", + "showavailable": "" + }, + "successes": { + "deleted": "", + "inserted": "", + "updated": "" + } + }, + "job_lifecycle": { + "columns": { + "duration": "", + "end": "", + "human_readable": "", + "percentage": "", + "relative_end": "", + "relative_start": "", + "start": "", + "status": "", + "status_count": "", + "value": "" + }, + "content": { + "calculated_based_on": "", + "current_status_accumulated_time": "", + "data_unavailable": "", + "jobs_in_since": "", + "legend_title": "", + "loading": "", + "not_available": "", + "previous_status_accumulated_time": "", + "title": "", + "title_durations": "", + "title_loading": "", + "title_transitions": "" + }, + "errors": { + "fetch": "Erreur lors de l'obtention des données du cycle de vie des tâches" + }, + "titles": { + "dashboard": "", + "top_durations": "" + } + }, + "job_payments": { + "buttons": { + "create_short_link": "", + "goback": "", + "proceedtopayment": "", + "refundpayment": "" + }, + "notifications": { + "error": { + "description": "", + "openingip": "", + "title": "" + } + }, + "titles": { + "amount": "", + "dateOfPayment": "", + "descriptions": "", + "hint": "", + "payer": "", + "payername": "", + "paymentid": "", + "paymentnum": "", + "paymenttype": "", + "refundamount": "", + "transactionid": "" + } + }, + "joblines": { + "actions": { + "assign_team": "", + "converttolabor": "", + "dispatchparts": "", + "new": "" + }, + "errors": { + "creating": "", + "updating": "" + }, + "fields": { + "act_price": "Prix actuel", + "act_price_before_ppc": "", + "adjustment": "", + "ah_detail_line": "", + "amount": "", + "assigned_team": "", + "assigned_team_name": "", + "create_ppc": "", + "db_price": "Prix de la base de données", + "lbr_types": { + "LA1": "", + "LA2": "", + "LA3": "", + "LA4": "", + "LAA": "", + "LAB": "", + "LAD": "", + "LAE": "", + "LAF": "", + "LAG": "", + "LAM": "", + "LAR": "", + "LAS": "", + "LAU": "" + }, + "line_desc": "Description de la ligne", + "line_ind": "S#", + "line_no": "", + "location": "", + "mod_lb_hrs": "Heures de travail", + "mod_lbr_ty": "Type de travail", + "notes": "", + "oem_partno": "Pièce OEM #", + "op_code_desc": "", + "part_qty": "", + "part_type": "Type de pièce", + "part_types": { + "CCC": "", + "CCD": "", + "CCDR": "", + "CCF": "", + "CCM": "", + "PAA": "", + "PAC": "", + "PAE": "", + "PAG": "", + "PAL": "", + "PAM": "", + "PAN": "", + "PAO": "", + "PAP": "", + "PAR": "", + "PAS": "", + "PASL": "" + }, + "profitcenter_labor": "", + "profitcenter_part": "", + "prt_dsmk_m": "", + "prt_dsmk_p": "", + "status": "Statut", + "tax_part": "", + "total": "", + "unq_seq": "Seq #" + }, + "labels": { + "adjustmenttobeadded": "", + "billref": "", + "convertedtolabor": "", + "edit": "Ligne d'édition", + "ioucreated": "", + "new": "Nouvelle ligne", + "nostatus": "", + "presets": "" + }, + "successes": { + "created": "", + "saved": "", + "updated": "" + }, + "validations": { + "ahdetailonlyonuserdefinedtypes": "", + "hrsrequirediflbrtyp": "", + "requiredifparttype": "", + "zeropriceexistingpart": "" + } + }, + "jobs": { + "actions": { + "addDocuments": "Ajouter des documents de travail", + "addNote": "Ajouter une note", + "addtopartsqueue": "", + "addtoproduction": "", + "addtoscoreboard": "", + "allocate": "", + "autoallocate": "", + "changefilehandler": "", + "changelaborrate": "", + "changestatus": "Changer le statut", + "changestimator": "", + "convert": "Convertir", + "createiou": "", + "deliver": "", + "dms": { + "addpayer": "", + "createnewcustomer": "", + "findmakemodelcode": "", + "getmakes": "", + "labels": { + "refreshallocations": "" + }, + "post": "", + "refetchmakesmodels": "", + "usegeneric": "", + "useselected": "" + }, + "dmsautoallocate": "", + "export": "", + "exportcustdata": "", + "exportselected": "", + "filterpartsonly": "", + "generatecsi": "", + "gotojob": "", + "intake": "", + "manualnew": "", + "mark": "", + "markasexported": "", + "markpstexempt": "", + "markpstexemptconfirm": "", + "postbills": "Poster des factures", + "printCenter": "Centre d'impression", + "recalculate": "", + "reconcile": "", + "removefromproduction": "", + "schedule": "Programme", + "sendcsi": "", + "sendpartspricechange": "", + "sendtodms": "", + "sync": "", + "taxprofileoverride": "", + "taxprofileoverride_confirm": "", + "uninvoice": "", + "unvoid": "", + "viewchecklist": "", + "viewdetail": "" + }, + "errors": { + "addingtoproduction": "", + "cannotintake": "", + "closing": "", + "creating": "", + "deleted": "Erreur lors de la suppression du travail.", + "exporting": "", + "exporting-partner": "", + "invoicing": "", + "noaccess": "Ce travail n'existe pas ou vous n'y avez pas accès.", + "nodamage": "", + "nodates": "Aucune date spécifiée pour ce travail.", + "nofinancial": "", + "nojobselected": "Aucun travail n'est sélectionné.", + "noowner": "Aucun propriétaire associé.", + "novehicle": "Aucun véhicule associé.", + "partspricechange": "", + "saving": "Erreur rencontrée lors de la sauvegarde de l'enregistrement.", + "scanimport": "", + "totalscalc": "", + "updating": "", + "validation": "Veuillez vous assurer que tous les champs sont correctement entrés.", + "validationtitle": "Erreur de validation", + "voiding": "" + }, + "fields": { + "active_tasks": "", + "actual_completion": "Achèvement réel", + "actual_delivery": "Livraison réelle", + "actual_in": "En réel", + "adjustment_bottom_line": "Ajustements", + "adjustmenthours": "", + "alt_transport": "", + "area_of_damage_impact": { + "10": "", + "11": "", + "12": "", + "13": "", + "14": "", + "15": "", + "16": "", + "25": "", + "26": "", + "27": "", + "28": "", + "34": "", + "01": "", + "02": "", + "03": "", + "04": "", + "05": "", + "06": "", + "07": "", + "08": "", + "09": "" + }, + "auto_add_ats": "", + "ca_bc_pvrt": "", + "ca_customer_gst": "", + "ca_gst_registrant": "", + "category": "", + "ccc": "", + "ccd": "", + "ccdr": "", + "ccf": "", + "ccm": "", + "cieca_id": "CIECA ID", + "cieca_pfl": { + "lbr_adjp": "", + "lbr_tax_in": "", + "lbr_taxp": "", + "lbr_tx_in1": "", + "lbr_tx_in2": "", + "lbr_tx_in3": "", + "lbr_tx_in4": "", + "lbr_tx_in5": "" + }, + "cieca_pfo": { + "stor_t_in1": "", + "stor_t_in2": "", + "stor_t_in3": "", + "stor_t_in4": "", + "stor_t_in5": "", + "tow_t_in1": "", + "tow_t_in2": "", + "tow_t_in3": "", + "tow_t_in4": "", + "tow_t_in5": "" + }, + "claim_total": "Total réclamation", + "class": "", + "clm_no": "Prétendre #", + "clm_total": "Total réclamation", + "comment": "", + "customerowing": "Client propriétaire", + "date_estimated": "Date estimée", + "date_exported": "Exportés", + "date_invoiced": "Facturé", + "date_last_contacted": "", + "date_lost_sale": "", + "date_next_contact": "", + "date_open": "Ouvrir", + "date_rentalresp": "", + "date_repairstarted": "", + "date_scheduled": "Prévu", + "date_towin": "", + "date_void": "", + "ded_amt": "Déductible", + "ded_note": "", + "ded_status": "Statut de franchise", + "depreciation_taxes": "Amortissement / taxes", + "dms": { + "address": "", + "amount": "", + "center": "", + "control_type": { + "account_number": "" + }, + "cost": "", + "cost_dms_acctnumber": "", + "dms_make": "", + "dms_model": "", + "dms_model_override": "", + "dms_unsold": "", + "dms_wip_acctnumber": "", + "id": "", + "inservicedate": "", + "journal": "", + "lines": "", + "name1": "", + "payer": { + "amount": "", + "control_type": "", + "controlnumber": "", + "dms_acctnumber": "", + "name": "" + }, + "sale": "", + "sale_dms_acctnumber": "", + "story": "", + "vinowner": "" + }, + "dms_allocation": "", + "driveable": "", + "employee_body": "", + "employee_csr": "représentant du service à la clientèle", + "employee_csr_writer": "", + "employee_prep": "", + "employee_refinish": "", + "est_addr1": "Adresse de l'évaluateur", + "est_co_nm": "Expert", + "est_ct_fn": "Prénom de l'évaluateur", + "est_ct_ln": "Nom de l'évaluateur", + "est_ea": "Courriel de l'évaluateur", + "est_ph1": "Numéro de téléphone de l'évaluateur", + "federal_tax_payable": "Impôt fédéral à payer", + "federal_tax_rate": "", + "ins_addr1": "Adresse Insurance Co.", + "ins_city": "Insurance City", + "ins_co_id": "ID de la compagnie d'assurance", + "ins_co_nm": "Nom de la compagnie d'assurance", + "ins_co_nm_short": "", + "ins_ct_fn": "Prénom du gestionnaire de fichiers", + "ins_ct_ln": "Nom du gestionnaire de fichiers", + "ins_ea": "Courriel du gestionnaire de fichiers", + "ins_ph1": "Numéro de téléphone du gestionnaire de fichiers", + "intake": { + "label": "", + "max": "", + "min": "", + "name": "", + "required": "", + "type": "" + }, + "invoice_final_note": "", + "kmin": "Kilométrage en", + "kmout": "Kilométrage hors", + "la1": "", + "la2": "", + "la3": "", + "la4": "", + "laa": "", + "lab": "", + "labor_rate_desc": "Nom du taux de main-d'œuvre", + "lad": "", + "lae": "", + "laf": "", + "lag": "", + "lam": "", + "lar": "", + "las": "", + "lau": "", + "local_tax_rate": "", + "loss_date": "Date de perte", + "loss_desc": "", + "loss_of_use": "", + "lost_sale_reason": "", + "ma2s": "", + "ma3s": "", + "mabl": "", + "macs": "", + "mahw": "", + "mapa": "", + "mash": "", + "matd": "", + "materials": { + "MAPA": "", + "MASH": "", + "cal_maxdlr": "", + "cal_opcode": "", + "mat_adjp": "", + "mat_taxp": "", + "mat_tx_in1": "", + "mat_tx_in2": "", + "mat_tx_in3": "", + "mat_tx_in4": "", + "mat_tx_in5": "", + "materials": "", + "tax_ind": "" + }, + "other_amount_payable": "Autre montant à payer", + "owner": "Propriétaire", + "owner_owing": "Cust. Owes", + "ownr_ea": "Email", + "ownr_ph1": "Téléphone 1", + "ownr_ph2": "", + "paa": "", + "pac": "", + "pae": "", + "pag": "", + "pal": "", + "pam": "", + "pan": "", + "pao": "", + "pap": "", + "par": "", + "parts_tax_rates": { + "prt_discp": "", + "prt_mktyp": "", + "prt_mkupp": "", + "prt_tax_in": "", + "prt_tax_rt": "", + "prt_tx_in1": "", + "prt_tx_in2": "", + "prt_tx_in3": "", + "prt_tx_in4": "", + "prt_tx_in5": "", + "prt_tx_ty1": "", + "prt_type": "" + }, + "partsstatus": "", + "pas": "", + "pay_date": "Date d'Pay", + "phoneshort": "PH", + "po_number": "", + "policy_no": "Politique #", + "ponumber": "Numéro de bon de commande", + "production_vars": { + "note": "" + }, + "qb_multiple_payers": { + "amount": "", + "name": "" + }, + "queued_for_parts": "", + "rate_ats": "", + "rate_la1": "Taux LA1", + "rate_la2": "Taux LA2", + "rate_la3": "Taux LA3", + "rate_la4": "Taux LA4", + "rate_laa": "Taux d'aluminium", + "rate_lab": "Taux de la main-d'œuvre", + "rate_lad": "Taux de diagnostic", + "rate_lae": "Tarif électrique", + "rate_laf": "Taux de trame", + "rate_lag": "Taux de verre", + "rate_lam": "Taux mécanique", + "rate_lar": "Taux de finition", + "rate_las": "", + "rate_lau": "Taux d'aluminium", + "rate_ma2s": "Taux de peinture en 2 étapes", + "rate_ma3s": "Taux de peinture en 3 étapes", + "rate_mabl": "MABL ??", + "rate_macs": "MACS ??", + "rate_mahw": "Taux de déchets dangereux", + "rate_mapa": "Taux de matériaux de peinture", + "rate_mash": "Tarif du matériel de la boutique", + "rate_matd": "Taux d'élimination des pneus", + "referral_source_extra": "", + "referral_source_other": "", + "referralsource": "Source de référence", + "regie_number": "Enregistrement #", + "repairtotal": "Réparation totale", + "ro_number": "RO #", + "scheduled_completion": "Achèvement planifié", + "scheduled_delivery": "Livraison programmée", + "scheduled_in": "Planifié dans", + "selling_dealer": "Revendeur vendeur", + "selling_dealer_contact": "Contacter le revendeur", + "servicecar": "Voiture de service", + "servicing_dealer": "Concessionnaire", + "servicing_dealer_contact": "Contacter le concessionnaire", + "special_coverage_policy": "Politique de couverture spéciale", + "specialcoveragepolicy": "Politique de couverture spéciale", + "state_tax_rate": "", + "status": "Statut de l'emploi", + "storage_payable": "Stockage", + "tax_lbr_rt": "", + "tax_levies_rt": "", + "tax_paint_mat_rt": "", + "tax_registration_number": "", + "tax_shop_mat_rt": "", + "tax_str_rt": "", + "tax_sub_rt": "", + "tax_tow_rt": "", + "towin": "", + "towing_payable": "Remorquage à payer", + "unitnumber": "Unité #", + "updated_at": "Mis à jour à", + "uploaded_by": "Telechargé par", + "vehicle": "Véhicule" + }, + "forms": { + "admindates": "", + "appraiserinfo": "", + "claiminfo": "", + "estdates": "", + "laborrates": "", + "lossinfo": "", + "other": "", + "repairdates": "", + "scheddates": "" + }, + "labels": { + "accountsreceivable": "", + "act_price_ppc": "", + "actual_completion_inferred": "", + "actual_delivery_inferred": "", + "actual_in_inferred": "", + "additionalpayeroverallocation": "", + "additionaltotal": "", + "adjustmentrate": "", + "adjustments": "", + "adminwarning": "", + "allocations": "", + "alreadyaddedtoscoreboard": "", + "alreadyclosed": "", + "appointmentconfirmation": "Envoyer une confirmation au client?", + "associationwarning": "", + "audit": "", + "available": "", + "availablejobs": "", + "ca_bc_pvrt": { + "days": "", + "rate": "" + }, + "ca_gst_all_if_null": "", + "calc_repair_days": "", + "calc_repair_days_tt": "", + "calc_scheuled_completion": "", + "cards": { + "customer": "Informations client", + "damage": "Zone de dommages", + "dates": "Rendez-vous", + "documents": "Documents récents", + "estimator": "Estimateur", + "filehandler": "Gestionnaire de fichiers", + "insurance": "Détails de l'assurance", + "more": "Plus", + "notes": "Remarques", + "parts": "les pièces", + "totals": "Totaux", + "vehicle": "Véhicule" + }, + "changeclass": "", + "checklistcompletedby": "", + "checklistdocuments": "", + "checklists": "", + "cieca_pfl": "", + "cieca_pfo": "", + "cieca_pft": "", + "closeconfirm": "", + "closejob": "", + "closingperiod": "", + "contracts": "", + "convertedtolabor": "", + "cost": "", + "cost_Additional": "", + "cost_labor": "", + "cost_parts": "", + "cost_sublet": "", + "costs": "", + "create": { + "jobinfo": "", + "newowner": "", + "newvehicle": "", + "novehicle": "", + "ownerinfo": "", + "vehicleinfo": "" + }, + "createiouwarning": "", + "creating_new_job": "Création d'un nouvel emploi ...", + "deductible": { + "stands": "", + "waived": "" + }, + "deleteconfirm": "", + "deletedelivery": "", + "deleteintake": "", + "deliverchecklist": "", + "difference": "", + "diskscan": "", + "dms": { + "apexported": "", + "damageto": "", + "defaultstory": "", + "disablebillwip": "", + "invoicedatefuture": "", + "kmoutnotgreaterthankmin": "", + "logs": "", + "notallocated": "", + "postingform": "", + "totalallocated": "" + }, + "documents": "Les documents", + "documents-images": "", + "documents-other": "", + "duplicateconfirm": "", + "emailaudit": "", + "employeeassignments": "", + "estimatelines": "", + "estimator": "", + "existing_jobs": "Emplois existants", + "federal_tax_amt": "", + "gpdollars": "", + "gppercent": "", + "hrs_claimed": "", + "hrs_total": "", + "importnote": "", + "inproduction": "", + "intakechecklist": "", + "iou": "", + "job": "", + "jobcosting": "", + "jobtotals": "", + "labor_hrs": "", + "labor_rates_subtotal": "", + "laborallocations": "", + "labortotals": "", + "lines": "Estimer les lignes", + "local_tax_amt": "", + "mapa": "", + "markforreexport": "", + "mash": "", + "masterbypass": "", + "materials": { + "mapa": "" + }, + "missingprofileinfo": "", + "multipayers": "", + "net_repairs": "", + "notes": "Remarques", + "othertotal": "", + "outstanding_ar": "", + "outstanding_credit_memos": "", + "outstanding_ppd": "", + "outstanding_reconciliation_discrep": "", + "outstanding_sublets": "", + "outstandinghours": "", + "override_header": "Remplacer l'en-tête d'estimation à l'importation?", + "ownerassociation": "", + "parts": "les pièces", + "parts_lines": "", + "parts_received": "", + "parts_tax_rates": "", + "partsfilter": "", + "partssubletstotal": "", + "partstotal": "", + "performance": "", + "pimraryamountpayable": "", + "plitooltips": { + "billtotal": "", + "calculatedcreditsnotreceived": "", + "creditmemos": "", + "creditsnotreceived": "", + "discrep1": "", + "discrep2": "", + "discrep3": "", + "laboradj": "", + "partstotal": "", + "totalreturns": "" + }, + "ppc": "", + "ppdnotexported": "", + "profileadjustments": "", + "profitbypassrequired": "", + "profits": "", + "prt_dsmk_total": "", + "rates": "Les taux", + "rates_subtotal": "", + "reconciliation": { + "billlinestotal": "", + "byassoc": "", + "byprice": "", + "clear": "", + "discrepancy": "", + "joblinestotal": "", + "multipleactprices": "", + "multiplebilllines": "", + "multiplebillsforactprice": "", + "removedpartsstrikethrough": "" + }, + "reconciliationheader": "", + "relatedros": "", + "remove_from_ar": "", + "returntotals": "", + "ro_guard": { + "enforce_ar": "", + "enforce_bills": "", + "enforce_cm": "", + "enforce_labor": "", + "enforce_ppd": "", + "enforce_profit": "", + "enforce_sublet": "", + "enforce_validation": "", + "enforced": "" + }, + "roguard": "", + "roguardwarnings": "", + "rosaletotal": "", + "sale_additional": "", + "sale_labor": "", + "sale_parts": "", + "sale_sublet": "", + "sales": "", + "savebeforeconversion": "", + "scheduledinchange": "", + "specialcoveragepolicy": "", + "state_tax_amt": "", + "subletsnotcompleted": "", + "subletstotal": "", + "subtotal": "", + "supplementnote": "", + "suspended": "", + "suspense": "", + "tasks": "", + "threshhold": "", + "total_cost": "", + "total_cust_payable": "", + "total_repairs": "", + "total_sales": "", + "total_sales_tax": "", + "totals": "", + "unvoidnote": "", + "update_scheduled_completion": "", + "vehicle_info": "Véhicule", + "vehicleassociation": "", + "viewallocations": "", + "voidjob": "", + "voidnote": "" + }, + "successes": { + "addedtoproduction": "", + "all_deleted": "{{count}} travaux supprimés avec succès.", + "closed": "", + "converted": "Travail converti avec succès.", + "created": "Le travail a été créé avec succès. Clique pour voir.", + "creatednoclick": "", + "delete": "", + "deleted": "Le travail a bien été supprimé.", + "duplicated": "", + "exported": "", + "invoiced": "", + "ioucreated": "", + "partsqueue": "", + "save": "Le travail a été enregistré avec succès.", + "savetitle": "Enregistrement enregistré avec succès.", + "supplemented": "Travail complété avec succès.", + "updated": "", + "voided": "" + } + }, + "landing": { + "bigfeature": { + "subtitle": "", + "title": "" + }, + "footer": { + "company": { + "about": "", + "contact": "", + "disclaimers": "", + "name": "", + "privacypolicy": "" + }, + "io": { + "help": "", + "name": "", + "status": "" + }, + "slogan": "" + }, + "hero": { + "button": "", + "title": "" + }, + "labels": { + "features": "", + "managemyshop": "", + "pricing": "" + }, + "pricing": { + "basic": { + "name": "", + "sub": "" + }, + "essentials": { + "name": "", + "sub": "" + }, + "pricingtitle": "", + "pro": { + "name": "", + "sub": "" + }, + "title": "", + "unlimited": { + "name": "", + "sub": "" + } + } + }, + "menus": { + "currentuser": { + "languageselector": "La langue", + "profile": "Profil" + }, + "header": { + "accounting": "", + "accounting-payables": "", + "accounting-payments": "", + "accounting-receivables": "", + "activejobs": "Emplois actifs", + "all_tasks": "", + "alljobs": "", + "allpayments": "", + "availablejobs": "Emplois disponibles", + "bills": "", + "courtesycars": "", + "courtesycars-all": "", + "courtesycars-contracts": "", + "courtesycars-newcontract": "", + "create_task": "", + "customers": "Les clients", + "dashboard": "", + "enterbills": "", + "entercardpayment": "", + "enterpayment": "", + "entertimeticket": "", + "export": "", + "export-logs": "", + "help": "", + "home": "Accueil", + "inventory": "", + "jobs": "Emplois", + "my_tasks": "", + "newjob": "", + "owners": "Propriétaires", + "parts-queue": "", + "phonebook": "", + "productionboard": "", + "productionlist": "", + "readyjobs": "", + "recent": "", + "reportcenter": "", + "rescueme": "", + "schedule": "Programme", + "scoreboard": "", + "search": { + "bills": "", + "jobs": "", + "owners": "", + "payments": "", + "phonebook": "", + "vehicles": "" + }, + "shiftclock": "", + "shop": "Mon magasin", + "shop_config": "Configuration", + "shop_csi": "", + "shop_templates": "", + "shop_vendors": "Vendeurs", + "tasks": "", + "temporarydocs": "", + "timetickets": "", + "ttapprovals": "", + "vehicles": "Véhicules" + }, + "jobsactions": { + "admin": "", + "cancelallappointments": "", + "closejob": "", + "deletejob": "", + "duplicate": "", + "duplicatenolines": "", + "newcccontract": "", + "void": "" + }, + "jobsdetail": { + "claimdetail": "Détails de la réclamation", + "dates": "Rendez-vous", + "financials": "", + "general": "", + "insurance": "", + "labor": "La main d'oeuvre", + "lifecycle": "", + "parts": "", + "partssublet": "Pièces / Sous-location", + "rates": "", + "repairdata": "Données de réparation", + "totals": "" + }, + "profilesidebar": { + "profile": "Mon profil", + "shops": "Mes boutiques" + }, + "tech": { + "assignedjobs": "", + "claimtask": "", + "dispatchedparts": "", + "home": "", + "jobclockin": "", + "jobclockout": "", + "joblookup": "", + "login": "", + "logout": "", + "productionboard": "", + "productionlist": "", + "shiftclockin": "" + } + }, + "messaging": { + "actions": { + "link": "", + "new": "" + }, + "errors": { + "invalidphone": "", + "noattachedjobs": "", + "updatinglabel": "" + }, + "labels": { + "addlabel": "", + "archive": "", + "maxtenimages": "", + "messaging": "Messagerie", + "noallowtxt": "", + "nojobs": "", + "nopush": "", + "phonenumber": "", + "presets": "", + "recentonly": "", + "selectmedia": "", + "sentby": "", + "typeamessage": "Envoyer un message...", + "unarchive": "" + }, + "render": { + "conversation_list": "" + } + }, + "notes": { + "actions": { + "actions": "actes", + "deletenote": "Supprimer la note", + "edit": "Note éditée", + "new": "Nouvelle note", + "savetojobnotes": "" + }, + "errors": { + "inserting": "" + }, + "fields": { + "createdby": "Créé par", + "critical": "Critique", + "private": "privé", + "text": "Contenu", + "type": "", + "types": { + "customer": "", + "general": "", + "office": "", + "paint": "", + "parts": "", + "shop": "", + "supplement": "" + }, + "updatedat": "Mis à jour à" + }, + "labels": { + "addtorelatedro": "", + "newnoteplaceholder": "Ajouter une note...", + "notetoadd": "", + "systemnotes": "", + "usernotes": "" + }, + "successes": { + "create": "Remarque créée avec succès.", + "deleted": "Remarque supprimée avec succès.", + "updated": "Remarque mise à jour avec succès." + } + }, + "owner": { + "labels": { + "noownerinfo": "" + } + }, + "owners": { + "actions": { + "update": "" + }, + "errors": { + "deleting": "", + "noaccess": "L'enregistrement n'existe pas ou vous n'y avez pas accès.", + "saving": "", + "selectexistingornew": "" + }, + "fields": { + "address": "Adresse", + "allow_text_message": "Autorisation de texte?", + "name": "Prénom", + "note": "", + "ownr_addr1": "Adresse", + "ownr_addr2": "Adresse 2 ", + "ownr_city": "Ville", + "ownr_co_nm": "", + "ownr_ctry": "Pays", + "ownr_ea": "Email", + "ownr_fn": "Prénom", + "ownr_ln": "Nom de famille", + "ownr_ph1": "Téléphone 1", + "ownr_ph2": "", + "ownr_st": "Etat / Province", + "ownr_title": "Titre", + "ownr_zip": "Zip / code postal", + "preferred_contact": "Méthode de contact préférée", + "tax_number": "" + }, + "forms": { + "address": "", + "contact": "", + "name": "" + }, + "labels": { + "create_new": "Créez un nouvel enregistrement de propriétaire.", + "deleteconfirm": "", + "existing_owners": "Propriétaires existants", + "fromclaim": "", + "fromowner": "", + "relatedjobs": "", + "updateowner": "" + }, + "successes": { + "delete": "", + "save": "Le propriétaire a bien enregistré." + } + }, + "parts": { + "actions": { + "order": "Commander des pièces", + "orderinhouse": "" + } + }, + "parts_dispatch": { + "actions": { + "accept": "" + }, + "errors": { + "accepting": "", + "creating": "" + }, + "fields": { + "number": "", + "percent_accepted": "" + }, + "labels": { + "notyetdispatched": "", + "parts_dispatch": "" + } + }, + "parts_dispatch_lines": { + "fields": { + "accepted_at": "" + } + }, + "parts_orders": { + "actions": { + "backordered": "", + "receive": "", + "receivebill": "" + }, + "errors": { + "associatedbills": "", + "backordering": "", + "creating": "Erreur rencontrée lors de la création de la commande de pièces.", + "oec": "", + "saving": "", + "updating": "" + }, + "fields": { + "act_price": "", + "backordered_eta": "", + "backordered_on": "", + "cm_received": "", + "comments": "", + "cost": "", + "db_price": "", + "deliver_by": "", + "job_line_id": "", + "line_desc": "", + "line_remarks": "", + "lineremarks": "Remarques sur la ligne", + "oem_partno": "", + "order_date": "", + "order_number": "", + "orderedby": "", + "part_type": "", + "quantity": "", + "return": "", + "status": "" + }, + "labels": { + "allpartsto": "", + "confirmdelete": "", + "custompercent": "", + "discount": "", + "email": "Envoyé par email", + "inthisorder": "Pièces dans cette commande", + "is_quote": "", + "mark_as_received": "", + "newpartsorder": "", + "notyetordered": "", + "oec": "", + "order_type": "", + "orderhistory": "Historique des commandes", + "parts_order": "", + "parts_orders": "", + "print": "Afficher le formulaire imprimé", + "receive": "", + "removefrompartsqueue": "", + "returnpartsorder": "", + "sublet_order": "" + }, + "successes": { + "created": "Commande de pièces créée avec succès.", + "line_updated": "", + "received": "", + "return_created": "" + } + }, + "payments": { + "actions": { + "generatepaymentlink": "" + }, + "errors": { + "exporting": "", + "exporting-partner": "", + "inserting": "" + }, + "fields": { + "amount": "", + "created_at": "", + "date": "", + "exportedat": "", + "memo": "", + "payer": "", + "paymentnum": "", + "stripeid": "", + "transactionid": "", + "type": "" + }, + "labels": { + "balance": "", + "ca_bc_etf_table": "", + "customer": "", + "edit": "", + "electronicpayment": "", + "external": "", + "findermodal": "", + "insurance": "", + "markexported": "", + "markforreexport": "", + "new": "", + "signup": "", + "smspaymentreminder": "", + "title": "", + "totalpayments": "" + }, + "successes": { + "exported": "", + "markexported": "", + "markreexported": "", + "payment": "", + "paymentupdate": "", + "stripe": "" + } + }, + "phonebook": { + "actions": { + "new": "" + }, + "errors": { + "adding": "", + "saving": "" + }, + "fields": { + "address1": "", + "address2": "", + "category": "", + "city": "", + "company": "", + "country": "", + "email": "", + "fax": "", + "firstname": "", + "lastname": "", + "phone1": "", + "phone2": "", + "state": "" + }, + "labels": { + "noneselected": "", + "onenamerequired": "", + "vendorcategory": "" + }, + "successes": { + "added": "", + "deleted": "", + "saved": "" + } + }, + "printcenter": { + "appointments": { + "appointment_confirmation": "" + }, + "bills": { + "inhouse_invoice": "" + }, + "courtesycarcontract": { + "courtesy_car_contract": "", + "courtesy_car_impound": "", + "courtesy_car_inventory": "", + "courtesy_car_terms": "" + }, + "errors": { + "nocontexttype": "" + }, + "jobs": { + "3rdpartyfields": { + "addr1": "", + "addr2": "", + "addr3": "", + "attn": "", + "city": "", + "custgst": "", + "ded_amt": "", + "depreciation": "", + "other": "", + "ponumber": "", + "refnumber": "", + "sendtype": "", + "state": "", + "zip": "" + }, + "3rdpartypayer": "", + "ab_proof_of_loss": "", + "appointment_confirmation": "", + "appointment_reminder": "", + "casl_authorization": "", + "committed_timetickets_ro": "", + "coversheet_landscape": "", + "coversheet_portrait": "", + "csi_invitation": "", + "csi_invitation_action": "", + "diagnostic_authorization": "", + "dms_posting_sheet": "", + "envelope_return_address": "", + "estimate": "", + "estimate_detail": "", + "estimate_followup": "", + "express_repair_checklist": "", + "filing_coversheet_landscape": "", + "filing_coversheet_portrait": "", + "final_invoice": "", + "fippa_authorization": "", + "folder_label_multiple": "", + "glass_express_checklist": "", + "guarantee": "", + "individual_job_note": "", + "invoice_customer_payable": "", + "invoice_total_payable": "", + "iou_form": "", + "job_costing_ro": "", + "job_lifecycle_ro": "", + "job_notes": "", + "job_tasks": "", + "key_tag": "", + "labels": { + "count": "", + "labels": "", + "position": "" + }, + "lag_time_ro": "", + "mechanical_authorization": "", + "mpi_animal_checklist": "", + "mpi_eglass_auth": "", + "mpi_final_acct_sheet": "", + "mpi_final_repair_acct_sheet": "", + "paint_grid": "", + "parts_dispatch": "", + "parts_invoice_label_single": "", + "parts_label_multiple": "", + "parts_label_single": "", + "parts_list": "", + "parts_order": "", + "parts_order_confirmation": "", + "parts_order_history": "", + "parts_return_slip": "", + "payment_receipt": "", + "payment_request": "", + "payments_by_job": "", + "purchases_by_ro_detail": "", + "purchases_by_ro_summary": "", + "qc_sheet": "", + "rental_reservation": "", + "ro_totals": "", + "ro_with_description": "", + "sgi_certificate_of_repairs": "", + "sgi_windshield_auth": "", + "stolen_recovery_checklist": "", + "sublet_order": "", + "supplement_request": "", + "thank_you_ro": "", + "thirdpartypayer": "", + "timetickets_ro": "", + "vehicle_check_in": "", + "vehicle_delivery_check": "", + "window_tag": "", + "window_tag_sublet": "", + "work_authorization": "", + "worksheet_by_line_number": "", + "worksheet_sorted_by_operation": "", + "worksheet_sorted_by_operation_no_hours": "", + "worksheet_sorted_by_operation_part_type": "", + "worksheet_sorted_by_operation_type": "", + "worksheet_sorted_by_team": "" + }, + "labels": { + "groups": { + "authorization": "", + "financial": "", + "post": "", + "pre": "", + "ro": "", + "worksheet": "" + }, + "misc": "", + "repairorder": "", + "reportcentermodal": "", + "speedprint": "", + "title": "" + }, + "payments": { + "ca_bc_etf_table": "", + "exported_payroll": "" + }, + "special": { + "attendance_detail_csv": "" + }, + "subjects": { + "jobs": { + "individual_job_note": "", + "parts_dispatch": "", + "parts_order": "", + "parts_return_slip": "", + "sublet_order": "" + } + }, + "vendors": { + "purchases_by_vendor_detailed": "", + "purchases_by_vendor_summary": "" + } + }, + "production": { + "actions": { + "addcolumns": "", + "bodypriority-clear": "", + "bodypriority-set": "", + "detailpriority-clear": "", + "detailpriority-set": "", + "paintpriority-clear": "", + "paintpriority-set": "", + "remove": "", + "removecolumn": "", + "saveconfig": "", + "suspend": "", + "unsuspend": "" + }, + "constants": { + "main_profile": "" + }, + "errors": { + "boardupdate": "", + "name_exists": "", + "name_required": "", + "removing": "", + "settings": "" + }, + "labels": { + "actual_in": "", + "addnewprofile": "", + "alert": "", + "alertoff": "", + "alerton": "", + "alerts": "", + "ats": "", + "bodyhours": "", + "bodypriority": "", + "bodyshop": { + "labels": { + "qbo_departmentid": "", + "qbo_usa": "" + } + }, + "card_size": "", + "cardcolor": "", + "cardsettings": "", + "clm_no": "", + "comment": "", + "compact": "", + "detailpriority": "", + "employeeassignments": "", + "employeesearch": "", + "estimator": "", + "horizontal": "", + "ins_co_nm": "", + "jobdetail": "", + "kiosk_mode": "", + "laborhrs": "", + "legend": "", + "model_info": "", + "note": "", + "off": "", + "on": "", + "orientation": "", + "ownr_nm": "", + "paintpriority": "", + "partsstatus": "", + "production_note": "", + "refinishhours": "", + "scheduled_completion": "", + "selectview": "", + "stickyheader": "", + "sublets": "", + "subtotal": "", + "tall": "", + "tasks": "", + "totalhours": "", + "touchtime": "", + "vertical": "", + "viewname": "", + "wide": "" + }, + "options": { + "horizontal": "", + "large": "", + "medium": "", + "small": "", + "vertical": "" + }, + "settings": { + "board_settings": "", + "filters": { + "md_estimators": "", + "md_ins_cos": "" + }, + "filters_title": "", + "information": "", + "layout": "", "statistics": { "jobs_in_production": "", "tasks_in_production": "", @@ -2865,8 +2865,8 @@ "total_lar_on_board": "", "total_lar_in_view": "" }, - "statistics_title": "" - }, + "statistics_title": "" + }, "statistics": { "currency_symbol": "", "hours": "", @@ -2891,708 +2891,709 @@ "total_lar_on_board": "", "total_lar_in_view": "" }, - "successes": { - "removed": "" - } - }, - "profile": { - "errors": { - "state": "Erreur lors de la lecture de l'état de la page. Rafraichissez, s'il vous plait." - }, - "labels": { - "activeshop": "" - }, - "successes": { - "updated": "" - } - }, - "reportcenter": { - "actions": { - "generate": "" - }, - "labels": { - "advanced_filters": "", - "advanced_filters_false": "", - "advanced_filters_filter_field": "", - "advanced_filters_filter_operator": "", - "advanced_filters_filter_value": "", - "advanced_filters_filters": "", - "advanced_filters_hide": "", - "advanced_filters_show": "", - "advanced_filters_sorter_direction": "", - "advanced_filters_sorter_field": "", - "advanced_filters_sorters": "", - "advanced_filters_true": "", - "dates": "", - "employee": "", - "filterson": "", - "generateasemail": "", - "groups": { - "customers": "", - "jobs": "", - "payroll": "", - "purchases": "", - "sales": "" - }, - "key": "", - "objects": { - "appointments": "", - "bills": "", - "csi": "", - "exportlogs": "", - "jobs": "", - "parts_orders": "", - "payments": "", - "scoreboard": "", - "tasks": "", - "timetickets": "" - }, - "vendor": "" - }, - "templates": { - "adp_payroll_flat": "", - "adp_payroll_straight": "", - "anticipated_revenue": "", - "ar_aging": "", - "attendance_detail": "", - "attendance_employee": "", - "attendance_summary": "", - "committed_timetickets": "", - "committed_timetickets_employee": "", - "committed_timetickets_summary": "", - "credits_not_received_date": "", - "credits_not_received_date_vendorid": "", - "csi": "", - "customer_list": "", - "cycle_time_analysis": "", - "estimates_written_converted": "", - "estimator_detail": "", - "estimator_summary": "", - "export_payables": "", - "export_payments": "", - "export_receivables": "", - "exported_gsr_by_ro": "", - "exported_gsr_by_ro_labor": "", - "gsr_by_atp": "", - "gsr_by_ats": "", - "gsr_by_category": "", - "gsr_by_csr": "", - "gsr_by_delivery_date": "", - "gsr_by_estimator": "", - "gsr_by_exported_date": "", - "gsr_by_ins_co": "", - "gsr_by_make": "", - "gsr_by_referral": "", - "gsr_by_ro": "", - "gsr_labor_only": "", - "hours_sold_detail_closed": "", - "hours_sold_detail_closed_csr": "", - "hours_sold_detail_closed_estimator": "", - "hours_sold_detail_closed_ins_co": "", - "hours_sold_detail_closed_status": "", - "hours_sold_detail_open": "", - "hours_sold_detail_open_csr": "", - "hours_sold_detail_open_estimator": "", - "hours_sold_detail_open_ins_co": "", - "hours_sold_detail_open_status": "", - "hours_sold_summary_closed": "", - "hours_sold_summary_closed_csr": "", - "hours_sold_summary_closed_estimator": "", - "hours_sold_summary_closed_ins_co": "", - "hours_sold_summary_closed_status": "", - "hours_sold_summary_open": "", - "hours_sold_summary_open_csr": "", - "hours_sold_summary_open_estimator": "", - "hours_sold_summary_open_ins_co": "", - "hours_sold_summary_open_status": "", - "job_costing_ro_csr": "", - "job_costing_ro_date_detail": "", - "job_costing_ro_date_summary": "", - "job_costing_ro_estimator": "", - "job_costing_ro_ins_co": "", - "job_lifecycle_date_detail": "", - "job_lifecycle_date_summary": "", - "jobs_completed_not_invoiced": "", - "jobs_invoiced_not_exported": "", - "jobs_reconcile": "", - "jobs_scheduled_completion": "", - "lag_time": "", - "load_level": "", - "lost_sales": "", - "open_orders": "", - "open_orders_csr": "", - "open_orders_estimator": "", - "open_orders_excel": "", - "open_orders_ins_co": "", - "open_orders_referral": "", - "open_orders_specific_csr": "", - "open_orders_status": "", - "parts_backorder": "", - "parts_not_recieved": "", - "parts_not_recieved_vendor": "", - "parts_received_not_scheduled": "", - "payments_by_date": "", - "payments_by_date_payment": "", - "payments_by_date_type": "", - "production_by_category": "", - "production_by_category_one": "", - "production_by_csr": "", - "production_by_last_name": "", - "production_by_repair_status": "", - "production_by_repair_status_one": "", - "production_by_ro": "", - "production_by_target_date": "", - "production_by_technician": "", - "production_by_technician_one": "", - "production_over_time": "", - "psr_by_make": "", - "purchase_return_ratio_grouped_by_vendor_detail": "", - "purchase_return_ratio_grouped_by_vendor_summary": "", - "purchases_by_cost_center_detail": "", - "purchases_by_cost_center_summary": "", - "purchases_by_date_range_detail": "", - "purchases_by_date_range_summary": "", - "purchases_by_ro_detail_date": "", - "purchases_by_ro_summary_date": "", - "purchases_by_vendor_detailed_date_range": "", - "purchases_by_vendor_summary_date_range": "", - "purchases_grouped_by_vendor_detailed": "", - "purchases_grouped_by_vendor_summary": "", - "returns_grouped_by_vendor_detailed": "", - "returns_grouped_by_vendor_summary": "", - "schedule": "", - "scheduled_parts_list": "", - "scoreboard_detail": "", - "scoreboard_summary": "", - "supplement_ratio_ins_co": "", - "tasks_date": "", - "tasks_date_employee": "", - "thank_you_date": "", - "timetickets": "", - "timetickets_employee": "", - "timetickets_summary": "", - "unclaimed_hrs": "", - "void_ros": "", - "work_in_progress_committed_labour": "", - "work_in_progress_jobs": "", - "work_in_progress_labour": "", - "work_in_progress_payables": "" - } - }, - "schedule": { - "labels": { - "atssummary": "", - "employeevacation": "", - "estimators": "", - "ins_co_nm_filter": "", - "intake": "", - "manual": "", - "manualevent": "" - } - }, - "scoreboard": { - "actions": { - "edit": "" - }, - "errors": { - "adding": "", - "removing": "", - "updating": "" - }, - "fields": { - "bodyhrs": "", - "date": "", - "painthrs": "" - }, - "labels": { - "allemployeetimetickets": "", - "asoftodaytarget": "", - "body": "", - "bodyabbrev": "", - "bodycharttitle": "", - "calendarperiod": "", - "combinedcharttitle": "", - "dailyactual": "", - "dailytarget": "", - "efficiencyoverperiod": "", - "entries": "", - "jobs": "", - "jobscompletednotinvoiced": "", - "lastmonth": "", - "lastweek": "", - "monthlytarget": "", - "priorweek": "", - "productivestatistics": "", - "productivetimeticketsoverdate": "", - "refinish": "", - "refinishabbrev": "", - "refinishcharttitle": "", - "targets": "", - "thismonth": "", - "thisweek": "", - "timetickets": "", - "timeticketsemployee": "", - "todateactual": "", - "total": "", - "totalhrs": "", - "totaloverperiod": "", - "weeklyactual": "", - "weeklytarget": "", - "workingdays": "" - }, - "successes": { - "added": "", - "removed": "", - "updated": "" - } - }, - "tasks": { - "actions": { - "edit": "", - "new": "" - }, - "buttons": { - "allTasks": "", - "complete": "", - "create": "", - "delete": "", - "edit": "", - "myTasks": "", - "refresh": "" - }, - "date_presets": { - "completion": "", - "day": "", - "days": "", - "delivery": "", - "next_week": "", - "one_month": "", - "three_months": "", - "three_weeks": "", - "today": "", - "tomorrow": "", - "two_weeks": "" - }, - "failures": { - "completed": "", - "created": "", - "deleted": "", - "updated": "" - }, - "fields": { - "actions": "", - "assigned_to": "", - "bill": "", - "billid": "", - "completed": "", - "created_at": "", - "description": "", - "due_date": "", - "job": { - "ro_number": "" - }, - "jobid": "", - "jobline": "", - "joblineid": "", - "parts_order": "", - "partsorderid": "", - "priorities": { - "high": "", - "low": "", - "medium": "" - }, - "priority": "", - "remind_at": "", - "title": "" - }, - "placeholders": { - "assigned_to": "", - "billid": "", - "description": "", - "jobid": "", - "joblineid": "", - "partsorderid": "" - }, - "successes": { - "completed": "", - "created": "", - "deleted": "", - "updated": "" - }, - "titles": { - "all_tasks": "", - "completed": "", - "deleted": "", - "job_tasks": "", - "mine": "", - "my_tasks": "" - }, - "validation": { - "due_at_error_message": "", - "remind_at_error_message": "" - } - }, - "tech": { - "fields": { - "employeeid": "", - "pin": "" - }, - "labels": { - "loggedin": "", - "notloggedin": "" - } - }, - "templates": { - "errors": { - "updating": "" - }, - "successes": { - "updated": "" - } - }, - "timetickets": { - "actions": { - "claimtasks": "", - "clockin": "", - "clockout": "", - "commit": "", - "commitone": "", - "enter": "", - "payall": "", - "printemployee": "", - "uncommit": "" - }, - "errors": { - "clockingin": "", - "clockingout": "", - "creating": "", - "deleting": "", - "noemployeeforuser": "", - "noemployeeforuser_sub": "", - "payall": "", - "shiftalreadyclockedon": "" - }, - "fields": { - "actualhrs": "", - "ciecacode": "", - "clockhours": "", - "clockoff": "", - "clockon": "", - "committed": "", - "committed_at": "", - "cost_center": "", - "created_by": "", - "date": "", - "efficiency": "", - "employee": "", - "employee_team": "", - "flat_rate": "", - "memo": "", - "productivehrs": "", - "ro_number": "", - "task_name": "" - }, - "labels": { - "alreadyclockedon": "", - "ambreak": "", - "amshift": "", - "claimtaskpreview": "", - "clockhours": "", - "clockintojob": "", - "deleteconfirm": "", - "edit": "", - "efficiency": "", - "flat_rate": "", - "jobhours": "", - "lunch": "", - "new": "", - "payrollclaimedtasks": "", - "pmbreak": "", - "pmshift": "", - "shift": "", - "shiftalreadyclockedon": "", - "straight_time": "", - "task": "", - "timetickets": "", - "unassigned": "", - "zeroactualnegativeprod": "" - }, - "successes": { - "clockedin": "", - "clockedout": "", - "committed": "", - "created": "", - "deleted": "", - "payall": "" - }, - "validation": { - "clockoffmustbeafterclockon": "", - "clockoffwithoutclockon": "", - "hoursenteredmorethanavailable": "", - "unassignedlines": "" - } - }, - "titles": { - "accounting-payables": "", - "accounting-payments": "", - "accounting-receivables": "", - "all_tasks": "", - "app": "", - "bc": { - "accounting-payables": "", - "accounting-payments": "", - "accounting-receivables": "", - "all_tasks": "", - "availablejobs": "", - "bills-list": "", - "contracts": "", - "contracts-create": "", - "contracts-detail": "", - "courtesycars": "", - "courtesycars-detail": "", - "courtesycars-new": "", - "dashboard": "", - "dms": "", - "export-logs": "", - "inventory": "", - "jobs": "", - "jobs-active": "", - "jobs-admin": "", - "jobs-all": "", - "jobs-checklist": "", - "jobs-close": "", - "jobs-deliver": "", - "jobs-detail": "", - "jobs-intake": "", - "jobs-new": "", - "jobs-ready": "", - "my_tasks": "", - "owner-detail": "", - "owners": "", - "parts-queue": "", - "payments-all": "", - "phonebook": "", - "productionboard": "", - "productionlist": "", - "profile": "", - "schedule": "", - "scoreboard": "", - "shop": "", - "shop-csi": "", - "shop-templates": "", - "shop-vendors": "", - "tasks": "", - "temporarydocs": "", - "timetickets": "", - "ttapprovals": "", - "vehicle-details": "", - "vehicles": "" - }, - "bills-list": "", - "contracts": "", - "contracts-create": "", - "contracts-detail": "", - "courtesycars": "", - "courtesycars-create": "", - "courtesycars-detail": "", - "dashboard": "", - "dms": "", - "export-logs": "", - "imexonline": "", - "inventory": "", - "jobs": "Tous les emplois | {{app}}", - "jobs-admin": "", - "jobs-all": "", - "jobs-checklist": "", - "jobs-close": "", - "jobs-create": "", - "jobs-deliver": "", - "jobs-intake": "", - "jobsavailable": "Emplois disponibles | {{app}}", - "jobsdetail": "Travail {{ro_number}} | {{app}}", - "jobsdocuments": "Documents de travail {{ro_number}} | {{app}}", - "manageroot": "Accueil | {{app}}", - "my_tasks": "", - "owners": "Tous les propriétaires | {{app}}", - "owners-detail": "", - "parts-queue": "", - "payments-all": "", - "phonebook": "", - "productionboard": "", - "productionlist": "", - "profile": "Mon profil | {{app}}", - "promanager": "", - "readyjobs": "", - "resetpassword": "", - "resetpasswordvalidate": "", - "romeonline": "", - "schedule": "Horaire | {{app}}", - "scoreboard": "", - "shop": "Mon magasin | {{app}}", - "shop-csi": "", - "shop-templates": "", - "shop_vendors": "Vendeurs | {{app}}", - "tasks": "", - "techconsole": "{{app}}", - "techjobclock": "{{app}}", - "techjoblookup": "{{app}}", - "techshiftclock": "{{app}}", - "temporarydocs": "", - "timetickets": "", - "ttapprovals": "", - "vehicledetail": "Détails du véhicule {{vehicle} | {{app}}", - "vehicles": "Tous les véhicules | {{app}}" - }, - "trello": { - "labels": { - "add_card": "", - "add_lane": "", - "cancel": "", - "delete_lane": "", - "description": "", - "label": "", - "lane_actions": "", - "title": "" - } - }, - "tt_approvals": { - "actions": { - "approveselected": "" - }, - "labels": { - "approval_queue_in_use": "", - "calculate": "" - } - }, - "user": { - "actions": { - "changepassword": "", - "signout": "Déconnexion", - "updateprofile": "Mettre à jour le profil" - }, - "errors": { - "updating": "" - }, - "fields": { - "authlevel": "", - "displayname": "Afficher un nom", - "email": "", - "photourl": "URL de l'avatar" - }, - "labels": { - "actions": "", - "changepassword": "", - "profileinfo": "" - }, - "successess": { - "passwordchanged": "" - } - }, - "users": { - "errors": { - "signinerror": { - "auth/user-disabled": "", - "auth/user-not-found": "", - "auth/wrong-password": "" - } - } - }, - "vehicles": { - "errors": { - "deleting": "", - "noaccess": "Le véhicule n'existe pas ou vous n'y avez pas accès.", - "selectexistingornew": "", - "validation": "Veuillez vous assurer que tous les champs sont correctement entrés.", - "validationtitle": "Erreur de validation" - }, - "fields": { - "description": "Description du véhicule", - "notes": "", - "plate_no": "Plaque d'immatriculation", - "plate_st": "Juridiction de la plaque", - "trim_color": "Couleur de garniture", - "v_bstyle": "Style corporel", - "v_color": "Couleur", - "v_cond": "Etat", - "v_engine": "moteur", - "v_make_desc": "Faire", - "v_makecode": "Faire du code", - "v_mldgcode": "Code de moulage", - "v_model_desc": "Modèle", - "v_model_yr": "année", - "v_options": "Les options", - "v_paint_codes": "Codes de peinture", - "v_prod_dt": "Date de production", - "v_stage": "Étape", - "v_tone": "ton", - "v_trimcode": "Code de coupe", - "v_type": "Type", - "v_vin": "V.I.N." - }, - "forms": { - "detail": "", - "misc": "", - "registration": "" - }, - "labels": { - "deleteconfirm": "", - "fromvehicle": "", - "novehinfo": "", - "relatedjobs": "", - "updatevehicle": "" - }, - "successes": { - "delete": "", - "save": "Le véhicule a été enregistré avec succès." - } - }, - "vendors": { - "actions": { - "addtophonebook": "", - "new": "Nouveau vendeur", - "newpreferredmake": "" - }, - "errors": { - "deleting": "Erreur rencontrée lors de la suppression du fournisseur.", - "saving": "Erreur rencontrée lors de l'enregistrement du fournisseur." - }, - "fields": { - "active": "", - "am": "", - "city": "Ville", - "cost_center": "Centre de coûts", - "country": "Pays", - "discount": "Remise %", - "display_name": "Afficher un nom", - "dmsid": "", - "due_date": "Date limite de paiement", - "email": "Email du contact", - "favorite": "Préféré?", - "lkq": "", - "make": "", - "name": "Nom du vendeur", - "oem": "", - "phone": "", - "prompt_discount": "Remise rapide%", - "state": "Etat / Province", - "street1": "rue", - "street2": "Adresse 2 ", - "taxid": "Identifiant de taxe", - "terms": "Modalités de paiement", - "zip": "Zip / code postal" - }, - "labels": { - "noneselected": "Aucun fournisseur n'est sélectionné.", - "preferredmakes": "", - "search": "Tapez le nom d'un vendeur" - }, - "successes": { - "deleted": "Le fournisseur a bien été supprimé.", - "saved": "Le fournisseur a bien enregistré." - }, - "validation": { - "unique_vendor_name": "" - } - } - } + "successes": { + "removed": "" + } + }, + "profile": { + "errors": { + "state": "Erreur lors de la lecture de l'état de la page. Rafraichissez, s'il vous plait." + }, + "labels": { + "activeshop": "" + }, + "successes": { + "updated": "" + } + }, + "reportcenter": { + "actions": { + "generate": "" + }, + "labels": { + "advanced_filters": "", + "advanced_filters_false": "", + "advanced_filters_filter_field": "", + "advanced_filters_filter_operator": "", + "advanced_filters_filter_value": "", + "advanced_filters_filters": "", + "advanced_filters_hide": "", + "advanced_filters_show": "", + "advanced_filters_sorter_direction": "", + "advanced_filters_sorter_field": "", + "advanced_filters_sorters": "", + "advanced_filters_true": "", + "dates": "", + "employee": "", + "filterson": "", + "generateasemail": "", + "groups": { + "customers": "", + "jobs": "", + "payroll": "", + "purchases": "", + "sales": "" + }, + "key": "", + "objects": { + "appointments": "", + "bills": "", + "csi": "", + "exportlogs": "", + "jobs": "", + "parts_orders": "", + "payments": "", + "scoreboard": "", + "tasks": "", + "timetickets": "" + }, + "vendor": "" + }, + "templates": { + "adp_payroll_flat": "", + "adp_payroll_straight": "", + "anticipated_revenue": "", + "ar_aging": "", + "attendance_detail": "", + "attendance_employee": "", + "attendance_summary": "", + "committed_timetickets": "", + "committed_timetickets_employee": "", + "committed_timetickets_summary": "", + "credits_not_received_date": "", + "credits_not_received_date_vendorid": "", + "csi": "", + "customer_list": "", + "cycle_time_analysis": "", + "estimates_written_converted": "", + "estimator_detail": "", + "estimator_summary": "", + "export_payables": "", + "export_payments": "", + "export_receivables": "", + "exported_gsr_by_ro": "", + "exported_gsr_by_ro_labor": "", + "gsr_by_atp": "", + "gsr_by_ats": "", + "gsr_by_category": "", + "gsr_by_csr": "", + "gsr_by_delivery_date": "", + "gsr_by_estimator": "", + "gsr_by_exported_date": "", + "gsr_by_ins_co": "", + "gsr_by_make": "", + "gsr_by_referral": "", + "gsr_by_ro": "", + "gsr_labor_only": "", + "hours_sold_detail_closed": "", + "hours_sold_detail_closed_csr": "", + "hours_sold_detail_closed_estimator": "", + "hours_sold_detail_closed_ins_co": "", + "hours_sold_detail_closed_status": "", + "hours_sold_detail_open": "", + "hours_sold_detail_open_csr": "", + "hours_sold_detail_open_estimator": "", + "hours_sold_detail_open_ins_co": "", + "hours_sold_detail_open_status": "", + "hours_sold_summary_closed": "", + "hours_sold_summary_closed_csr": "", + "hours_sold_summary_closed_estimator": "", + "hours_sold_summary_closed_ins_co": "", + "hours_sold_summary_closed_status": "", + "hours_sold_summary_open": "", + "hours_sold_summary_open_csr": "", + "hours_sold_summary_open_estimator": "", + "hours_sold_summary_open_ins_co": "", + "hours_sold_summary_open_status": "", + "job_costing_ro_csr": "", + "job_costing_ro_date_detail": "", + "job_costing_ro_date_summary": "", + "job_costing_ro_estimator": "", + "job_costing_ro_ins_co": "", + "job_lifecycle_date_detail": "", + "job_lifecycle_date_summary": "", + "jobs_completed_not_invoiced": "", + "jobs_invoiced_not_exported": "", + "jobs_reconcile": "", + "jobs_scheduled_completion": "", + "lag_time": "", + "load_level": "", + "lost_sales": "", + "open_orders": "", + "open_orders_csr": "", + "open_orders_estimator": "", + "open_orders_excel": "", + "open_orders_ins_co": "", + "open_orders_referral": "", + "open_orders_specific_csr": "", + "open_orders_status": "", + "parts_backorder": "", + "parts_not_recieved": "", + "parts_not_recieved_vendor": "", + "parts_received_not_scheduled": "", + "payments_by_date": "", + "payments_by_date_payment": "", + "payments_by_date_type": "", + "production_by_category": "", + "production_by_category_one": "", + "production_by_csr": "", + "production_by_last_name": "", + "production_by_repair_status": "", + "production_by_repair_status_one": "", + "production_by_ro": "", + "production_by_target_date": "", + "production_by_technician": "", + "production_by_technician_one": "", + "production_over_time": "", + "psr_by_make": "", + "purchase_return_ratio_grouped_by_vendor_detail": "", + "purchase_return_ratio_grouped_by_vendor_summary": "", + "purchases_by_cost_center_detail": "", + "purchases_by_cost_center_summary": "", + "purchases_by_date_range_detail": "", + "purchases_by_date_range_summary": "", + "purchases_by_ro_detail_date": "", + "purchases_by_ro_summary_date": "", + "purchases_by_vendor_detailed_date_range": "", + "purchases_by_vendor_summary_date_range": "", + "purchases_grouped_by_vendor_detailed": "", + "purchases_grouped_by_vendor_summary": "", + "returns_grouped_by_vendor_detailed": "", + "returns_grouped_by_vendor_summary": "", + "schedule": "", + "scheduled_parts_list": "", + "scoreboard_detail": "", + "scoreboard_summary": "", + "supplement_ratio_ins_co": "", + "tasks_date": "", + "tasks_date_employee": "", + "thank_you_date": "", + "timetickets": "", + "timetickets_employee": "", + "timetickets_summary": "", + "unclaimed_hrs": "", + "void_ros": "", + "work_in_progress_committed_labour": "", + "work_in_progress_jobs": "", + "work_in_progress_labour": "", + "work_in_progress_payables": "" + } + }, + "schedule": { + "labels": { + "atssummary": "", + "employeevacation": "", + "estimators": "", + "ins_co_nm_filter": "", + "intake": "", + "manual": "", + "manualevent": "" + } + }, + "scoreboard": { + "actions": { + "edit": "" + }, + "errors": { + "adding": "", + "removing": "", + "updating": "" + }, + "fields": { + "bodyhrs": "", + "date": "", + "painthrs": "" + }, + "labels": { + "allemployeetimetickets": "", + "asoftodaytarget": "", + "body": "", + "bodyabbrev": "", + "bodycharttitle": "", + "calendarperiod": "", + "combinedcharttitle": "", + "dailyactual": "", + "dailytarget": "", + "efficiencyoverperiod": "", + "entries": "", + "jobs": "", + "jobscompletednotinvoiced": "", + "lastmonth": "", + "lastweek": "", + "monthlytarget": "", + "priorweek": "", + "productivestatistics": "", + "productivetimeticketsoverdate": "", + "refinish": "", + "refinishabbrev": "", + "refinishcharttitle": "", + "targets": "", + "thismonth": "", + "thisweek": "", + "timetickets": "", + "timeticketsemployee": "", + "todateactual": "", + "total": "", + "totalhrs": "", + "totaloverperiod": "", + "weeklyactual": "", + "weeklytarget": "", + "workingdays": "" + }, + "successes": { + "added": "", + "removed": "", + "updated": "" + } + }, + "tasks": { + "actions": { + "edit": "", + "new": "" + }, + "buttons": { + "allTasks": "", + "complete": "", + "create": "", + "delete": "", + "edit": "", + "myTasks": "", + "refresh": "" + }, + "date_presets": { + "completion": "", + "day": "", + "days": "", + "delivery": "", + "next_week": "", + "one_month": "", + "three_months": "", + "three_weeks": "", + "today": "", + "tomorrow": "", + "two_weeks": "" + }, + "failures": { + "completed": "", + "created": "", + "deleted": "", + "updated": "" + }, + "fields": { + "actions": "", + "assigned_to": "", + "bill": "", + "billid": "", + "completed": "", + "created_at": "", + "created_by": "", + "description": "", + "due_date": "", + "job": { + "ro_number": "" + }, + "jobid": "", + "jobline": "", + "joblineid": "", + "parts_order": "", + "partsorderid": "", + "priorities": { + "high": "", + "low": "", + "medium": "" + }, + "priority": "", + "remind_at": "", + "title": "" + }, + "placeholders": { + "assigned_to": "", + "billid": "", + "description": "", + "jobid": "", + "joblineid": "", + "partsorderid": "" + }, + "successes": { + "completed": "", + "created": "", + "deleted": "", + "updated": "" + }, + "titles": { + "all_tasks": "", + "completed": "", + "deleted": "", + "job_tasks": "", + "mine": "", + "my_tasks": "" + }, + "validation": { + "due_at_error_message": "", + "remind_at_error_message": "" + } + }, + "tech": { + "fields": { + "employeeid": "", + "pin": "" + }, + "labels": { + "loggedin": "", + "notloggedin": "" + } + }, + "templates": { + "errors": { + "updating": "" + }, + "successes": { + "updated": "" + } + }, + "timetickets": { + "actions": { + "claimtasks": "", + "clockin": "", + "clockout": "", + "commit": "", + "commitone": "", + "enter": "", + "payall": "", + "printemployee": "", + "uncommit": "" + }, + "errors": { + "clockingin": "", + "clockingout": "", + "creating": "", + "deleting": "", + "noemployeeforuser": "", + "noemployeeforuser_sub": "", + "payall": "", + "shiftalreadyclockedon": "" + }, + "fields": { + "actualhrs": "", + "ciecacode": "", + "clockhours": "", + "clockoff": "", + "clockon": "", + "committed": "", + "committed_at": "", + "cost_center": "", + "created_by": "", + "date": "", + "efficiency": "", + "employee": "", + "employee_team": "", + "flat_rate": "", + "memo": "", + "productivehrs": "", + "ro_number": "", + "task_name": "" + }, + "labels": { + "alreadyclockedon": "", + "ambreak": "", + "amshift": "", + "claimtaskpreview": "", + "clockhours": "", + "clockintojob": "", + "deleteconfirm": "", + "edit": "", + "efficiency": "", + "flat_rate": "", + "jobhours": "", + "lunch": "", + "new": "", + "payrollclaimedtasks": "", + "pmbreak": "", + "pmshift": "", + "shift": "", + "shiftalreadyclockedon": "", + "straight_time": "", + "task": "", + "timetickets": "", + "unassigned": "", + "zeroactualnegativeprod": "" + }, + "successes": { + "clockedin": "", + "clockedout": "", + "committed": "", + "created": "", + "deleted": "", + "payall": "" + }, + "validation": { + "clockoffmustbeafterclockon": "", + "clockoffwithoutclockon": "", + "hoursenteredmorethanavailable": "", + "unassignedlines": "" + } + }, + "titles": { + "accounting-payables": "", + "accounting-payments": "", + "accounting-receivables": "", + "all_tasks": "", + "app": "", + "bc": { + "accounting-payables": "", + "accounting-payments": "", + "accounting-receivables": "", + "all_tasks": "", + "availablejobs": "", + "bills-list": "", + "contracts": "", + "contracts-create": "", + "contracts-detail": "", + "courtesycars": "", + "courtesycars-detail": "", + "courtesycars-new": "", + "dashboard": "", + "dms": "", + "export-logs": "", + "inventory": "", + "jobs": "", + "jobs-active": "", + "jobs-admin": "", + "jobs-all": "", + "jobs-checklist": "", + "jobs-close": "", + "jobs-deliver": "", + "jobs-detail": "", + "jobs-intake": "", + "jobs-new": "", + "jobs-ready": "", + "my_tasks": "", + "owner-detail": "", + "owners": "", + "parts-queue": "", + "payments-all": "", + "phonebook": "", + "productionboard": "", + "productionlist": "", + "profile": "", + "schedule": "", + "scoreboard": "", + "shop": "", + "shop-csi": "", + "shop-templates": "", + "shop-vendors": "", + "tasks": "", + "temporarydocs": "", + "timetickets": "", + "ttapprovals": "", + "vehicle-details": "", + "vehicles": "" + }, + "bills-list": "", + "contracts": "", + "contracts-create": "", + "contracts-detail": "", + "courtesycars": "", + "courtesycars-create": "", + "courtesycars-detail": "", + "dashboard": "", + "dms": "", + "export-logs": "", + "imexonline": "", + "inventory": "", + "jobs": "Tous les emplois | {{app}}", + "jobs-admin": "", + "jobs-all": "", + "jobs-checklist": "", + "jobs-close": "", + "jobs-create": "", + "jobs-deliver": "", + "jobs-intake": "", + "jobsavailable": "Emplois disponibles | {{app}}", + "jobsdetail": "Travail {{ro_number}} | {{app}}", + "jobsdocuments": "Documents de travail {{ro_number}} | {{app}}", + "manageroot": "Accueil | {{app}}", + "my_tasks": "", + "owners": "Tous les propriétaires | {{app}}", + "owners-detail": "", + "parts-queue": "", + "payments-all": "", + "phonebook": "", + "productionboard": "", + "productionlist": "", + "profile": "Mon profil | {{app}}", + "promanager": "", + "readyjobs": "", + "resetpassword": "", + "resetpasswordvalidate": "", + "romeonline": "", + "schedule": "Horaire | {{app}}", + "scoreboard": "", + "shop": "Mon magasin | {{app}}", + "shop-csi": "", + "shop-templates": "", + "shop_vendors": "Vendeurs | {{app}}", + "tasks": "", + "techconsole": "{{app}}", + "techjobclock": "{{app}}", + "techjoblookup": "{{app}}", + "techshiftclock": "{{app}}", + "temporarydocs": "", + "timetickets": "", + "ttapprovals": "", + "vehicledetail": "Détails du véhicule {{vehicle} | {{app}}", + "vehicles": "Tous les véhicules | {{app}}" + }, + "trello": { + "labels": { + "add_card": "", + "add_lane": "", + "cancel": "", + "delete_lane": "", + "description": "", + "label": "", + "lane_actions": "", + "title": "" + } + }, + "tt_approvals": { + "actions": { + "approveselected": "" + }, + "labels": { + "approval_queue_in_use": "", + "calculate": "" + } + }, + "user": { + "actions": { + "changepassword": "", + "signout": "Déconnexion", + "updateprofile": "Mettre à jour le profil" + }, + "errors": { + "updating": "" + }, + "fields": { + "authlevel": "", + "displayname": "Afficher un nom", + "email": "", + "photourl": "URL de l'avatar" + }, + "labels": { + "actions": "", + "changepassword": "", + "profileinfo": "" + }, + "successess": { + "passwordchanged": "" + } + }, + "users": { + "errors": { + "signinerror": { + "auth/user-disabled": "", + "auth/user-not-found": "", + "auth/wrong-password": "" + } + } + }, + "vehicles": { + "errors": { + "deleting": "", + "noaccess": "Le véhicule n'existe pas ou vous n'y avez pas accès.", + "selectexistingornew": "", + "validation": "Veuillez vous assurer que tous les champs sont correctement entrés.", + "validationtitle": "Erreur de validation" + }, + "fields": { + "description": "Description du véhicule", + "notes": "", + "plate_no": "Plaque d'immatriculation", + "plate_st": "Juridiction de la plaque", + "trim_color": "Couleur de garniture", + "v_bstyle": "Style corporel", + "v_color": "Couleur", + "v_cond": "Etat", + "v_engine": "moteur", + "v_make_desc": "Faire", + "v_makecode": "Faire du code", + "v_mldgcode": "Code de moulage", + "v_model_desc": "Modèle", + "v_model_yr": "année", + "v_options": "Les options", + "v_paint_codes": "Codes de peinture", + "v_prod_dt": "Date de production", + "v_stage": "Étape", + "v_tone": "ton", + "v_trimcode": "Code de coupe", + "v_type": "Type", + "v_vin": "V.I.N." + }, + "forms": { + "detail": "", + "misc": "", + "registration": "" + }, + "labels": { + "deleteconfirm": "", + "fromvehicle": "", + "novehinfo": "", + "relatedjobs": "", + "updatevehicle": "" + }, + "successes": { + "delete": "", + "save": "Le véhicule a été enregistré avec succès." + } + }, + "vendors": { + "actions": { + "addtophonebook": "", + "new": "Nouveau vendeur", + "newpreferredmake": "" + }, + "errors": { + "deleting": "Erreur rencontrée lors de la suppression du fournisseur.", + "saving": "Erreur rencontrée lors de l'enregistrement du fournisseur." + }, + "fields": { + "active": "", + "am": "", + "city": "Ville", + "cost_center": "Centre de coûts", + "country": "Pays", + "discount": "Remise %", + "display_name": "Afficher un nom", + "dmsid": "", + "due_date": "Date limite de paiement", + "email": "Email du contact", + "favorite": "Préféré?", + "lkq": "", + "make": "", + "name": "Nom du vendeur", + "oem": "", + "phone": "", + "prompt_discount": "Remise rapide%", + "state": "Etat / Province", + "street1": "rue", + "street2": "Adresse 2 ", + "taxid": "Identifiant de taxe", + "terms": "Modalités de paiement", + "zip": "Zip / code postal" + }, + "labels": { + "noneselected": "Aucun fournisseur n'est sélectionné.", + "preferredmakes": "", + "search": "Tapez le nom d'un vendeur" + }, + "successes": { + "deleted": "Le fournisseur a bien été supprimé.", + "saved": "Le fournisseur a bien enregistré." + }, + "validation": { + "unique_vendor_name": "" + } + } + } } diff --git a/server/email/tasksEmails.js b/server/email/tasksEmails.js index c8aebaa64..719c4f051 100644 --- a/server/email/tasksEmails.js +++ b/server/email/tasksEmails.js @@ -77,6 +77,7 @@ const formatPriority = (priority) => { * @param priority * @param description * @param dueDate + * @param createdBy * @param bodyshop * @param job * @param taskId @@ -96,11 +97,11 @@ const getEndpoints = (bodyshop) => : "https://romeonline.io" }); -const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, job, taskId, dateLine) => { +const generateTemplateArgs = (title, priority, description, dueDate, createdBy, bodyshop, job, taskId, dateLine) => { const endPoints = getEndpoints(bodyshop); return { header: title, - subHeader: `Body Shop: ${bodyshop.shopname} | Priority: ${formatPriority(priority)} ${formatDate(dueDate)}`, + subHeader: `Body Shop: ${bodyshop.shopname} | Priority: ${formatPriority(priority)} | Due on: ${formatDate(dueDate)} | Created by: ${createdBy || "N/A"}`, body: `Reference: ${job.ro_number || "N/A"} | ${job.ownr_co_nm ? job.ownr_co_nm : `${job.ownr_fn || ""} ${job.ownr_ln || ""}`.trim()} | ${`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${job.v_model_desc || ""}`.trim()}
    ${description ? description.concat("
    ") : ""}View this task.`, dateLine }; @@ -178,6 +179,7 @@ const taskAssignedEmail = async (req, res) => { newTask.priority, newTask.description, newTask.due_date, + newTask.created_by, tasks_by_pk.bodyshop, tasks_by_pk.job, newTask.id, @@ -265,6 +267,7 @@ const tasksRemindEmail = async (req, res) => { onlyTask.priority, onlyTask.description, onlyTask.due_date, + onlyTask.created_by, onlyTask.bodyshop, onlyTask.job, onlyTask.id, From eeb8d8d26f1cd9a47c6d54211535641051e0092b Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 25 Oct 2024 11:21:10 -0700 Subject: [PATCH 45/79] release/2024-10-25 - Clean up referenceDocuments Signed-off-by: Dave Richer --- _reference/{ => Documents}/DeploymentChecklist.md | 0 _reference/{ => Documents}/JSReportSetup.md | 0 _reference/{ => Documents}/Jest CheatSheet.md | 0 _reference/{ => Documents}/New Hasura Deployment.md | 0 _reference/{ => Documents}/Responsibility Center Setup.md | 0 _reference/{ => Documents}/SampleMetadata.md | 0 _reference/{ => Documents}/TeamsSlackInvestigationFinalVersion.md | 0 _reference/{ => Documents}/dockerreadme.md | 0 _reference/{ => Documents}/dropletSetup.md | 0 _reference/{ => Documents}/firebase.md | 0 _reference/{ => Documents}/productionBoardNotes.md | 0 _reference/{ => Documents}/reportFiltersAndSorters.md | 0 _reference/{ => Documents}/test api setup.md | 0 _reference/{ => JSON}/BodyshopFeatures.json | 0 _reference/{ => JSON}/CiecaOpCodesReference.json | 0 _reference/{ => JSON}/Test_CDK_Acct Config.json | 0 _reference/{ => SQL}/AuditTriggerFunctions.sql | 0 _reference/{prHelper.html => prHelper/index.html} | 0 18 files changed, 0 insertions(+), 0 deletions(-) rename _reference/{ => Documents}/DeploymentChecklist.md (100%) rename _reference/{ => Documents}/JSReportSetup.md (100%) rename _reference/{ => Documents}/Jest CheatSheet.md (100%) rename _reference/{ => Documents}/New Hasura Deployment.md (100%) rename _reference/{ => Documents}/Responsibility Center Setup.md (100%) rename _reference/{ => Documents}/SampleMetadata.md (100%) rename _reference/{ => Documents}/TeamsSlackInvestigationFinalVersion.md (100%) rename _reference/{ => Documents}/dockerreadme.md (100%) rename _reference/{ => Documents}/dropletSetup.md (100%) rename _reference/{ => Documents}/firebase.md (100%) rename _reference/{ => Documents}/productionBoardNotes.md (100%) rename _reference/{ => Documents}/reportFiltersAndSorters.md (100%) rename _reference/{ => Documents}/test api setup.md (100%) rename _reference/{ => JSON}/BodyshopFeatures.json (100%) rename _reference/{ => JSON}/CiecaOpCodesReference.json (100%) rename _reference/{ => JSON}/Test_CDK_Acct Config.json (100%) rename _reference/{ => SQL}/AuditTriggerFunctions.sql (100%) rename _reference/{prHelper.html => prHelper/index.html} (100%) diff --git a/_reference/DeploymentChecklist.md b/_reference/Documents/DeploymentChecklist.md similarity index 100% rename from _reference/DeploymentChecklist.md rename to _reference/Documents/DeploymentChecklist.md diff --git a/_reference/JSReportSetup.md b/_reference/Documents/JSReportSetup.md similarity index 100% rename from _reference/JSReportSetup.md rename to _reference/Documents/JSReportSetup.md diff --git a/_reference/Jest CheatSheet.md b/_reference/Documents/Jest CheatSheet.md similarity index 100% rename from _reference/Jest CheatSheet.md rename to _reference/Documents/Jest CheatSheet.md diff --git a/_reference/New Hasura Deployment.md b/_reference/Documents/New Hasura Deployment.md similarity index 100% rename from _reference/New Hasura Deployment.md rename to _reference/Documents/New Hasura Deployment.md diff --git a/_reference/Responsibility Center Setup.md b/_reference/Documents/Responsibility Center Setup.md similarity index 100% rename from _reference/Responsibility Center Setup.md rename to _reference/Documents/Responsibility Center Setup.md diff --git a/_reference/SampleMetadata.md b/_reference/Documents/SampleMetadata.md similarity index 100% rename from _reference/SampleMetadata.md rename to _reference/Documents/SampleMetadata.md diff --git a/_reference/TeamsSlackInvestigationFinalVersion.md b/_reference/Documents/TeamsSlackInvestigationFinalVersion.md similarity index 100% rename from _reference/TeamsSlackInvestigationFinalVersion.md rename to _reference/Documents/TeamsSlackInvestigationFinalVersion.md diff --git a/_reference/dockerreadme.md b/_reference/Documents/dockerreadme.md similarity index 100% rename from _reference/dockerreadme.md rename to _reference/Documents/dockerreadme.md diff --git a/_reference/dropletSetup.md b/_reference/Documents/dropletSetup.md similarity index 100% rename from _reference/dropletSetup.md rename to _reference/Documents/dropletSetup.md diff --git a/_reference/firebase.md b/_reference/Documents/firebase.md similarity index 100% rename from _reference/firebase.md rename to _reference/Documents/firebase.md diff --git a/_reference/productionBoardNotes.md b/_reference/Documents/productionBoardNotes.md similarity index 100% rename from _reference/productionBoardNotes.md rename to _reference/Documents/productionBoardNotes.md diff --git a/_reference/reportFiltersAndSorters.md b/_reference/Documents/reportFiltersAndSorters.md similarity index 100% rename from _reference/reportFiltersAndSorters.md rename to _reference/Documents/reportFiltersAndSorters.md diff --git a/_reference/test api setup.md b/_reference/Documents/test api setup.md similarity index 100% rename from _reference/test api setup.md rename to _reference/Documents/test api setup.md diff --git a/_reference/BodyshopFeatures.json b/_reference/JSON/BodyshopFeatures.json similarity index 100% rename from _reference/BodyshopFeatures.json rename to _reference/JSON/BodyshopFeatures.json diff --git a/_reference/CiecaOpCodesReference.json b/_reference/JSON/CiecaOpCodesReference.json similarity index 100% rename from _reference/CiecaOpCodesReference.json rename to _reference/JSON/CiecaOpCodesReference.json diff --git a/_reference/Test_CDK_Acct Config.json b/_reference/JSON/Test_CDK_Acct Config.json similarity index 100% rename from _reference/Test_CDK_Acct Config.json rename to _reference/JSON/Test_CDK_Acct Config.json diff --git a/_reference/AuditTriggerFunctions.sql b/_reference/SQL/AuditTriggerFunctions.sql similarity index 100% rename from _reference/AuditTriggerFunctions.sql rename to _reference/SQL/AuditTriggerFunctions.sql diff --git a/_reference/prHelper.html b/_reference/prHelper/index.html similarity index 100% rename from _reference/prHelper.html rename to _reference/prHelper/index.html From e7909205d12501e604ec7d683a68e998b1f394c2 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 25 Oct 2024 11:50:11 -0700 Subject: [PATCH 46/79] feature/IO-2973-Created-By-Tasks - Merge in release, fix conflicts Signed-off-by: Dave Richer --- server/email/tasksEmails.js | 12 ++++++------ server/graphql-client/queries.js | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/server/email/tasksEmails.js b/server/email/tasksEmails.js index 719c4f051..ab25343e0 100644 --- a/server/email/tasksEmails.js +++ b/server/email/tasksEmails.js @@ -97,11 +97,11 @@ const getEndpoints = (bodyshop) => : "https://romeonline.io" }); -const generateTemplateArgs = (title, priority, description, dueDate, createdBy, bodyshop, job, taskId, dateLine) => { +const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, job, taskId, dateLine, createdBy) => { const endPoints = getEndpoints(bodyshop); return { header: title, - subHeader: `Body Shop: ${bodyshop.shopname} | Priority: ${formatPriority(priority)} | Due on: ${formatDate(dueDate)} | Created by: ${createdBy || "N/A"}`, + subHeader: `Body Shop: ${bodyshop.shopname} | Priority: ${formatPriority(priority)} ${formatDate(dueDate)} | Created By: ${createdBy || "N/A"}`, body: `Reference: ${job.ro_number || "N/A"} | ${job.ownr_co_nm ? job.ownr_co_nm : `${job.ownr_fn || ""} ${job.ownr_ln || ""}`.trim()} | ${`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${job.v_model_desc || ""}`.trim()}
    ${description ? description.concat("
    ") : ""}View this task.`, dateLine }; @@ -179,11 +179,11 @@ const taskAssignedEmail = async (req, res) => { newTask.priority, newTask.description, newTask.due_date, - newTask.created_by, tasks_by_pk.bodyshop, tasks_by_pk.job, newTask.id, - dateLine + dateLine, + newTask.created_by ) ), null, @@ -267,11 +267,11 @@ const tasksRemindEmail = async (req, res) => { onlyTask.priority, onlyTask.description, onlyTask.due_date, - onlyTask.created_by, onlyTask.bodyshop, onlyTask.job, onlyTask.id, - dateLine + dateLine, + onlyTask.created_by ) ); } diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index b1de44a34..99e37bebe 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -2506,6 +2506,7 @@ exports.QUERY_TASK_BY_ID = ` query QUERY_TASK_BY_ID($id: uuid!) { tasks_by_pk(id: $id) { id + created_by assigned_to_employee{ id user_email From 9793daa04c178d63a4c38d5c42d56218e1236a55 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 25 Oct 2024 11:58:50 -0700 Subject: [PATCH 47/79] release/2024-10-25 - Add The local email viewer to the reference folder. Signed-off-by: Dave Richer --- _reference/localEmailViewer/.gitignore | 1 + _reference/localEmailViewer/README.md | 7 + _reference/localEmailViewer/index.js | 116 ++ _reference/localEmailViewer/package-lock.json | 1214 +++++++++++++++++ _reference/localEmailViewer/package.json | 18 + 5 files changed, 1356 insertions(+) create mode 100644 _reference/localEmailViewer/.gitignore create mode 100644 _reference/localEmailViewer/README.md create mode 100644 _reference/localEmailViewer/index.js create mode 100644 _reference/localEmailViewer/package-lock.json create mode 100644 _reference/localEmailViewer/package.json diff --git a/_reference/localEmailViewer/.gitignore b/_reference/localEmailViewer/.gitignore new file mode 100644 index 000000000..b512c09d4 --- /dev/null +++ b/_reference/localEmailViewer/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/_reference/localEmailViewer/README.md b/_reference/localEmailViewer/README.md new file mode 100644 index 000000000..3f8a6fc71 --- /dev/null +++ b/_reference/localEmailViewer/README.md @@ -0,0 +1,7 @@ +This will connect to your dockers local stack session and render the email in HTML. + +```shell +node index.js +``` + +http://localhost:3334 diff --git a/_reference/localEmailViewer/index.js b/_reference/localEmailViewer/index.js new file mode 100644 index 000000000..2b4c21444 --- /dev/null +++ b/_reference/localEmailViewer/index.js @@ -0,0 +1,116 @@ +// index.js + +import express from 'express'; +import fetch from 'node-fetch'; +import {simpleParser} from 'mailparser'; + +const app = express(); +const PORT = 3334; + +app.get('/', async (req, res) => { + try { + const response = await fetch('http://localhost:4566/_aws/ses'); + if (!response.ok) { + throw new Error('Network response was not ok'); + } + const data = await response.json(); + const messagesHtml = await parseMessages(data.messages); + res.send(renderHtml(messagesHtml)); + } catch (error) { + console.error('Error fetching messages:', error); + res.status(500).send('Error fetching messages'); + } +}); + +async function parseMessages(messages) { + const parsedMessages = await Promise.all( + messages.map(async (message, index) => { + try { + const parsed = await simpleParser(message.RawData); + return ` +
    +
    +
    + Message ${index + 1} +
    +
    + From: ${message.Source} +
    +
    + Region: ${message.Region} +
    +
    + Timestamp: ${message.Timestamp} +
    +
    +
    + ${parsed.html || parsed.textAsHtml || 'No HTML content available'} +
    +
    + `; + } catch (error) { + console.error('Error parsing email:', error); + return ` +
    +
    + Message ${index + 1} +
    +
    + From: ${message.Source} +
    +
    + Region: ${message.Region} +
    +
    + Timestamp: ${message.Timestamp} +
    +
    + Error parsing email content +
    +
    + `; + } + }) + ); + return parsedMessages.join(''); +} + +function renderHtml(messagesHtml) { + return ` + + + + + + Email Messages Viewer + + + + +
    +

    Email Messages Viewer

    +
    + ${messagesHtml} +
    +
    + + + `; +} + +app.listen(PORT, () => { + console.log(`Server is running on http://localhost:${PORT}`); +}); \ No newline at end of file diff --git a/_reference/localEmailViewer/package-lock.json b/_reference/localEmailViewer/package-lock.json new file mode 100644 index 000000000..d8d53da2e --- /dev/null +++ b/_reference/localEmailViewer/package-lock.json @@ -0,0 +1,1214 @@ +{ + "name": "localemailviewer", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "localemailviewer", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "express": "^4.21.1", + "mailparser": "^3.7.1", + "node-fetch": "^3.3.2" + } + }, + "node_modules/@selderee/plugin-htmlparser2": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", + "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "selderee": "^0.11.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding-japanese": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.1.0.tgz", + "integrity": "sha512-58XySVxUgVlBikBTbQ8WdDxBDHIdXucB16LO5PBHR8t75D54wQrNo4cg+58+R1CtJfKnsVsvt9XlteRaR8xw1w==", + "license": "MIT", + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/html-to-text": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz", + "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==", + "license": "MIT", + "dependencies": { + "@selderee/plugin-htmlparser2": "^0.11.0", + "deepmerge": "^4.3.1", + "dom-serializer": "^2.0.0", + "htmlparser2": "^8.0.2", + "selderee": "^0.11.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/leac": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", + "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==", + "license": "MIT", + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, + "node_modules/libbase64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.3.0.tgz", + "integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==", + "license": "MIT" + }, + "node_modules/libmime": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.5.tgz", + "integrity": "sha512-nSlR1yRZ43L3cZCiWEw7ali3jY29Hz9CQQ96Oy+sSspYnIP5N54ucOPHqooBsXzwrX1pwn13VUE05q4WmzfaLg==", + "license": "MIT", + "dependencies": { + "encoding-japanese": "2.1.0", + "iconv-lite": "0.6.3", + "libbase64": "1.3.0", + "libqp": "2.1.0" + } + }, + "node_modules/libmime/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/libqp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/libqp/-/libqp-2.1.0.tgz", + "integrity": "sha512-O6O6/fsG5jiUVbvdgT7YX3xY3uIadR6wEZ7+vy9u7PKHAlSEB6blvC1o5pHBjgsi95Uo0aiBBdkyFecj6jtb7A==", + "license": "MIT" + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/mailparser": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.7.1.tgz", + "integrity": "sha512-RCnBhy5q8XtB3mXzxcAfT1huNqN93HTYYyL6XawlIKycfxM/rXPg9tXoZ7D46+SgCS1zxKzw+BayDQSvncSTTw==", + "license": "MIT", + "dependencies": { + "encoding-japanese": "2.1.0", + "he": "1.2.0", + "html-to-text": "9.0.5", + "iconv-lite": "0.6.3", + "libmime": "5.3.5", + "linkify-it": "5.0.0", + "mailsplit": "5.4.0", + "nodemailer": "6.9.13", + "punycode.js": "2.3.1", + "tlds": "1.252.0" + } + }, + "node_modules/mailparser/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mailsplit": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.0.tgz", + "integrity": "sha512-wnYxX5D5qymGIPYLwnp6h8n1+6P6vz/MJn5AzGjZ8pwICWssL+CCQjWBIToOVHASmATot4ktvlLo6CyLfOXWYA==", + "license": "(MIT OR EUPL-1.1+)", + "dependencies": { + "libbase64": "1.2.1", + "libmime": "5.2.0", + "libqp": "2.0.1" + } + }, + "node_modules/mailsplit/node_modules/encoding-japanese": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.0.0.tgz", + "integrity": "sha512-++P0RhebUC8MJAwJOsT93dT+5oc5oPImp1HubZpAuCZ5kTLnhuuBhKHj2jJeO/Gj93idPBWmIuQ9QWMe5rX3pQ==", + "license": "MIT", + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/mailsplit/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mailsplit/node_modules/libbase64": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.2.1.tgz", + "integrity": "sha512-l+nePcPbIG1fNlqMzrh68MLkX/gTxk/+vdvAb388Ssi7UuUN31MI44w4Yf33mM3Cm4xDfw48mdf3rkdHszLNew==", + "license": "MIT" + }, + "node_modules/mailsplit/node_modules/libmime": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.2.0.tgz", + "integrity": "sha512-X2U5Wx0YmK0rXFbk67ASMeqYIkZ6E5vY7pNWRKtnNzqjvdYYG8xtPDpCnuUEnPU9vlgNev+JoSrcaKSUaNvfsw==", + "license": "MIT", + "dependencies": { + "encoding-japanese": "2.0.0", + "iconv-lite": "0.6.3", + "libbase64": "1.2.1", + "libqp": "2.0.1" + } + }, + "node_modules/mailsplit/node_modules/libqp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/libqp/-/libqp-2.0.1.tgz", + "integrity": "sha512-Ka0eC5LkF3IPNQHJmYBWljJsw0UvM6j+QdKRbWyCdTmYwvIDE6a7bCm0UkTAL/K+3KXK5qXT/ClcInU01OpdLg==", + "license": "MIT" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/nodemailer": { + "version": "6.9.13", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.13.tgz", + "integrity": "sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseley": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", + "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==", + "license": "MIT", + "dependencies": { + "leac": "^0.6.0", + "peberminta": "^0.9.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "license": "MIT" + }, + "node_modules/peberminta": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", + "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==", + "license": "MIT", + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/selderee": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", + "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==", + "license": "MIT", + "dependencies": { + "parseley": "^0.12.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/tlds": { + "version": "1.252.0", + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.252.0.tgz", + "integrity": "sha512-GA16+8HXvqtfEnw/DTcwB0UU354QE1n3+wh08oFjr6Znl7ZLAeUgYzCcK+/CCrOyE0vnHR8/pu3XXG3vDijXpQ==", + "license": "MIT", + "bin": { + "tlds": "bin.js" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + } + } +} diff --git a/_reference/localEmailViewer/package.json b/_reference/localEmailViewer/package.json new file mode 100644 index 000000000..ad795b60f --- /dev/null +++ b/_reference/localEmailViewer/package.json @@ -0,0 +1,18 @@ +{ + "name": "localemailviewer", + "version": "1.0.0", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "express": "^4.21.1", + "mailparser": "^3.7.1", + "node-fetch": "^3.3.2" + } +} From 1f2786ddec0b26b955d799677b0b25375767b96d Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 28 Oct 2024 09:31:37 -0700 Subject: [PATCH 48/79] release/2024-11-01 - Fix some log things Signed-off-by: Dave Richer --- server.js | 28 +++++++------------- server/utils/logger.js | 34 +++++++++++++++++++++---- server/web-sockets/redisSocketEvents.js | 23 ++++++++--------- 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/server.js b/server.js index 8acba572a..a92ab7241 100644 --- a/server.js +++ b/server.js @@ -153,18 +153,13 @@ const connectToRedisCluster = async () => { } else { // Use the Dockerized Redis cluster in development if (isEmpty(process.env?.REDIS_URL) || !isString(process.env?.REDIS_URL)) { - logger.log(`[${process.env.NODE_ENV}] No or Malformed REDIS_URL present.`, "ERROR", "redis", "api"); + logger.log(`No or Malformed REDIS_URL present.`, "ERROR", "redis", "api"); process.exit(1); } try { redisServers = JSON.parse(process.env.REDIS_URL); } catch (error) { - logger.log( - `[${process.env.NODE_ENV}] Failed to parse REDIS_URL: ${error.message}. Exiting...`, - "ERROR", - "redis", - "api" - ); + logger.log(`Failed to parse REDIS_URL: ${error.message}. Exiting...`, "ERROR", "redis", "api"); process.exit(1); } } @@ -172,12 +167,7 @@ const connectToRedisCluster = async () => { const clusterRetryStrategy = (times) => { const delay = Math.min(CLUSTER_RETRY_BASE_DELAY + times * 50, CLUSTER_RETRY_MAX_DELAY) + Math.random() * CLUSTER_RETRY_JITTER; - logger.log( - `[${process.env.NODE_ENV}] Redis cluster not yet ready. Retrying in ${delay.toFixed(2)}ms`, - "WARN", - "redis", - "api" - ); + logger.log(`Redis cluster not yet ready. Retrying in ${delay.toFixed(2)}ms`, "WARN", "redis", "api"); return delay; }; @@ -194,12 +184,12 @@ const connectToRedisCluster = async () => { return new Promise((resolve, reject) => { redisCluster.on("ready", () => { - logger.log(`[${process.env.NODE_ENV}] Redis cluster connection established.`, "INFO", "redis", "api"); + logger.log(`Redis cluster connection established.`, "INFO", "redis", "api"); resolve(redisCluster); }); redisCluster.on("error", (err) => { - logger.log(`[${process.env.NODE_ENV}] Redis cluster connection failed: ${err.message}`, "ERROR", "redis", "api"); + logger.log(`Redis cluster connection failed: ${err.message}`, "ERROR", "redis", "api"); reject(err); }); }); @@ -215,7 +205,7 @@ const applySocketIO = async ({ server, app }) => { // Handle errors redisCluster.on("error", (err) => { - logger.log(`[${process.env.NODE_ENV}] Redis ERROR`, "ERROR", "redis", "api"); + logger.log(`Redis ERROR`, "ERROR", "redis", "api"); }); const pubClient = redisCluster; @@ -249,7 +239,7 @@ const applySocketIO = async ({ server, app }) => { }); if (isString(process.env.REDIS_ADMIN_PASS) && !isEmpty(process.env.REDIS_ADMIN_PASS)) { - logger.log(`[${process.env.NODE_ENV}] Initializing Redis Admin UI....`, "INFO", "redis", "api"); + logger.log(`Initializing Redis Admin UI....`, "INFO", "redis", "api"); instrument(ioRedis, { auth: { type: "basic", @@ -312,9 +302,9 @@ const main = async () => { try { await server.listen(port); - logger.log(`[${process.env.NODE_ENV}] Server started on port ${port}`, "INFO", "api"); + logger.log(`Server started on port ${port}`, "INFO", "api"); } catch (error) { - logger.log(`[${process.env.NODE_ENV}] Server failed to start on port ${port}`, "ERROR", "api", error); + logger.log(`Server failed to start on port ${port}`, "ERROR", "api", error); } }; diff --git a/server/utils/logger.js b/server/utils/logger.js index 3a1742432..1344c34ac 100644 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -8,6 +8,7 @@ const InstanceManager = require("../utils/instanceMgr").default; const winston = require("winston"); const WinstonCloudWatch = require("winston-cloudwatch"); const { isString, isEmpty } = require("lodash"); +const { networkInterfaces } = require("node:os"); const createLogger = () => { try { @@ -42,6 +43,19 @@ const createLogger = () => { })(); }; + const getPrivateIP = () => { + const interfaces = networkInterfaces(); + for (const name of Object.keys(interfaces)) { + for (const iface of interfaces[name]) { + // Find an IPv4 address that's not internal (like localhost) + if (iface.family === "IPv4" && !iface.internal) { + return iface.address; + } + } + } + return "127.0.0.1"; + }; + const createProductionTransport = (level, logStreamName, filters) => { return new WinstonCloudWatch({ level, @@ -51,17 +65,26 @@ const createLogger = () => { }); }; + const hostname = process.env?.HOSTNAME || getPrivateIP(); + const getDevelopmentTransports = () => [ new winston.transports.Console({ level: "silly", format: winston.format.combine( winston.format.colorize(), winston.format.timestamp(), - winston.format.printf(({ level, message, timestamp, user, record, object }) => { - return `${timestamp} [${level}]: ${message} ${ - user ? `| user: ${JSON.stringify(user)}` : "" - } ${record ? `| record: ${JSON.stringify(record)}` : ""} ${ - object ? `| object: ${JSON.stringify(object, null, 2)}` : "" + winston.format.printf(({ level, message, timestamp, user, record, meta }) => { + const hostnameColor = `\x1b[34m${hostname}\x1b[0m`; // Blue + const timestampColor = `\x1b[36m${timestamp}\x1b[0m`; // Cyan + const labelColor = "\x1b[33m"; // Yellow + const separatorColor = "\x1b[35m|\x1b[0m"; // Magenta for separators + + return `${timestampColor} [${hostnameColor}] [${level}]: ${message} ${ + user ? `${separatorColor} ${labelColor}user:\x1b[0m ${JSON.stringify(user)}` : "" + } ${record ? `${separatorColor} ${labelColor}record:\x1b[0m ${JSON.stringify(record)}` : ""}${ + meta + ? `\n${separatorColor} ${labelColor}meta:\x1b[0m ${JSON.stringify(meta, null, 2)} ${separatorColor}` + : "" }`; }) ) @@ -89,6 +112,7 @@ const createLogger = () => { message, user, record, + hostname, meta }); }; diff --git a/server/web-sockets/redisSocketEvents.js b/server/web-sockets/redisSocketEvents.js index a19953311..0e8a3a449 100644 --- a/server/web-sockets/redisSocketEvents.js +++ b/server/web-sockets/redisSocketEvents.js @@ -8,7 +8,6 @@ const redisSocketEvents = ({ }) => { // Logging helper functions const createLogEvent = (socket, level, message) => { - //console.log(`[IOREDIS LOG EVENT] - ${socket?.user?.email} - ${socket.id} - ${message}`); logger.log("ioredis-log-event", level, socket?.user?.email, null, { wsmessage: message }); }; @@ -33,7 +32,6 @@ const redisSocketEvents = ({ next(new Error("Authentication error - no authorization token.")); } } catch (error) { - //console.log("Uncaught connection error:::", error); logger.log("websocket-connection-error", "error", null, null, { ...error }); @@ -43,7 +41,7 @@ const redisSocketEvents = ({ // Register Socket Events const registerSocketEvents = (socket) => { - createLogEvent(socket, "DEBUG", `Registering RedisIO Socket Events.`); + createLogEvent(socket, "debug", `Registering RedisIO Socket Events.`); // Token Update Events const registerUpdateEvents = (socket) => { @@ -56,7 +54,7 @@ const redisSocketEvents = ({ // If We ever want to persist user Data across workers // await setSessionData(socket.id, "user", user); - createLogEvent(socket, "INFO", "Token updated successfully"); + createLogEvent(socket, "debug", "Token updated successfully"); socket.emit("token-updated", { success: true }); } catch (error) { @@ -67,7 +65,7 @@ const redisSocketEvents = ({ error: "Stale token." }); } else { - createLogEvent(socket, "ERROR", `Token update failed: ${error.message}`); + createLogEvent(socket, "error", `Token update failed: ${error.message}`); socket.emit("token-updated", { success: false, error: error.message }); // For any other errors, optionally disconnect the socket socket.disconnect(); @@ -82,9 +80,9 @@ const redisSocketEvents = ({ try { const room = getBodyshopRoom(bodyshopUUID); socket.join(room); - createLogEvent(socket, "DEBUG", `Client joined bodyshop room: ${room}`); + createLogEvent(socket, "debug", `Client joined bodyshop room: ${room}`); } catch (error) { - createLogEvent(socket, "ERROR", `Error joining room: ${error}`); + createLogEvent(socket, "error", `Error joining room: ${error}`); } }; @@ -92,9 +90,9 @@ const redisSocketEvents = ({ try { const room = getBodyshopRoom(bodyshopUUID); socket.leave(room); - createLogEvent(socket, "DEBUG", `Client left bodyshop room: ${room}`); + createLogEvent(socket, "debug", `Client left bodyshop room: ${room}`); } catch (error) { - createLogEvent(socket, "ERROR", `Error joining room: ${error}`); + createLogEvent(socket, "error", `Error joining room: ${error}`); } }; @@ -102,9 +100,10 @@ const redisSocketEvents = ({ try { const room = getBodyshopRoom(bodyshopUUID); io.to(room).emit("bodyshop-message", message); - createLogEvent(socket, "DEBUG", `Broadcast message to bodyshop ${room}`); + // We do not need this as these can be debugged live + // createLogEvent(socket, "debug", `Broadcast message to bodyshop ${room}`); } catch (error) { - createLogEvent(socket, "ERROR", `Error getting room: ${error}`); + createLogEvent(socket, "error", `Error getting room: ${error}`); } }; @@ -115,7 +114,7 @@ const redisSocketEvents = ({ // Disconnect Events const registerDisconnectEvents = (socket) => { const disconnect = () => { - createLogEvent(socket, "DEBUG", `User disconnected.`); + createLogEvent(socket, "debug", `User disconnected.`); const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id); for (const room of rooms) { socket.leave(room); From d4e8803b13b3164d3439790a7cf96b8df2c91246 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 28 Oct 2024 09:47:27 -0700 Subject: [PATCH 49/79] release/2024-11-01 - Adjust client body buffer size Signed-off-by: Dave Richer --- .platform/nginx/conf.d/proxy.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.platform/nginx/conf.d/proxy.conf b/.platform/nginx/conf.d/proxy.conf index ae3fb47f6..2dc60b344 100644 --- a/.platform/nginx/conf.d/proxy.conf +++ b/.platform/nginx/conf.d/proxy.conf @@ -1 +1,2 @@ -client_max_body_size 50M; \ No newline at end of file +client_max_body_size 50M; +client_body_buffer_size 5M; From c4c30d98d4ff36dbce7af649c8fb359f35083293 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 28 Oct 2024 10:07:10 -0700 Subject: [PATCH 50/79] release/2024-11-01 - Adjust hostname check Signed-off-by: Dave Richer --- server/utils/logger.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/utils/logger.js b/server/utils/logger.js index 1344c34ac..75d282fa2 100644 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -65,7 +65,7 @@ const createLogger = () => { }); }; - const hostname = process.env?.HOSTNAME || getPrivateIP(); + const hostname = process.env.HOSTNAME || getPrivateIP(); const getDevelopmentTransports = () => [ new winston.transports.Console({ From a57156756e927fade89ac6f04752a7784d84937c Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 28 Oct 2024 11:03:30 -0700 Subject: [PATCH 51/79] feature/IO-2979-DST - Normalize usages of dayjs to dayjs not day, move locale hook Signed-off-by: Dave Richer --- client/src/App/App.container.jsx | 4 ---- client/src/components/eula/eula.component.jsx | 4 ++-- .../job-lifecycle/job-lifecycle.component.jsx | 6 +++--- .../job-line-dispatch-button.component.jsx | 10 +++++++--- .../parts-dispatch-expander.component.jsx | 4 ++-- .../time-tickets-commit-toggle.component.jsx | 4 ++-- .../time-tickets-commit.component.jsx | 6 +++--- .../tt-approve-button/tt-approve-button.component.jsx | 4 ++-- client/src/redux/user/user.sagas.js | 7 +++---- client/src/utils/day.js | 3 +++ 10 files changed, 27 insertions(+), 25 deletions(-) diff --git a/client/src/App/App.container.jsx b/client/src/App/App.container.jsx index e4df37c61..d6f3a53fd 100644 --- a/client/src/App/App.container.jsx +++ b/client/src/App/App.container.jsx @@ -2,8 +2,6 @@ import { ApolloProvider } from "@apollo/client"; import { SplitFactoryProvider, SplitSdk } from "@splitsoftware/splitio-react"; import { ConfigProvider } from "antd"; import enLocale from "antd/es/locale/en_US"; -import dayjs from "../utils/day"; -import "dayjs/locale/en"; import React from "react"; import { useTranslation } from "react-i18next"; import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component"; @@ -19,8 +17,6 @@ if (import.meta.env.DEV) { Userpilot.initialize("NX-69145f08"); } -dayjs.locale("en"); - const config = { core: { authorizationKey: import.meta.env.VITE_APP_SPLIT_API, diff --git a/client/src/components/eula/eula.component.jsx b/client/src/components/eula/eula.component.jsx index 8d2227e02..399a52b40 100644 --- a/client/src/components/eula/eula.component.jsx +++ b/client/src/components/eula/eula.component.jsx @@ -8,7 +8,7 @@ import { INSERT_EULA_ACCEPTANCE } from "../../graphql/user.queries"; import { useMutation } from "@apollo/client"; import { acceptEula } from "../../redux/user/user.actions"; import { useTranslation } from "react-i18next"; -import day from "../../utils/day"; +import dayjs from "../../utils/day"; import "./eula.styles.scss"; import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx"; @@ -208,7 +208,7 @@ const EulaFormComponent = ({ form, handleChange, onFinish, t }) => ( { required: true, validator: (_, value) => { - if (day(value).isSame(day(), "day")) { + if (dayjs(value).isSame(dayjs(), "day")) { return Promise.resolve(); } return Promise.reject(new Error(t("eula.messages.date_accepted"))); diff --git a/client/src/components/job-lifecycle/job-lifecycle.component.jsx b/client/src/components/job-lifecycle/job-lifecycle.component.jsx index 794524c2a..e648ad4d5 100644 --- a/client/src/components/job-lifecycle/job-lifecycle.component.jsx +++ b/client/src/components/job-lifecycle/job-lifecycle.component.jsx @@ -1,5 +1,5 @@ import React, { useCallback, useEffect, useState } from "react"; -import day from "../../utils/day"; +import dayjs from "../../utils/day"; import axios from "axios"; import { Badge, Card, Space, Table, Tag } from "antd"; import { gql, useQuery } from "@apollo/client"; @@ -72,7 +72,7 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) { dataIndex: "start", key: "start", render: (text) => DateTimeFormatterFunction(text), - sorter: (a, b) => day(a.start).unix() - day(b.start).unix() + sorter: (a, b) => dayjs(a.start).unix() - dayjs(b.start).unix() }, { title: t("job_lifecycle.columns.relative_start"), @@ -90,7 +90,7 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) { } return isEmpty(a.end) ? 1 : -1; } - return day(a.end).unix() - day(b.end).unix(); + return dayjs(a.end).unix() - dayjs(b.end).unix(); }, render: (text) => (isEmpty(text) ? t("job_lifecycle.content.not_available") : DateTimeFormatterFunction(text)) }, diff --git a/client/src/components/job-line-dispatch-button/job-line-dispatch-button.component.jsx b/client/src/components/job-line-dispatch-button/job-line-dispatch-button.component.jsx index 8e570ab2d..ce0b6e4fe 100644 --- a/client/src/components/job-line-dispatch-button/job-line-dispatch-button.component.jsx +++ b/client/src/components/job-line-dispatch-button/job-line-dispatch-button.component.jsx @@ -2,7 +2,7 @@ import React, { useState } from "react"; import { useMutation } from "@apollo/client"; import { Button, Form, notification, Popover, Select, Space } from "antd"; -import day from "../../utils/day"; +import dayjs from "../../utils/day"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; @@ -48,7 +48,7 @@ export function JobLineDispatchButton({ const result = await dispatchLines({ variables: { partsDispatch: { - dispatched_at: day(), + dispatched_at: dayjs(), employeeid: values.employeeid, jobid: job.id, dispatched_by: currentUser.email, @@ -138,7 +138,11 @@ export function JobLineDispatchButton({ return ( - diff --git a/client/src/components/parts-dispatch-expander/parts-dispatch-expander.component.jsx b/client/src/components/parts-dispatch-expander/parts-dispatch-expander.component.jsx index 477240357..2a84527cc 100644 --- a/client/src/components/parts-dispatch-expander/parts-dispatch-expander.component.jsx +++ b/client/src/components/parts-dispatch-expander/parts-dispatch-expander.component.jsx @@ -1,6 +1,6 @@ import { useMutation } from "@apollo/client"; import { Button, Card, Col, notification, Row, Table } from "antd"; -import day from "../../utils/day"; +import dayjs from "../../utils/day"; import React from "react"; import { useTranslation } from "react-i18next"; import { UPDATE_PARTS_DISPATCH_LINE } from "../../graphql/parts-dispatch.queries"; @@ -11,7 +11,7 @@ export default function PartsDispatchExpander({ dispatch, job }) { const [updateDispatchLine] = useMutation(UPDATE_PARTS_DISPATCH_LINE); const handleAccept = async ({ partsDispatchLineId }) => { - const accepted_at = day(); + const accepted_at = dayjs(); const result = await updateDispatchLine({ variables: { id: partsDispatchLineId, line: { accepted_at } }, optimisticResponse: { diff --git a/client/src/components/time-tickets-commit-toggle/time-tickets-commit-toggle.component.jsx b/client/src/components/time-tickets-commit-toggle/time-tickets-commit-toggle.component.jsx index 3ee60583a..07aa3234d 100644 --- a/client/src/components/time-tickets-commit-toggle/time-tickets-commit-toggle.component.jsx +++ b/client/src/components/time-tickets-commit-toggle/time-tickets-commit-toggle.component.jsx @@ -1,6 +1,6 @@ import { useMutation } from "@apollo/client"; import { Button, notification } from "antd"; -import day from "../../utils/day"; +import dayjs from "../../utils/day"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -29,7 +29,7 @@ export function TimeTicketsCommit({ bodyshop, currentUser, timeticket, disabled, ? { commited_by: null, committed_at: null } : { commited_by: currentUser.email, - committed_at: day() + committed_at: dayjs() }; const result = await updateTimeTicket({ diff --git a/client/src/components/time-tickets-commit/time-tickets-commit.component.jsx b/client/src/components/time-tickets-commit/time-tickets-commit.component.jsx index 52aef7401..c817afd2e 100644 --- a/client/src/components/time-tickets-commit/time-tickets-commit.component.jsx +++ b/client/src/components/time-tickets-commit/time-tickets-commit.component.jsx @@ -1,6 +1,6 @@ import { useMutation } from "@apollo/client"; import { Button, notification } from "antd"; -import day from "../../utils/day"; +import dayjs from "../../utils/day"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -34,7 +34,7 @@ export function TimeTicketsCommit({ timeticketIds: timetickets.map((ticket) => ticket.id), timeticket: { commited_by: currentUser.email, - committed_at: day() + committed_at: dayjs() } }, update(cache) { @@ -47,7 +47,7 @@ export function TimeTicketsCommit({ return { ...ticket, commited_by: currentUser.email, - committed_at: day() + committed_at: dayjs() }; } return ticket; diff --git a/client/src/components/tt-approve-button/tt-approve-button.component.jsx b/client/src/components/tt-approve-button/tt-approve-button.component.jsx index 8a31528d7..48daee263 100644 --- a/client/src/components/tt-approve-button/tt-approve-button.component.jsx +++ b/client/src/components/tt-approve-button/tt-approve-button.component.jsx @@ -1,7 +1,7 @@ import { useApolloClient } from "@apollo/client"; import { Button, notification } from "antd"; import _ from "lodash"; -import day from "../../utils/day"; +import dayjs from "../../utils/day"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -49,7 +49,7 @@ export function TtApproveButton({ })), approvalIds: selectedTickets, approvalUpdate: { - approved_at: day(), + approved_at: dayjs(), approved_by: currentUser.email } } diff --git a/client/src/redux/user/user.sagas.js b/client/src/redux/user/user.sagas.js index f565ea544..423b40283 100644 --- a/client/src/redux/user/user.sagas.js +++ b/client/src/redux/user/user.sagas.js @@ -28,7 +28,7 @@ import { } from "../../firebase/firebase.utils"; import { QUERY_EULA } from "../../graphql/bodyshop.queries"; import client from "../../utils/GraphQLClient"; -import day from "../../utils/day"; +import dayjs from "../../utils/day"; import InstanceRenderManager from "../../utils/instanceRenderMgr"; import { checkInstanceId, @@ -96,7 +96,7 @@ export function* isUserAuthenticated() { const eulaQuery = yield client.query({ query: QUERY_EULA, variables: { - now: day() + now: dayjs() } }); @@ -314,8 +314,7 @@ export function* SetAuthLevelFromShopDetails({ payload }) { try { const userEmail = yield select((state) => state.user.currentUser.email); try { - console.log("Setting shop timezone."); - day.tz.setDefault(payload.timezone); + dayjs.tz.setDefault(payload.timezone); } catch (error) { console.log(error); } diff --git a/client/src/utils/day.js b/client/src/utils/day.js index 3fb824b11..3194cfb31 100644 --- a/client/src/utils/day.js +++ b/client/src/utils/day.js @@ -1,5 +1,6 @@ import dayjs from "dayjs"; +import "dayjs/locale/en"; import dayjsBusinessDays from "dayjs-business-days2"; import isSameOrAfter from "dayjs/plugin/isSameOrAfter"; import updateLocale from "dayjs/plugin/updateLocale"; @@ -64,4 +65,6 @@ dayjs.extend(minMax); dayjs.extend(isBetween); dayjs.extend(dayjsBusinessDays); +dayjs.locale("en"); + export default dayjs; From 0b7d469e0e88a2b8ecf0173b948c288e95ca0af3 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 28 Oct 2024 11:55:13 -0700 Subject: [PATCH 52/79] feature/IO-2979-DST - Finish DST Signed-off-by: Dave Richer --- .../components/schedule-calendar-wrapper/localizer.js | 11 ++++++++--- .../scheduler-calendar-wrapper.component.jsx | 6 +++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/client/src/components/schedule-calendar-wrapper/localizer.js b/client/src/components/schedule-calendar-wrapper/localizer.js index e91016416..871511ce2 100644 --- a/client/src/components/schedule-calendar-wrapper/localizer.js +++ b/client/src/components/schedule-calendar-wrapper/localizer.js @@ -119,7 +119,7 @@ var formats = { agendaTimeRangeFormat: timeRangeFormat }; -const localizer = (dayjsLib) => { +const localizer = (dayjsLib, timezone) => { // load dayjs plugins dayjsLib.extend(isBetween); dayjsLib.extend(isSameOrAfter); @@ -128,6 +128,10 @@ const localizer = (dayjsLib) => { dayjsLib.extend(localizedFormat); dayjsLib.extend(minMax); dayjsLib.extend(utc); + + dayjsLib.locale("en"); + dayjsLib.tz.setDefault(timezone); + var locale = function locale(dj, c) { return c ? dj.locale(c) : dj; }; @@ -136,8 +140,9 @@ const localizer = (dayjsLib) => { // then use the timezone aware version //TODO This was the issue entirely... - // var dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib; - var dayjs = dayjsLib; + var dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib; + + // var dayjs = dayjsLib; function getTimezoneOffset(date) { // ensures this gets cast to timezone diff --git a/client/src/components/schedule-calendar-wrapper/scheduler-calendar-wrapper.component.jsx b/client/src/components/schedule-calendar-wrapper/scheduler-calendar-wrapper.component.jsx index fb866d89d..1d9e14eb9 100644 --- a/client/src/components/schedule-calendar-wrapper/scheduler-calendar-wrapper.component.jsx +++ b/client/src/components/schedule-calendar-wrapper/scheduler-calendar-wrapper.component.jsx @@ -1,7 +1,7 @@ import dayjs from "../../utils/day"; import queryString from "query-string"; import React from "react"; -import { Calendar } from "react-big-calendar"; +import { Calendar, dayjsLocalizer } from "react-big-calendar"; import { connect } from "react-redux"; import { Link, useLocation, useNavigate } from "react-router-dom"; import { createStructuredSelector } from "reselect"; @@ -14,13 +14,13 @@ import { selectProblemJobs } from "../../redux/application/application.selectors import { Alert, Collapse, Space } from "antd"; import { Trans, useTranslation } from "react-i18next"; import InstanceRenderManager from "../../utils/instanceRenderMgr"; -import local from "./localizer"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, problemJobs: selectProblemJobs }); -const localizer = local(dayjs); + +const localizer = dayjsLocalizer(dayjs); export function ScheduleCalendarWrapperComponent({ bodyshop, From 785449a9868bc51edfb0db2ec79e5f99125bccae Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 28 Oct 2024 12:03:48 -0700 Subject: [PATCH 53/79] release/2024-11-01 - Remove Trace Log Level Signed-off-by: Dave Richer --- .../dms-log-events.component.jsx | 2 -- .../dms-payables/dms-payables.container.jsx | 1 - client/src/pages/dms/dms.container.jsx | 1 - server/accounting/pbs/pbs-ap-allocations.js | 6 ++-- server/accounting/pbs/pbs-job-export.js | 8 ++--- server/cdk/cdk-calculate-allocations.js | 12 ++++++-- server/cdk/cdk-job-export.js | 30 +++++++++---------- server/ioevent/ioevent.js | 2 +- server/web-sockets/web-socket.js | 20 ++++++------- 9 files changed, 41 insertions(+), 41 deletions(-) diff --git a/client/src/components/dms-log-events/dms-log-events.component.jsx b/client/src/components/dms-log-events/dms-log-events.component.jsx index 037664900..9391d8edb 100644 --- a/client/src/components/dms-log-events/dms-log-events.component.jsx +++ b/client/src/components/dms-log-events/dms-log-events.component.jsx @@ -40,8 +40,6 @@ export function DmsLogEvents({ socket, logs, bodyshop }) { function LogLevelHierarchy(level) { switch (level) { - case "TRACE": - return "pink"; case "DEBUG": return "orange"; case "INFO": diff --git a/client/src/pages/dms-payables/dms-payables.container.jsx b/client/src/pages/dms-payables/dms-payables.container.jsx index de796ca6b..47659cd9b 100644 --- a/client/src/pages/dms-payables/dms-payables.container.jsx +++ b/client/src/pages/dms-payables/dms-payables.container.jsx @@ -123,7 +123,6 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { socket.emit("set-log-level", value); }} > - TRACE DEBUG INFO WARNING diff --git a/client/src/pages/dms/dms.container.jsx b/client/src/pages/dms/dms.container.jsx index 9cbc3ea50..3f7569cbd 100644 --- a/client/src/pages/dms/dms.container.jsx +++ b/client/src/pages/dms/dms.container.jsx @@ -173,7 +173,6 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse socket.emit("set-log-level", value); }} > - TRACE DEBUG INFO WARNING diff --git a/server/accounting/pbs/pbs-ap-allocations.js b/server/accounting/pbs/pbs-ap-allocations.js index 269e22c4f..49d11eaa0 100644 --- a/server/accounting/pbs/pbs-ap-allocations.js +++ b/server/accounting/pbs/pbs-ap-allocations.js @@ -26,7 +26,7 @@ axios.interceptors.request.use((x) => { } | ${JSON.stringify(x.data)} | ${JSON.stringify(headers)}`; //console.log(printable); - CdkBase.createJsonEvent(socket, "TRACE", `Raw Request: ${printable}`, x.data); + CdkBase.createJsonEvent(socket, "DEBUG", `Raw Request: ${printable}`, x.data); return x; }); @@ -36,7 +36,7 @@ axios.interceptors.response.use((x) => { const printable = `${new Date()} | Response: ${x.status} | ${JSON.stringify(x.data)}`; //console.log(printable); - CdkBase.createJsonEvent(socket, "TRACE", `Raw Response: ${printable}`, x.data); + CdkBase.createJsonEvent(socket, "DEBUG", `Raw Response: ${printable}`, x.data); return x; }); @@ -181,7 +181,7 @@ async function QueryBillData(socket, billids) { const result = await client .setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` }) .request(queries.GET_PBS_AP_ALLOCATIONS, { billids: billids }); - CdkBase.createLogEvent(socket, "TRACE", `Bill data query result ${JSON.stringify(result, null, 2)}`); + CdkBase.createLogEvent(socket, "DEBUG", `Bill data query result ${JSON.stringify(result, null, 2)}`); return result; } diff --git a/server/accounting/pbs/pbs-job-export.js b/server/accounting/pbs/pbs-job-export.js index 34db63a17..9ea3e1f91 100644 --- a/server/accounting/pbs/pbs-job-export.js +++ b/server/accounting/pbs/pbs-job-export.js @@ -28,7 +28,7 @@ axios.interceptors.request.use((x) => { } | ${JSON.stringify(x.data)} | ${JSON.stringify(headers)}`; //console.log(printable); - CdkBase.createJsonEvent(socket, "TRACE", `Raw Request: ${printable}`, x.data); + CdkBase.createJsonEvent(socket, "DEBUG", `Raw Request: ${printable}`, x.data); return x; }); @@ -38,7 +38,7 @@ axios.interceptors.response.use((x) => { const printable = `${new Date()} | Response: ${x.status} | ${JSON.stringify(x.data)}`; //console.log(printable); - CdkBase.createJsonEvent(socket, "TRACE", `Raw Response: ${printable}`, x.data); + CdkBase.createJsonEvent(socket, "DEBUG", `Raw Response: ${printable}`, x.data); return x; }); @@ -118,7 +118,7 @@ async function CheckForErrors(socket, response) { CdkBase.createLogEvent(socket, "DEBUG", `Successful response from DMS. ${response.Message || ""}`); } else { CdkBase.createLogEvent(socket, "ERROR", `Error received from DMS: ${response.Message}`); - CdkBase.createLogEvent(socket, "TRACE", `Error received from DMS: ${JSON.stringify(response)}`); + CdkBase.createLogEvent(socket, "DEBUG", `Error received from DMS: ${JSON.stringify(response)}`); } } @@ -130,7 +130,7 @@ async function QueryJobData(socket, jobid) { const result = await client .setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` }) .request(queries.QUERY_JOBS_FOR_PBS_EXPORT, { id: jobid }); - CdkBase.createLogEvent(socket, "TRACE", `Job data query result ${JSON.stringify(result, null, 2)}`); + CdkBase.createLogEvent(socket, "DEBUG", `Job data query result ${JSON.stringify(result, null, 2)}`); return result.jobs_by_pk; } diff --git a/server/cdk/cdk-calculate-allocations.js b/server/cdk/cdk-calculate-allocations.js index afe9549ea..82610dcb3 100644 --- a/server/cdk/cdk-calculate-allocations.js +++ b/server/cdk/cdk-calculate-allocations.js @@ -42,7 +42,7 @@ async function QueryJobData(connectionData, token, jobid) { CdkBase.createLogEvent(connectionData, "DEBUG", `Querying job data for id ${jobid}`); const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {}); const result = await client.setHeaders({ Authorization: token }).request(queries.GET_CDK_ALLOCATIONS, { id: jobid }); - CdkBase.createLogEvent(connectionData, "TRACE", `Job data query result ${JSON.stringify(result, null, 2)}`); + CdkBase.createLogEvent(connectionData, "DEBUG", `Job data query result ${JSON.stringify(result, null, 2)}`); return result.jobs_by_pk; } @@ -373,13 +373,19 @@ function calculateAllocations(connectionData, job) { }); //profile level adjustments for labor and materials Object.keys(job.job_totals.rates).forEach((key) => { - if (job.job_totals.rates[key] && job.job_totals.rates[key].adjustment && Dinero(job.job_totals.rates[key].adjustment).isZero() === false) { + if ( + job.job_totals.rates[key] && + job.job_totals.rates[key].adjustment && + Dinero(job.job_totals.rates[key].adjustment).isZero() === false + ) { const accountName = selectedDmsAllocationConfig.profits[key.toUpperCase()]; const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName); if (otherAccount) { if (!profitCenterHash[accountName]) profitCenterHash[accountName] = Dinero(); - profitCenterHash[accountName] = profitCenterHash[accountName].add(Dinero(job.job_totals.rates[key].adjustments)); + profitCenterHash[accountName] = profitCenterHash[accountName].add( + Dinero(job.job_totals.rates[key].adjustments) + ); } else { CdkBase.createLogEvent( connectionData, diff --git a/server/cdk/cdk-job-export.js b/server/cdk/cdk-job-export.js index 222a2b485..ec7d355b5 100644 --- a/server/cdk/cdk-job-export.js +++ b/server/cdk/cdk-job-export.js @@ -151,7 +151,7 @@ async function QueryJobData(socket, jobid) { const result = await client .setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` }) .request(queries.QUERY_JOBS_FOR_CDK_EXPORT, { id: jobid }); - CdkBase.createLogEvent(socket, "TRACE", `Job data query result ${JSON.stringify(result, null, 2)}`); + CdkBase.createLogEvent(socket, "DEBUG", `Job data query result ${JSON.stringify(result, null, 2)}`); return result.jobs_by_pk; } @@ -171,7 +171,7 @@ async function CalculateDmsVid(socket, JobData) { CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientVehicleInsertUpdate.getVehIdsAsync Result ${JSON.stringify(result, null, 2)}` ); CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate); @@ -214,7 +214,7 @@ async function QueryDmsVehicleById(socket, JobData, DMSVid) { CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientVehicleInsertUpdate.readAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientVehicleInsertUpdate.readAsync response.`); @@ -246,7 +246,7 @@ async function QueryDmsCustomerById(socket, JobData, CustomerId) { CdkBase.createXmlEvent(socket, rawResponse, `soapClientCustomerInsertUpdate.readAsync response.`); CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientCustomerInsertUpdate.readAsync Result ${JSON.stringify(result, null, 2)}` ); CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate); @@ -295,7 +295,7 @@ async function QueryDmsCustomerByName(socket, JobData) { CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientCustomerSearch.executeSearchBulkAsync Result ${JSON.stringify(result, null, 2)}` ); CheckCdkResponseForError(socket, soapResponseCustomerSearch); @@ -337,7 +337,7 @@ async function GenerateDmsCustomerNumber(socket) { CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientCustomerInsertUpdate.getCustomerNumberAsync Result ${JSON.stringify(result, null, 2)}` ); CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate); @@ -425,7 +425,7 @@ async function InsertDmsCustomer(socket, newCustomerNumber) { CdkBase.createXmlEvent(socket, rawResponse, `soapClientCustomerInsertUpdate.insertAsync response.`); CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientCustomerInsertUpdate.insertAsync Result ${JSON.stringify(result, null, 2)}` ); CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate); @@ -505,7 +505,7 @@ async function InsertDmsVehicle(socket) { CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientVehicleInsertUpdate.insertAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientVehicleInsertUpdate.insertAsync response.`); @@ -611,7 +611,7 @@ async function UpdateDmsVehicle(socket) { CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientVehicleInsertUpdate.updateAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientVehicleInsertUpdate.updateAsync response.`); @@ -650,7 +650,7 @@ async function InsertServiceVehicleHistory(socket) { CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientServiceHistoryInsert.serviceHistoryHeaderInsert Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientServiceHistoryInsert.serviceHistoryHeaderInsert response.`); @@ -690,7 +690,7 @@ async function InsertDmsStartWip(socket) { CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientAccountingGLInsertUpdate.doStartWIPAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doStartWIPAsync response.`); @@ -721,7 +721,7 @@ async function InsertDmsBatchWip(socket) { CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientAccountingGLInsertUpdate.doTransBatchWIPAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doTransBatchWIPAsync response.`); @@ -885,7 +885,7 @@ async function PostDmsBatchWip(socket) { CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync response.`); @@ -914,7 +914,7 @@ async function QueryDmsErrWip(socket) { CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientAccountingGLInsertUpdate.doErrWIPAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doErrWIPAsync response.`); @@ -945,7 +945,7 @@ async function DeleteDmsWip(socket) { CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync response.`); diff --git a/server/ioevent/ioevent.js b/server/ioevent/ioevent.js index 5d4223f73..914c15c54 100644 --- a/server/ioevent/ioevent.js +++ b/server/ioevent/ioevent.js @@ -35,7 +35,7 @@ exports.default = async (req, res) => { res.sendStatus(200); } catch (error) { - logger.log("ioevent-error", "trace", user, null, { + logger.log("ioevent-error", "debug", user, null, { operationname: operationName, time, dbevent, diff --git a/server/web-sockets/web-socket.js b/server/web-sockets/web-socket.js index 3140c2e87..bd6147d36 100644 --- a/server/web-sockets/web-socket.js +++ b/server/web-sockets/web-socket.js @@ -41,7 +41,7 @@ io.use(function (socket, next) { }); io.on("connection", (socket) => { - socket.log_level = "TRACE"; + socket.log_level = "DEBUG"; createLogEvent(socket, "DEBUG", `Connected and Authenticated.`); socket.on("set-log-level", (level) => { @@ -75,7 +75,7 @@ io.on("connection", (socket) => { socket.on("cdk-calculate-allocations", async (jobid, callback) => { const allocations = await CdkCalculateAllocations(socket, jobid); createLogEvent(socket, "DEBUG", `Allocations calculated.`); - createLogEvent(socket, "TRACE", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`); + createLogEvent(socket, "DEBUG", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`); callback(allocations); }); @@ -85,7 +85,7 @@ io.on("connection", (socket) => { socket.on("pbs-calculate-allocations", async (jobid, callback) => { const allocations = await CdkCalculateAllocations(socket, jobid); createLogEvent(socket, "DEBUG", `Allocations calculated.`); - createLogEvent(socket, "TRACE", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`); + createLogEvent(socket, "DEBUG", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`); callback(allocations); }); @@ -103,7 +103,7 @@ io.on("connection", (socket) => { socket.on("pbs-calculate-allocations-ap", async (billids, callback) => { const allocations = await PbsCalculateAllocationsAp(socket, billids); createLogEvent(socket, "DEBUG", `AP Allocations calculated.`); - createLogEvent(socket, "TRACE", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`); + createLogEvent(socket, "DEBUG", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`); socket.apAllocations = allocations; callback(allocations); }); @@ -122,7 +122,7 @@ io.on("connection", (socket) => { function createLogEvent(socket, level, message) { if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy(level)) { - // console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`); + // console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`); socket.emit("log-event", { timestamp: new Date(), level, @@ -173,17 +173,17 @@ function createJsonEvent(socket, level, message, json) { } function createXmlEvent(socket, xml, message, isError = false) { - if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy("TRACE")) { + if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy("DEBUG")) { socket.emit("log-event", { timestamp: new Date(), - level: isError ? "ERROR" : "TRACE", + level: isError ? "ERROR" : "DEBUG", message: `${message}: ${xml}` }); } logger.log( isError ? "ws-log-event-xml-error" : "ws-log-event-xml", - isError ? "ERROR" : "TRACE", + isError ? "ERROR" : "DEBUG", socket.user.email, socket.recordid, { @@ -195,7 +195,7 @@ function createXmlEvent(socket, xml, message, isError = false) { if (socket.logEvents && isArray(socket.logEvents)) { socket.logEvents.push({ timestamp: new Date(), - level: isError ? "ERROR" : "TRACE", + level: isError ? "ERROR" : "DEBUG", message, xml }); @@ -206,8 +206,6 @@ function LogLevelHierarchy(level) { switch (level) { case "XML": return 5; - case "TRACE": - return 5; case "DEBUG": return 4; case "INFO": From 79ed6f238854880d8d773d15ecc26418816e03fb Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 28 Oct 2024 12:24:40 -0700 Subject: [PATCH 54/79] release/2024-11-01 - Remove Trace Log Level Signed-off-by: Dave Richer --- .../dms-log-events.component.jsx | 2 ++ .../dms-payables/dms-payables.container.jsx | 1 + client/src/pages/dms/dms.container.jsx | 1 + server/accounting/pbs/pbs-ap-allocations.js | 6 ++--- server/accounting/pbs/pbs-job-export.js | 8 +++--- server/cdk/cdk-calculate-allocations.js | 2 +- server/cdk/cdk-job-export.js | 26 +++++++++---------- server/ioevent/ioevent.js | 2 +- server/web-sockets/web-socket.js | 16 +++++++----- 9 files changed, 35 insertions(+), 29 deletions(-) diff --git a/client/src/components/dms-log-events/dms-log-events.component.jsx b/client/src/components/dms-log-events/dms-log-events.component.jsx index 9391d8edb..c3e46a877 100644 --- a/client/src/components/dms-log-events/dms-log-events.component.jsx +++ b/client/src/components/dms-log-events/dms-log-events.component.jsx @@ -40,6 +40,8 @@ export function DmsLogEvents({ socket, logs, bodyshop }) { function LogLevelHierarchy(level) { switch (level) { + case "SILLY": + return "pink"; case "DEBUG": return "orange"; case "INFO": diff --git a/client/src/pages/dms-payables/dms-payables.container.jsx b/client/src/pages/dms-payables/dms-payables.container.jsx index 47659cd9b..e81597bed 100644 --- a/client/src/pages/dms-payables/dms-payables.container.jsx +++ b/client/src/pages/dms-payables/dms-payables.container.jsx @@ -123,6 +123,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { socket.emit("set-log-level", value); }} > + SILLY DEBUG INFO WARNING diff --git a/client/src/pages/dms/dms.container.jsx b/client/src/pages/dms/dms.container.jsx index 3f7569cbd..f05eae615 100644 --- a/client/src/pages/dms/dms.container.jsx +++ b/client/src/pages/dms/dms.container.jsx @@ -173,6 +173,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse socket.emit("set-log-level", value); }} > + SILLY DEBUG INFO WARNING diff --git a/server/accounting/pbs/pbs-ap-allocations.js b/server/accounting/pbs/pbs-ap-allocations.js index 49d11eaa0..a969e82c8 100644 --- a/server/accounting/pbs/pbs-ap-allocations.js +++ b/server/accounting/pbs/pbs-ap-allocations.js @@ -26,7 +26,7 @@ axios.interceptors.request.use((x) => { } | ${JSON.stringify(x.data)} | ${JSON.stringify(headers)}`; //console.log(printable); - CdkBase.createJsonEvent(socket, "DEBUG", `Raw Request: ${printable}`, x.data); + CdkBase.createJsonEvent(socket, "SILLY", `Raw Request: ${printable}`, x.data); return x; }); @@ -36,7 +36,7 @@ axios.interceptors.response.use((x) => { const printable = `${new Date()} | Response: ${x.status} | ${JSON.stringify(x.data)}`; //console.log(printable); - CdkBase.createJsonEvent(socket, "DEBUG", `Raw Response: ${printable}`, x.data); + CdkBase.createJsonEvent(socket, "SILLY", `Raw Response: ${printable}`, x.data); return x; }); @@ -181,7 +181,7 @@ async function QueryBillData(socket, billids) { const result = await client .setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` }) .request(queries.GET_PBS_AP_ALLOCATIONS, { billids: billids }); - CdkBase.createLogEvent(socket, "DEBUG", `Bill data query result ${JSON.stringify(result, null, 2)}`); + CdkBase.createLogEvent(socket, "SILLY", `Bill data query result ${JSON.stringify(result, null, 2)}`); return result; } diff --git a/server/accounting/pbs/pbs-job-export.js b/server/accounting/pbs/pbs-job-export.js index 9ea3e1f91..c2f6b96b7 100644 --- a/server/accounting/pbs/pbs-job-export.js +++ b/server/accounting/pbs/pbs-job-export.js @@ -28,7 +28,7 @@ axios.interceptors.request.use((x) => { } | ${JSON.stringify(x.data)} | ${JSON.stringify(headers)}`; //console.log(printable); - CdkBase.createJsonEvent(socket, "DEBUG", `Raw Request: ${printable}`, x.data); + CdkBase.createJsonEvent(socket, "SILLY", `Raw Request: ${printable}`, x.data); return x; }); @@ -38,7 +38,7 @@ axios.interceptors.response.use((x) => { const printable = `${new Date()} | Response: ${x.status} | ${JSON.stringify(x.data)}`; //console.log(printable); - CdkBase.createJsonEvent(socket, "DEBUG", `Raw Response: ${printable}`, x.data); + CdkBase.createJsonEvent(socket, "SILLY", `Raw Response: ${printable}`, x.data); return x; }); @@ -118,7 +118,7 @@ async function CheckForErrors(socket, response) { CdkBase.createLogEvent(socket, "DEBUG", `Successful response from DMS. ${response.Message || ""}`); } else { CdkBase.createLogEvent(socket, "ERROR", `Error received from DMS: ${response.Message}`); - CdkBase.createLogEvent(socket, "DEBUG", `Error received from DMS: ${JSON.stringify(response)}`); + CdkBase.createLogEvent(socket, "SILLY", `Error received from DMS: ${JSON.stringify(response)}`); } } @@ -130,7 +130,7 @@ async function QueryJobData(socket, jobid) { const result = await client .setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` }) .request(queries.QUERY_JOBS_FOR_PBS_EXPORT, { id: jobid }); - CdkBase.createLogEvent(socket, "DEBUG", `Job data query result ${JSON.stringify(result, null, 2)}`); + CdkBase.createLogEvent(socket, "SILLY", `Job data query result ${JSON.stringify(result, null, 2)}`); return result.jobs_by_pk; } diff --git a/server/cdk/cdk-calculate-allocations.js b/server/cdk/cdk-calculate-allocations.js index 82610dcb3..f78c48b91 100644 --- a/server/cdk/cdk-calculate-allocations.js +++ b/server/cdk/cdk-calculate-allocations.js @@ -42,7 +42,7 @@ async function QueryJobData(connectionData, token, jobid) { CdkBase.createLogEvent(connectionData, "DEBUG", `Querying job data for id ${jobid}`); const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {}); const result = await client.setHeaders({ Authorization: token }).request(queries.GET_CDK_ALLOCATIONS, { id: jobid }); - CdkBase.createLogEvent(connectionData, "DEBUG", `Job data query result ${JSON.stringify(result, null, 2)}`); + CdkBase.createLogEvent(connectionData, "SILLY", `Job data query result ${JSON.stringify(result, null, 2)}`); return result.jobs_by_pk; } diff --git a/server/cdk/cdk-job-export.js b/server/cdk/cdk-job-export.js index ec7d355b5..7fedbc608 100644 --- a/server/cdk/cdk-job-export.js +++ b/server/cdk/cdk-job-export.js @@ -151,7 +151,7 @@ async function QueryJobData(socket, jobid) { const result = await client .setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` }) .request(queries.QUERY_JOBS_FOR_CDK_EXPORT, { id: jobid }); - CdkBase.createLogEvent(socket, "DEBUG", `Job data query result ${JSON.stringify(result, null, 2)}`); + CdkBase.createLogEvent(socket, "SILLY", `Job data query result ${JSON.stringify(result, null, 2)}`); return result.jobs_by_pk; } @@ -171,7 +171,7 @@ async function CalculateDmsVid(socket, JobData) { CdkBase.createLogEvent( socket, - "DEBUG", + "SILLY", `soapClientVehicleInsertUpdate.getVehIdsAsync Result ${JSON.stringify(result, null, 2)}` ); CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate); @@ -214,7 +214,7 @@ async function QueryDmsVehicleById(socket, JobData, DMSVid) { CdkBase.createLogEvent( socket, - "DEBUG", + "SILLY", `soapClientVehicleInsertUpdate.readAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientVehicleInsertUpdate.readAsync response.`); @@ -246,7 +246,7 @@ async function QueryDmsCustomerById(socket, JobData, CustomerId) { CdkBase.createXmlEvent(socket, rawResponse, `soapClientCustomerInsertUpdate.readAsync response.`); CdkBase.createLogEvent( socket, - "DEBUG", + "SILLY", `soapClientCustomerInsertUpdate.readAsync Result ${JSON.stringify(result, null, 2)}` ); CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate); @@ -295,7 +295,7 @@ async function QueryDmsCustomerByName(socket, JobData) { CdkBase.createLogEvent( socket, - "DEBUG", + "SILLY", `soapClientCustomerSearch.executeSearchBulkAsync Result ${JSON.stringify(result, null, 2)}` ); CheckCdkResponseForError(socket, soapResponseCustomerSearch); @@ -337,7 +337,7 @@ async function GenerateDmsCustomerNumber(socket) { CdkBase.createLogEvent( socket, - "DEBUG", + "SILLY", `soapClientCustomerInsertUpdate.getCustomerNumberAsync Result ${JSON.stringify(result, null, 2)}` ); CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate); @@ -425,7 +425,7 @@ async function InsertDmsCustomer(socket, newCustomerNumber) { CdkBase.createXmlEvent(socket, rawResponse, `soapClientCustomerInsertUpdate.insertAsync response.`); CdkBase.createLogEvent( socket, - "DEBUG", + "SILLY", `soapClientCustomerInsertUpdate.insertAsync Result ${JSON.stringify(result, null, 2)}` ); CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate); @@ -505,7 +505,7 @@ async function InsertDmsVehicle(socket) { CdkBase.createLogEvent( socket, - "DEBUG", + "SILLY", `soapClientVehicleInsertUpdate.insertAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientVehicleInsertUpdate.insertAsync response.`); @@ -650,7 +650,7 @@ async function InsertServiceVehicleHistory(socket) { CdkBase.createLogEvent( socket, - "DEBUG", + "SILLY", `soapClientServiceHistoryInsert.serviceHistoryHeaderInsert Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientServiceHistoryInsert.serviceHistoryHeaderInsert response.`); @@ -690,7 +690,7 @@ async function InsertDmsStartWip(socket) { CdkBase.createLogEvent( socket, - "DEBUG", + "SILLY", `soapClientAccountingGLInsertUpdate.doStartWIPAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doStartWIPAsync response.`); @@ -721,7 +721,7 @@ async function InsertDmsBatchWip(socket) { CdkBase.createLogEvent( socket, - "DEBUG", + "SILLY", `soapClientAccountingGLInsertUpdate.doTransBatchWIPAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doTransBatchWIPAsync response.`); @@ -885,7 +885,7 @@ async function PostDmsBatchWip(socket) { CdkBase.createLogEvent( socket, - "DEBUG", + "SILLY", `soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync response.`); @@ -945,7 +945,7 @@ async function DeleteDmsWip(socket) { CdkBase.createLogEvent( socket, - "DEBUG", + "SILLY", `soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync Result ${JSON.stringify(result, null, 2)}` ); CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync response.`); diff --git a/server/ioevent/ioevent.js b/server/ioevent/ioevent.js index 914c15c54..6ca37f27e 100644 --- a/server/ioevent/ioevent.js +++ b/server/ioevent/ioevent.js @@ -35,7 +35,7 @@ exports.default = async (req, res) => { res.sendStatus(200); } catch (error) { - logger.log("ioevent-error", "debug", user, null, { + logger.log("ioevent-error", "silly", user, null, { operationname: operationName, time, dbevent, diff --git a/server/web-sockets/web-socket.js b/server/web-sockets/web-socket.js index bd6147d36..6b14503d8 100644 --- a/server/web-sockets/web-socket.js +++ b/server/web-sockets/web-socket.js @@ -41,7 +41,7 @@ io.use(function (socket, next) { }); io.on("connection", (socket) => { - socket.log_level = "DEBUG"; + socket.log_level = "SILLY"; createLogEvent(socket, "DEBUG", `Connected and Authenticated.`); socket.on("set-log-level", (level) => { @@ -75,7 +75,7 @@ io.on("connection", (socket) => { socket.on("cdk-calculate-allocations", async (jobid, callback) => { const allocations = await CdkCalculateAllocations(socket, jobid); createLogEvent(socket, "DEBUG", `Allocations calculated.`); - createLogEvent(socket, "DEBUG", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`); + createLogEvent(socket, "SILLY", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`); callback(allocations); }); @@ -85,7 +85,7 @@ io.on("connection", (socket) => { socket.on("pbs-calculate-allocations", async (jobid, callback) => { const allocations = await CdkCalculateAllocations(socket, jobid); createLogEvent(socket, "DEBUG", `Allocations calculated.`); - createLogEvent(socket, "DEBUG", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`); + createLogEvent(socket, "SILLY", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`); callback(allocations); }); @@ -173,17 +173,17 @@ function createJsonEvent(socket, level, message, json) { } function createXmlEvent(socket, xml, message, isError = false) { - if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy("DEBUG")) { + if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy("SILLY")) { socket.emit("log-event", { timestamp: new Date(), - level: isError ? "ERROR" : "DEBUG", + level: isError ? "ERROR" : "SILLY", message: `${message}: ${xml}` }); } logger.log( isError ? "ws-log-event-xml-error" : "ws-log-event-xml", - isError ? "ERROR" : "DEBUG", + isError ? "ERROR" : "SILLY", socket.user.email, socket.recordid, { @@ -195,7 +195,7 @@ function createXmlEvent(socket, xml, message, isError = false) { if (socket.logEvents && isArray(socket.logEvents)) { socket.logEvents.push({ timestamp: new Date(), - level: isError ? "ERROR" : "DEBUG", + level: isError ? "ERROR" : "SILLY", message, xml }); @@ -206,6 +206,8 @@ function LogLevelHierarchy(level) { switch (level) { case "XML": return 5; + case "SILLY": + return 5; case "DEBUG": return 4; case "INFO": From b9ebb70b7a966c8f26948e68f0294f4919990503 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 28 Oct 2024 13:06:47 -0700 Subject: [PATCH 55/79] release/2024-11-01 - Remove Trace Log Level Signed-off-by: Dave Richer --- .../src/components/dms-log-events/dms-log-events.component.jsx | 2 -- client/src/pages/dms-payables/dms-payables.container.jsx | 1 - client/src/pages/dms/dms.container.jsx | 1 - server/web-sockets/web-socket.js | 2 +- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/client/src/components/dms-log-events/dms-log-events.component.jsx b/client/src/components/dms-log-events/dms-log-events.component.jsx index c3e46a877..9391d8edb 100644 --- a/client/src/components/dms-log-events/dms-log-events.component.jsx +++ b/client/src/components/dms-log-events/dms-log-events.component.jsx @@ -40,8 +40,6 @@ export function DmsLogEvents({ socket, logs, bodyshop }) { function LogLevelHierarchy(level) { switch (level) { - case "SILLY": - return "pink"; case "DEBUG": return "orange"; case "INFO": diff --git a/client/src/pages/dms-payables/dms-payables.container.jsx b/client/src/pages/dms-payables/dms-payables.container.jsx index e81597bed..47659cd9b 100644 --- a/client/src/pages/dms-payables/dms-payables.container.jsx +++ b/client/src/pages/dms-payables/dms-payables.container.jsx @@ -123,7 +123,6 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { socket.emit("set-log-level", value); }} > - SILLY DEBUG INFO WARNING diff --git a/client/src/pages/dms/dms.container.jsx b/client/src/pages/dms/dms.container.jsx index f05eae615..3f7569cbd 100644 --- a/client/src/pages/dms/dms.container.jsx +++ b/client/src/pages/dms/dms.container.jsx @@ -173,7 +173,6 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse socket.emit("set-log-level", value); }} > - SILLY DEBUG INFO WARNING diff --git a/server/web-sockets/web-socket.js b/server/web-sockets/web-socket.js index 6b14503d8..a56f6cff6 100644 --- a/server/web-sockets/web-socket.js +++ b/server/web-sockets/web-socket.js @@ -41,7 +41,7 @@ io.use(function (socket, next) { }); io.on("connection", (socket) => { - socket.log_level = "SILLY"; + socket.log_level = "DEBUG"; createLogEvent(socket, "DEBUG", `Connected and Authenticated.`); socket.on("set-log-level", (level) => { From 971a81fc272c44f9c43c119eeb4df848c0233edc Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 28 Oct 2024 14:04:14 -0700 Subject: [PATCH 56/79] feature/IO-2979-DST - Finish DST Stuff Signed-off-by: Dave Richer --- .../form-date-time-picker.component.jsx | 26 ++++++++++++++++--- .../schedule-calendar-wrapper/localizer.js | 18 +++---------- .../scheduler-calendar-wrapper.component.jsx | 5 ++-- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx b/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx index e34ae14f7..707dfbdf8 100644 --- a/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx +++ b/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx @@ -4,19 +4,37 @@ import React, { useCallback, useState } from "react"; import { useTranslation } from "react-i18next"; import dayjs from "../../utils/day"; import { fuzzyMatchDate } from "./formats.js"; +import { createStructuredSelector } from "reselect"; +import { selectBodyshop } from "../../redux/user/user.selectors.js"; +import { connect } from "react-redux"; -const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, onlyToday, isDateOnly = false, ...restProps }) => { +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop +}); + +const DateTimePicker = ({ + value, + onChange, + onBlur, + id, + onlyFuture, + onlyToday, + isDateOnly = false, + bodyshop, + ...restProps +}) => { const [isManualInput, setIsManualInput] = useState(false); const { t } = useTranslation(); const handleChange = useCallback( (newDate) => { + if (!newDate) return; if (onChange) { - onChange(newDate || null); + onChange(bodyshop?.timezone ? dayjs(newDate).tz(bodyshop.timezone, true) : newDate); } setIsManualInput(false); }, - [onChange] + [onChange, bodyshop?.timezone] ); const handleBlur = useCallback( @@ -102,4 +120,4 @@ DateTimePicker.propTypes = { isDateOnly: PropTypes.bool }; -export default React.memo(DateTimePicker); +export default connect(mapStateToProps, null)(DateTimePicker); diff --git a/client/src/components/schedule-calendar-wrapper/localizer.js b/client/src/components/schedule-calendar-wrapper/localizer.js index 871511ce2..9935252b4 100644 --- a/client/src/components/schedule-calendar-wrapper/localizer.js +++ b/client/src/components/schedule-calendar-wrapper/localizer.js @@ -119,19 +119,7 @@ var formats = { agendaTimeRangeFormat: timeRangeFormat }; -const localizer = (dayjsLib, timezone) => { - // load dayjs plugins - dayjsLib.extend(isBetween); - dayjsLib.extend(isSameOrAfter); - dayjsLib.extend(isSameOrBefore); - dayjsLib.extend(localeData); - dayjsLib.extend(localizedFormat); - dayjsLib.extend(minMax); - dayjsLib.extend(utc); - - dayjsLib.locale("en"); - dayjsLib.tz.setDefault(timezone); - +const localizer = (dayjsLib) => { var locale = function locale(dj, c) { return c ? dj.locale(c) : dj; }; @@ -140,9 +128,9 @@ const localizer = (dayjsLib, timezone) => { // then use the timezone aware version //TODO This was the issue entirely... - var dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib; + // var dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib; - // var dayjs = dayjsLib; + var dayjs = dayjsLib; function getTimezoneOffset(date) { // ensures this gets cast to timezone diff --git a/client/src/components/schedule-calendar-wrapper/scheduler-calendar-wrapper.component.jsx b/client/src/components/schedule-calendar-wrapper/scheduler-calendar-wrapper.component.jsx index 1d9e14eb9..4d6f8fe78 100644 --- a/client/src/components/schedule-calendar-wrapper/scheduler-calendar-wrapper.component.jsx +++ b/client/src/components/schedule-calendar-wrapper/scheduler-calendar-wrapper.component.jsx @@ -1,7 +1,7 @@ import dayjs from "../../utils/day"; import queryString from "query-string"; import React from "react"; -import { Calendar, dayjsLocalizer } from "react-big-calendar"; +import { Calendar } from "react-big-calendar"; import { connect } from "react-redux"; import { Link, useLocation, useNavigate } from "react-router-dom"; import { createStructuredSelector } from "reselect"; @@ -14,13 +14,14 @@ import { selectProblemJobs } from "../../redux/application/application.selectors import { Alert, Collapse, Space } from "antd"; import { Trans, useTranslation } from "react-i18next"; import InstanceRenderManager from "../../utils/instanceRenderMgr"; +import local from "./localizer"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, problemJobs: selectProblemJobs }); -const localizer = dayjsLocalizer(dayjs); +const localizer = local(dayjs); export function ScheduleCalendarWrapperComponent({ bodyshop, From d75ea2b1a6ffcabe85ef5c5db101a9b4f1ca516a Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 28 Oct 2024 17:38:46 -0700 Subject: [PATCH 57/79] release/2024-11-01 - Misc fixes Signed-off-by: Dave Richer --- .../components/header/header.component.jsx | 21 ++++++++----------- server/accounting/qbo/qbo-payables.js | 2 +- server/web-sockets/redisSocketEvents.js | 2 +- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx index c00aa33e5..341e19ba0 100644 --- a/client/src/components/header/header.component.jsx +++ b/client/src/components/header/header.component.jsx @@ -116,18 +116,15 @@ function Header({ const { t } = useTranslation(); - const deleteBetaCookie = () => { - const cookieExists = document.cookie.split("; ").some((row) => row.startsWith(`betaSwitchImex=`)); - if (cookieExists) { - const domain = window.location.hostname.split(".").slice(-2).join("."); - document.cookie = `betaSwitchImex=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`; - console.log(`betaSwitchImex cookie deleted`); - } else { - console.log(`betaSwitchImex cookie does not exist`); - } - }; - - deleteBetaCookie(); + // const deleteBetaCookie = () => { + // const cookieExists = document.cookie.split("; ").some((row) => row.startsWith(`betaSwitchImex=`)); + // if (cookieExists) { + // const domain = window.location.hostname.split(".").slice(-2).join("."); + // document.cookie = `betaSwitchImex=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`; + // } + // }; + // + // deleteBetaCookie(); const accountingChildren = []; diff --git a/server/accounting/qbo/qbo-payables.js b/server/accounting/qbo/qbo-payables.js index 9b5cf2558..de0c8ad4a 100644 --- a/server/accounting/qbo/qbo-payables.js +++ b/server/accounting/qbo/qbo-payables.js @@ -45,7 +45,7 @@ exports.default = async (req, res) => { const BearerToken = req.BearerToken; const client = req.userGraphQLClient; - logger.log("qbo-payable-create", "DEBUG", req.user.email, billsToQuery); + logger.log("qbo-payable-create", "DEBUG", req.user.email, null, { billsToQuery }); const result = await client .setHeaders({ Authorization: BearerToken }) diff --git a/server/web-sockets/redisSocketEvents.js b/server/web-sockets/redisSocketEvents.js index 0e8a3a449..25e101013 100644 --- a/server/web-sockets/redisSocketEvents.js +++ b/server/web-sockets/redisSocketEvents.js @@ -80,7 +80,7 @@ const redisSocketEvents = ({ try { const room = getBodyshopRoom(bodyshopUUID); socket.join(room); - createLogEvent(socket, "debug", `Client joined bodyshop room: ${room}`); + // createLogEvent(socket, "debug", `Client joined bodyshop room: ${room}`); } catch (error) { createLogEvent(socket, "error", `Error joining room: ${error}`); } From c1331956070c7685a90d2033786ef275bb71fb96 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 28 Oct 2024 17:48:43 -0700 Subject: [PATCH 58/79] release/2024-11-01 - Misc fixes Signed-off-by: Dave Richer --- server/accounting/qbo/qbo-payables.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/accounting/qbo/qbo-payables.js b/server/accounting/qbo/qbo-payables.js index de0c8ad4a..c6e935060 100644 --- a/server/accounting/qbo/qbo-payables.js +++ b/server/accounting/qbo/qbo-payables.js @@ -122,7 +122,7 @@ exports.default = async (req, res) => { res.status(200).json(ret); } catch (error) { //console.log(error); - logger.log("qbo-payable-create-error", "ERROR", req.user.email, { + logger.log("qbo-payable-create-error", "ERROR", req.user.email, null, { error: error.message, stack: error.stack }); From 96e970faf71db79659111445e8c15c3533873d0e Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 28 Oct 2024 18:16:48 -0700 Subject: [PATCH 59/79] release/2024-11-01 - Misc fixes Signed-off-by: Dave Richer --- server/accounting/qbo/qbo-payables.js | 6 ++++++ server/accounting/qbo/qbo-payments.js | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/server/accounting/qbo/qbo-payables.js b/server/accounting/qbo/qbo-payables.js index c6e935060..196520de0 100644 --- a/server/accounting/qbo/qbo-payables.js +++ b/server/accounting/qbo/qbo-payables.js @@ -91,6 +91,12 @@ exports.default = async (req, res) => { ret.push({ billid: bill.id, success: true }); } catch (error) { + logger.log("qbo-paybles-create-error", "ERROR", req.user.email, null, { + error: + (error && error.authResponse && error.authResponse.body) || + error.response?.data?.Fault?.Error.map((e) => e.Detail).join(", ") || + (error && error.message) + }); ret.push({ billid: bill.id, success: false, diff --git a/server/accounting/qbo/qbo-payments.js b/server/accounting/qbo/qbo-payments.js index b5d884f02..6426bfa4f 100644 --- a/server/accounting/qbo/qbo-payments.js +++ b/server/accounting/qbo/qbo-payments.js @@ -49,7 +49,7 @@ exports.default = async (req, res) => { const BearerToken = req.BearerToken; const client = req.userGraphQLClient; - logger.log("qbo-payment-create", "DEBUG", req.user.email, paymentsToQuery); + logger.log("qbo-payment-create", "DEBUG", req.user.email, null, { paymentsToQuery }); const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_PAYMENTS_FOR_EXPORT, { payments: paymentsToQuery @@ -152,7 +152,7 @@ exports.default = async (req, res) => { ret.push({ paymentid: payment.id, success: true }); } catch (error) { - logger.log("qbo-payment-create-error", "ERROR", req.user.email, { + logger.log("qbo-payment-create-error", "ERROR", req.user.email, null, { error: (error && error.authResponse && error.authResponse.body) || (error && error.message) }); //Add the export log error. @@ -183,7 +183,7 @@ exports.default = async (req, res) => { res.status(200).json(ret); } catch (error) { //console.log(error); - logger.log("qbo-payment-create-error", "ERROR", req.user.email, { + logger.log("qbo-payment-create-error", "ERROR", req.user.email, null, { error: error.message, stack: error.stack }); From fc3ea2bdf8c97d80645ded1c9ec6dcd0ce007f25 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Tue, 29 Oct 2024 07:37:40 -0700 Subject: [PATCH 60/79] release/2024-11-01 - Misc fixes Signed-off-by: Dave Richer --- server/accounting/qb-receivables-lines.js | 2 +- server/accounting/qbxml/qbxml-payables.js | 7 ++++--- server/accounting/qbxml/qbxml-payments.js | 7 +++++-- server/accounting/qbxml/qbxml-receivables.js | 7 +++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/server/accounting/qb-receivables-lines.js b/server/accounting/qb-receivables-lines.js index 8476ce6d4..043dc8e89 100644 --- a/server/accounting/qb-receivables-lines.js +++ b/server/accounting/qb-receivables-lines.js @@ -63,7 +63,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes ); if (!account) { - logger.log("qbxml-receivables-no-account", "warn", null, jobline.id, null); + logger.log("qbxml-receivables-no-account", "warn", null, jobline.id); throw new Error( `A matching account does not exist for the part allocation. Center: ${jobline.profitcenter_part}` ); diff --git a/server/accounting/qbxml/qbxml-payables.js b/server/accounting/qbxml/qbxml-payables.js index 9ffe4513f..ef588e0fb 100644 --- a/server/accounting/qbxml/qbxml-payables.js +++ b/server/accounting/qbxml/qbxml-payables.js @@ -42,9 +42,10 @@ exports.default = async (req, res) => { //For each invoice. res.status(200).json(QbXmlToExecute); } catch (error) { - logger.log("qbxml-payable-error", "ERROR", req.user.email, req.body.billsToQuery, { - error: error.message, - stack: error.stack + logger.log("qbxml-payable-error", "ERROR", req?.user?.email, null, { + billsToQuery: req?.body?.billsToQuery, + error: error?.message, + stack: error?.stack }); res.status(400).send(JSON.stringify(error)); } diff --git a/server/accounting/qbxml/qbxml-payments.js b/server/accounting/qbxml/qbxml-payments.js index cdc08d2e4..68e7b8778 100644 --- a/server/accounting/qbxml/qbxml-payments.js +++ b/server/accounting/qbxml/qbxml-payments.js @@ -21,7 +21,9 @@ exports.default = async (req, res) => { const client = req.userGraphQLClient; try { - logger.log("qbxml-payments-create", "DEBUG", req.user.email, req.body.paymentsToQuery, null); + logger.log("qbxml-payments-create", "DEBUG", req?.user?.email, null, { + paymentsToQuery: req.body?.paymentsToQuery + }); const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_PAYMENTS_FOR_EXPORT, { payments: paymentsToQuery @@ -62,7 +64,8 @@ exports.default = async (req, res) => { res.status(200).json(QbXmlToExecute); } catch (error) { - logger.log("qbxml-payments-error", "error", req.user.email, req.body.paymentsToQuery, { + logger.log("qbxml-payments-error", "error", req?.user?.email, null, { + paymentsToQuery: req.body?.paymentsToQuery, error: error.message, stack: error.stack }); diff --git a/server/accounting/qbxml/qbxml-receivables.js b/server/accounting/qbxml/qbxml-receivables.js index 0e8a4f20d..c4353704e 100644 --- a/server/accounting/qbxml/qbxml-receivables.js +++ b/server/accounting/qbxml/qbxml-receivables.js @@ -23,7 +23,9 @@ exports.default = async (req, res) => { const client = req.userGraphQLClient; try { - logger.log("qbxml-receivables-create", "DEBUG", req.user.email, req.body.jobIds, null); + logger.log("qbxml-receivables-create", "DEBUG", req?.user?.email, null, { + jobIds: req?.body?.jobIds + }); const result = await client .setHeaders({ Authorization: BearerToken }) @@ -74,7 +76,8 @@ exports.default = async (req, res) => { res.status(200).json(QbXmlToExecute); } catch (error) { - logger.log("qbxml-receivables-error", "error", req.user.email, req.body.jobIds, { + logger.log("qbxml-receivables-error", "error", req?.user?.email, null, { + jobIds: req.body?.jobIds, error: error.message, stack: error.stack }); From 23f8f69bbeb38111951b8ee87e3e6ac7835e2c18 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Tue, 29 Oct 2024 08:19:58 -0700 Subject: [PATCH 61/79] release/2024-11-01 - Misc fixes Signed-off-by: Dave Richer --- server/email/mailer.js | 3 ++- server/utils/logger.js | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/server/email/mailer.js b/server/email/mailer.js index 6503e1f8c..654f56cb3 100644 --- a/server/email/mailer.js +++ b/server/email/mailer.js @@ -3,6 +3,7 @@ const { defaultProvider } = require("@aws-sdk/credential-provider-node"); const { default: InstanceManager } = require("../utils/instanceMgr"); const aws = require("@aws-sdk/client-ses"); const nodemailer = require("nodemailer"); +const logger = require("../utils/logger"); const isLocal = isString(process.env?.LOCALSTACK_HOSTNAME) && !isEmpty(process.env?.LOCALSTACK_HOSTNAME); @@ -19,7 +20,7 @@ const sesConfig = { if (isLocal) { sesConfig.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`; - console.log(`SES Mailer set to LocalStack end point: ${sesConfig.endpoint}`); + logger.logger.debug(`SES Mailer set to LocalStack end point: ${sesConfig.endpoint}`); } const ses = new aws.SES(sesConfig); diff --git a/server/utils/logger.js b/server/utils/logger.js index 75d282fa2..b1e96e02d 100644 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -8,7 +8,7 @@ const InstanceManager = require("../utils/instanceMgr").default; const winston = require("winston"); const WinstonCloudWatch = require("winston-cloudwatch"); const { isString, isEmpty } = require("lodash"); -const { networkInterfaces } = require("node:os"); +const { networkInterfaces, hostname } = require("node:os"); const createLogger = () => { try { @@ -28,9 +28,6 @@ const createLogger = () => { if (isLocal) { winstonCloudwatchTransportDefaults.awsOptions.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`; - console.log( - `Winston Transports set to LocalStack end point: ${winstonCloudwatchTransportDefaults.awsOptions.endpoint}` - ); } const levelFilter = (levels) => { @@ -43,19 +40,22 @@ const createLogger = () => { })(); }; - const getPrivateIP = () => { + const getHostNameOrIP = () => { + // Try to get the hostname first + const hostName = hostname(); + if (hostName) return hostName; + const interfaces = networkInterfaces(); for (const name of Object.keys(interfaces)) { for (const iface of interfaces[name]) { - // Find an IPv4 address that's not internal (like localhost) if (iface.family === "IPv4" && !iface.internal) { return iface.address; } } } + return "127.0.0.1"; }; - const createProductionTransport = (level, logStreamName, filters) => { return new WinstonCloudWatch({ level, @@ -65,7 +65,7 @@ const createLogger = () => { }); }; - const hostname = process.env.HOSTNAME || getPrivateIP(); + const hostname = process.env.HOSTNAME || getHostNameOrIP(); const getDevelopmentTransports = () => [ new winston.transports.Console({ @@ -106,6 +106,12 @@ const createLogger = () => { : [...getDevelopmentTransports(), ...getProductionTransports()] }); + if (isLocal) { + winstonLogger.debug( + `CloudWatch set to LocalStack end point: ${winstonCloudwatchTransportDefaults.awsOptions.endpoint}` + ); + } + const log = (message, type, user, record, meta) => { winstonLogger.log({ level: type.toLowerCase(), From 63b914731b781e07d86bd7598715d17dc02d2e39 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Tue, 29 Oct 2024 08:25:54 -0700 Subject: [PATCH 62/79] release/2024-11-01 - Misc fixes Signed-off-by: Dave Richer --- server/utils/logger.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/utils/logger.js b/server/utils/logger.js index b1e96e02d..26dd72150 100644 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -65,7 +65,7 @@ const createLogger = () => { }); }; - const hostname = process.env.HOSTNAME || getHostNameOrIP(); + const internalHostname = process.env.HOSTNAME || getHostNameOrIP(); const getDevelopmentTransports = () => [ new winston.transports.Console({ @@ -74,7 +74,7 @@ const createLogger = () => { winston.format.colorize(), winston.format.timestamp(), winston.format.printf(({ level, message, timestamp, user, record, meta }) => { - const hostnameColor = `\x1b[34m${hostname}\x1b[0m`; // Blue + const hostnameColor = `\x1b[34m${internalHostname}\x1b[0m`; // Blue const timestampColor = `\x1b[36m${timestamp}\x1b[0m`; // Cyan const labelColor = "\x1b[33m"; // Yellow const separatorColor = "\x1b[35m|\x1b[0m"; // Magenta for separators @@ -118,7 +118,7 @@ const createLogger = () => { message, user, record, - hostname, + hostname: internalHostname, meta }); }; From 3f247a9227ecdfedbae4cf53a69413dcdd8fc5f4 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Tue, 29 Oct 2024 09:54:45 -0700 Subject: [PATCH 63/79] release/2024-11-01 - Misc fixes Signed-off-by: Dave Richer --- server/job/job-updated.js | 2 +- server/mixdata/mixdata.js | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/server/job/job-updated.js b/server/job/job-updated.js index f218f83bc..606e6682c 100644 --- a/server/job/job-updated.js +++ b/server/job/job-updated.js @@ -15,7 +15,7 @@ const jobUpdated = async (req, res) => { }); } - logger.log("job-update", "INFO", req.user?.email, null, { + logger.log("job-update", "DEBUG", req.user?.email, null, { message: `Job updated event received from Hasura`, jobid: req?.body?.event?.data?.new?.id }); diff --git a/server/mixdata/mixdata.js b/server/mixdata/mixdata.js index 0dca3705b..d61989103 100644 --- a/server/mixdata/mixdata.js +++ b/server/mixdata/mixdata.js @@ -9,11 +9,9 @@ require("dotenv").config({ }); exports.mixdataUpload = async (req, res) => { - const { bodyshopid } = req.body; - const client = req.userGraphQLClient; - logger.log("job-mixdata-upload", "DEBUG", req.user.email, null, null); + logger.log("job-mixdata-upload", "DEBUG", req?.user?.email, null, null); try { for (const element of req.files) { @@ -23,7 +21,7 @@ exports.mixdataUpload = async (req, res) => { explicitArray: false }); - logger.log("job-mixdata-parse", "DEBUG", req.user.email, inboundRequest); + logger.log("job-mixdata-parse", "DEBUG", req?.user?.email, null, { inboundRequest }); const ScaleType = DetermineScaleType(inboundRequest); const RoNumbersFromInboundRequest = GetListOfRos(inboundRequest, ScaleType); @@ -70,7 +68,7 @@ function DetermineScaleType(inboundRequest) { const ret = { type: "", verson: 0 }; //PPG Mix Data - if (inboundRequest.PPG && inboundRequest.PPG.Header.Protocol.Name === "PPG") { + if (inboundRequest?.PPG?.Header?.Protocol?.Name === "PPG") { return { type: inboundRequest.PPG.Header.Protocol.Name, company: "PPG", @@ -80,13 +78,13 @@ function DetermineScaleType(inboundRequest) { } function GetListOfRos(inboundRequest, ScaleType) { - if (ScaleType.company === "PPG" && ScaleType.version === "1.3.0") { + if (ScaleType?.company === "PPG" && ScaleType?.version === "1.3.0") { return inboundRequest.PPG.MixDataInterface.ROData.RepairOrders.RO.map((r) => r.RONumber); } } function GenerateMixDataArray(inboundRequest, ScaleType, jobHash) { - if (ScaleType.company === "PPG" && ScaleType.version === "1.3.0") { + if (ScaleType?.company === "PPG" && ScaleType?.version === "1.3.0") { return inboundRequest.PPG.MixDataInterface.ROData.RepairOrders.RO.map((r) => { return { jobid: jobHash[r.RONumber]?.jobid, From 42f1d6fa1370880e520d3351bd3a5496dcf728e5 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Tue, 29 Oct 2024 10:53:09 -0700 Subject: [PATCH 64/79] release/2024-11-01 - Misc fixes Signed-off-by: Dave Richer --- server/cdk/cdk-get-makes.js | 3 +- server/email/sendemail.js | 35 ++++++------ server/email/tasksEmails.js | 4 +- server/email/tasksEmailsQueue.js | 5 +- server/firebase/firebase-handler.js | 8 ++- server/job/job-costing.js | 55 +++++++++++++++---- server/job/job-totals-USA.js | 16 +++--- .../validateFirebaseIdTokenMiddleware.js | 18 +++--- server/payroll/pay-all.js | 6 +- server/scheduling/scheduling-job.js | 8 +-- server/stripe/payment.js | 2 +- server/tasks/tasks.js | 9 ++- 12 files changed, 108 insertions(+), 61 deletions(-) diff --git a/server/cdk/cdk-get-makes.js b/server/cdk/cdk-get-makes.js index 06ccc53e2..90accf64e 100644 --- a/server/cdk/cdk-get-makes.js +++ b/server/cdk/cdk-get-makes.js @@ -39,8 +39,8 @@ exports.default = async function ReloadCdkMakes(req, res) { const deleteResult = await client .setHeaders({ Authorization: BearerToken }) .request(queries.DELETE_ALL_DMS_VEHICLES, {}); - console.log("🚀 ~ file: cdk-get-makes.js ~ line 53 ~ deleteResult", deleteResult); + // logger.logger.debug("🚀 ~ file: cdk-get-makes.js ~ line 53 ~ deleteResult", { deleteResult }); //Insert the new ones. const insertResult = await client.setHeaders({ Authorization: BearerToken }).request(queries.INSERT_DMS_VEHICLES, { @@ -59,6 +59,7 @@ exports.default = async function ReloadCdkMakes(req, res) { cdk_dealerid, count: newList.length }); + res.sendStatus(200); } catch (error) { logger.log("cdk-replace-makes-models-error", "ERROR", req.user.email, null, { diff --git a/server/email/sendemail.js b/server/email/sendemail.js index 97e8f74ad..9d103ef81 100644 --- a/server/email/sendemail.js +++ b/server/email/sendemail.js @@ -21,7 +21,7 @@ const getImage = async (imageUrl) => { // Log the email in the database const logEmail = async (req, email) => { try { - const insertresult = await client.request(queries.INSERT_EMAIL_AUDIT, { + await client.request(queries.INSERT_EMAIL_AUDIT, { email: { to: email.to, cc: email.cc, @@ -34,13 +34,13 @@ const logEmail = async (req, email) => { status: "Sent" } }); - console.log(insertresult); } catch (error) { - logger.log("email-log-error", "error", req.user.email, null, { + logger.log("email-log-error", "error", req?.user?.email, null, { from: `${req.body.from.name} <${req.body.from.address}>`, - to: req.body.to, - cc: req.body.cc, - subject: req.body.subject + to: req?.body?.to, + cc: req?.body?.cc, + subject: req?.body?.subject, + email // info, }); } @@ -70,12 +70,11 @@ const sendServerEmail = async ({ subject, text }) => { } }, (err, info) => { - console.log(err || info); + logger.log("server-email-failure", err ? "error" : "debug", null, null, { message: err || info }); } ); } catch (error) { - console.log(error); - logger.log("server-email-failure", "error", null, null, error); + logger.log("server-email-failure", "error", null, null, { error }); } }; @@ -88,8 +87,7 @@ const sendProManagerWelcomeEmail = async ({ to, subject, html }) => { html }); } catch (error) { - console.log(error); - logger.log("server-email-failure", "error", null, null, error); + logger.log("server-email-failure", "error", null, null, { error }); } }; @@ -108,12 +106,12 @@ const sendTaskEmail = async ({ to, subject, type = "text", html, text, attachmen attachments: attachments || null }, (err, info) => { - console.log(err || info); + // (message, type, user, record, meta + logger.log("server-email", err ? "error" : "debug", null, null, { message: err || info }); } ); } catch (error) { - console.log(error); - logger.log("server-email-failure", "error", null, null, error); + logger.log("server-email-failure", "error", null, null, { error }); } }; @@ -184,9 +182,8 @@ const sendEmail = async (req, res) => { } }, (err, info) => { - console.log(err || info); if (info) { - logger.log("send-email-success", "DEBUG", req.user.email, null, { + logger.log("send-email-success", "DEBUG", req?.user?.email, null, { from: `${req.body.from.name} <${req.body.from.address}>`, replyTo: req.body.ReplyTo.Email, to: req.body.to, @@ -205,7 +202,7 @@ const sendEmail = async (req, res) => { success: true //response: info }); } else { - logger.log("send-email-failure", "ERROR", req.user.email, null, { + logger.log("send-email-failure", "ERROR", req?.user?.email, null, { from: `${req.body.from.name} <${req.body.from.address}>`, replyTo: req.body.ReplyTo.Email, to: req.body.to, @@ -290,7 +287,9 @@ ${body.bounce?.bouncedRecipients.map( ` }, (err, info) => { - console.log("***", err || info); + logger.log("sns-error", err ? "error" : "debug", "api", null, { + message: err ? JSON.stringify(error) : info + }); } ); } diff --git a/server/email/tasksEmails.js b/server/email/tasksEmails.js index ab25343e0..c05185b6b 100644 --- a/server/email/tasksEmails.js +++ b/server/email/tasksEmails.js @@ -18,10 +18,10 @@ const tasksEmailQueue = taskEmailQueue(); const tasksEmailQueueCleanup = async () => { try { // Example async operation - console.log("Performing Tasks Email Reminder process cleanup..."); + // console.log("Performing Tasks Email Reminder process cleanup..."); await new Promise((resolve) => tasksEmailQueue.destroy(() => resolve())); } catch (err) { - console.error("Tasks Email Reminder process cleanup failed:", err); + // console.error("Tasks Email Reminder process cleanup failed:", err); } }; diff --git a/server/email/tasksEmailsQueue.js b/server/email/tasksEmailsQueue.js index dc004abc1..c1828b858 100644 --- a/server/email/tasksEmailsQueue.js +++ b/server/email/tasksEmailsQueue.js @@ -10,8 +10,9 @@ const logger = require("../utils/logger"); const taskEmailQueue = () => new Queue( (taskIds, cb) => { - console.log("Processing reminds for taskIds: ", taskIds.join(", ")); - + logger.log("Processing reminds for taskIds: ", "silly", null, null, { + taskIds: taskIds?.join(", ") + }); // Set the remind_at_sent to the current time. const now = moment().toISOString(); diff --git a/server/firebase/firebase-handler.js b/server/firebase/firebase-handler.js index ec20114f9..e24c86174 100644 --- a/server/firebase/firebase-handler.js +++ b/server/firebase/firebase-handler.js @@ -269,10 +269,14 @@ const sendNotification = async (req, res) => { }) .then((response) => { // Response is a message ID string. - console.log("Successfully sent message:", response); + logger.log("Successfully sent message:", "debug", req?.user?.email, null, { + response + }); }) .catch((error) => { - console.log("Error sending message:", error); + logger.log("Successfully sent message:", "error", req?.user?.email, null, { + error + }); }); res.sendStatus(200); diff --git a/server/job/job-costing.js b/server/job/job-costing.js index 9ce65f71d..c0a3ee149 100644 --- a/server/job/job-costing.js +++ b/server/job/job-costing.js @@ -46,7 +46,9 @@ async function JobCostingMulti(req, res) { const BearerToken = req.BearerToken; const client = req.userGraphQLClient; - logger.log("job-costing-multi-start", "DEBUG", req.user.email, jobids, null); + logger.log("job-costing-multi-start", "DEBUG", req?.user?.email, null, { + jobids + }); try { const resp = await client @@ -244,7 +246,8 @@ async function JobCostingMulti(req, res) { data: ret }); } catch (error) { - logger.log("job-costing-multi-error", "ERROR", req.user.email, [jobids], { + logger.log("job-costing-multi-error", "ERROR", req?.user?.email, null, { + jobids, message: error.message, stack: error.stack }); @@ -282,7 +285,12 @@ function GenerateCostingData(job) { if (val.mod_lbr_ty) { const laborProfitCenter = val.profitcenter_labor || defaultProfits[val.mod_lbr_ty] || "Unknown"; - if (laborProfitCenter === "Unknown") console.log("Unknown type", val.line_desc, val.mod_lbr_ty); + if (laborProfitCenter === "Unknown") { + logger.log("job-costing unknown type", "debug", null, null, { + line_desc: val.line_desc, + mod_lbr_ty: val.mod_lbr_ty + }); + } const rateName = `rate_${(val.mod_lbr_ty || "").toLowerCase()}`; @@ -349,10 +357,21 @@ function GenerateCostingData(job) { if (val.part_type && val.part_type !== "PAE" && val.part_type !== "PAS" && val.part_type !== "PASL") { const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown"; - if (partsProfitCenter === "Unknown") console.log("Unknown type", val.line_desc, val.part_type); + if (partsProfitCenter === "Unknown" || !partsProfitCenter) { + logger.log( + partsProfitCenter === "Unknown" + ? "job-costing unknown type" + : "Unknown cost/profit center mapping for parts.", + "debug", + null, + null, + { + line_desc: val.line_desc, + part_type: val.part_type + } + ); + } - if (!partsProfitCenter) - console.log("Unknown cost/profit center mapping for parts.", val.line_desc, val.part_type); let partsAmount = Dinero({ amount: val.act_price_before_ppc ? Math.round(val.act_price_before_ppc * 100) @@ -409,10 +428,21 @@ function GenerateCostingData(job) { if (val.part_type && val.part_type !== "PAE" && (val.part_type === "PAS" || val.part_type === "PASL")) { const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown"; - if (partsProfitCenter === "Unknown") console.log("Unknown type", val.line_desc, val.part_type); + if (partsProfitCenter === "Unknown" || !partsProfitCenter) { + logger.log( + partsProfitCenter === "Unknown" + ? "job-costing unknown type" + : "job-costing Unknown cost/profit center mapping for sublet", + "debug", + null, + null, + { + line_desc: val.line_desc, + part_type: val.part_type + } + ); + } - if (!partsProfitCenter) - console.log("Unknown cost/profit center mapping for sublet.", val.line_desc, val.part_type); const partsAmount = Dinero({ amount: Math.round((val.act_price || 0) * 100) }) @@ -444,7 +474,10 @@ function GenerateCostingData(job) { const partsProfitCenter = val.profitcenter_part || getAdditionalCostCenter(val, defaultProfits) || "Unknown"; if (partsProfitCenter === "Unknown") { - console.log("Unknown type", val.line_desc, val.part_type); + logger.log("job-costing unknown type", "debug", null, null, { + line_desc: val.line_desc, + part_type: val.part_type + }); } const partsAmount = Dinero({ amount: Math.round((val.act_price || 0) * 100) @@ -476,7 +509,7 @@ function GenerateCostingData(job) { if (!hasMapaLine) { if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]]) jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = Dinero(); - + jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = jobLineTotalsByProfitCenter.additional[ defaultProfits["MAPA"] ].add( diff --git a/server/job/job-totals-USA.js b/server/job/job-totals-USA.js index 4e123850e..c23a64068 100644 --- a/server/job/job-totals-USA.js +++ b/server/job/job-totals-USA.js @@ -26,7 +26,7 @@ exports.totalsSsu = async function (req, res) { const BearerToken = req.BearerToken; const client = req.userGraphQLClient; - logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, id, null); + logger.log("job-totals-ssu-USA", "DEBUG", req?.user?.email, id); try { const job = await client.setHeaders({ Authorization: BearerToken }).request(queries.GET_JOB_BY_PK, { @@ -47,7 +47,7 @@ exports.totalsSsu = async function (req, res) { res.status(200).send(); } catch (error) { - logger.log("job-totals-ssu-USA-error", "ERROR", req.user.email, id, { + logger.log("job-totals-ssu-USA-error", "ERROR", req?.user?.email, id, { jobid: id, error }); @@ -84,12 +84,10 @@ async function Totals(req, res) { const logger = req.logger; const client = req.userGraphQLClient; - logger.log("job-totals-USA", "DEBUG", req.user.email, job.id, { + logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, job.id, { jobid: job.id }); - logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, id, null); - await AutoAddAtsIfRequired({ job, client }); try { @@ -961,7 +959,9 @@ function CalculateTaxesTotals(job, otherTotals) { } } } catch (error) { - console.error("Key with issue", key); + logger.log("job-totals-USA Key with issue", "error", null, null, { + key + }); } }); @@ -1026,7 +1026,9 @@ function CalculateTaxesTotals(job, otherTotals) { totalTaxByTier[taxTierKey] = totalTaxByTier[taxTierKey].add(taxAmountToAdd); } } catch (error) { - console.error("PFP Calculation error", error); + logger.log("job-totals-USA - PFP Calculation Error", "error", null, null, { + error + }); } }); diff --git a/server/middleware/validateFirebaseIdTokenMiddleware.js b/server/middleware/validateFirebaseIdTokenMiddleware.js index d76cc8019..83ab38eaf 100644 --- a/server/middleware/validateFirebaseIdTokenMiddleware.js +++ b/server/middleware/validateFirebaseIdTokenMiddleware.js @@ -16,7 +16,11 @@ const validateFirebaseIdTokenMiddleware = async (req, res, next) => { (!req.headers.authorization || !req.headers.authorization.startsWith("Bearer ")) && !(req.cookies && req.cookies.__session) ) { - console.error("Unauthorized attempt. No authorization provided."); + logger.log("api-authorization-call", "warn", req?.user?.email, null, { + type: "unauthorized", + path: req.path, + body: req.body + }); return res.status(403).send("Unauthorized"); } @@ -32,10 +36,10 @@ const validateFirebaseIdTokenMiddleware = async (req, res, next) => { idToken = req.cookies.__session; } else { // No cookie - console.error("Unauthorized attempt. No cookie provided."); - logger.log("api-unauthorized-call", "WARN", null, null, { - req, - type: "no-cookie" + logger.log("api-unauthorized-call", "warn", null, null, { + type: "unauthorized", + path: req.path, + body: req.body }); return res.status(403).send("Unauthorized"); @@ -47,11 +51,11 @@ const validateFirebaseIdTokenMiddleware = async (req, res, next) => { req.user = decodedIdToken; next(); } catch (error) { - logger.log("api-unauthorized-call", "WARN", null, null, { + logger.log("api-unauthorized-call", "warn", null, null, { path: req.path, body: req.body, - type: "unauthroized", + type: "unauthorized", ...error }); diff --git a/server/payroll/pay-all.js b/server/payroll/pay-all.js index 9288e256a..03c6fbee8 100644 --- a/server/payroll/pay-all.js +++ b/server/payroll/pay-all.js @@ -45,12 +45,12 @@ exports.payall = async function (req, res) { const path = diffParser(diff); if (diff.op === "add") { - console.log(Object.keys(diff.val)); + // console.log(Object.keys(diff.val)); if (typeof diff.val === "object" && Object.keys(diff.val).length > 1) { //Multiple values to add. Object.keys(diff.val).forEach((key) => { - console.log("Hours", diff.val[key][Object.keys(diff.val[key])[0]]); - console.log("Rate", Object.keys(diff.val[key])[0]); + // console.log("Hours", diff.val[key][Object.keys(diff.val[key])[0]]); + // console.log("Rate", Object.keys(diff.val[key])[0]); ticketsToInsert.push({ task_name: "Pay All", jobid: job.id, diff --git a/server/scheduling/scheduling-job.js b/server/scheduling/scheduling-job.js index a005a8d72..11b881f70 100644 --- a/server/scheduling/scheduling-job.js +++ b/server/scheduling/scheduling-job.js @@ -49,7 +49,7 @@ exports.job = async (req, res) => { if (bucketId) { load.productionTotal[bucketId].count = load.productionTotal[bucketId].count + 1; } else { - console.log("Uh oh, this job doesn't fit in a bucket!", item); + // console.log("Uh oh, this job doesn't fit in a bucket!", item); } }); @@ -254,7 +254,7 @@ const CalculateLoad = (currentLoad, buckets, jobsIn, jobsOut) => { if (bucketId) { newLoad[bucketId].count = newLoad[bucketId].count + 1; } else { - console.log("[Util Arr Job]Uh oh, this job doesn't fit in a bucket!", job); + // console.log("[Util Arr Job]Uh oh, this job doesn't fit in a bucket!", job); } }); @@ -263,10 +263,10 @@ const CalculateLoad = (currentLoad, buckets, jobsIn, jobsOut) => { if (bucketId) { newLoad[bucketId].count = newLoad[bucketId].count - 1; if (newLoad[bucketId].count < 0) { - console.log("***ERROR: NEGATIVE LOAD Bucket =>", bucketId, job); + // console.log("***ERROR: NEGATIVE LOAD Bucket =>", bucketId, job); } } else { - console.log("[Util Out Job]Uh oh, this job doesn't fit in a bucket!", job); + // console.log("[Util Out Job]Uh oh, this job doesn't fit in a bucket!", job); } }); diff --git a/server/stripe/payment.js b/server/stripe/payment.js index 3f79c78d0..7b7bc1dc8 100644 --- a/server/stripe/payment.js +++ b/server/stripe/payment.js @@ -39,7 +39,7 @@ const processor = async (req, res) => { } }); } catch (error) { - console.log("error", error); + // console.log("error", error); res.status(400).send(error); } }; diff --git a/server/tasks/tasks.js b/server/tasks/tasks.js index d59d834eb..2ae944e60 100644 --- a/server/tasks/tasks.js +++ b/server/tasks/tasks.js @@ -6,10 +6,11 @@ const client = require("../graphql-client/graphql-client").client; const emailer = require("../email/sendemail"); const moment = require("moment-timezone"); const converter = require("json-2-csv"); +const logger = require("../utils/logger"); exports.taskHandler = async (req, res) => { try { - const { bodyshopid, query, variables, text, to, subject, timezone } = req.body; + const { query, variables, text, to, subject, timezone } = req.body; //Check the variables to see if they are an object. Object.keys(variables).forEach((key) => { @@ -32,8 +33,10 @@ exports.taskHandler = async (req, res) => { text, attachments: [{ filename: "query.csv", content: csv }] }) - .catch((err) => { - console.error("Errors sending CSV Email."); + .catch((error) => { + logger.log("Tasks - Error sending CSV EMAIL", "error", req?.user?.email, null, { + error + }); }); return res.status(200).send(csv); From 6b501e4619ddebf2c7ba960cb48272d515363999 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Tue, 29 Oct 2024 11:02:08 -0700 Subject: [PATCH 65/79] release/2024-11-01 - Misc fixes Signed-off-by: Dave Richer --- server/job/job-costing.js | 95 +++++++++++++------------ server/web-sockets/redisSocketEvents.js | 12 ++-- 2 files changed, 59 insertions(+), 48 deletions(-) diff --git a/server/job/job-costing.js b/server/job/job-costing.js index c0a3ee149..668a35673 100644 --- a/server/job/job-costing.js +++ b/server/job/job-costing.js @@ -19,7 +19,8 @@ async function JobCosting(req, res) { const BearerToken = req.BearerToken; const client = req.userGraphQLClient; - logger.log("job-costing-start", "DEBUG", req.user.email, jobid, null); + //Uncomment for further testing + // logger.log("job-costing-start", "DEBUG", req.user.email, jobid, null); try { const resp = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_JOB_COSTING_DETAILS, { @@ -46,9 +47,10 @@ async function JobCostingMulti(req, res) { const BearerToken = req.BearerToken; const client = req.userGraphQLClient; - logger.log("job-costing-multi-start", "DEBUG", req?.user?.email, null, { - jobids - }); + //Uncomment for further testing + // logger.log("job-costing-multi-start", "DEBUG", req?.user?.email, null, { + // jobids + // }); try { const resp = await client @@ -285,12 +287,13 @@ function GenerateCostingData(job) { if (val.mod_lbr_ty) { const laborProfitCenter = val.profitcenter_labor || defaultProfits[val.mod_lbr_ty] || "Unknown"; - if (laborProfitCenter === "Unknown") { - logger.log("job-costing unknown type", "debug", null, null, { - line_desc: val.line_desc, - mod_lbr_ty: val.mod_lbr_ty - }); - } + //Uncomment for further testing + // if (laborProfitCenter === "Unknown") { + // logger.log("job-costing unknown type", "debug", null, null, { + // line_desc: val.line_desc, + // mod_lbr_ty: val.mod_lbr_ty + // }); + // } const rateName = `rate_${(val.mod_lbr_ty || "").toLowerCase()}`; @@ -357,20 +360,21 @@ function GenerateCostingData(job) { if (val.part_type && val.part_type !== "PAE" && val.part_type !== "PAS" && val.part_type !== "PASL") { const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown"; - if (partsProfitCenter === "Unknown" || !partsProfitCenter) { - logger.log( - partsProfitCenter === "Unknown" - ? "job-costing unknown type" - : "Unknown cost/profit center mapping for parts.", - "debug", - null, - null, - { - line_desc: val.line_desc, - part_type: val.part_type - } - ); - } + //Uncomment for further testing + // if (partsProfitCenter === "Unknown" || !partsProfitCenter) { + // logger.log( + // partsProfitCenter === "Unknown" + // ? "job-costing unknown type" + // : "Unknown cost/profit center mapping for parts.", + // "debug", + // null, + // null, + // { + // line_desc: val.line_desc, + // part_type: val.part_type + // } + // ); + // } let partsAmount = Dinero({ amount: val.act_price_before_ppc @@ -428,20 +432,21 @@ function GenerateCostingData(job) { if (val.part_type && val.part_type !== "PAE" && (val.part_type === "PAS" || val.part_type === "PASL")) { const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown"; - if (partsProfitCenter === "Unknown" || !partsProfitCenter) { - logger.log( - partsProfitCenter === "Unknown" - ? "job-costing unknown type" - : "job-costing Unknown cost/profit center mapping for sublet", - "debug", - null, - null, - { - line_desc: val.line_desc, - part_type: val.part_type - } - ); - } + //Uncomment for further testing + // if (partsProfitCenter === "Unknown" || !partsProfitCenter) { + // logger.log( + // partsProfitCenter === "Unknown" + // ? "job-costing unknown type" + // : "job-costing Unknown cost/profit center mapping for sublet", + // "debug", + // null, + // null, + // { + // line_desc: val.line_desc, + // part_type: val.part_type + // } + // ); + // } const partsAmount = Dinero({ amount: Math.round((val.act_price || 0) * 100) @@ -473,12 +478,14 @@ function GenerateCostingData(job) { //If so, use it, otherwise try to use the same from the auto-allocate logic in IO app jobs-close-auto-allocate. const partsProfitCenter = val.profitcenter_part || getAdditionalCostCenter(val, defaultProfits) || "Unknown"; - if (partsProfitCenter === "Unknown") { - logger.log("job-costing unknown type", "debug", null, null, { - line_desc: val.line_desc, - part_type: val.part_type - }); - } + //Uncomment for further testing + // if (partsProfitCenter === "Unknown") { + // logger.log("job-costing unknown type", "debug", null, null, { + // line_desc: val.line_desc, + // part_type: val.part_type + // }); + // } + const partsAmount = Dinero({ amount: Math.round((val.act_price || 0) * 100) }) diff --git a/server/web-sockets/redisSocketEvents.js b/server/web-sockets/redisSocketEvents.js index 25e101013..7ae8cd8c4 100644 --- a/server/web-sockets/redisSocketEvents.js +++ b/server/web-sockets/redisSocketEvents.js @@ -41,7 +41,8 @@ const redisSocketEvents = ({ // Register Socket Events const registerSocketEvents = (socket) => { - createLogEvent(socket, "debug", `Registering RedisIO Socket Events.`); + // Uncomment for further testing + // createLogEvent(socket, "debug", `Registering RedisIO Socket Events.`); // Token Update Events const registerUpdateEvents = (socket) => { @@ -54,12 +55,13 @@ const redisSocketEvents = ({ // If We ever want to persist user Data across workers // await setSessionData(socket.id, "user", user); - createLogEvent(socket, "debug", "Token updated successfully"); + // Uncomment for further testing + // createLogEvent(socket, "debug", "Token updated successfully"); socket.emit("token-updated", { success: true }); } catch (error) { if (error.code === "auth/id-token-expired") { - createLogEvent(socket, "WARNING", "Stale token received, waiting for new token"); + createLogEvent(socket, "warn", "Stale token received, waiting for new token"); socket.emit("token-updated", { success: false, error: "Stale token." @@ -114,7 +116,9 @@ const redisSocketEvents = ({ // Disconnect Events const registerDisconnectEvents = (socket) => { const disconnect = () => { - createLogEvent(socket, "debug", `User disconnected.`); + // Uncomment for further testing + // createLogEvent(socket, "debug", `User disconnected.`); + const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id); for (const room of rooms) { socket.leave(room); From 80f235f12e89d121e596d128e8c929cb9ca89565 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Tue, 29 Oct 2024 13:33:40 -0700 Subject: [PATCH 66/79] IO-3006 CDK PBS Error Log on INSERT_EXPORT_LOG Signed-off-by: Allan Carr --- server/accounting/pbs/pbs-job-export.js | 2 +- server/cdk/cdk-job-export.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/accounting/pbs/pbs-job-export.js b/server/accounting/pbs/pbs-job-export.js index c2f6b96b7..c38560293 100644 --- a/server/accounting/pbs/pbs-job-export.js +++ b/server/accounting/pbs/pbs-job-export.js @@ -611,7 +611,7 @@ async function InsertFailedExportLog(socket, error) { bodyshopid: socket.JobData.bodyshop.id, jobid: socket.JobData.id, successful: false, - message: [error], + message: JSON.stringify(error), useremail: socket.user.email } }); diff --git a/server/cdk/cdk-job-export.js b/server/cdk/cdk-job-export.js index 7fedbc608..90001fa28 100644 --- a/server/cdk/cdk-job-export.js +++ b/server/cdk/cdk-job-export.js @@ -995,7 +995,7 @@ async function InsertFailedExportLog(socket, error) { bodyshopid: socket.JobData.bodyshop.id, jobid: socket.JobData.id, successful: false, - message: [error], + message: JSON.stringify(error), useremail: socket.user.email } }); From 1b30c1ab58fe50ab600ef34a8d77ddcc40bc2b42 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Tue, 29 Oct 2024 20:03:58 -0700 Subject: [PATCH 67/79] IO-3008 Save and New Flat Rate value Signed-off-by: Allan Carr --- .../time-ticket-modal.container.jsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/components/time-ticket-modal/time-ticket-modal.container.jsx b/client/src/components/time-ticket-modal/time-ticket-modal.container.jsx index 5f4bd4385..b4ef464f2 100644 --- a/client/src/components/time-ticket-modal/time-ticket-modal.container.jsx +++ b/client/src/components/time-ticket-modal/time-ticket-modal.container.jsx @@ -1,7 +1,7 @@ -import { useMutation, useQuery } from "@apollo/client"; -import { Button, Form, Modal, notification, Space } from "antd"; import { PageHeader } from "@ant-design/pro-layout"; -import dayjs from "../../utils/day"; +import { useMutation, useQuery } from "@apollo/client"; +import { useSplitTreatments } from "@splitsoftware/splitio-react"; +import { Button, Form, Modal, notification, Space } from "antd"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -11,9 +11,9 @@ import { INSERT_NEW_TIME_TICKET, UPDATE_TIME_TICKET } from "../../graphql/timeti import { toggleModalVisible } from "../../redux/modals/modals.actions"; import { selectTimeTicket } from "../../redux/modals/modals.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; -import TimeTicketModalComponent from "./time-ticket-modal.component"; +import dayjs from "../../utils/day"; import TimeTicketsCommitToggleComponent from "../time-tickets-commit-toggle/time-tickets-commit-toggle.component"; -import { useSplitTreatments } from "@splitsoftware/splitio-react"; +import TimeTicketModalComponent from "./time-ticket-modal.component"; const mapStateToProps = createStructuredSelector({ timeTicketModal: selectTimeTicket, @@ -87,7 +87,7 @@ export function TimeTicketModalContainer({ timeTicketModal, toggleModalVisible, if (enterAgain) { //Capture the existing information and repopulate it. - const prev = form.getFieldsValue(["date", "employeeid"]); + const prev = form.getFieldsValue(["date", "employeeid", "flat_rate"]); form.resetFields(); From a29e8407970e8965ec83e9db0877ae07731ccfb8 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 30 Oct 2024 09:09:16 -0700 Subject: [PATCH 68/79] release/2024-11-01 - Misc fixes Signed-off-by: Dave Richer --- server/job/job-updated.js | 10 ++++++---- server/mixdata/mixdata.js | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/server/job/job-updated.js b/server/job/job-updated.js index 606e6682c..3373c94a7 100644 --- a/server/job/job-updated.js +++ b/server/job/job-updated.js @@ -15,10 +15,12 @@ const jobUpdated = async (req, res) => { }); } - logger.log("job-update", "DEBUG", req.user?.email, null, { - message: `Job updated event received from Hasura`, - jobid: req?.body?.event?.data?.new?.id - }); + // Uncomment for further testing + // You can also test this using SocketIOAdmin + // logger.log("job-update", "DEBUG", req.user?.email, null, { + // message: `Job updated event received from Hasura`, + // jobid: req?.body?.event?.data?.new?.id + // }); const updatedJob = req.body.event.data.new; const bodyshopID = updatedJob.shopid; diff --git a/server/mixdata/mixdata.js b/server/mixdata/mixdata.js index d61989103..919726efd 100644 --- a/server/mixdata/mixdata.js +++ b/server/mixdata/mixdata.js @@ -59,7 +59,7 @@ exports.mixdataUpload = async (req, res) => { res.status(500).json(error); logger.log("job-mixdata-upload-error", "ERROR", null, null, { error: error.message, - ...error + stack: error.stack }); } }; From 3d10c9da7fbf3c88db2bf739fff2bf5d1ad795d3 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 30 Oct 2024 09:38:27 -0700 Subject: [PATCH 69/79] release/2024-11-01 - Misc fixes Signed-off-by: Dave Richer --- .../dms-log-events/dms-log-events.component.jsx | 2 +- .../dms-payables/dms-payables.container.jsx | 4 ++-- client/src/pages/dms/dms.container.jsx | 4 ++-- server/cdk/cdk-wsdl.js | 2 +- server/utils/logger.js | 17 +++++++++++++++-- server/web-sockets/web-socket.js | 2 +- 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/client/src/components/dms-log-events/dms-log-events.component.jsx b/client/src/components/dms-log-events/dms-log-events.component.jsx index 9391d8edb..b73e5dbe7 100644 --- a/client/src/components/dms-log-events/dms-log-events.component.jsx +++ b/client/src/components/dms-log-events/dms-log-events.component.jsx @@ -44,7 +44,7 @@ function LogLevelHierarchy(level) { return "orange"; case "INFO": return "blue"; - case "WARNING": + case "WARN": return "yellow"; case "ERROR": return "red"; diff --git a/client/src/pages/dms-payables/dms-payables.container.jsx b/client/src/pages/dms-payables/dms-payables.container.jsx index 47659cd9b..4fa92b9fb 100644 --- a/client/src/pages/dms-payables/dms-payables.container.jsx +++ b/client/src/pages/dms-payables/dms-payables.container.jsx @@ -71,7 +71,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { ...logs, { timestamp: new Date(), - level: "WARNING", + level: "WARN", message: "Reconnected to CDK Export Service" } ]; @@ -125,7 +125,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { > DEBUG INFO - WARNING + WARN ERROR diff --git a/client/src/pages/dms/dms.container.jsx b/client/src/pages/dms/dms.container.jsx index 3f7569cbd..3a8ac77b0 100644 --- a/client/src/pages/dms/dms.container.jsx +++ b/client/src/pages/dms/dms.container.jsx @@ -90,7 +90,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse ...logs, { timestamp: new Date(), - level: "WARNING", + level: "warn", message: "Reconnected to CDK Export Service" } ]; @@ -175,7 +175,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse > DEBUG INFO - WARNING + WARN ERROR diff --git a/server/cdk/cdk-wsdl.js b/server/cdk/cdk-wsdl.js index 032d780c2..8926e98ae 100644 --- a/server/cdk/cdk-wsdl.js +++ b/server/cdk/cdk-wsdl.js @@ -20,7 +20,7 @@ function CheckCdkResponseForError(socket, soapResponse) { //The response was null, this might be ok, it might not. CdkBase.createLogEvent( socket, - "WARNING", + "warn", `Warning detected in CDK Response - it appears to be null. Stack: ${new Error().stack}` ); return; diff --git a/server/utils/logger.js b/server/utils/logger.js index 26dd72150..bfb0c0cda 100644 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -10,6 +10,18 @@ const WinstonCloudWatch = require("winston-cloudwatch"); const { isString, isEmpty } = require("lodash"); const { networkInterfaces, hostname } = require("node:os"); +const LOG_LEVELS = { + error: { level: 0, name: "error" }, + warn: { level: 1, name: "warn" }, + info: { level: 2, name: "info" }, + http: { level: 3, name: "http" }, + verbose: { level: 4, name: "verbose" }, + debug: { level: 5, name: "debug" }, + silly: { level: 6, name: "silly" } +}; + +const normalizeLevel = (level) => (level ? level.toLowerCase() : LOG_LEVELS.debug.name); + const createLogger = () => { try { const isLocal = isString(process.env?.LOCALSTACK_HOSTNAME) && !isEmpty(process.env?.LOCALSTACK_HOSTNAME); @@ -114,7 +126,7 @@ const createLogger = () => { const log = (message, type, user, record, meta) => { winstonLogger.log({ - level: type.toLowerCase(), + level: normalizeLevel(type), message, user, record, @@ -131,7 +143,8 @@ const createLogger = () => { console.error("Error setting up enhanced Logger, defaulting to console.: " + e?.message || ""); return { log: console.log, - logger: console.log + logger: console.log, + LOG_LEVELS }; } }; diff --git a/server/web-sockets/web-socket.js b/server/web-sockets/web-socket.js index a56f6cff6..c5e5012c8 100644 --- a/server/web-sockets/web-socket.js +++ b/server/web-sockets/web-socket.js @@ -212,7 +212,7 @@ function LogLevelHierarchy(level) { return 4; case "INFO": return 3; - case "WARNING": + case "WARN": return 2; case "ERROR": return 1; From 77e009f31663be6838c95330701fe14888eba4a6 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Wed, 30 Oct 2024 11:19:46 -0700 Subject: [PATCH 70/79] IO-3012 Remove Sort from SB Timeticket Query Signed-off-by: Allan Carr --- client/src/graphql/timetickets.queries.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/src/graphql/timetickets.queries.js b/client/src/graphql/timetickets.queries.js index f56976e2b..ba7cf60fc 100644 --- a/client/src/graphql/timetickets.queries.js +++ b/client/src/graphql/timetickets.queries.js @@ -145,7 +145,6 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql` ) { timetickets( where: { date: { _gte: $start, _lte: $end }, cost_center: { _neq: "timetickets.labels.shift" } } - order_by: { date: desc_nulls_first } ) { actualhrs ciecacode @@ -180,7 +179,6 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql` } fixedperiod: timetickets( where: { date: { _gte: $fixedStart, _lte: $fixedEnd }, cost_center: { _neq: "timetickets.labels.shift" } } - order_by: { date: desc_nulls_first } ) { actualhrs ciecacode From dd5961d4199d09fe579bf87b6e42b40b818c21d3 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 30 Oct 2024 12:07:50 -0700 Subject: [PATCH 71/79] release/2024-11-01 - Update Trigger for job_updated Signed-off-by: Dave Richer --- hasura/metadata/tables.yaml | 62 ++++++++++++------------------------- server/job/job-updated.js | 4 +-- 2 files changed, 22 insertions(+), 44 deletions(-) diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml index 70be46ad0..240b218a4 100644 --- a/hasura/metadata/tables.yaml +++ b/hasura/metadata/tables.yaml @@ -69,7 +69,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: jobline: job: @@ -180,7 +179,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bodyshop: associations: @@ -387,7 +385,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bodyshop: associations: @@ -504,7 +501,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bill: job: @@ -671,7 +667,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: _and: - job: @@ -1285,7 +1280,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: courtesycar: bodyshop: @@ -1526,7 +1520,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bodyshop: associations: @@ -1786,7 +1779,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bodyshop: associations: @@ -1920,7 +1912,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: _or: - job: @@ -2105,7 +2096,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: employee_team: bodyshop: @@ -2268,7 +2258,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: employee: bodyshop: @@ -2449,7 +2438,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bodyshop: associations: @@ -2696,7 +2684,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bodyshop: associations: @@ -2808,7 +2795,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: conversation: bodyshop: @@ -3123,7 +3109,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: job: bodyshop: @@ -4232,7 +4217,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bodyshop: associations: @@ -4248,41 +4232,41 @@ enable_manual: false update: columns: - - clm_no - - v_make_desc - - date_next_contact - - status - - employee_csr - employee_prep - clm_total - suspended - employee_body - ro_number - - actual_in - ownr_co_nm - - v_model_yr - - comment - - job_totals - v_vin - - ownr_fn - scheduled_completion - special_coverage_policy - - v_color - - ca_gst_registrant - scheduled_delivery - actual_delivery - actual_completion - kanbanparent - est_ct_fn + - alt_transport + - v_model_desc + - clm_no + - v_make_desc + - date_next_contact + - status + - employee_csr + - actual_in + - v_model_yr + - comment + - job_totals + - ownr_fn + - v_color + - ca_gst_registrant - employee_refinish - ownr_ph1 - date_last_contacted - - alt_transport - inproduction - est_ct_ln - production_vars - category - - v_model_desc - date_invoiced - est_co_nm - ownr_ln @@ -4295,6 +4279,12 @@ - name: event-secret value_from_env: EVENT_SECRET request_transform: + body: + action: transform + template: |- + { + "data": {{$body?.event?.data?.new}} + } method: POST query_params: {} template_engine: Kriti @@ -4496,7 +4486,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: conversation: bodyshop: @@ -4670,7 +4659,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: job: bodyshop: @@ -4805,7 +4793,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bodyshop: associations: @@ -5110,7 +5097,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: parts_order: job: @@ -5243,7 +5229,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: job: bodyshop: @@ -5419,7 +5404,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: job: bodyshop: @@ -5559,7 +5543,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bodyshop: associations: @@ -5670,7 +5653,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: _or: - parentjob_rel: @@ -5760,7 +5742,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: job: bodyshop: @@ -6045,7 +6026,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bodyshop: associations: @@ -6541,7 +6521,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bodyshop: associations: @@ -6698,7 +6677,6 @@ delete_permissions: - role: user permission: - backend_only: false filter: bodyshop: associations: diff --git a/server/job/job-updated.js b/server/job/job-updated.js index 3373c94a7..62f63b0e2 100644 --- a/server/job/job-updated.js +++ b/server/job/job-updated.js @@ -3,7 +3,7 @@ const { isObject } = require("lodash"); const jobUpdated = async (req, res) => { const { ioRedis, logger, ioHelpers } = req; - if (!req?.body?.event?.data?.new || !isObject(req?.body?.event?.data?.new)) { + if (!req?.body?.data || !isObject(req.body.data)) { logger.log("job-update-error", "ERROR", req.user?.email, null, { message: `Malformed Job Update request sent from Hasura`, body: req?.body @@ -22,7 +22,7 @@ const jobUpdated = async (req, res) => { // jobid: req?.body?.event?.data?.new?.id // }); - const updatedJob = req.body.event.data.new; + const updatedJob = req.body.data; const bodyshopID = updatedJob.shopid; // Emit the job-updated event only to the room corresponding to the bodyshop From 2ab4615642921ea568e8627e65fb4dd9319c96c6 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Wed, 30 Oct 2024 12:48:27 -0700 Subject: [PATCH 72/79] IO-3009 Clear Dates Signed-off-by: Allan Carr --- .../form-date-time-picker.component.jsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx b/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx index 707dfbdf8..0ef0faf80 100644 --- a/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx +++ b/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx @@ -2,11 +2,11 @@ import { DatePicker } from "antd"; import PropTypes from "prop-types"; import React, { useCallback, useState } from "react"; import { useTranslation } from "react-i18next"; -import dayjs from "../../utils/day"; -import { fuzzyMatchDate } from "./formats.js"; +import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors.js"; -import { connect } from "react-redux"; +import dayjs from "../../utils/day"; +import { fuzzyMatchDate } from "./formats.js"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop @@ -28,7 +28,6 @@ const DateTimePicker = ({ const handleChange = useCallback( (newDate) => { - if (!newDate) return; if (onChange) { onChange(bodyshop?.timezone ? dayjs(newDate).tz(bodyshop.timezone, true) : newDate); } From 6cac0f95947db654606724492c22d5c099a54149 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Wed, 30 Oct 2024 17:38:09 -0700 Subject: [PATCH 73/79] IO-3010 Task Table UI refactor Signed-off-by: Allan Carr --- .../task-list/task-list.component.jsx | 115 +++++++++--------- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + 4 files changed, 63 insertions(+), 55 deletions(-) diff --git a/client/src/components/task-list/task-list.component.jsx b/client/src/components/task-list/task-list.component.jsx index 0c01ef6a8..ba7d71b17 100644 --- a/client/src/components/task-list/task-list.component.jsx +++ b/client/src/components/task-list/task-list.component.jsx @@ -144,7 +144,7 @@ function TaskListComponent({ title: t("tasks.fields.created_by"), dataIndex: "created_by", key: "created_by", - width: "10%", + width: "8%", defaultSortOrder: "descend", sorter: true, sortOrder: sortcolumn === "created_by" && sortorder, @@ -166,65 +166,70 @@ function TaskListComponent({ }); } - if (showRo) { - columns.push({ - title: t("tasks.fields.job.ro_number"), - dataIndex: ["job", "ro_number"], - key: "job.ro_number", - width: "8%", - render: (text, record) => - record.job ? ( - {record.job.ro_number || t("general.labels.na")} - ) : ( - t("general.labels.na") - ) - }); - } + columns.push({ + title: t("tasks.fields.related_items"), + key: "related_items", + width: "12%", + render: (text, record) => { + const items = []; + + // Job + if (showRo && record.job) { + items.push( + + {t("tasks.fields.job.ro_number")}: {record.job.ro_number} + + ); + } + if (showRo && !record.job) { + items.push(`${t("tasks.fields.job.ro_number")}: ${t("general.labels.na")}`); + } + + // Jobline + if (record.jobline?.line_desc) { + items.push( + + {t("tasks.fields.jobline")}: {record.jobline.line_desc} + + ); + } + + // Parts Order + if (record.parts_order) { + const { order_number, vendor } = record.parts_order; + const partsOrderText = + order_number && vendor?.name ? `${order_number} - ${vendor.name}` : t("general.labels.na"); + items.push( + + {t("tasks.fields.parts_order")}: {partsOrderText} + + ); + } + + // Bill + if (record.bill) { + const { invoice_number, vendor } = record.bill; + const billText = invoice_number && vendor?.name ? `${invoice_number} - ${vendor.name}` : t("general.labels.na"); + items.push( + + {t("tasks.fields.bill")}: {billText} + + ); + } + + return items.length > 0 ? {items} : null; + } + }); columns.push( - { - title: t("tasks.fields.jobline"), - dataIndex: ["jobline", "id"], - key: "jobline.id", - width: "8%", - render: (text, record) => record?.jobline?.line_desc || "" - }, - { - title: t("tasks.fields.parts_order"), - dataIndex: ["parts_order", "id"], - key: "part_order.id", - width: "8%", - render: (text, record) => - record.parts_order ? ( - - {record.parts_order.order_number && record.parts_order.vendor && record.parts_order.vendor.name - ? `${record.parts_order.order_number} - ${record.parts_order.vendor.name}` - : t("general.labels.na")} - - ) : ( - "" - ) - }, - { - title: t("tasks.fields.bill"), - dataIndex: ["bill", "id"], - key: "bill.id", - width: "10%", - render: (text, record) => - record.bill ? ( - - {record.bill.invoice_number && record.bill.vendor && record.bill.vendor.name - ? `${record.bill.invoice_number} - ${record.bill.vendor.name}` - : t("general.labels.na")} - - ) : ( - "" - ) - }, { title: t("tasks.fields.title"), dataIndex: "title", key: "title", + minWidth: "20%", sorter: true, sortOrder: sortcolumn === "title" && sortorder }, @@ -258,7 +263,7 @@ function TaskListComponent({ { title: t("tasks.fields.actions"), key: "toggleCompleted", - width: "5%", + width: "8%", render: (text, record) => (