Adding archive button to products, updating README

This commit is contained in:
Finley Ghosh 2025-12-26 19:17:03 +11:00
parent a251da2d95
commit a6798def0f
6 changed files with 166 additions and 4 deletions

View file

@ -21,7 +21,7 @@ The PHP application currently handles most functionality, while the Go applicati
### Quick Start ### Quick Start
``` shell ``` shell
git clone git@code.springupsoftware.com:cmc/cmc-sales.git git clone git@code.springupsoftware.com:springup/cmc-sales.git
cd cmc-sales cd cmc-sales
# Easy way - use the setup script # Easy way - use the setup script
@ -54,6 +54,28 @@ gunzip < backups/backup_*.sql.gz | mariadb -h 127.0.0.1 -u cmc -p cmc
Both applications share the same database, allowing for gradual migration. Both applications share the same database, allowing for gradual migration.
### Database Migrations
Database schema changes are managed using [Goose](https://github.com/pressly/goose) migrations in the `go/sql/migrations/` directory.
**Creating a new migration:**
```bash
cd go
make migrate-create name=add_new_column_to_table
```
**Running migrations:**
```bash
cd go
make migrate # Apply all pending migrations
make migrate-status # Check migration status
make migrate-down # Rollback last migration
```
**Migration files** use the Goose format with `-- +goose Up` and `-- +goose Down` sections. See `go/sql/migrations/` for examples.
**Configuration:** Database connection settings are in `go/goose.env` (create from `goose.env.example`).
### Requirements ### Requirements
- **Go Application**: Requires Go 1.23+ (for latest sqlc) - **Go Application**: Requires Go 1.23+ (for latest sqlc)

View file

@ -0,0 +1,7 @@
-- +goose Up
-- Add archived field to products table
ALTER TABLE products ADD COLUMN archived TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Product is archived and hidden from main listing';
-- +goose Down
-- Remove archived column from products
ALTER TABLE products DROP COLUMN archived;

View file

@ -19,10 +19,21 @@ class ProductsController extends AppController {
$this->Session->setFlash(__('Invalid Principle ID', true)); $this->Session->setFlash(__('Invalid Principle ID', true));
$this->redirect(array('action'=>'index')); $this->redirect(array('action'=>'index'));
} }
$this->set('products', $this->Product->find('all', array('conditions'=>array('Product.principle_id'=>$id),'order'=>'Product.title ASC'))); $this->set('products', $this->Product->find('all', array('conditions'=>array('Product.principle_id'=>$id, 'Product.archived'=>0),'order'=>'Product.title ASC')));
$this->set('principle', $this->Product->Principle->findById($id)); $this->set('principle', $this->Product->Principle->findById($id));
} }
function view_archived_principle($id = null) {
if(!$id) {
$this->Session->setFlash(__('Invalid Principle ID', true));
$this->redirect(array('action'=>'index'));
}
$this->set('products', $this->Product->find('all', array('conditions'=>array('Product.principle_id'=>$id, 'Product.archived'=>1),'order'=>'Product.title ASC')));
$this->set('principle', $this->Product->Principle->findById($id));
$currentuser = $this->getCurrentUser();
$this->set('is_admin', $currentuser['User']['access_level'] == 'admin');
}
function view($id = null) { function view($id = null) {
if (!$id) { if (!$id) {
$this->Session->setFlash(__('Invalid Product.', true)); $this->Session->setFlash(__('Invalid Product.', true));
@ -122,9 +133,73 @@ class ProductsController extends AppController {
$this->Session->setFlash(__('Invalid id for Product', true)); $this->Session->setFlash(__('Invalid id for Product', true));
$this->redirect(array('action'=>'index')); $this->redirect(array('action'=>'index'));
} }
// Check if user is admin
$currentuser = $this->getCurrentUser();
if($currentuser['User']['access_level'] != 'admin') {
$this->Session->setFlash(__('Only administrators can delete products', true));
$this->redirect(array('action'=>'index'));
return;
}
$product = $this->Product->findById($id);
if (!$product) {
$this->Session->setFlash(__('Invalid Product', true));
$this->redirect(array('action'=>'index'));
return;
}
if ($this->Product->del($id)) { if ($this->Product->del($id)) {
$this->Session->setFlash(__('Product deleted', true)); $this->Session->setFlash(__('Product deleted', true));
$this->redirect(array('action'=>'view_archived_principle', $product['Product']['principle_id']));
}
}
function archive($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid id for Product', true));
$this->redirect(array('action'=>'index')); $this->redirect(array('action'=>'index'));
return;
}
$product = $this->Product->findById($id);
if (!$product) {
$this->Session->setFlash(__('Invalid Product', true));
$this->redirect(array('action'=>'index'));
return;
}
$this->Product->id = $id;
if ($this->Product->saveField('archived', 1)) {
$this->Session->setFlash(__('Product archived', true));
$this->redirect(array('action'=>'view_principle', $product['Product']['principle_id']));
} else {
$this->Session->setFlash(__('Failed to archive product', true));
$this->redirect(array('action'=>'view_principle', $product['Product']['principle_id']));
}
}
function unarchive($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid id for Product', true));
$this->redirect(array('action'=>'index'));
return;
}
$product = $this->Product->findById($id);
if (!$product) {
$this->Session->setFlash(__('Invalid Product', true));
$this->redirect(array('action'=>'index'));
return;
}
$this->Product->id = $id;
if ($this->Product->saveField('archived', 0)) {
$this->Session->setFlash(__('Product unarchived', true));
$this->redirect(array('action'=>'view_archived_principle', $product['Product']['principle_id']));
} else {
$this->Session->setFlash(__('Failed to unarchive product', true));
$this->redirect(array('action'=>'view_archived_principle', $product['Product']['principle_id']));
} }
} }

