diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/Controller/Budget.php | 111 | ||||
-rw-r--r-- | app/Model/Acl.php | 1 | ||||
-rw-r--r-- | app/Model/Base.php | 1 | ||||
-rw-r--r-- | app/Model/Budget.php | 101 | ||||
-rw-r--r-- | app/Schema/Mysql.php | 15 | ||||
-rw-r--r-- | app/Schema/Postgres.php | 14 | ||||
-rw-r--r-- | app/Schema/Sqlite.php | 14 | ||||
-rw-r--r-- | app/ServiceProvider/ClassProvider.php | 1 | ||||
-rw-r--r-- | app/Template/budget/create.php | 51 | ||||
-rw-r--r-- | app/Template/budget/index.php | 9 | ||||
-rw-r--r-- | app/Template/budget/remove.php | 13 | ||||
-rw-r--r-- | app/Template/project/sidebar.php | 5 |
12 files changed, 332 insertions, 4 deletions
diff --git a/app/Controller/Budget.php b/app/Controller/Budget.php new file mode 100644 index 00000000..01090550 --- /dev/null +++ b/app/Controller/Budget.php @@ -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']))); + } +} diff --git a/app/Model/Acl.php b/app/Model/Acl.php index 56938f9d..b52a7864 100644 --- a/app/Model/Acl.php +++ b/app/Model/Acl.php @@ -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' => '*', ); /** diff --git a/app/Model/Base.php b/app/Model/Base.php index f836231c..8a90e286 100644 --- a/app/Model/Base.php +++ b/app/Model/Base.php @@ -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 diff --git a/app/Model/Budget.php b/app/Model/Budget.php new file mode 100644 index 00000000..03a90f7f --- /dev/null +++ b/app/Model/Budget.php @@ -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() + ); + } +}
\ No newline at end of file diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index 44ca7fd4..03868748 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -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) { diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index fe01b1e9..124aec76 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -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) { diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index eaa5c734..818ed78d 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -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) { diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index a94bb745..6f597a5c 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -17,6 +17,7 @@ class ClassProvider implements ServiceProviderInterface 'Action', 'Authentication', 'Board', + 'Budget', 'Category', 'Color', 'Comment', diff --git a/app/Template/budget/create.php b/app/Template/budget/create.php new file mode 100644 index 00000000..0ff395c9 --- /dev/null +++ b/app/Template/budget/create.php @@ -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>
\ No newline at end of file diff --git a/app/Template/budget/index.php b/app/Template/budget/index.php new file mode 100644 index 00000000..8bdf1a57 --- /dev/null +++ b/app/Template/budget/index.php @@ -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> diff --git a/app/Template/budget/remove.php b/app/Template/budget/remove.php new file mode 100644 index 00000000..97f9c3dc --- /dev/null +++ b/app/Template/budget/remove.php @@ -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>
\ No newline at end of file diff --git a/app/Template/project/sidebar.php b/app/Template/project/sidebar.php index f4809fde..4afc8ba9 100644 --- a/app/Template/project/sidebar.php +++ b/app/Template/project/sidebar.php @@ -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']): ?> |