<?php
// ============================================================
//  MJPOS – PurchaseController
// ============================================================

class PurchaseController extends Controller
{
    public function index(): void
    {
        Auth::requirePermission('purchases.view');

        $from      = $this->get('from',   date('Y-m-d'));
        $to        = $this->get('to',     date('Y-m-d'));
        $search    = trim($this->get('search', ''));
        $pmtStatus = $this->get('pmt',    'all');      // all|paid|partial|due
        $purStatus = $this->get('status', 'received'); // received|cancelled|all

        $where  = ['p.purchase_date BETWEEN ? AND ?'];
        $params = [$from, $to];

        if ($purStatus !== 'all') {
            $where[]  = 'p.status = ?';
            $params[] = $purStatus;
        }
        if ($pmtStatus !== 'all') {
            $where[]  = 'p.payment_status = ?';
            $params[] = $pmtStatus;
        }
        if ($search) {
            $where[]  = '(p.invoice_no LIKE ? OR s.supplier_name LIKE ?)';
            $params[] = "%$search%";
            $params[] = "%$search%";
        }

        $sql = 'SELECT p.*, s.supplier_name, s.phone AS supplier_phone
                FROM purchases p
                JOIN suppliers s ON s.id = p.supplier_id
                WHERE ' . implode(' AND ', $where) . '
                ORDER BY p.purchase_date DESC, p.id DESC';

        $pagination = Database::paginate($sql, $params, max(1, (int)$this->get('page', 1)));

        // Summary for current filter
        $summary = Database::fetchOne(
            'SELECT COUNT(*)                   AS count,
                    COALESCE(SUM(p.total),0)   AS total,
                    COALESCE(SUM(p.paid),0)    AS paid,
                    COALESCE(SUM(p.balance),0) AS balance
             FROM purchases p
             JOIN suppliers s ON s.id = p.supplier_id
             WHERE ' . implode(' AND ', $where),
            $params
        );

        // Pending purchase cheques badge
        $pendingCheques = (int) Database::fetchColumn(
            "SELECT COUNT(*) FROM cheque_tracking
             WHERE status = 'pending' AND transaction_type = 'purchase'"
        );

        $pageTitle  = 'Purchases';
        $breadcrumb = [['label' => 'Purchases']];
        ob_start();
        require APP_PATH . '/views/purchases/index.php';
        $content = ob_get_clean();
        require APP_PATH . '/views/layouts/main.php';
    }

    public function create(): void
    {
        Auth::requirePermission('purchases.create');
        $suppliers = Database::fetchAll(
            "SELECT id, supplier_name FROM suppliers WHERE status = 'active' ORDER BY supplier_name"
        );
        $pageTitle  = 'New Purchase';
        $breadcrumb = [
            ['label' => 'Purchases', 'url' => APP_URL . '/purchases'],
            ['label' => 'New Purchase'],
        ];
        ob_start();
        require APP_PATH . '/views/purchases/form.php';
        $content = ob_get_clean();
        require APP_PATH . '/views/layouts/main.php';
    }

    /**
     * AJAX: Return products previously purchased from a given supplier,
     * with the last cost price paid to that supplier for each product.
     * If the supplier has no purchase history yet, returns an empty array
     * so the frontend can fall back to showing all products.
     */
    public function supplierProducts(string $id): void
    {
        Auth::requirePermission('purchases.create');
        header('Content-Type: application/json');

        $supplierId = (int) $id;
        if (!$supplierId) {
            echo json_encode([]);
            return;
        }

        try {
            $rows = Database::fetchAll(
                "SELECT p.id, p.product_code, p.product_name, p.barcode,
                        p.current_stock, p.unit_id,
                        u.short_name AS unit,
                        p.tax_percent,
                        (SELECT pi2.cost_price
                         FROM purchase_items pi2
                         JOIN purchases pu2 ON pu2.id = pi2.purchase_id
                         WHERE pi2.product_id = p.id AND pu2.supplier_id = ?
                         ORDER BY pu2.id DESC LIMIT 1) AS last_cost_price,
                        MAX(pu.purchase_date) AS last_purchase_date,
                        COUNT(pi.id) AS times_purchased
                 FROM purchase_items pi
                 JOIN purchases pu ON pu.id = pi.purchase_id
                 JOIN products  p  ON p.id  = pi.product_id
                 LEFT JOIN units u ON u.id  = p.unit_id
                 WHERE pu.supplier_id = ? AND p.status = 'active'
                 GROUP BY p.id
                 ORDER BY times_purchased DESC, p.product_name ASC",
                [$supplierId, $supplierId]
            );

            // Use last_cost_price if available, else fall back to product's own cost_price
            foreach ($rows as &$r) {
                if ($r['last_cost_price'] === null) {
                    $r['cost_price'] = (float) Database::fetchColumn(
                        'SELECT cost_price FROM products WHERE id = ?', [$r['id']]
                    );
                } else {
                    $r['cost_price'] = (float) $r['last_cost_price'];
                }
            }

            echo json_encode($rows);
        } catch (\Exception $e) {
            echo json_encode([]);
        }
    }

