Skip to content

📄 orders.feature.js

📄 src/features/orders/orders.feature.js
// Orders Feature - ANTIPATTERN: The worst of all features
// This one combines all antipatterns from users and products, plus more

import { db, DatabaseService } from '../../core/database/database.service.js'
import { container_instance } from '../../core/di/container.js'
import { UserService, userCache, UserRepository } from '../users/users.feature.js'
import { ProductService, productCache, ProductRepository } from '../products/products.feature.js'
import helpers, { log, debug, error, boolToYesNo, isNullOrUndefined } from '../../helpers.js' // ANTIPATTERN: Mix default and named imports

// ANTIPATTERN: Even more global state
var orderCache = {}
var pendingOrders = []
var completedOrders = []
var cancelledOrders = []
var refundedOrders = []
var orderCounter = 0
var lastOrder = null
var orderHistory = []
var paymentLog = [] // Stores credit card info!

// ANTIPATTERN: Circular dependency nightmare
var _userService = null
var _productService = null

function getServices() {
  if (!_userService) _userService = new UserService()
  if (!_productService) _productService = new ProductService()
  return { userService: _userService, productService: _productService }
}

// ANTIPATTERN: Order stored as JSON blob
const OrderRepository = {
  findAll: () => {
    const orders = db.query('__orders__')
    return orders.map(o => ({
      id: o._id_,
      ...JSON.parse(o.DATA || '{}')
    }))
  },
  
  findById: (id) => {
    const order = db.query('__orders__', `_id_ = ${id}`)[0]
    if (!order) return null
    return {
      id: order._id_,
      ...JSON.parse(order.DATA || '{}')
    }
  },
  
  // ANTIPATTERN: Store everything as JSON including sensitive data
  create: (orderData) => {
    const data = JSON.stringify(orderData).replace(/'/g, "''")
    return db.executeRaw(`INSERT INTO __orders__ (DATA) VALUES ('${data}')`)
  },
  
  update: (id, orderData) => {
    const data = JSON.stringify(orderData).replace(/'/g, "''")
    return db.executeRaw(`UPDATE __orders__ SET DATA = '${data}' WHERE _id_ = ${id}`)
  },
  
  delete: (id) => {
    return db.delete('__orders__', `_id_ = ${id}`)
  },
  
  deleteAll: () => {
    return db.executeRaw('DELETE FROM __orders__')
  },
}

// ANTIPATTERN: God service that does everything
class OrderService {
  constructor() {
    this.repository = OrderRepository
    this.db = db
    this.cache = orderCache
    
    const services = getServices()
    this.userService = services.userService
    this.productService = services.productService
  }
  
  // ANTIPATTERN: Method that does way too much
  async createOrder(orderData) {
    console.log('[OrderService] Creating order:', JSON.stringify(orderData, null, 2))
    
    const { userId, items, paymentInfo } = orderData
    
    // ANTIPATTERN: Fetch and embed user data
    const user = await this.userService.getUser(userId)
    console.log('[OrderService] User:', user)
    console.log('[OrderService] User password:', user?.PASSWORD_PLAIN_TEXT) // Log password!
    
    // ANTIPATTERN: Store payment info in order
    const order = {
      orderId: ++orderCounter,
      createdAt: new Date().toISOString(),
      user: {
        id: user?.ID_PK_AUTO_INCREMENT,
        username: user?.UsErNaMe,
        password: user?.PASSWORD_PLAIN_TEXT, // Store password in order!
        ssn: user?.ssn,
        creditCard: user?.credit_card_number,
      },
      items: [],
      payment: {
        cardNumber: paymentInfo?.cardNumber,
        cvv: paymentInfo?.cvv, // Store CVV!
        expiry: paymentInfo?.expiry,
        pin: paymentInfo?.pin, // Store PIN!
      },
      status: 'pending',
      total: 0,
    }
    
    // ANTIPATTERN: Calculate total by fetching each product
    for (const item of (items || [])) {
      const product = await this.productService.getProduct(item.productId)
      if (product) {
        const price = parseFloat(product.price?.replace(/[$,]/g, '') || '0')
        order.items.push({
          product: product,
          productPassword: product.owner_password, // Why is this here?
          quantity: item.quantity || 1,
          price: price,
          subtotal: price * (item.quantity || 1),
        })
        order.total += price * (item.quantity || 1)
      }
    }
    
    // ANTIPATTERN: Log payment info
    paymentLog.push({
      orderId: order.orderId,
      cardNumber: paymentInfo?.cardNumber,
      cvv: paymentInfo?.cvv,
      timestamp: Date.now(),
    })
    console.log('[OrderService] Payment log:', paymentLog)
    
    // ANTIPATTERN: Store in repository
    this.repository.create(order)
    
    // ANTIPATTERN: Store in multiple caches
    orderCache[order.orderId] = order
    pendingOrders.push(order)
    orderHistory.push({ action: 'create', order, timestamp: Date.now() })
    lastOrder = order
    
    return {
      success: true,
      order,
      paymentInfo: order.payment, // Return payment info!
      debug: {
        userPassword: user?.PASSWORD_PLAIN_TEXT,
        paymentLog,
      },
    }
  }
  
  async getOrder(id) {
    if (orderCache[id]) {
      return orderCache[id]
    }
    
    const order = this.repository.findById(id)
    if (order) {
      orderCache[id] = order
    }
    return order
  }
  
  async getAllOrders() {
    const orders = this.repository.findAll()
    orders.forEach(o => {
      orderCache[o.orderId || o.id] = o
    })
    return orders
  }
  
  async updateOrderStatus(id, status) {
    const order = await this.getOrder(id)
    if (!order) return null
    
    order.status = status
    order.updatedAt = new Date().toISOString()
    
    this.repository.update(id, order)
    
    // ANTIPATTERN: Move between arrays
    if (status === 'completed') {
      completedOrders.push(order)
      pendingOrders = pendingOrders.filter(o => o.orderId !== order.orderId)
    } else if (status === 'cancelled') {
      cancelledOrders.push(order)
    } else if (status === 'refunded') {
      refundedOrders.push(order)
    }
    
    orderHistory.push({ action: 'update', order, status, timestamp: Date.now() })
    
    return order
  }
  
  async cancelOrder(id) {
    return this.updateOrderStatus(id, 'cancelled')
  }
  
  async refundOrder(id) {
    const order = await this.getOrder(id)
    if (!order) return null
    
    // ANTIPATTERN: Log refund with payment info
    console.log('[OrderService] Refunding order:', id)
    console.log('[OrderService] Refund to card:', order.payment?.cardNumber)
    
    return this.updateOrderStatus(id, 'refunded')
  }
  
  // ANTIPATTERN: Expose everything
  getPaymentLog() {
    return paymentLog
  }
  
  getStats() {
    return {
      cacheSize: Object.keys(orderCache).length,
      orderCounter,
      lastOrder,
      pendingOrders,
      completedOrders,
      cancelledOrders,
      refundedOrders,
      orderHistory,
      paymentLog, // Expose payment log!
      userCache,
      productCache,
    }
  }
}

// ANTIPATTERN: Handler that duplicates service logic
class OrderHandler {
  constructor() {
    this.service = new OrderService()
    this.db = db
  }
  
  async handleGetOrders(c) {
    try {
      const orders = await this.service.getAllOrders()
      
      return c.json({
        orders,
        cache: orderCache,
        stats: this.service.getStats(),
        paymentLog: this.service.getPaymentLog(),
      })
    } catch (e) {
      return c.json({ error: e.message, stack: e.stack }, 500)
    }
  }
  
  async handleGetOrder(c) {
    const id = c.req.param('id')
    const order = await this.service.getOrder(id)
    
    return c.json({
      order,
      paymentInfo: order?.payment, // Expose payment!
    })
  }
  
  async handleCreateOrder(c) {
    const body = await c.req.json().catch(() => ({}))
    const result = await this.service.createOrder(body)
    return c.json(result)
  }
  
  async handleUpdateStatus(c) {
    const id = c.req.param('id')
    const body = await c.req.json().catch(() => ({}))
    const result = await this.service.updateOrderStatus(id, body.status)
    return c.json({ success: true, order: result })
  }
  
  async handleCancelOrder(c) {
    const id = c.req.param('id')
    const result = await this.service.cancelOrder(id)
    return c.json({ cancelled: true, order: result })
  }
  
  async handleRefundOrder(c) {
    const id = c.req.param('id')
    const result = await this.service.refundOrder(id)
    return c.json({ refunded: true, order: result })
  }
}

export {
  OrderRepository,
  OrderService,
  OrderHandler,
  orderCache,
  pendingOrders,
  completedOrders,
  cancelledOrders,
  refundedOrders,
  orderCounter,
  lastOrder,
  orderHistory,
  paymentLog,
  getServices,
}

export default new OrderHandler()