View file

@ -0,0 +1,42 @@
<div class="products view">
<h2><?php echo $principle['Principle']['name']; ?>: Archived Products
<span style="float: right; font-size: 14px;">
<?php echo $html->link(__('Back to Active Products', true), array('action'=>'view_principle', $principle['Principle']['id'])); ?>
</span>
</h2>
<table cellpadding="0" cellspacing="0" class="productTable">
<tr>
<th>Title</th>
<th class="actions"><?php __('Actions');?></th>
</tr>
<?php
$i = 0;
foreach ($products as $product):
$class = null;
if ($i++ % 2 == 0) {
$class = ' class="altrow"';
}
?>
<tr<?php echo $class;?>>
<td>
<?php echo $product['Product']['title']; ?>
</td>
<td class="actions">
<?php echo $html->link(__('View', true), array('action'=>'view', $product['Product']['id'])); ?>
<?php echo $html->link(__('Un-Archive', true), array('action'=>'unarchive', $product['Product']['id']), null, sprintf(__('Are you sure you want to un-archive %s?', true), $product['Product']['title'])); ?>
<?php if($is_admin): ?>
<?php echo $html->link(__('Delete', true), array('action'=>'delete', $product['Product']['id']), null, sprintf(__('Are you sure you want to permanently delete %s?', true), $product['Product']['title'])); ?>
<?php endif; ?>
</td>
<?php endforeach; ?>
</table>
</div>
<?php debug($products); ?>

View file

@ -1,6 +1,10 @@
<div class="products view"> <div class="products view">
<h2><?php echo $principle['Principle']['name']; ?>: Products</h2> <h2><?php echo $principle['Principle']['name']; ?>: Products
<span style="float: right; font-size: 14px;">
<?php echo $html->link(__('View Archived Products', true), array('action'=>'view_archived_principle', $principle['Principle']['id'])); ?>
</span>
</h2>
<table cellpadding="0" cellspacing="0" class="productTable"> <table cellpadding="0" cellspacing="0" class="productTable">
<tr> <tr>
<th>Title</th> <th>Title</th>
@ -24,6 +28,7 @@ foreach ($products as $product):
<?php echo $html->link(__('View', true), array('action'=>'view', $product['Product']['id'])); ?> <?php echo $html->link(__('View', true), array('action'=>'view', $product['Product']['id'])); ?>
<?php echo $html->link(__('Edit', true), array('action'=>'edit', $product['Product']['id'])); ?> <?php echo $html->link(__('Edit', true), array('action'=>'edit', $product['Product']['id'])); ?>
<?php echo $html->link(__('Create New Product based on this', true), array('action'=>'cloneProduct', $product['Product']['id'])); ?> <?php echo $html->link(__('Create New Product based on this', true), array('action'=>'cloneProduct', $product['Product']['id'])); ?>
<?php echo $html->link(__('Archive', true), array('action'=>'archive', $product['Product']['id']), null, sprintf(__('Are you sure you want to archive %s?', true), $product['Product']['title'])); ?>
</td> </td>
<?php endforeach; ?> <?php endforeach; ?>
</table> </table>

View file

@ -618,8 +618,19 @@ td.rightAlign {
/* View Products Table */ /* View Products Table */
table.productTable { table.productTable {
width: auto; width: 100%;
}
table.productTable th {
text-align: center;
}
table.productTable td {
text-align: left;
}
table.productTable td.actions {
text-align: right;
} }