feature/IO-3390-Parts-Management-2 - Add Job status patch route, Bodyshop Patch route, remove PAO from simplified parts filter.
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
const logger = require("../utils/logger");
|
||||
|
||||
const GraphQLClient = require("graphql-request").GraphQLClient;
|
||||
|
||||
//New bug introduced with Graphql Request.
|
||||
@@ -14,17 +12,18 @@ const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
|
||||
});
|
||||
|
||||
const rpsClient =
|
||||
process.env.RPS_GRAPHQL_ENDPOINT && process.env.RPS_HASURA_ADMIN_SECRET ?
|
||||
new GraphQLClient(process.env.RPS_GRAPHQL_ENDPOINT, {
|
||||
headers: {
|
||||
"x-hasura-admin-secret": process.env.RPS_HASURA_ADMIN_SECRET
|
||||
}
|
||||
}) : null;
|
||||
process.env.RPS_GRAPHQL_ENDPOINT && process.env.RPS_HASURA_ADMIN_SECRET
|
||||
? new GraphQLClient(process.env.RPS_GRAPHQL_ENDPOINT, {
|
||||
headers: {
|
||||
"x-hasura-admin-secret": process.env.RPS_HASURA_ADMIN_SECRET
|
||||
}
|
||||
})
|
||||
: null;
|
||||
|
||||
if (!rpsClient) {
|
||||
//System log to disable RPS functions
|
||||
logger.log(`RPS secrets are not set. Client is not configured.`, "WARN", "redis", "api", {
|
||||
});
|
||||
|
||||
console.log(`RPS secrets are not set. Client is not configured.`, "WARN", "redis", "api", {});
|
||||
}
|
||||
|
||||
const unauthorizedClient = new GraphQLClient(process.env.GRAPHQL_ENDPOINT);
|
||||
|
||||
@@ -7,7 +7,8 @@ const {
|
||||
CREATE_SHOP,
|
||||
DELETE_VENDORS_BY_SHOP,
|
||||
DELETE_SHOP,
|
||||
CREATE_USER
|
||||
CREATE_USER,
|
||||
UPDATE_BODYSHOP_BY_ID
|
||||
} = require("../partsManagement.queries");
|
||||
|
||||
/**
|
||||
@@ -131,6 +132,61 @@ const insertUserAssociation = async (uid, email, shopId) => {
|
||||
return resp.insert_users_one;
|
||||
};
|
||||
|
||||
/**
|
||||
* PATCH handler for updating bodyshop fields.
|
||||
* Allows patching: shopname, address1, address2, city, state, zip_post, country, email, timezone, phone, logo_img_path
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const patchPartsManagementProvisioning = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const allowedFields = [
|
||||
"shopname",
|
||||
"address1",
|
||||
"address2",
|
||||
"city",
|
||||
"state",
|
||||
"zip_post",
|
||||
"country",
|
||||
"email",
|
||||
"timezone",
|
||||
"phone",
|
||||
"logo_img_path"
|
||||
];
|
||||
const updateFields = {};
|
||||
for (const field of allowedFields) {
|
||||
if (req.body[field] !== undefined) {
|
||||
updateFields[field] = req.body[field];
|
||||
}
|
||||
}
|
||||
if (Object.keys(updateFields).length === 0) {
|
||||
return res.status(400).json({ error: "No valid fields provided for update." });
|
||||
}
|
||||
// Check that the bodyshop has an external_shop_id before allowing patch
|
||||
try {
|
||||
// Fetch the bodyshop by id
|
||||
const shopResp = await client.request(
|
||||
`query GetBodyshop($id: uuid!) { bodyshops_by_pk(id: $id) { id external_shop_id } }`,
|
||||
{ id }
|
||||
);
|
||||
if (!shopResp.bodyshops_by_pk?.external_shop_id) {
|
||||
return res.status(400).json({ error: "Cannot patch: bodyshop does not have an external_shop_id." });
|
||||
}
|
||||
} catch (err) {
|
||||
return res.status(500).json({ error: "Failed to validate bodyshop external_shop_id.", detail: err });
|
||||
}
|
||||
try {
|
||||
const resp = await client.request(UPDATE_BODYSHOP_BY_ID, { id, fields: updateFields });
|
||||
if (!resp.update_bodyshops_by_pk) {
|
||||
return res.status(404).json({ error: "Bodyshop not found." });
|
||||
}
|
||||
return res.json(resp.update_bodyshops_by_pk);
|
||||
} catch (err) {
|
||||
return res.status(500).json({ error: "Failed to update bodyshop.", detail: err });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles provisioning a new shop for parts management.
|
||||
* @param req
|
||||
@@ -259,4 +315,4 @@ const partsManagementProvisioning = async (req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = partsManagementProvisioning;
|
||||
module.exports = { partsManagementProvisioning, patchPartsManagementProvisioning };
|
||||
|
||||
@@ -298,6 +298,25 @@ const UPDATE_JOBLINE_BY_PK = `
|
||||
}
|
||||
`;
|
||||
|
||||
const UPDATE_BODYSHOP_BY_ID = `
|
||||
mutation UpdateBodyshopById($id: uuid!, $fields: bodyshops_set_input!) {
|
||||
update_bodyshops_by_pk(pk_columns: { id: $id }, _set: $fields) {
|
||||
id
|
||||
shopname
|
||||
address1
|
||||
address2
|
||||
city
|
||||
state
|
||||
zip_post
|
||||
country
|
||||
email
|
||||
timezone
|
||||
phone
|
||||
logo_img_path
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
module.exports = {
|
||||
GET_BODYSHOP_STATUS,
|
||||
GET_VEHICLE_BY_SHOP_VIN,
|
||||
@@ -329,5 +348,6 @@ module.exports = {
|
||||
DELETE_PARTS_ORDERS_BY_JOB_IDS,
|
||||
UPSERT_JOBLINES,
|
||||
GET_JOBLINE_IDS_BY_JOBID_UNQSEQ,
|
||||
UPDATE_JOBLINE_BY_PK
|
||||
UPDATE_JOBLINE_BY_PK,
|
||||
UPDATE_BODYSHOP_BY_ID
|
||||
};
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Parts Management Provisioning API
|
||||
description: API endpoint to provision a new shop and user in the Parts Management system.
|
||||
version: 1.0.0
|
||||
|
||||
paths:
|
||||
/parts-management/provision:
|
||||
post:
|
||||
summary: Provision a new parts management shop and user
|
||||
operationId: partsManagementProvisioning
|
||||
tags:
|
||||
- Parts Management
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- external_shop_id
|
||||
- shopname
|
||||
- address1
|
||||
- city
|
||||
- state
|
||||
- zip_post
|
||||
- country
|
||||
- email
|
||||
- phone
|
||||
- userEmail
|
||||
properties:
|
||||
external_shop_id:
|
||||
type: string
|
||||
description: External shop ID (must be unique)
|
||||
shopname:
|
||||
type: string
|
||||
address1:
|
||||
type: string
|
||||
address2:
|
||||
type: string
|
||||
nullable: true
|
||||
city:
|
||||
type: string
|
||||
state:
|
||||
type: string
|
||||
zip_post:
|
||||
type: string
|
||||
country:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
phone:
|
||||
type: string
|
||||
userEmail:
|
||||
type: string
|
||||
format: email
|
||||
userPassword:
|
||||
type: string
|
||||
description: Optional password for the new user. If provided, the password is set directly, and no password reset link is sent. Must be at least 6 characters.
|
||||
nullable: true
|
||||
logoUrl:
|
||||
type: string
|
||||
format: uri
|
||||
nullable: true
|
||||
timezone:
|
||||
type: string
|
||||
nullable: true
|
||||
vendors:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
street1:
|
||||
type: string
|
||||
nullable: true
|
||||
street2:
|
||||
type: string
|
||||
nullable: true
|
||||
city:
|
||||
type: string
|
||||
nullable: true
|
||||
state:
|
||||
type: string
|
||||
nullable: true
|
||||
zip:
|
||||
type: string
|
||||
nullable: true
|
||||
country:
|
||||
type: string
|
||||
nullable: true
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
nullable: true
|
||||
discount:
|
||||
type: number
|
||||
nullable: true
|
||||
due_date:
|
||||
type: string
|
||||
format: date
|
||||
nullable: true
|
||||
cost_center:
|
||||
type: string
|
||||
nullable: true
|
||||
favorite:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
phone:
|
||||
type: string
|
||||
nullable: true
|
||||
active:
|
||||
type: boolean
|
||||
nullable: true
|
||||
dmsid:
|
||||
type: string
|
||||
nullable: true
|
||||
responses:
|
||||
'200':
|
||||
description: Shop and user successfully created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
shop:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
shopname:
|
||||
type: string
|
||||
user:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
resetLink:
|
||||
type: string
|
||||
format: uri
|
||||
nullable: true
|
||||
description: Password reset link for the user. Only included if userPassword is not provided in the request.
|
||||
'400':
|
||||
description: Bad request (missing or invalid fields)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
'500':
|
||||
description: Internal server error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
40
server/job/patchJobStatus.js
Normal file
40
server/job/patchJobStatus.js
Normal file
@@ -0,0 +1,40 @@
|
||||
const client = require("../graphql-client/graphql-client").client;
|
||||
const { UPDATE_JOB_BY_ID } = require("../integrations/partsManagement/partsManagement.queries");
|
||||
|
||||
/**
|
||||
* PATCH handler to update job status (parts management only)
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
module.exports = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { status } = req.body;
|
||||
if (!status) {
|
||||
return res.status(400).json({ error: "Missing required field: status" });
|
||||
}
|
||||
try {
|
||||
// Fetch job to get shopid
|
||||
const jobResp = await client.request(`query GetJob($id: uuid!) { jobs_by_pk(id: $id) { id shopid } }`, { id });
|
||||
const job = jobResp.jobs_by_pk;
|
||||
if (!job) {
|
||||
return res.status(404).json({ error: "Job not found" });
|
||||
}
|
||||
// Fetch bodyshop to check external_shop_id
|
||||
const shopResp = await client.request(
|
||||
`query GetBodyshop($id: uuid!) { bodyshops_by_pk(id: $id) { id external_shop_id } }`,
|
||||
{ id: job.shopid }
|
||||
);
|
||||
if (!shopResp.bodyshops_by_pk || !shopResp.bodyshops_by_pk.external_shop_id) {
|
||||
return res.status(400).json({ error: "Cannot patch: parent bodyshop does not have an external_shop_id." });
|
||||
}
|
||||
// Update job status
|
||||
const updateResp = await client.request(UPDATE_JOB_BY_ID, { id, job: { status } });
|
||||
if (!updateResp.update_jobs_by_pk) {
|
||||
return res.status(404).json({ error: "Job not found after update" });
|
||||
}
|
||||
return res.json(updateResp.update_jobs_by_pk);
|
||||
} catch (err) {
|
||||
return res.status(500).json({ error: "Failed to update job status.", detail: err });
|
||||
}
|
||||
};
|
||||
@@ -19,11 +19,15 @@ if (typeof VSSTA_INTEGRATION_SECRET === "string" && VSSTA_INTEGRATION_SECRET.len
|
||||
if (typeof PARTS_MANAGEMENT_INTEGRATION_SECRET === "string" && PARTS_MANAGEMENT_INTEGRATION_SECRET.length > 0) {
|
||||
const XML_BODY_LIMIT = "10mb"; // Set a limit for XML body size
|
||||
|
||||
const partsManagementProvisioning = require("../integrations/partsManagement/endpoints/partsManagementProvisioning");
|
||||
const {
|
||||
partsManagementProvisioning,
|
||||
patchPartsManagementProvisioning
|
||||
} = require("../integrations/partsManagement/endpoints/partsManagementProvisioning");
|
||||
const partsManagementDeprovisioning = require("../integrations/partsManagement/endpoints/partsManagementDeprovisioning");
|
||||
const partsManagementIntegrationMiddleware = require("../middleware/partsManagementIntegrationMiddleware");
|
||||
const partsManagementVehicleDamageEstimateAddRq = require("../integrations/partsManagement/endpoints/vehicleDamageEstimateAddRq");
|
||||
const partsManagementVehicleDamageEstimateChqRq = require("../integrations/partsManagement/endpoints/vehicleDamageEstimateChgRq");
|
||||
const patchJobStatus = require("../job/patchJobStatus");
|
||||
|
||||
/**
|
||||
* Route to handle Vehicle Damage Estimate Add Request
|
||||
@@ -55,6 +59,20 @@ if (typeof PARTS_MANAGEMENT_INTEGRATION_SECRET === "string" && PARTS_MANAGEMENT_
|
||||
* Route to handle Parts Management Provisioning
|
||||
*/
|
||||
router.post("/parts-management/provision", partsManagementIntegrationMiddleware, partsManagementProvisioning);
|
||||
|
||||
/**
|
||||
* PATCH route to update Parts Management Provisioning info
|
||||
*/
|
||||
router.patch(
|
||||
"/parts-management/provision/:id",
|
||||
partsManagementIntegrationMiddleware,
|
||||
patchPartsManagementProvisioning
|
||||
);
|
||||
|
||||
/**
|
||||
* PATCH route to update job status (parts management only)
|
||||
*/
|
||||
router.patch("/parts-management/job/:id/status", partsManagementIntegrationMiddleware, patchJobStatus);
|
||||
} else {
|
||||
logger.logger.warn("PARTS_MANAGEMENT_INTEGRATION_SECRET is not set — skipping /parts-management/provision route");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user