seed stuff
This commit is contained in:
@@ -406,7 +406,7 @@ router.get('/products', async (req, res, next) => {
|
||||
// @access Private (Admin)
|
||||
router.post('/products', validateRequest(productSchema), async (req, res, next) => {
|
||||
try {
|
||||
const { name, brand, categoryId, productType, activeIngredients, description } = req.body;
|
||||
const { name, brand, categoryId, productType, activeIngredients, description, seedBlend } = req.body;
|
||||
|
||||
// Check if category exists
|
||||
const categoryCheck = await pool.query(
|
||||
@@ -419,10 +419,10 @@ router.post('/products', validateRequest(productSchema), async (req, res, next)
|
||||
}
|
||||
|
||||
const result = await pool.query(
|
||||
`INSERT INTO products (name, brand, category_id, product_type, active_ingredients, description)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
`INSERT INTO products (name, brand, category_id, product_type, active_ingredients, description, seed_blend)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING *`,
|
||||
[name, brand, categoryId, productType, activeIngredients, description]
|
||||
[name, brand, categoryId, productType, activeIngredients, description, seedBlend ? JSON.stringify(seedBlend) : null]
|
||||
);
|
||||
|
||||
const product = result.rows[0];
|
||||
@@ -439,7 +439,8 @@ router.post('/products', validateRequest(productSchema), async (req, res, next)
|
||||
productType: product.product_type,
|
||||
activeIngredients: product.active_ingredients,
|
||||
description: product.description,
|
||||
createdAt: product.created_at
|
||||
createdAt: product.created_at,
|
||||
seedBlend: product.seed_blend
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -454,7 +455,7 @@ router.post('/products', validateRequest(productSchema), async (req, res, next)
|
||||
router.put('/products/:id', validateParams(idParamSchema), validateRequest(productSchema), async (req, res, next) => {
|
||||
try {
|
||||
const productId = req.params.id;
|
||||
const { name, brand, categoryId, productType, activeIngredients, description } = req.body;
|
||||
const { name, brand, categoryId, productType, activeIngredients, description, seedBlend } = req.body;
|
||||
|
||||
// Check if product exists
|
||||
const productCheck = await pool.query(
|
||||
@@ -479,10 +480,10 @@ router.put('/products/:id', validateParams(idParamSchema), validateRequest(produ
|
||||
const result = await pool.query(
|
||||
`UPDATE products
|
||||
SET name = $1, brand = $2, category_id = $3, product_type = $4,
|
||||
active_ingredients = $5, description = $6
|
||||
WHERE id = $7
|
||||
active_ingredients = $5, description = $6, seed_blend = $7
|
||||
WHERE id = $8
|
||||
RETURNING *`,
|
||||
[name, brand, categoryId, productType, activeIngredients, description, productId]
|
||||
[name, brand, categoryId, productType, activeIngredients, description, seedBlend ? JSON.stringify(seedBlend) : null, productId]
|
||||
);
|
||||
|
||||
const product = result.rows[0];
|
||||
@@ -498,6 +499,7 @@ router.put('/products/:id', validateParams(idParamSchema), validateRequest(produ
|
||||
categoryId: product.category_id,
|
||||
productType: product.product_type,
|
||||
activeIngredients: product.active_ingredients,
|
||||
seedBlend: product.seed_blend,
|
||||
description: product.description,
|
||||
createdAt: product.created_at
|
||||
}
|
||||
@@ -1120,4 +1122,4 @@ router.put('/settings', async (req, res, next) => {
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
|
||||
@@ -989,6 +989,7 @@ router.get('/logs', async (req, res, next) => {
|
||||
averageSpeed: parseFloat(log.average_speed),
|
||||
areaCovered: parseFloat(log.area_covered),
|
||||
notes: log.notes,
|
||||
seedingType: log.seeding_type,
|
||||
sectionName: log.section_name,
|
||||
sectionArea: parseFloat(log.section_area),
|
||||
propertyName: log.property_name,
|
||||
@@ -1020,7 +1021,8 @@ router.post('/logs', validateRequest(applicationLogSchema), async (req, res, nex
|
||||
averageSpeed,
|
||||
areaCovered,
|
||||
notes,
|
||||
products
|
||||
products,
|
||||
seedingType
|
||||
} = req.body;
|
||||
|
||||
// Start transaction
|
||||
@@ -1083,6 +1085,8 @@ router.post('/logs', validateRequest(applicationLogSchema), async (req, res, nex
|
||||
|
||||
// Add products to log
|
||||
console.log('Adding products to log:', products);
|
||||
// Track seed product names for lawn section update
|
||||
const seedProductNames = [];
|
||||
for (const product of products) {
|
||||
const {
|
||||
productId,
|
||||
@@ -1109,6 +1113,17 @@ router.post('/logs', validateRequest(applicationLogSchema), async (req, res, nex
|
||||
);
|
||||
|
||||
console.log('Product inserted successfully');
|
||||
|
||||
// Determine if this product is of type 'seed' and capture its name
|
||||
try {
|
||||
if (productId) {
|
||||
const pr = await client.query('SELECT name, product_type FROM products WHERE id=$1', [productId]);
|
||||
if (pr.rows[0]?.product_type === 'seed') seedProductNames.push(pr.rows[0].name);
|
||||
} else if (userProductId) {
|
||||
const upr = await client.query('SELECT custom_name, custom_product_type FROM user_products WHERE id=$1 AND user_id=$2', [userProductId, req.user.id]);
|
||||
if (upr.rows[0]?.custom_product_type === 'seed') seedProductNames.push(upr.rows[0].custom_name);
|
||||
}
|
||||
} catch (e) { console.warn('Seed product detection failed', e.message); }
|
||||
}
|
||||
|
||||
// If this was from a plan, mark the plan as completed
|
||||
@@ -1119,6 +1134,15 @@ router.post('/logs', validateRequest(applicationLogSchema), async (req, res, nex
|
||||
);
|
||||
}
|
||||
|
||||
// If seed was applied, update the lawn section grass type to reflect seeds
|
||||
if (seedProductNames.length > 0) {
|
||||
const blendLabel = seedProductNames.join(' + ');
|
||||
const suffix = seedingType === 'new_seed' ? ' (New Seed)' : (seedingType === 'overseed' ? ' (Overseed)' : '');
|
||||
try {
|
||||
await client.query('UPDATE lawn_sections SET grass_type=$1, updated_at=CURRENT_TIMESTAMP WHERE id=$2', [blendLabel + suffix, lawnSectionId]);
|
||||
} catch (e) { console.warn('Failed to update grass_type for section', lawnSectionId, e.message); }
|
||||
}
|
||||
|
||||
await client.query('COMMIT');
|
||||
|
||||
res.status(201).json({
|
||||
|
||||
@@ -110,7 +110,7 @@ router.get('/:id', validateParams(idParamSchema), async (req, res, next) => {
|
||||
|
||||
// Get lawn sections
|
||||
const sectionsResult = await pool.query(
|
||||
'SELECT * FROM lawn_sections WHERE property_id = $1 ORDER BY name',
|
||||
'SELECT *, grass_types FROM lawn_sections WHERE property_id = $1 ORDER BY name',
|
||||
[propertyId]
|
||||
);
|
||||
|
||||
@@ -132,6 +132,7 @@ router.get('/:id', validateParams(idParamSchema), async (req, res, next) => {
|
||||
area: parseFloat(section.area),
|
||||
polygonData: section.polygon_data,
|
||||
grassType: section.grass_type,
|
||||
grassTypes: section.grass_types || null,
|
||||
soilType: section.soil_type,
|
||||
createdAt: section.created_at,
|
||||
updatedAt: section.updated_at
|
||||
@@ -277,7 +278,7 @@ router.delete('/:id', validateParams(idParamSchema), async (req, res, next) => {
|
||||
router.post('/:id/sections', validateParams(idParamSchema), validateRequest(lawnSectionSchema), async (req, res, next) => {
|
||||
try {
|
||||
const propertyId = req.params.id;
|
||||
const { name, area, polygonData, grassType, soilType } = req.body;
|
||||
const { name, area, polygonData, grassType, grassTypes, soilType } = req.body;
|
||||
|
||||
// Check if property exists and belongs to user
|
||||
const propertyResult = await pool.query(
|
||||
@@ -299,10 +300,18 @@ router.post('/:id/sections', validateParams(idParamSchema), validateRequest(lawn
|
||||
}
|
||||
|
||||
const result = await pool.query(
|
||||
`INSERT INTO lawn_sections (property_id, name, area, polygon_data, grass_type, soil_type)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
`INSERT INTO lawn_sections (property_id, name, area, polygon_data, grass_type, grass_types, soil_type)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING *`,
|
||||
[propertyId, name, calculatedArea, JSON.stringify(polygonData), grassType, soilType]
|
||||
[
|
||||
propertyId,
|
||||
name,
|
||||
calculatedArea,
|
||||
JSON.stringify(polygonData),
|
||||
grassType || (Array.isArray(grassTypes) ? grassTypes.join(', ') : null),
|
||||
grassTypes ? JSON.stringify(grassTypes) : null,
|
||||
soilType
|
||||
]
|
||||
);
|
||||
|
||||
const section = result.rows[0];
|
||||
@@ -317,6 +326,7 @@ router.post('/:id/sections', validateParams(idParamSchema), validateRequest(lawn
|
||||
area: parseFloat(section.area),
|
||||
polygonData: section.polygon_data,
|
||||
grassType: section.grass_type,
|
||||
grassTypes: section.grass_types,
|
||||
soilType: section.soil_type,
|
||||
createdAt: section.created_at,
|
||||
updatedAt: section.updated_at
|
||||
@@ -334,7 +344,7 @@ router.post('/:id/sections', validateParams(idParamSchema), validateRequest(lawn
|
||||
router.put('/:propertyId/sections/:sectionId', async (req, res, next) => {
|
||||
try {
|
||||
const { propertyId, sectionId } = req.params;
|
||||
const { name, area, polygonData, grassType, soilType } = req.body;
|
||||
const { name, area, polygonData, grassType, grassTypes, soilType } = req.body;
|
||||
|
||||
// Check if section exists and user owns the property
|
||||
const checkResult = await pool.query(
|
||||
@@ -357,10 +367,18 @@ router.put('/:propertyId/sections/:sectionId', async (req, res, next) => {
|
||||
|
||||
const result = await pool.query(
|
||||
`UPDATE lawn_sections
|
||||
SET name = $1, area = $2, polygon_data = $3, grass_type = $4, soil_type = $5, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $6
|
||||
SET name = $1, area = $2, polygon_data = $3, grass_type = $4, grass_types=$5, soil_type = $6, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $7
|
||||
RETURNING *`,
|
||||
[name, calculatedArea, JSON.stringify(polygonData), grassType, soilType, sectionId]
|
||||
[
|
||||
name,
|
||||
calculatedArea,
|
||||
JSON.stringify(polygonData),
|
||||
grassType || (Array.isArray(grassTypes) ? grassTypes.join(', ') : null),
|
||||
grassTypes ? JSON.stringify(grassTypes) : null,
|
||||
soilType,
|
||||
sectionId
|
||||
]
|
||||
);
|
||||
|
||||
const section = result.rows[0];
|
||||
@@ -375,6 +393,7 @@ router.put('/:propertyId/sections/:sectionId', async (req, res, next) => {
|
||||
area: parseFloat(section.area),
|
||||
polygonData: section.polygon_data,
|
||||
grassType: section.grass_type,
|
||||
grassTypes: section.grass_types,
|
||||
soilType: section.soil_type,
|
||||
createdAt: section.created_at,
|
||||
updatedAt: section.updated_at
|
||||
@@ -429,4 +448,4 @@ router.delete('/:propertyId/sections/:sectionId', async (req, res, next) => {
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
|
||||
@@ -63,9 +63,13 @@ const productSchema = Joi.object({
|
||||
name: Joi.string().max(255).required(),
|
||||
brand: Joi.string().max(100),
|
||||
categoryId: Joi.number().integer().positive().required(),
|
||||
productType: Joi.string().valid('granular', 'liquid').required(),
|
||||
productType: Joi.string().valid('granular', 'liquid', 'seed').required(),
|
||||
activeIngredients: Joi.string(),
|
||||
description: Joi.string()
|
||||
description: Joi.string(),
|
||||
seedBlend: Joi.alternatives().try(Joi.array().items(Joi.object({
|
||||
cultivar: Joi.string().max(200).required(),
|
||||
percent: Joi.number().min(0).max(100).required()
|
||||
})), Joi.object()).optional()
|
||||
});
|
||||
|
||||
const productRateSchema = Joi.object({
|
||||
@@ -169,6 +173,7 @@ const applicationLogSchema = Joi.object({
|
||||
averageSpeed: Joi.number().positive(),
|
||||
areaCovered: Joi.number().positive(),
|
||||
notes: Joi.string(),
|
||||
seedingType: Joi.string().valid('overseed','new_seed').allow(null).optional(),
|
||||
products: Joi.array().items(Joi.object({
|
||||
productId: Joi.number().integer().positive(),
|
||||
userProductId: Joi.number().integer().positive(),
|
||||
|
||||
Reference in New Issue
Block a user