    public function store(): void
    {
        Auth::requirePermission('purchases.create');
        Auth::requireCsrf();

        $supplierId  = (int)   $this->post('supplier_id');
        $date        = $this->post('purchase_date', date('Y-m-d'));
        $discount    = (float) $this->post('discount', 0);
        $paid        = (float) $this->post('paid', 0);
        $note        = trim($this->post('note', ''));
        $pmtMethod   = $this->post('payment_method_type', 'cash');
        $items       = json_decode($this->post('items_json', '[]'), true);

        // 'due' = no payment yet, zero paid, record internally as cash
        if ($pmtMethod === 'due') { $pmtMethod = 'cash'; $paid = 0.0; }

        // Cheque fields
        $chequeNo     = trim($this->post('cheque_no', ''));
        $chequeDate   = $this->post('cheque_date', $date);
        $chequeBank   = trim($this->post('cheque_bank', ''));
        $chequeBranch = trim($this->post('cheque_branch', ''));
        $chequeDrawer = trim($this->post('cheque_drawer', ''));

        if (!$supplierId || empty($items)) {
            $this->flash('error', 'Supplier and at least one product are required.');
            $this->redirect(APP_URL . '/purchases/create');
            return;
        }

        if ($pmtMethod === 'cheque' && empty($chequeNo)) {
            $this->flash('error', 'Cheque number is required for cheque payments.');
            $this->redirect(APP_URL . '/purchases/create');
            return;
        }

        $subtotal = 0;
        $tax      = 0;
        foreach ($items as &$item) {
            $item['total']   = ($item['qty'] * $item['cost']) - ($item['disc'] ?? 0);
            $item['tax_amt'] = round($item['total'] * ($item['tax_pct'] ?? 0) / 100, 2);
            $subtotal += $item['total'];
            $tax      += $item['tax_amt'];
        }
        unset($item);

        // Cheques are PENDING — don't count as paid until cleared
        $effectivePaid = ($pmtMethod === 'cheque') ? 0 : $paid;
        $total     = $subtotal - $discount + $tax;
        $balance   = $total - $effectivePaid;
        $pmtStatus = $balance <= 0 ? 'paid' : ($effectivePaid > 0 ? 'partial' : 'due');
        $invoiceNo = $this->generateInvoiceNo(setting('purchase_prefix', 'PUR'), 'purchases');

        Database::beginTransaction();
        try {
            $purId = (int) Database::insert(
                'INSERT INTO purchases
                 (supplier_id, invoice_no, purchase_date, subtotal, discount, tax, total,
                  paid, balance, payment_status, note, status, created_by)
                 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
                [$supplierId, $invoiceNo, $date, $subtotal, $discount, $tax,
                 $total, $effectivePaid, $balance, $pmtStatus, $note, 'received', Auth::id()]
            );

            // Record initial payment in supplier_payments (if any paid now)
            if ($effectivePaid > 0 || $pmtMethod === 'cheque') {
                $pmtAmount = $pmtMethod === 'cheque' ? $paid : $effectivePaid;
                if ($pmtAmount > 0) {
                    $purPmtId = (int) Database::insert(
                        'INSERT INTO supplier_payments
                         (supplier_id, purchase_id, amount, payment_date, payment_method, reference, note, created_by)
                         VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
                        [$supplierId, $purId, $pmtAmount, $date,
                         $pmtMethod, null, null, Auth::id()]
                    );

                    // Track cheque
                    if ($pmtMethod === 'cheque' && !empty($chequeNo)) {
                        $supplier = Database::fetchOne(
                            'SELECT supplier_name, phone FROM suppliers WHERE id = ?', [$supplierId]
                        );
                        Database::insert(
                            'INSERT INTO cheque_tracking
                             (transaction_type, purchase_payment_id, purchase_id, party_name, party_phone,
                              cheque_no, bank_name, branch, cheque_date, amount, status, created_by)
                             VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
                            ['purchase', $purPmtId, $purId,
                             $supplier['supplier_name'] ?? '',
                             $supplier['phone'] ?? '',
                             $chequeNo,
                             $chequeBank ?: null,
                             $chequeBranch ?: null,
                             $chequeDate ?: null,
                             $paid, 'pending', Auth::id()]
                        );
                    }
                }
            }

            foreach ($items as $item) {
                Database::execute(
                    'INSERT INTO purchase_items
                     (purchase_id, product_id, quantity, cost_price, discount, tax, total)
                     VALUES (?, ?, ?, ?, ?, ?, ?)',
                    [$purId, (int)$item['id'], $item['qty'], $item['cost'],
                     $item['disc'] ?? 0, $item['tax_amt'], $item['total']]
                );

                $newStock = (float) Database::fetchColumn(
                    'SELECT current_stock FROM products WHERE id = ?', [(int)$item['id']]
                ) + (float)$item['qty'];

                Database::execute(
                    'UPDATE products SET current_stock = current_stock + ?, cost_price = ? WHERE id = ?',
                    [$item['qty'], $item['cost'], (int)$item['id']]
                );

                Database::execute(
                    'INSERT INTO stock_movements
                     (product_id, movement_type, quantity_in, quantity_out, stock_after, reference_no, note, created_by)
                     VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
                    [(int)$item['id'], 'purchase', $item['qty'], 0, $newStock,
                     $invoiceNo, 'Purchase: ' . $invoiceNo, Auth::id()]
                );
            }

            if ($balance > 0) {
                Database::execute(
                    'UPDATE suppliers SET current_balance = current_balance + ? WHERE id = ?',
                    [$balance, $supplierId]
                );
            }

            Database::commit();
            Auth::logAudit(Auth::id(), 'purchase_create', 'purchases', "Purchase $invoiceNo");
            redirectWith(APP_URL . '/purchases', 'success', "Purchase $invoiceNo saved successfully.");

        } catch (Exception $e) {
            Database::rollback();
            $this->flash('error', 'Transaction failed: ' . $e->getMessage());
            $this->redirect(APP_URL . '/purchases/create');
        }
    }

    // ── Edit Purchase (admin only) ────────────────────────────
    public function edit(string $id): void
    {
        // Admin/super_admin/developer only
        if (!in_array(Auth::role(), ['super_admin','admin','developer'], true)) {
            redirectWith(APP_URL.'/purchases','error','Only administrators can edit purchase orders.');
            return;
        }

        $purchase = Database::fetchOne(
            'SELECT p.*, s.supplier_name
             FROM purchases p
             JOIN suppliers s ON s.id = p.supplier_id
             WHERE p.id = ?',
            [(int)$id]
        );
        if (!$purchase) {
            redirectWith(APP_URL.'/purchases','error','Purchase not found.');
            return;
        }
        if ($purchase['status'] === 'cancelled') {
            redirectWith(APP_URL.'/purchases/view/'.$id,'error','Cancelled purchases cannot be edited.');
            return;
        }

        $items = Database::fetchAll(
            'SELECT pi.*, p.product_name, p.product_code
             FROM purchase_items pi
             JOIN products p ON p.id = pi.product_id
             WHERE pi.purchase_id = ?',
            [(int)$id]
        );

        $suppliers = Database::fetchAll(
            "SELECT id, supplier_name FROM suppliers WHERE status='active' ORDER BY supplier_name"
        );

        $pageTitle  = 'Edit Purchase — ' . $purchase['invoice_no'];
        $breadcrumb = [
            ['label'=>'Purchases','url'=>APP_URL.'/purchases'],
            ['label'=>$purchase['invoice_no'],'url'=>APP_URL.'/purchases/view/'.$id],
            ['label'=>'Edit'],
        ];
        ob_start();
        require APP_PATH . '/views/purchases/edit.php';
        $content = ob_get_clean();
        require APP_PATH . '/views/layouts/main.php';
    }

