Start to develop the budget module

This commit is contained in:
Frederic Guillot
2015-03-12 23:03:51 -04:00
parent 925ede9b48
commit 4700139a86
12 changed files with 332 additions and 4 deletions

111
app/Controller/Budget.php Normal file
View File

@@ -0,0 +1,111 @@
<?php
namespace Controller;
/**
* Budget
*
* @package controller
* @author Frederic Guillot
*/
class Budget extends Base
{
/**
* Budget index page
*
* @access public
*/
public function index()
{
$project = $this->getProject();
$this->response->html($this->projectLayout('budget/index', array(
'total' => $this->budget->getTotal($project['id']),
'project' => $project,
'title' => t('Budget')
)));
}
/**
* Create budget lines
*
* @access public
*/
public function create(array $values = array(), array $errors = array())
{
$project = $this->getProject();
if (empty($values)) {
$values['date'] = date('Y-m-d');
}
$this->response->html($this->projectLayout('budget/create', array(
'lines' => $this->budget->getAll($project['id']),
'values' => $values + array('project_id' => $project['id']),
'errors' => $errors,
'project' => $project,
'title' => t('Budget')
)));
}
/**
* Validate and save a new budget
*
* @access public
*/
public function save()
{
$project = $this->getProject();
$values = $this->request->getValues();
list($valid, $errors) = $this->budget->validateCreation($values);
if ($valid) {
if ($this->budget->create($values['project_id'], $values['amount'], $values['comment'], $values['date'])) {
$this->session->flash(t('The budget line have been created successfully.'));
$this->response->redirect($this->helper->url('budget', 'create', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to create the budget line.'));
}
}
$this->create($values, $errors);
}
/**
* Confirmation dialog before removing a budget
*
* @access public
*/
public function confirm()
{
$project = $this->getProject();
$this->response->html($this->projectLayout('budget/remove', array(
'project' => $project,
'budget_id' => $this->request->getIntegerParam('budget_id'),
'title' => t('Remove a budget line'),
)));
}
/**
* Remove a budget
*
* @access public
*/
public function remove()
{
$this->checkCSRFParam();
$project = $this->getProject();
if ($this->budget->remove($this->request->getIntegerParam('budget_id'))) {
$this->session->flash(t('Budget line removed successfully.'));
} else {
$this->session->flashError(t('Unable to remove this budget line.'));
}
$this->response->redirect($this->helper->url('budget', 'create', array('project_id' => $project['id'])));
}
}

View File

@@ -56,6 +56,7 @@ class Acl extends Base
'export' => array('tasks', 'subtasks', 'summary'),
'project' => array('edit', 'update', 'share', 'integration', 'users', 'alloweverybody', 'allow', 'setowner', 'revoke', 'duplicate', 'disable', 'enable'),
'swimlane' => '*',
'budget' => '*',
);
/**

View File

@@ -16,6 +16,7 @@ use Pimple\Container;
* @property \Model\Action $action
* @property \Model\Authentication $authentication
* @property \Model\Board $board
* @property \Model\Budget $budget
* @property \Model\Category $category
* @property \Model\Comment $comment
* @property \Model\CommentHistory $commentHistory

101
app/Model/Budget.php Normal file
View File

@@ -0,0 +1,101 @@
<?php
namespace Model;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
/**
* Budget
*
* @package model
* @author Frederic Guillot
*/
class Budget extends Base
{
/**
* SQL table name
*
* @var string
*/
const TABLE = 'budget_lines';
/**
* Get all budget lines for a project
*
* @access public
* @param integer $project_id
* @return array
*/
public function getAll($project_id)
{
return $this->db->table(self::TABLE)->eq('project_id', $project_id)->desc('date')->findAll();
}
/**
* Get the current total of the budget
*
* @access public
* @param integer $project_id
* @return float
*/
public function getTotal($project_id)
{
$result = $this->db->table(self::TABLE)->columns('SUM(amount) as total')->eq('project_id', $project_id)->findOne();
return isset($result['total']) ? (float) $result['total'] : 0;
}
/**
* Add a new budget line in the database
*
* @access public
* @param integer $project_id
* @param float $amount
* @param string $comment
* @param string $date
* @return boolean|integer
*/
public function create($project_id, $amount, $comment, $date = '')
{
$values = array(
'project_id' => $project_id,
'amount' => $amount,
'comment' => $comment,
'date' => $date ?: date('Y-m-d'),
);
return $this->persist(self::TABLE, $values);
}
/**
* Remove a specific budget line
*
* @access public
* @param integer $budget_id
* @return boolean
*/
public function remove($budget_id)
{
return $this->db->table(self::TABLE)->eq('id', $budget_id)->remove();
}
/**
* Validate creation
*
* @access public
* @param array $values Form values
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
*/
public function validateCreation(array $values)
{
$v = new Validator($values, array(
new Validators\Required('project_id', t('Field required')),
new Validators\Required('amount', t('Field required')),
));
return array(
$v->execute(),
$v->getErrors()
);
}
}

View File

@@ -6,7 +6,20 @@ use PDO;
use Core\Security;
use Model\Link;
const VERSION = 51;
const VERSION = 52;
function version_52($pdo)
{
$pdo->exec('CREATE TABLE budget_lines (
`id` INT NOT NULL AUTO_INCREMENT,
`project_id` INT NOT NULL,
`amount` FLOAT NOT NULL,
`date` VARCHAR(10) NOT NULL,
`comment` TEXT,
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE,
PRIMARY KEY(id)
) ENGINE=InnoDB CHARSET=utf8');
}
function version_51($pdo)
{

View File

@@ -6,7 +6,19 @@ use PDO;
use Core\Security;
use Model\Link;
const VERSION = 32;
const VERSION = 33;
function version_33($pdo)
{
$pdo->exec('CREATE TABLE budget_lines (
"id" SERIAL PRIMARY KEY,
"project_id" INTEGER NOT NULL,
"amount" REAL NOT NULL,
"date" VARCHAR(10) NOT NULL,
"comment" TEXT,
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE
)');
}
function version_32($pdo)
{

View File

@@ -6,7 +6,19 @@ use Core\Security;
use PDO;
use Model\Link;
const VERSION = 50;
const VERSION = 51;
function version_51($pdo)
{
$pdo->exec('CREATE TABLE budget_lines (
"id" INTEGER PRIMARY KEY,
"project_id" INTEGER NOT NULL,
"amount" REAL NOT NULL,
"date" TEXT NOT NULL,
"comment" TEXT,
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE
)');
}
function version_50($pdo)
{

View File

@@ -17,6 +17,7 @@ class ClassProvider implements ServiceProviderInterface
'Action',
'Authentication',
'Board',
'Budget',
'Category',
'Color',
'Comment',

View File

@@ -0,0 +1,51 @@
<div class="page-header">
<h2><?= t('Budget') ?></h2>
<ul>
<li><?= $this->a(t('Budget lines'), 'budget', 'create', array('project_id' => $project['id'])) ?></li>
<li><?= $this->a(t('Burn rate'), 'budget', 'index', array('project_id' => $project['id'])) ?></li>
</ul>
</div>
<?php if (! empty($lines)): ?>
<table class="table-fixed table-stripped">
<tr>
<th class="column-20"><?= t('Budget line') ?></th>
<th class="column-20"><?= t('Date') ?></th>
<th><?= t('Comment') ?></th>
<th><?= t('Action') ?></th>
</tr>
<?php foreach ($lines as $line): ?>
<tr>
<td><?= n($line['amount']) ?></td>
<td><?= $this->e($line['date']) ?></td>
<td><?= $this->e($line['comment']) ?></td>
<td>
<?= $this->a(t('Remove'), 'budget', 'confirm', array('project_id' => $project['id'], 'budget_id' => $line['id'])) ?>
</td>
</tr>
<?php endforeach ?>
</table>
<h3><?= t('New budget line') ?></h3>
<?php endif ?>
<form method="post" action="<?= $this->u('budget', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->formCsrf() ?>
<?= $this->formHidden('id', $values) ?>
<?= $this->formHidden('project_id', $values) ?>
<?= $this->formLabel(t('Amount'), 'amount') ?>
<?= $this->formText('amount', $values, $errors, array('required'), 'form-numeric') ?>
<?= $this->formLabel(t('Date'), 'date') ?>
<?= $this->formText('date', $values, $errors, array('required'), 'form-date') ?>
<?= $this->formLabel(t('Comment'), 'comment') ?>
<?= $this->formText('comment', $values, $errors) ?>
<div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
</div>
</form>

View File

@@ -0,0 +1,9 @@
<div class="page-header">
<h2><?= t('Budget') ?></h2>
<ul>
<li><?= $this->a(t('Budget lines'), 'budget', 'create', array('project_id' => $project['id'])) ?></li>
<li><?= $this->a(t('Burn rate'), 'budget', 'index', array('project_id' => $project['id'])) ?></li>
</ul>
</div>
<p><?= t('Current budget: ') ?><strong><?= n($total) ?></strong></p>

View File

@@ -0,0 +1,13 @@
<div class="page-header">
<h2><?= t('Remove budget line') ?></h2>
</div>
<div class="confirm">
<p class="alert alert-info"><?= t('Do you really want to remove this budget line?') ?></p>
<div class="form-actions">
<?= $this->a(t('Yes'), 'budget', 'remove', array('project_id' => $project['id'], 'budget_id' => $budget_id), true, 'btn btn-red') ?>
<?= t('or') ?>
<?= $this->a(t('cancel'), 'budget', 'create', array('project_id' => $project['id'])) ?>
</div>
</div>

View File

@@ -33,7 +33,10 @@
<?= $this->a(t('Automatic actions'), 'action', 'index', array('project_id' => $project['id'])) ?>
</li>
<li>
<?= $this->a(t('Duplicate'), 'project', 'duplicate', array('project_id' => $project['id']), true) ?>
<?= $this->a(t('Duplicate'), 'project', 'duplicate', array('project_id' => $project['id'])) ?>
</li>
<li>
<?= $this->a(t('Budget'), 'budget', 'index', array('project_id' => $project['id'])) ?>
</li>
<li>
<?php if ($project['is_active']): ?>