const CoffeeRepository = require('../../repositories/subscriptions/CoffeeRepository'); const UnitOfWork = require('../../database/UnitOfWork'); const { logger } = require('../../middleware/logger'); 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'); } } return errors; } class CoffeeService { async list() { return CoffeeRepository.listAll(); } async get(id) { return CoffeeRepository.getById(id); } async create(data) { const errors = validate(data); if (errors.length) { logger.warn('[CoffeeService.create] validation_failed', { errors }); throw Object.assign(new Error('Validation failed'), { code: 'VALIDATION_ERROR', errors }); } const uow = new UnitOfWork(); try { await uow.start(); const result = await CoffeeRepository.create(data, uow.connection); await uow.commit(); return result; } catch (e) { try { await uow.rollback(e); } catch(_) {} throw e; } } async update(id, data) { const errors = validate(data); if (errors.length) { logger.warn('[CoffeeService.update] validation_failed', { id, errors }); throw Object.assign(new Error('Validation failed'), { code: 'VALIDATION_ERROR', errors }); } const uow = new UnitOfWork(); try { await uow.start(); await CoffeeRepository.update(id, data, uow.connection); const updated = await CoffeeRepository.getById(id, uow.connection); await uow.commit(); return updated; } catch (e) { try { await uow.rollback(e); } catch(_) {} throw e; } } async setState(id, state) { const uow = new UnitOfWork(); try { await uow.start(); await CoffeeRepository.setState(id, !!state, uow.connection); const updated = await CoffeeRepository.getById(id, uow.connection); await uow.commit(); return updated; } catch (e) { try { await uow.rollback(e); } catch(_) {} throw e; } } async delete(id) { const uow = new UnitOfWork(); try { await uow.start(); const ok = await CoffeeRepository.delete(id, uow.connection); await uow.commit(); return ok; } catch (e) { try { await uow.rollback(e); } catch(_) {} throw e; } } } module.exports = new CoffeeService();