    // ── Update Purchase (admin only) ──────────────────────────
    public function update(string $id): void
    {
        if (!in_array(Auth::role(), ['super_admin','admin','developer'], true)) {
            redirectWith(APP_URL.'/purchases','error','Only administrators can edit purchase orders.');
            return;
        }
        Auth::requireCsrf();

        $purId      = (int) $id;
        $purchase   = Database::fetchOne('SELECT * FROM purchases WHERE id=?', [$purId]);
        if (!$purchase || $purchase['status'] === 'cancelled') {
            redirectWith(APP_URL.'/purchases','error','Purchase not found or cancelled.');
            return;
        }

        $date     = $this->post('purchase_date', date('Y-m-d'));
        $discount = (float) $this->post('discount', 0);
        $note     = trim($this->post('note', ''));
        $items    = json_decode($this->post('items_json','[]'), true);

        if (empty($items)) {
            redirectWith(APP_URL.'/purchases/edit/'.$purId,'error','At least one product is required.');
            return;
        }

        // Recalculate totals
        $subtotal = 0;
        $tax      = 0;
        foreach ($items as &$item) {
            $item['total']   = ($item['qty'] * $item['cost']) - ($item['disc'] ?? 0);
            $item['tax_amt'] = round($item['total'] * ($item['tax_pct'] ?? 0) / 100, 2);
            $subtotal       += $item['total'];
            $tax            += $item['tax_amt'];
        }
        unset($item);

        $total      = $subtotal - $discount + $tax;
        $paid       = (float) $purchase['paid'];
        $balance    = max(0, $total - $paid);
        $pmtStatus  = $balance <= 0 ? 'paid' : ($paid > 0 ? 'partial' : 'due');

        Database::beginTransaction();
        try {
            // ── Reverse old stock movements ────────────────────
            $oldItems = Database::fetchAll(
                'SELECT product_id, quantity, cost_price FROM purchase_items WHERE purchase_id=?',
                [$purId]
            );
            foreach ($oldItems as $old) {
                Database::execute(
                    'UPDATE products SET current_stock = current_stock - ? WHERE id=?',
                    [$old['quantity'], $old['product_id']]
                );
                // Remove matching stock movement
                Database::execute(
                    "DELETE FROM stock_movements WHERE product_id=? AND reference_no=? AND movement_type='purchase'",
                    [$old['product_id'], $purchase['invoice_no']]
                );
            }

            // ── Reverse old supplier balance impact ────────────
            $oldBalance = (float)$purchase['balance'];
            if ($oldBalance > 0) {
                Database::execute(
                    'UPDATE suppliers SET current_balance = current_balance - ? WHERE id=?',
                    [$oldBalance, $purchase['supplier_id']]
                );
            }

            // ── Delete old items, insert new ───────────────────
            Database::execute('DELETE FROM purchase_items WHERE purchase_id=?', [$purId]);

            foreach ($items as $item) {
                Database::execute(
                    'INSERT INTO purchase_items
                     (purchase_id,product_id,quantity,cost_price,discount,tax,total)
                     VALUES (?,?,?,?,?,?,?)',
                    [$purId,(int)$item['id'],$item['qty'],$item['cost'],
                     $item['disc']??0,$item['tax_amt'],$item['total']]
                );
                $newStock = (float)Database::fetchColumn(
                    'SELECT current_stock FROM products WHERE id=?',[(int)$item['id']]
                ) + (float)$item['qty'];

                Database::execute(
                    'UPDATE products SET current_stock=current_stock+?, cost_price=? WHERE id=?',
                    [$item['qty'],$item['cost'],(int)$item['id']]
                );
                Database::execute(
                    'INSERT INTO stock_movements
                     (product_id,movement_type,quantity_in,quantity_out,stock_after,reference_no,note,created_by)
                     VALUES (?,?,?,?,?,?,?,?)',
                    [(int)$item['id'],'purchase',$item['qty'],0,$newStock,
                     $purchase['invoice_no'],'Purchase edit: '.$purchase['invoice_no'],Auth::id()]
                );
            }

            // ── Update purchases header ────────────────────────
            Database::execute(
                'UPDATE purchases SET
                 purchase_date=?,subtotal=?,discount=?,tax=?,total=?,
                 balance=?,payment_status=?,note=?,updated_by=?
                 WHERE id=?',
                [$date,$subtotal,$discount,$tax,$total,
                 $balance,$pmtStatus,$note,Auth::id(),$purId]
            );

            // ── Apply new supplier balance ─────────────────────
            if ($balance > 0) {
                Database::execute(
                    'UPDATE suppliers SET current_balance=current_balance+? WHERE id=?',
                    [$balance,$purchase['supplier_id']]
                );
            }

            Database::commit();
            Auth::logAudit(Auth::id(),'purchase_update','purchases',
                "Edited purchase {$purchase['invoice_no']}");
            redirectWith(APP_URL.'/purchases/view/'.$purId,'success',
                "Purchase {$purchase['invoice_no']} updated successfully.");

        } catch (Exception $e) {
            Database::rollback();
            redirectWith(APP_URL.'/purchases/edit/'.$purId,'error',
                'Update failed: '.$e->getMessage());
        }
    }

