From c62d775e668dcebdb6ed09ff4f2b4c8e6283cd48 Mon Sep 17 00:00:00 2001 From: seaznCode Date: Thu, 20 Nov 2025 17:38:04 +0100 Subject: [PATCH] feat: simplify Coffee management by removing unnecessary fields and enforcing fixed billing defaults --- controller/admin/CoffeeController.js | 27 +++------------- database/createDb.js | 12 +++---- .../subscriptions/CoffeeRepository.js | 22 ++++--------- services/subscriptions/CoffeeService.js | 32 ++++++------------- 4 files changed, 25 insertions(+), 68 deletions(-) diff --git a/controller/admin/CoffeeController.js b/controller/admin/CoffeeController.js index a09a2c6..868d1e3 100644 --- a/controller/admin/CoffeeController.js +++ b/controller/admin/CoffeeController.js @@ -23,14 +23,12 @@ exports.list = async (req, res) => { exports.create = async (req, res) => { try { - const { title, description, quantity, price } = req.body; + const { title, description, price } = req.body; const currency = req.body.currency || 'EUR'; - const tax_rate = req.body.tax_rate !== undefined ? Number(req.body.tax_rate) : null; const is_featured = req.body.is_featured === 'true' || req.body.is_featured === true ? true : false; - const billing_interval = req.body.billing_interval || null; // 'day'|'week'|'month'|'year' - const interval_count = req.body.interval_count !== undefined ? Number(req.body.interval_count) : null; // supports 6 months - const sku = req.body.sku || null; - const slug = req.body.slug || null; + // Fixed billing defaults + const billing_interval = 'month'; + const interval_count = 1; const state = req.body.state === 'false' || req.body.state === false ? false : true; // default available // If file uploaded, push to Exoscale and set object_storage_id @@ -62,15 +60,11 @@ exports.create = async (req, res) => { const created = await CoffeeService.create({ title, description, - quantity: Number(quantity), price: Number(price), currency, - tax_rate, is_featured, billing_interval, interval_count, - sku, - slug, object_storage_id, original_filename, state, @@ -105,14 +99,9 @@ exports.create = async (req, res) => { exports.update = async (req, res) => { try { const id = parseInt(req.params.id, 10); - const { title, description, quantity, price } = req.body; + const { title, description, price } = req.body; const currency = req.body.currency; - const tax_rate = req.body.tax_rate !== undefined ? Number(req.body.tax_rate) : undefined; const is_featured = req.body.is_featured === undefined ? undefined : (req.body.is_featured === 'true' || req.body.is_featured === true); - const billing_interval = req.body.billing_interval; - const interval_count = req.body.interval_count !== undefined ? Number(req.body.interval_count) : undefined; - const sku = req.body.sku; - const slug = req.body.slug; const state = req.body.state === undefined ? undefined : (req.body.state === 'false' || req.body.state === false ? false : true); let object_storage_id; @@ -141,15 +130,9 @@ exports.update = async (req, res) => { const updated = await CoffeeService.update(id, { title: title ?? current.title, description: description ?? current.description, - quantity: quantity !== undefined ? Number(quantity) : current.quantity, price: price !== undefined ? Number(price) : current.price, currency: currency !== undefined ? currency : current.currency, - tax_rate: tax_rate !== undefined ? tax_rate : current.tax_rate, is_featured: is_featured !== undefined ? is_featured : !!current.is_featured, - billing_interval: billing_interval !== undefined ? billing_interval : current.billing_interval, - interval_count: interval_count !== undefined ? interval_count : current.interval_count, - sku: sku !== undefined ? sku : current.sku, - slug: slug !== undefined ? slug : current.slug, object_storage_id: object_storage_id !== undefined ? object_storage_id : current.object_storage_id, original_filename: original_filename !== undefined ? original_filename : current.original_filename, state: state !== undefined ? state : !!current.state, diff --git a/database/createDb.js b/database/createDb.js index 813d324..ed911d8 100644 --- a/database/createDb.js +++ b/database/createDb.js @@ -540,7 +540,7 @@ async function createDatabase() { `); console.log('✅ Company stamps table created/verified'); - // --- Coffee / Subscriptions Table --- + // --- Coffee / Subscriptions Table (simplified) --- await connection.query(` CREATE TABLE IF NOT EXISTS coffee_table ( id BIGINT AUTO_INCREMENT PRIMARY KEY, @@ -548,21 +548,17 @@ async function createDatabase() { description TEXT NOT NULL, price DECIMAL(10,2) NOT NULL DEFAULT 0.00, currency CHAR(3) NOT NULL DEFAULT 'EUR', - tax_rate DECIMAL(5,2) NULL, is_featured BOOLEAN NOT NULL DEFAULT FALSE, billing_interval ENUM('day','week','month','year') NULL, interval_count INT UNSIGNED NULL, - sku VARCHAR(100) NULL, - slug VARCHAR(200) NULL, object_storage_id VARCHAR(255) NULL, original_filename VARCHAR(255) NULL, - state BOOLEAN NOT NULL DEFAULT TRUE, -- available=true, unavailable=false + state BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - UNIQUE KEY uq_slug (slug) + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); `); - console.log('✅ Coffee table created/verified'); + console.log('✅ Coffee table (simplified) created/verified'); // --- Matrix: Global 5-ary tree config and relations --- await connection.query(` diff --git a/repositories/subscriptions/CoffeeRepository.js b/repositories/subscriptions/CoffeeRepository.js index 38c321a..066142a 100644 --- a/repositories/subscriptions/CoffeeRepository.js +++ b/repositories/subscriptions/CoffeeRepository.js @@ -17,28 +17,24 @@ class CoffeeRepository { async create(data, conn) { const cx = conn || db; const sql = `INSERT INTO coffee_table ( - title, description, quantity, price, currency, tax_rate, is_featured, - billing_interval, interval_count, sku, slug, + title, description, price, currency, is_featured, + billing_interval, interval_count, object_storage_id, original_filename, state, created_at, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`; + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`; const params = [ data.title, data.description, - data.quantity, data.price, data.currency, - data.tax_rate, data.is_featured, data.billing_interval, data.interval_count, - data.sku, - data.slug, data.object_storage_id, data.original_filename, data.state ]; - const [result] = await cx.query(sql, params); + const [result] = await cx.query(sql, params); logger.info('[CoffeeRepository.create] insert', { id: result.insertId }); return { id: result.insertId, ...data }; } @@ -46,29 +42,25 @@ class CoffeeRepository { async update(id, data, conn) { const cx = conn || db; const sql = `UPDATE coffee_table - SET title = ?, description = ?, quantity = ?, price = ?, currency = ?, tax_rate = ?, is_featured = ?, - billing_interval = ?, interval_count = ?, sku = ?, slug = ?, + SET title = ?, description = ?, price = ?, currency = ?, is_featured = ?, + billing_interval = ?, interval_count = ?, object_storage_id = ?, original_filename = ?, state = ?, updated_at = NOW() WHERE id = ?`; const params = [ data.title, data.description, - data.quantity, data.price, data.currency, - data.tax_rate, data.is_featured, data.billing_interval, data.interval_count, - data.sku, - data.slug, data.object_storage_id, data.original_filename, data.state, id ]; - const [result] = await cx.query(sql, params); + const [result] = await cx.query(sql, params); logger.info('[CoffeeRepository.update] update', { id, affected: result.affectedRows }); return result.affectedRows > 0; } diff --git a/services/subscriptions/CoffeeService.js b/services/subscriptions/CoffeeService.js index 56233d6..cce175f 100644 --- a/services/subscriptions/CoffeeService.js +++ b/services/subscriptions/CoffeeService.js @@ -6,34 +6,14 @@ function validate(data) { const errors = []; if (!data.title || String(data.title).trim() === '') errors.push('title'); if (!data.description || String(data.description).trim() === '') errors.push('description'); - const q = Number(data.quantity); - if (!Number.isFinite(q) || q < 0) errors.push('quantity'); const price = Number(data.price); if (!Number.isFinite(price) || price < 0) errors.push('price'); - // state is boolean (available=true/unavailable=false) if (typeof data.state !== 'boolean') errors.push('state'); - - // currency optional; default EUR if missing if (data.currency && String(data.currency).length > 3) errors.push('currency'); - - // tax_rate optional must be >= 0 if provided - if (data.tax_rate !== undefined && data.tax_rate !== null) { - const tr = Number(data.tax_rate); - if (!Number.isFinite(tr) || tr < 0) errors.push('tax_rate'); - } - - // is_featured boolean if (typeof data.is_featured !== 'boolean') errors.push('is_featured'); - - // billing_interval/interval_count validation - if (data.billing_interval !== undefined || data.interval_count !== undefined) { - const allowed = ['day','week','month','year']; - if (data.billing_interval && !allowed.includes(String(data.billing_interval))) errors.push('billing_interval'); - if (data.interval_count !== undefined) { - const ic = Number(data.interval_count); - if (!Number.isFinite(ic) || ic <= 0) errors.push('interval_count'); - } - } + // Enforce fixed billing defaults (month/1) if provided differently + if (data.billing_interval && data.billing_interval !== 'month') errors.push('billing_interval'); + if (data.interval_count && Number(data.interval_count) !== 1) errors.push('interval_count'); return errors; } @@ -47,6 +27,9 @@ class CoffeeService { } async create(data) { + // Force billing defaults + data.billing_interval = 'month'; + data.interval_count = 1; const errors = validate(data); if (errors.length) { logger.warn('[CoffeeService.create] validation_failed', { errors }); @@ -65,6 +48,9 @@ class CoffeeService { } async update(id, data) { + // Keep billing values fixed regardless of incoming payload + data.billing_interval = 'month'; + data.interval_count = 1; const errors = validate(data); if (errors.length) { logger.warn('[CoffeeService.update] validation_failed', { id, errors });