seeding app

This commit is contained in:
Jake Kasper
2025-09-04 10:00:27 -05:00
parent 9d8b1a385c
commit 3ddbc32fe0
6 changed files with 60 additions and 13 deletions

View File

@@ -192,6 +192,8 @@ router.get('/plans', async (req, res, next) => {
status: plan.status,
plannedDate: plan.planned_date,
notes: plan.notes,
applicationType: plan.application_type,
seedingMode: plan.seeding_mode,
sectionNames: plan.section_names, // Multiple section names comma-separated
sectionCount: parseInt(plan.section_count),
totalSectionArea: parseFloat(plan.total_section_area),
@@ -296,6 +298,8 @@ router.get('/plans/:id', validateParams(idParamSchema), async (req, res, next) =
status: plan.status,
plannedDate: plan.planned_date,
notes: plan.notes,
applicationType: plan.application_type,
seedingMode: plan.seeding_mode,
sections: sections, // Array of sections instead of single section
totalArea: totalArea,
property: {
@@ -353,7 +357,9 @@ router.post('/plans', validateRequest(applicationPlanSchema), async (req, res, n
products,
areaSquareFeet,
equipment,
nozzle
nozzle,
applicationType: planApplicationType,
seedingMode
} = req.body;
// Handle both single and multiple lawn sections
@@ -427,10 +433,10 @@ router.post('/plans', validateRequest(applicationPlanSchema), async (req, res, n
// Create application plan (no longer has lawn_section_id column)
const planResult = await client.query(
`INSERT INTO application_plans (user_id, equipment_id, nozzle_id, planned_date, notes)
VALUES ($1, $2, $3, $4, $5)
`INSERT INTO application_plans (user_id, equipment_id, nozzle_id, planned_date, notes, application_type, seeding_mode)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING *`,
[req.user.id, equipmentId, nozzleId, plannedDate, notes]
[req.user.id, equipmentId, nozzleId, plannedDate, notes, planApplicationType || null, seedingMode || null]
);
const plan = planResult.rows[0];
@@ -686,10 +692,11 @@ router.put('/plans/:id', validateParams(idParamSchema), validateRequest(applicat
const updateResult = await client.query(
`UPDATE application_plans
SET equipment_id = $1, nozzle_id = $2,
planned_date = $3, notes = $4, updated_at = CURRENT_TIMESTAMP
WHERE id = $5
planned_date = $3, notes = $4, application_type = $5, seeding_mode = $6,
updated_at = CURRENT_TIMESTAMP
WHERE id = $7
RETURNING *`,
[equipmentId, nozzleId, plannedDate, notes, planId]
[equipmentId, nozzleId, plannedDate, notes, req.body.applicationType || null, req.body.seedingMode || null, planId]
);
const plan = updateResult.rows[0];

View File

@@ -99,6 +99,27 @@ router.get('/', async (req, res, next) => {
const userResult = await pool.query(userProductsQuery, [req.user.id]);
// Attach base product rates to user products so seed scenarios can pick proper rates
let baseRatesById = {};
const baseIds = userResult.rows.map(r => r.product_id).filter(Boolean);
if (baseIds.length) {
const ratesRes = await pool.query(
`SELECT product_id, id, application_type, rate_amount, rate_unit, notes
FROM product_rates
WHERE product_id = ANY($1::int[])`, [baseIds]
);
ratesRes.rows.forEach(r => {
if (!baseRatesById[r.product_id]) baseRatesById[r.product_id] = [];
baseRatesById[r.product_id].push({
id: r.id,
applicationType: r.application_type,
rateAmount: parseFloat(r.rate_amount),
rateUnit: r.rate_unit,
notes: r.notes
});
});
}
res.json({
success: true,
data: {
@@ -133,6 +154,7 @@ router.get('/', async (req, res, next) => {
customRateAmount: parseFloat(product.custom_rate_amount),
customRateUnit: product.custom_rate_unit,
notes: product.notes,
rates: baseRatesById[product.product_id] || [],
isShared: false,
createdAt: product.created_at,
updatedAt: product.updated_at

View File

@@ -140,6 +140,8 @@ const applicationPlanSchema = Joi.object({
nozzleId: Joi.number().integer().positive().optional(),
plannedDate: Joi.date().required(),
notes: Joi.string().allow('').optional(),
applicationType: Joi.string().valid('liquid','granular','seed').optional(),
seedingMode: Joi.string().valid('overseed','new_seed').allow(null).optional(),
areaSquareFeet: Joi.number().positive().optional(),
equipment: Joi.object({
id: Joi.number().integer().positive().optional(),