    public function show(string $id): void
    {
        Auth::requirePermission('purchases.view');
        $purchase = Database::fetchOne(
            'SELECT p.*, s.supplier_name, s.phone AS sup_phone
             FROM purchases p
             JOIN suppliers s ON s.id = p.supplier_id
             WHERE p.id = ?',
            [(int)$id]
        );
        if (!$purchase) {
            http_response_code(404);
            require APP_PATH . '/views/errors/404.php';
            return;
        }
        $items = Database::fetchAll(
            'SELECT pi.*, pr.product_name, pr.product_code
             FROM purchase_items pi
             JOIN products pr ON pr.id = pi.product_id
             WHERE pi.purchase_id = ?',
            [(int)$id]
        );
        $pageTitle  = 'Purchase ' . $purchase['invoice_no'];
        $breadcrumb = [
            ['label' => 'Purchases', 'url' => APP_URL . '/purchases'],
            ['label' => $purchase['invoice_no']],
        ];
        ob_start();
        require APP_PATH . '/views/purchases/view.php';
        $content = ob_get_clean();
        require APP_PATH . '/views/layouts/main.php';
    }

    public function recordPayment(string $id): void
    {
        Auth::requirePermission('purchases.edit');
        Auth::requireCsrf();

        $purchase = Database::fetchOne(
            "SELECT * FROM purchases WHERE id = ? AND status = 'received'",
            [(int)$id]
        );
        if (!$purchase) {
            $this->flash('error', 'Purchase not found.');
            $this->back();
            return;
        }

        $amount  = (float) $this->post('amount', 0);
        $method  = $this->post('payment_method', 'cash');
        $ref     = trim($this->post('reference', ''));
        $note    = trim($this->post('note', ''));
        $date    = $this->post('payment_date', date('Y-m-d'));

        // Cheque-specific fields
        $chequeNo     = trim($this->post('cheque_no', ''));
        $chequeDate   = $this->post('cheque_date', $date);
        $chequeBankName   = trim($this->post('cheque_bank', ''));
        $chequeBranch = trim($this->post('cheque_branch', ''));
        $chequeDrawer = trim($this->post('cheque_drawer', ''));

        if ($method === 'cheque' && empty($chequeNo)) {
            redirectWith(APP_URL.'/purchases/view/'.$id,'error','Cheque number is required.');
            return;
        }

        if ($amount <= 0) {
            $this->flash('error', 'Payment amount must be greater than zero.');
            $this->redirect(APP_URL . '/purchases/view/' . $id);
            return;
        }

        $maxPayable = (float) $purchase['balance'];
        if ($amount > $maxPayable) {
            $amount = $maxPayable;
        }

        Database::beginTransaction();
        try {
            // Record in supplier_payments
            $purPmtId = (int) Database::insert(
                'INSERT INTO supplier_payments
                 (supplier_id, purchase_id, amount, payment_date, payment_method, reference, note, created_by)
                 VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
                [$purchase['supplier_id'], (int)$id, $amount, $date,
                 $method, $ref ?: null, $note ?: null, Auth::id()]
            );

            // If cheque — save to cheque_tracking
            if ($method === 'cheque') {
                $supplier = Database::fetchOne(
                    'SELECT supplier_name, phone FROM suppliers WHERE id = ?',
                    [$purchase['supplier_id']]
                );
                Database::insert(
                    'INSERT INTO cheque_tracking
                     (transaction_type, purchase_payment_id, purchase_id, party_name, party_phone,
                      cheque_no, bank_name, branch, cheque_date, amount, status, created_by)
                     VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
                    ['purchase', $purPmtId, (int)$id,
                     $supplier['supplier_name'] ?? '',
                     $supplier['phone'] ?? '',
                     $chequeNo,
                     $chequeBankName ?: null,
                     $chequeBranch   ?: null,
                     $chequeDate     ?: null,
                     $amount, 'pending', Auth::id()]
                );
            }

            // Update purchase paid / balance
            $newPaid    = round((float)$purchase['paid']    + $amount, 2);
            $newBalance = round((float)$purchase['balance'] - $amount, 2);
            $newStatus  = $newBalance <= 0 ? 'paid' : 'partial';

            Database::execute(
                'UPDATE purchases SET paid = ?, balance = ?, payment_status = ? WHERE id = ?',
                [$newPaid, max(0, $newBalance), $newStatus, (int)$id]
            );

            // Reduce supplier outstanding balance
            Database::execute(
                'UPDATE suppliers SET current_balance = GREATEST(0, current_balance - ?) WHERE id = ?',
                [$amount, $purchase['supplier_id']]
            );

            Database::commit();

            Auth::logAudit(Auth::id(), 'purchase_payment', 'purchases',
                "Payment of {$amount} for purchase {$purchase['invoice_no']}");

            redirectWith(
                APP_URL . '/purchases/view/' . $id,
                'success',
                'Payment of ' . currency($amount) . ' recorded successfully.'
            );

        } catch (Exception $e) {
            Database::rollback();
            redirectWith(
                APP_URL . '/purchases/view/' . $id,
                'error',
                'Payment failed: ' . $e->getMessage()
            );
        }
    }

