Add user cost
This commit is contained in:
parent
313318a40d
commit
7328995645
|
|
@ -34,6 +34,7 @@ use Symfony\Component\EventDispatcher\Event;
|
|||
* @property \Model\Config $config
|
||||
* @property \Model\DateParser $dateParser
|
||||
* @property \Model\File $file
|
||||
* @property \Model\HourlyRate $hourlyRate
|
||||
* @property \Model\LastLogin $lastLogin
|
||||
* @property \Model\Notification $notification
|
||||
* @property \Model\Project $project
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
namespace Controller;
|
||||
|
||||
/**
|
||||
* Hourly Rate controller
|
||||
*
|
||||
* @package controller
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class HourlyRate extends User
|
||||
{
|
||||
/**
|
||||
* Display rate and form
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function index(array $values = array(), array $errors = array())
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
$this->response->html($this->layout('hourlyrate/index', array(
|
||||
'rates' => $this->hourlyRate->getAllByUser($user['id']),
|
||||
'currencies_list' => $this->config->getCurrencies(),
|
||||
'values' => $values + array('user_id' => $user['id']),
|
||||
'errors' => $errors,
|
||||
'user' => $user,
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and save a new rate
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$values = $this->request->getValues();
|
||||
list($valid, $errors) = $this->hourlyRate->validateCreation($values);
|
||||
|
||||
if ($valid) {
|
||||
|
||||
if ($this->hourlyRate->create($values['user_id'], $values['rate'], $values['currency'], $values['date_effective'])) {
|
||||
$this->session->flash(t('Hourly rate created successfully.'));
|
||||
$this->response->redirect($this->helper->url('hourlyrate', 'index', array('user_id' => $values['user_id'])));
|
||||
}
|
||||
else {
|
||||
$this->session->flashError(t('Unable to save the hourly rate.'));
|
||||
}
|
||||
}
|
||||
|
||||
$this->index($values, $errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirmation dialag box to remove a row
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function confirm()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
$this->response->html($this->layout('hourlyrate/remove', array(
|
||||
'rate_id' => $this->request->getIntegerParam('rate_id'),
|
||||
'user' => $user,
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a row
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function remove()
|
||||
{
|
||||
$this->checkCSRFParam();
|
||||
$user = $this->getUser();
|
||||
|
||||
if ($this->hourlyRate->remove($this->request->getIntegerParam('rate_id'))) {
|
||||
$this->session->flash(t('Rate removed successfully.'));
|
||||
}
|
||||
else {
|
||||
$this->session->flash(t('Unable to remove this rate.'));
|
||||
}
|
||||
|
||||
$this->response->redirect($this->helper->url('hourlyrate', 'index', array('user_id' => $user['id'])));
|
||||
}
|
||||
}
|
||||
|
|
@ -69,12 +69,12 @@ class User extends Base
|
|||
/**
|
||||
* Common layout for user views
|
||||
*
|
||||
* @access private
|
||||
* @access protected
|
||||
* @param string $template Template name
|
||||
* @param array $params Template parameters
|
||||
* @return string
|
||||
*/
|
||||
private function layout($template, array $params)
|
||||
protected function layout($template, array $params)
|
||||
{
|
||||
$content = $this->template->render($template, $params);
|
||||
$params['user_content_for_layout'] = $content;
|
||||
|
|
@ -90,10 +90,10 @@ class User extends Base
|
|||
/**
|
||||
* Common method to get the user
|
||||
*
|
||||
* @access private
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
private function getUser()
|
||||
protected function getUser()
|
||||
{
|
||||
$user = $this->user->getById($this->request->getIntegerParam('user_id'));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
|
||||
return array(
|
||||
'number.decimals_separator' => ',',
|
||||
'number.thousands_separator' => ' ',
|
||||
'None' => 'Aucun',
|
||||
'edit' => 'modifier',
|
||||
'Edit' => 'Modifier',
|
||||
|
|
@ -740,4 +742,15 @@ return array(
|
|||
'Horizontal scrolling' => 'Défilement horizontal',
|
||||
'Compact/wide view' => 'Basculer entre la vue compacte et étendue',
|
||||
'No results match:' => 'Aucun résultat :',
|
||||
'Remove hourly rate' => 'Supprimer un taux horaire',
|
||||
'Do you really want to remove this hourly rate?' => 'Voulez-vous vraiment supprimer ce taux horaire ?',
|
||||
'Hourly rates' => 'Taux horaires',
|
||||
'Hourly rate' => 'Taux horaire',
|
||||
'Currency' => 'Devise',
|
||||
'Effective date' => 'Date d\'effet',
|
||||
'Add new rate' => 'Ajouter un nouveau taux horaire',
|
||||
'Rate removed successfully.' => 'Taux horaire supprimé avec succès.',
|
||||
'Unable to remove this rate.' => 'Impossible de supprimer ce taux horaire.',
|
||||
'Unable to save the hourly rate.' => 'Impossible de sauvegarder ce taux horaire.',
|
||||
'Hourly rate created successfully.' => 'Taux horaire créé avec succès.',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ class Acl extends Base
|
|||
'config' => '*',
|
||||
'link' => '*',
|
||||
'project' => array('remove'),
|
||||
'hourlyrate' => '*',
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,6 +21,26 @@ class Config extends Base
|
|||
*/
|
||||
const TABLE = 'settings';
|
||||
|
||||
/**
|
||||
* Get available currencies
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getCurrencies()
|
||||
{
|
||||
return array(
|
||||
'USD' => t('USD - US Dollar'),
|
||||
'EUR' => t('EUR - Euro'),
|
||||
'GBP' => t('GBP - British Pound'),
|
||||
'CAD' => t('CAD - Canadian Dollar'),
|
||||
'AUD' => t('AUD - Australian Dollar'),
|
||||
'NZD' => t('NZD - New Zealand Dollar'),
|
||||
'INR' => t('INR - Indian Rupee'),
|
||||
'JPY' => t('JPY - Japanese Yen'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available timezones
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
namespace Model;
|
||||
|
||||
use SimpleValidator\Validator;
|
||||
use SimpleValidator\Validators;
|
||||
|
||||
/**
|
||||
* Hourly Rate
|
||||
*
|
||||
* @package model
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class HourlyRate extends Base
|
||||
{
|
||||
/**
|
||||
* SQL table name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TABLE = 'hourly_rates';
|
||||
|
||||
/**
|
||||
* Get all rates for a given user
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @return array
|
||||
*/
|
||||
public function getAllByUser($user_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('user_id', $user_id)->desc('date_effective')->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current rate for a given user
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @return float
|
||||
*/
|
||||
public function getCurrentRate($user_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('user_id', $user_id)->desc('date_effective')->findOneColumn('rate') ?: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new rate in the database
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @param float $rate Hourly rate
|
||||
* @param string $currency Currency code
|
||||
* @param string $date ISO8601 date format
|
||||
* @return boolean|integer
|
||||
*/
|
||||
public function create($user_id, $rate, $currency, $date)
|
||||
{
|
||||
$values = array(
|
||||
'user_id' => $user_id,
|
||||
'rate' => $rate,
|
||||
'currency' => $currency,
|
||||
'date_effective' => $this->dateParser->removeTimeFromTimestamp($this->dateParser->getTimestamp($date)),
|
||||
);
|
||||
|
||||
return $this->persist(self::TABLE, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific rate
|
||||
*
|
||||
* @access public
|
||||
* @param integer $rate_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove($rate_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('id', $rate_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('user_id', t('Field required')),
|
||||
new Validators\Required('rate', t('Field required')),
|
||||
new Validators\Numeric('rate', t('This value must be numeric')),
|
||||
new Validators\Required('date_effective', t('Field required')),
|
||||
new Validators\Required('currency', t('Field required')),
|
||||
));
|
||||
|
||||
return array(
|
||||
$v->execute(),
|
||||
$v->getErrors()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,20 @@ use PDO;
|
|||
use Core\Security;
|
||||
use Model\Link;
|
||||
|
||||
const VERSION = 49;
|
||||
const VERSION = 50;
|
||||
|
||||
function version_50($pdo)
|
||||
{
|
||||
$pdo->exec("CREATE TABLE hourly_rates (
|
||||
id INT NOT NULL AUTO_INCREMENT,
|
||||
user_id INT NOT NULL,
|
||||
rate FLOAT DEFAULT 0,
|
||||
date_effective INTEGER NOT NULL,
|
||||
currency TEXT NOT NULL,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY(id)
|
||||
) ENGINE=InnoDB CHARSET=utf8");
|
||||
}
|
||||
|
||||
function version_49($pdo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,19 @@ use PDO;
|
|||
use Core\Security;
|
||||
use Model\Link;
|
||||
|
||||
const VERSION = 30;
|
||||
const VERSION = 31;
|
||||
|
||||
function version_31($pdo)
|
||||
{
|
||||
$pdo->exec("CREATE TABLE hourly_rates (
|
||||
id SERIAL,
|
||||
user_id INTEGER NOT NULL,
|
||||
rate REAL DEFAULT 0,
|
||||
date_effective INTEGER NOT NULL,
|
||||
currency TEXT NOT NULL,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
)");
|
||||
}
|
||||
|
||||
function version_30($pdo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,19 @@ use Core\Security;
|
|||
use PDO;
|
||||
use Model\Link;
|
||||
|
||||
const VERSION = 48;
|
||||
const VERSION = 49;
|
||||
|
||||
function version_49($pdo)
|
||||
{
|
||||
$pdo->exec("CREATE TABLE hourly_rates (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL,
|
||||
rate REAL DEFAULT 0,
|
||||
date_effective INTEGER NOT NULL,
|
||||
currency TEXT NOT NULL,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
)");
|
||||
}
|
||||
|
||||
function version_48($pdo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class ClassProvider implements ServiceProviderInterface
|
|||
'Config',
|
||||
'DateParser',
|
||||
'File',
|
||||
'HourlyRate',
|
||||
'LastLogin',
|
||||
'Link',
|
||||
'Notification',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
<div class="page-header">
|
||||
<h2><?= t('Hourly rates') ?></h2>
|
||||
</div>
|
||||
|
||||
<?php if (! empty($rates)): ?>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th><?= t('Hourly rate') ?></th>
|
||||
<th><?= t('Currency') ?></th>
|
||||
<th><?= t('Effective date') ?></th>
|
||||
<th><?= t('Action') ?></th>
|
||||
</tr>
|
||||
<?php foreach ($rates as $rate): ?>
|
||||
<tr>
|
||||
<td><?= n($rate['rate']) ?></td>
|
||||
<td><?= $rate['currency'] ?></td>
|
||||
<td><?= dt('%b %e, %Y', $rate['date_effective']) ?></td>
|
||||
<td>
|
||||
<?= $this->a(t('Remove'), 'hourlyrate', 'confirm', array('user_id' => $user['id'], 'rate_id' => $rate['id'])) ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</table>
|
||||
|
||||
<h3><?= t('Add new rate') ?></h3>
|
||||
<?php endif ?>
|
||||
|
||||
<form method="post" action="<?= $this->u('hourlyrate', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
|
||||
|
||||
<?= $this->formHidden('user_id', $values) ?>
|
||||
<?= $this->formCsrf() ?>
|
||||
|
||||
<?= $this->formLabel(t('Hourly rate'), 'rate') ?>
|
||||
<?= $this->formText('rate', $values, $errors, array('required'), 'form-numeric') ?>
|
||||
|
||||
<?= $this->formLabel(t('Currency'), 'currency') ?>
|
||||
<?= $this->formSelect('currency', $currencies_list, $values, $errors, array('required')) ?>
|
||||
|
||||
<?= $this->formLabel(t('Effective date'), 'date_effective') ?>
|
||||
<?= $this->formText('date_effective', $values, $errors, array('required'), 'form-date') ?>
|
||||
|
||||
<div class="form-actions">
|
||||
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<div class="page-header">
|
||||
<h2><?= t('Remove hourly rate') ?></h2>
|
||||
</div>
|
||||
|
||||
<div class="confirm">
|
||||
<p class="alert alert-info"><?= t('Do you really want to remove this hourly rate?') ?></p>
|
||||
|
||||
<div class="form-actions">
|
||||
<?= $this->a(t('Yes'), 'hourlyrate', 'remove', array('user_id' => $user['id'], 'rate_id' => $rate_id), true, 'btn btn-red') ?>
|
||||
<?= t('or') ?>
|
||||
<?= $this->a(t('cancel'), 'hourlyrate', 'index', array('user_id' => $user['id'])) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
<?= $this->a(t('Time tracking'), 'user', 'timesheet', array('user_id' => $user['id'])) ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
|
||||
|
||||
<?php if ($this->userSession->isAdmin()): ?>
|
||||
<li>
|
||||
<?= $this->a(t('User dashboard'), 'app', 'dashboard', array('user_id' => $user['id'])) ?>
|
||||
|
|
@ -40,6 +40,9 @@
|
|||
<li>
|
||||
<?= $this->a(t('User calendar'), 'user', 'calendar', array('user_id' => $user['id'])) ?>
|
||||
</li>
|
||||
<li>
|
||||
<?= $this->a(t('Hourly rates'), 'hourlyrate', 'index', array('user_id' => $user['id'])) ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($this->userSession->isAdmin() && ! $this->userSession->isCurrentUser($user['id'])): ?>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__.'/Base.php';
|
||||
|
||||
use Model\User;
|
||||
use Model\HourlyRate;
|
||||
|
||||
class HourlyRateTest extends Base
|
||||
{
|
||||
public function testCreation()
|
||||
{
|
||||
$hr = new HourlyRate($this->container);
|
||||
$this->assertEquals(1, $hr->create(1, 32.4, 'EUR', '2015-01-01'));
|
||||
$this->assertEquals(2, $hr->create(1, 42, 'CAD', '2015-02-01'));
|
||||
|
||||
$rates = $hr->getAllByUser(0);
|
||||
$this->assertEmpty($rates);
|
||||
|
||||
$rates = $hr->getAllByUser(1);
|
||||
$this->assertNotEmpty($rates);
|
||||
$this->assertCount(2, $rates);
|
||||
|
||||
$this->assertEquals(42, $rates[0]['rate']);
|
||||
$this->assertEquals('CAD', $rates[0]['currency']);
|
||||
$this->assertEquals('2015-02-01', date('Y-m-d', $rates[0]['date_effective']));
|
||||
|
||||
$this->assertEquals(32.4, $rates[1]['rate']);
|
||||
$this->assertEquals('EUR', $rates[1]['currency']);
|
||||
$this->assertEquals('2015-01-01', date('Y-m-d', $rates[1]['date_effective']));
|
||||
|
||||
$this->assertEquals(0, $hr->getCurrentRate(0));
|
||||
$this->assertEquals(42, $hr->getCurrentRate(1));
|
||||
|
||||
$this->assertTrue($hr->remove(2));
|
||||
$this->assertEquals(32.4, $hr->getCurrentRate(1));
|
||||
|
||||
$this->assertTrue($hr->remove(1));
|
||||
$this->assertEquals(0, $hr->getCurrentRate(1));
|
||||
|
||||
$rates = $hr->getAllByUser(1);
|
||||
$this->assertEmpty($rates);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue