feat: simplify Coffee management by removing unnecessary fields and enforcing fixed billing defaults
This commit is contained in:
parent
20f69c272c
commit
c62d775e66
@ -23,14 +23,12 @@ exports.list = async (req, res) => {
|
|||||||
|
|
||||||
exports.create = async (req, res) => {
|
exports.create = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { title, description, quantity, price } = req.body;
|
const { title, description, price } = req.body;
|
||||||
const currency = req.body.currency || 'EUR';
|
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 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'
|
// Fixed billing defaults
|
||||||
const interval_count = req.body.interval_count !== undefined ? Number(req.body.interval_count) : null; // supports 6 months
|
const billing_interval = 'month';
|
||||||
const sku = req.body.sku || null;
|
const interval_count = 1;
|
||||||
const slug = req.body.slug || null;
|
|
||||||
const state = req.body.state === 'false' || req.body.state === false ? false : true; // default available
|
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
|
// 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({
|
const created = await CoffeeService.create({
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
quantity: Number(quantity),
|
|
||||||
price: Number(price),
|
price: Number(price),
|
||||||
currency,
|
currency,
|
||||||
tax_rate,
|
|
||||||
is_featured,
|
is_featured,
|
||||||
billing_interval,
|
billing_interval,
|
||||||
interval_count,
|
interval_count,
|
||||||
sku,
|
|
||||||
slug,
|
|
||||||
object_storage_id,
|
object_storage_id,
|
||||||
original_filename,
|
original_filename,
|
||||||
state,
|
state,
|
||||||
@ -105,14 +99,9 @@ exports.create = async (req, res) => {
|
|||||||
exports.update = async (req, res) => {
|
exports.update = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const id = parseInt(req.params.id, 10);
|
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 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 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);
|
const state = req.body.state === undefined ? undefined : (req.body.state === 'false' || req.body.state === false ? false : true);
|
||||||
|
|
||||||
let object_storage_id;
|
let object_storage_id;
|
||||||
@ -141,15 +130,9 @@ exports.update = async (req, res) => {
|
|||||||
const updated = await CoffeeService.update(id, {
|
const updated = await CoffeeService.update(id, {
|
||||||
title: title ?? current.title,
|
title: title ?? current.title,
|
||||||
description: description ?? current.description,
|
description: description ?? current.description,
|
||||||
quantity: quantity !== undefined ? Number(quantity) : current.quantity,
|
|
||||||
price: price !== undefined ? Number(price) : current.price,
|
price: price !== undefined ? Number(price) : current.price,
|
||||||
currency: currency !== undefined ? currency : current.currency,
|
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,
|
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,
|
object_storage_id: object_storage_id !== undefined ? object_storage_id : current.object_storage_id,
|
||||||
original_filename: original_filename !== undefined ? original_filename : current.original_filename,
|
original_filename: original_filename !== undefined ? original_filename : current.original_filename,
|
||||||
state: state !== undefined ? state : !!current.state,
|
state: state !== undefined ? state : !!current.state,
|
||||||
|
|||||||
@ -540,7 +540,7 @@ async function createDatabase() {
|
|||||||
`);
|
`);
|
||||||
console.log('✅ Company stamps table created/verified');
|
console.log('✅ Company stamps table created/verified');
|
||||||
|
|
||||||
// --- Coffee / Subscriptions Table ---
|
// --- Coffee / Subscriptions Table (simplified) ---
|
||||||
await connection.query(`
|
await connection.query(`
|
||||||
CREATE TABLE IF NOT EXISTS coffee_table (
|
CREATE TABLE IF NOT EXISTS coffee_table (
|
||||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||||
@ -548,21 +548,17 @@ async function createDatabase() {
|
|||||||
description TEXT NOT NULL,
|
description TEXT NOT NULL,
|
||||||
price DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
price DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||||
currency CHAR(3) NOT NULL DEFAULT 'EUR',
|
currency CHAR(3) NOT NULL DEFAULT 'EUR',
|
||||||
tax_rate DECIMAL(5,2) NULL,
|
|
||||||
is_featured BOOLEAN NOT NULL DEFAULT FALSE,
|
is_featured BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
billing_interval ENUM('day','week','month','year') NULL,
|
billing_interval ENUM('day','week','month','year') NULL,
|
||||||
interval_count INT UNSIGNED NULL,
|
interval_count INT UNSIGNED NULL,
|
||||||
sku VARCHAR(100) NULL,
|
|
||||||
slug VARCHAR(200) NULL,
|
|
||||||
object_storage_id VARCHAR(255) NULL,
|
object_storage_id VARCHAR(255) NULL,
|
||||||
original_filename 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,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
UNIQUE KEY uq_slug (slug)
|
|
||||||
);
|
);
|
||||||
`);
|
`);
|
||||||
console.log('✅ Coffee table created/verified');
|
console.log('✅ Coffee table (simplified) created/verified');
|
||||||
|
|
||||||
// --- Matrix: Global 5-ary tree config and relations ---
|
// --- Matrix: Global 5-ary tree config and relations ---
|
||||||
await connection.query(`
|
await connection.query(`
|
||||||
|
|||||||
@ -17,23 +17,19 @@ class CoffeeRepository {
|
|||||||
async create(data, conn) {
|
async create(data, conn) {
|
||||||
const cx = conn || db;
|
const cx = conn || db;
|
||||||
const sql = `INSERT INTO coffee_table (
|
const sql = `INSERT INTO coffee_table (
|
||||||
title, description, quantity, price, currency, tax_rate, is_featured,
|
title, description, price, currency, is_featured,
|
||||||
billing_interval, interval_count, sku, slug,
|
billing_interval, interval_count,
|
||||||
object_storage_id, original_filename,
|
object_storage_id, original_filename,
|
||||||
state, created_at, updated_at
|
state, created_at, updated_at
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`;
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`;
|
||||||
const params = [
|
const params = [
|
||||||
data.title,
|
data.title,
|
||||||
data.description,
|
data.description,
|
||||||
data.quantity,
|
|
||||||
data.price,
|
data.price,
|
||||||
data.currency,
|
data.currency,
|
||||||
data.tax_rate,
|
|
||||||
data.is_featured,
|
data.is_featured,
|
||||||
data.billing_interval,
|
data.billing_interval,
|
||||||
data.interval_count,
|
data.interval_count,
|
||||||
data.sku,
|
|
||||||
data.slug,
|
|
||||||
data.object_storage_id,
|
data.object_storage_id,
|
||||||
data.original_filename,
|
data.original_filename,
|
||||||
data.state
|
data.state
|
||||||
@ -46,23 +42,19 @@ class CoffeeRepository {
|
|||||||
async update(id, data, conn) {
|
async update(id, data, conn) {
|
||||||
const cx = conn || db;
|
const cx = conn || db;
|
||||||
const sql = `UPDATE coffee_table
|
const sql = `UPDATE coffee_table
|
||||||
SET title = ?, description = ?, quantity = ?, price = ?, currency = ?, tax_rate = ?, is_featured = ?,
|
SET title = ?, description = ?, price = ?, currency = ?, is_featured = ?,
|
||||||
billing_interval = ?, interval_count = ?, sku = ?, slug = ?,
|
billing_interval = ?, interval_count = ?,
|
||||||
object_storage_id = ?, original_filename = ?,
|
object_storage_id = ?, original_filename = ?,
|
||||||
state = ?, updated_at = NOW()
|
state = ?, updated_at = NOW()
|
||||||
WHERE id = ?`;
|
WHERE id = ?`;
|
||||||
const params = [
|
const params = [
|
||||||
data.title,
|
data.title,
|
||||||
data.description,
|
data.description,
|
||||||
data.quantity,
|
|
||||||
data.price,
|
data.price,
|
||||||
data.currency,
|
data.currency,
|
||||||
data.tax_rate,
|
|
||||||
data.is_featured,
|
data.is_featured,
|
||||||
data.billing_interval,
|
data.billing_interval,
|
||||||
data.interval_count,
|
data.interval_count,
|
||||||
data.sku,
|
|
||||||
data.slug,
|
|
||||||
data.object_storage_id,
|
data.object_storage_id,
|
||||||
data.original_filename,
|
data.original_filename,
|
||||||
data.state,
|
data.state,
|
||||||
|
|||||||
@ -6,34 +6,14 @@ function validate(data) {
|
|||||||
const errors = [];
|
const errors = [];
|
||||||
if (!data.title || String(data.title).trim() === '') errors.push('title');
|
if (!data.title || String(data.title).trim() === '') errors.push('title');
|
||||||
if (!data.description || String(data.description).trim() === '') errors.push('description');
|
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);
|
const price = Number(data.price);
|
||||||
if (!Number.isFinite(price) || price < 0) errors.push('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');
|
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');
|
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');
|
if (typeof data.is_featured !== 'boolean') errors.push('is_featured');
|
||||||
|
// Enforce fixed billing defaults (month/1) if provided differently
|
||||||
// billing_interval/interval_count validation
|
if (data.billing_interval && data.billing_interval !== 'month') errors.push('billing_interval');
|
||||||
if (data.billing_interval !== undefined || data.interval_count !== undefined) {
|
if (data.interval_count && Number(data.interval_count) !== 1) errors.push('interval_count');
|
||||||
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');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +27,9 @@ class CoffeeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async create(data) {
|
async create(data) {
|
||||||
|
// Force billing defaults
|
||||||
|
data.billing_interval = 'month';
|
||||||
|
data.interval_count = 1;
|
||||||
const errors = validate(data);
|
const errors = validate(data);
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
logger.warn('[CoffeeService.create] validation_failed', { errors });
|
logger.warn('[CoffeeService.create] validation_failed', { errors });
|
||||||
@ -65,6 +48,9 @@ class CoffeeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update(id, data) {
|
async update(id, data) {
|
||||||
|
// Keep billing values fixed regardless of incoming payload
|
||||||
|
data.billing_interval = 'month';
|
||||||
|
data.interval_count = 1;
|
||||||
const errors = validate(data);
|
const errors = validate(data);
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
logger.warn('[CoffeeService.update] validation_failed', { id, errors });
|
logger.warn('[CoffeeService.update] validation_failed', { id, errors });
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user