    public function cancel(string $id): void
    {
        Auth::requirePermission('purchases.edit');
        Auth::requireCsrf();

        $pur = Database::fetchOne(
            "SELECT * FROM purchases WHERE id = ? AND status = 'received'",
            [(int)$id]
        );
        if (!$pur) {
            $this->flash('error', 'Purchase not found or already cancelled.');
            $this->back();
            return;
        }

        Database::beginTransaction();
        try {
            $items = Database::fetchAll(
                'SELECT * FROM purchase_items WHERE purchase_id = ?', [(int)$id]
            );
            foreach ($items as $item) {
                $ns = max(0, (float) Database::fetchColumn(
                    'SELECT current_stock FROM products WHERE id = ?', [$item['product_id']]
                ) - (float)$item['quantity']);

                Database::execute(
                    'UPDATE products SET current_stock = current_stock - ? WHERE id = ?',
                    [$item['quantity'], $item['product_id']]
                );
                Database::execute(
                    'INSERT INTO stock_movements
                     (product_id, movement_type, quantity_in, quantity_out, stock_after, reference_no, note, created_by)
                     VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
                    [$item['product_id'], 'purchase_return', 0, $item['quantity'], $ns,
                     $pur['invoice_no'], 'Purchase cancelled', Auth::id()]
                );
            }

            Database::execute(
                "UPDATE purchases SET status = 'cancelled' WHERE id = ?", [(int)$id]
            );

            if ($pur['balance'] > 0) {
                Database::execute(
                    'UPDATE suppliers SET current_balance = GREATEST(0, current_balance - ?) WHERE id = ?',
                    [$pur['balance'], $pur['supplier_id']]
                );
            }

            Database::commit();
            Auth::logAudit(Auth::id(), 'purchase_cancel', 'purchases',
                "Cancelled purchase {$pur['invoice_no']}");
            redirectWith(APP_URL . '/purchases', 'success', 'Purchase cancelled.');

        } catch (Exception $e) {
            Database::rollback();
            $this->flash('error', $e->getMessage());
            $this->back();
        }
    }
}