Commit 7ed60619 authored by okhin's avatar okhin 🚴

Merge branch '50-support-de-batch-pour-les-contreparties' into 'preprod'

Resolve "Support de batch pour les contreparties"

Closes #76, #50, and #71

See merge request !73
parents 2559bc0a 375b289b
Pipeline #2296 passed with stages
in 1 minute and 23 seconds
......@@ -4,12 +4,15 @@ namespace Controller;
use LQDN\Command\AdminCreateCommand;
use LQDN\Command\AdminDeleteCommand;
use LQDN\Command\AdminChangePasswordCommand;
use LQDN\Command\CounterpartCreateCommand;
use LQDN\Command\DonationValidateCommand;
use LQDN\Command\DonationInvalidateCommand;
use LQDN\Command\DonationResetPdfCommand;
use LQDN\Command\DonationCreateCommand;
use LQDN\Command\UserUpdateByAdminCommand;
use LQDN\Command\UserCreateCommand;
use LQDN\Command\UserUpdateCumulCommand;
use LQDN\Command\AdminUpdateTotalUsersCommand;
class Admin extends Controller
{
......@@ -46,12 +49,27 @@ class Admin extends Controller
99 => "résilié",
100 => "non applicable",
));
$f3->set('TAILLES', array(
0 => _('PlaceHolder -- ne pas utiliser') . ' S',
1 => _('Coupe Homme, Taille') . ' S',
2 => _('Coupe Homme, Taille') . ' M',
3 => _('Coupe Homme, Taille') . ' L',
4 => _('Coupe Homme, Taille') . ' XL',
5 => _('Coupe Femme, Taille') . ' S',
6 => _('Coupe Femme, Taille') . ' M',
7 => _('Coupe Femme, Taille') . ' L',
8 => _('Coupe Femme, Taille') . ' XL',
9 => _('Coupe Homme, Taille') . ' XXL',
10 => _('Coupe Femme, Taille') . ' XXL',
));
if (!$f3->get('SESSION.admin')) {
$mapper = new\DB\SQL\Mapper($f3->get('DB'), 'admins');
$auth = new \Auth($mapper, array('id'=>'user_id', 'pw'=>'password'));
$success = $auth->basic('\Controller\Admin::hash_password');
if (!$success) {
$f3->push('SESSION.error', 'Accès non autorisé');
$f3->error(401);
} else {
$f3->set('SESSION.admin', true);
......@@ -61,6 +79,26 @@ class Admin extends Controller
$f3->set('PIPLOME_URL', PIPLOME_URL);
}
public function afterRoute($f3, $args)
{
// Test si il y a des messages
if (!$f3->exists('SESSION.message')) {
$f3->push('SESSION.message', '');
}
if (!$f3->exists('SESSION.error')) {
$f3->push('SESSION.error', '');
}
// Rendu de la page
if ($this->template!='') {
echo \Template::instance()->render($this->template);
}
// Une fois que tout est affiché, on peut supprimer les notifications
$f3->clear('SESSION.message');
$f3->clear('SESSION.error');
}
public static function hash_password($password)
{
return hash('sha256', $password);
......@@ -140,6 +178,7 @@ class Admin extends Controller
$cumul = $user_amount['total'] + $result['somme'];
}
if ($error != '') {
$f3->push('SESSION.error', $error);
} else {
$db->query(
"UPDATE dons
......@@ -190,6 +229,7 @@ class Admin extends Controller
}
}
if ($error != '') {
$f3->push('SESSION.error', $error);
} else {
$db->query(
"UPDATE dons
......@@ -341,6 +381,78 @@ class Admin extends Controller
public function counterparts_dashboard($f3, $args)
{
$db = $f3->get('DB');
$f3->set('counterparts_import', '');
$total = array("hoopie" => 0, "pishirt" => 0, "pibag" => 0, "piplome" => 0);
if ($f3->get('VERB') == 'POST') {
$separator = ';';
// Si on a un POST sur cette page, c'est que l'on a un csv à parser
if ($_FILES['file']['tmp_name'] == '') {
$f3->push('SESSION.error', 'Veuillez uploader un fichier au format csv');
} else {
// Lecture du fichier
if (($handle = fopen($_FILES['file']['tmp_name'], "r")) !== false) {
// D'abord le header : email / quoi
$fields = fgetcsv($handle, 1000, $separator);
$mail_idx = -1;
$quoi_idx = -1;
foreach ($fields as $key => $value) {
if ($value == "Quoi") {
$quoi_idx = $key;
}
if ($value == "Mail") {
$mail_idx = $key;
}
}
// On tourne sur le fichier maintenant
while (($data = fgetcsv($handle, 1000, $separator)) !== false) {
// Récupération des données
$mail = $data[$mail_idx];
$quoi = $data[$quoi_idx];
// On cherche l'utilisateur
$user = $f3->get('container')['user_finder']->findByEmail($mail);
// Et son addresse
$adresse = $f3->get('container')['address_finder']->findByUserId($user['id']);
if (count($user) >= 1 and is_array($user)) {
// On a un utilisateur, cool
// On crée une contrepartie, si son cumul est suffisant
switch ($quoi) {
case 'hoodie':
$needed = 250;
break;
case 'pishirt':
$needed = 100;
break;
case 'pibag':
$needed = 50;
break;
case 'piplome':
$needed = 30;
break;
}
if ($user['cumul'] >= $needed) {
// Assez de point, on crée
$f3->get('container')['command_handler']->handle(new CounterpartCreateCommand($adresse['id'], $user['id'], $quoi, 1, 2, date("Y-m-d H:i:s"), 'Imported from a file'));
// On mets à jour le cumul de l'utilisateur
$f3->get('container')['command_handler']->handle(new UserUpdateCumulCommand($user['id'], $user['cumul'] - $needed));
$total[$quoi] +=1;
} else {
$f3->push('SESSION.error', 'Pas assez de cumul pour un '.$quoi.' avec l\'email'.$mail);
}
} else {
$f3->push('SESSION.error', 'Pas d\'utilisateur avec l\'adresse '.$mail);
}
}
fclose($handle);
}
} // Fin de l'import CSV
$f3->set('counterparts_import', $total);
}
// On définit des valeurs par défaut
$query = "SELECT DISTINCT quoi FROM contreparties;";
$result = $db->query($query);
......@@ -990,8 +1102,8 @@ class Admin extends Controller
}
}
$f3->set('result', $result);
$f3->set('error', $error);
$f3->set('message', $message);
$f3->push('SESSION.error', $error);
$f3->push('SESSION.message', $message);
$f3->set('block_content', 'backend/banque.html');
}
......@@ -1398,6 +1510,12 @@ class Admin extends Controller
$f3->set('block_content', 'backend/stats.html');
}
public function recompute($f3, $args)
{
$f3->get('container')['command_handler']->handle(new AdminUpdateTotalUsersCommand());
$this->show($f3, $args);
}
public function accounts($f3, $args)
{
if ($f3->get('VERB') == 'POST') {
......
......@@ -3,6 +3,7 @@ namespace Controller;
use LQDN\Command\UserUpdateCumulCommand;
use LQDN\Command\UserUpdateTotalCommand;
use LQDN\Command\DonationIncStatusCommand;
class Bank extends Controller
{
......@@ -87,7 +88,8 @@ class Bank extends Controller
### Attempt to do it in hmac-sha256
$sig_hash = base64_encode(hash_hmac('sha256', $sig, CERTIFICATE, true));
$cb_log->write("sig: " . $signature . " == " . $sig_hash);
if ($sig_hash!=$signature) {
$cb_log->write("debug level: ". DEBUG);
if ($sig_hash!=$signature and DEBUG == 0) {
$error = "Error in signature: " . $signature . " != " . $sig_hash;
}
// Résultats des vérifications globales
......@@ -111,8 +113,7 @@ class Bank extends Controller
$db = $f3->get('DB');
$id = intval($order_id);
$cb_log->write("Id: ".$order_id);
$res = $db->query("SELECT * FROM dons WHERE id='".$id."';");
$don = $res->fetch(\PDO::FETCH_ASSOC);
$don = $f3->get('container')['donation_finder']->findById($id);
if (!$don) {
$cb_log->write("Transaction id not found: ".$order_id);
......@@ -148,18 +149,17 @@ class Bank extends Controller
bind_textdomain_codeset("messages", "$charset");
// ok, somme OK, status = completed, transaction found.
$db->query("UPDATE dons SET status=status+1 WHERE id='".$id."';");
$res = $db->query("SELECT status FROM dons WHERE id='".$id."';");
$status = $res->fetch(\PDO::FETCH_ASSOC);
$status = $status['status'];
$f3->get('container')['command_handler']->handle(new DonationIncStatusCommand($don['id']));
$don = $f3->get('container')['donation_finder']->findById($don['id']);
$status = $don['status'];
$user = $f3->get('container')['user_finder']->findById($don['user_id']);
$cb_log->write("Utilisation d'un utilisateur existant");
// Ajout du nouveau don au cumul actuel
if ($status!=101) {
$cb_log->write("Ajout de ".$don['somme']);
$f3->get('container')['command_handler']->handle(new UpdateUserTotalCommand($user['id'], (int) $user['total'] + $don['somme']));
$f3->get('container')['command_handler']->handle(new UpdateUserCumulCommand($user['id'], (int) $user['cumul'] + $don['cumul']));
$f3->get('container')['command_handler']->handle(new UserUpdateTotalCommand($user['id'], (int) $user['total'] + $don['somme']));
$f3->get('container')['command_handler']->handle(new UserUpdateCumulCommand($user['id'], (int) $user['cumul'] + $don['cumul']));
}
$result = $db->query("SELECT cumul FROM users WHERE id='".$don['user_id']."'");
$cumul = $result->fetch(\PDO::FETCH_ASSOC);
......
......@@ -29,6 +29,7 @@ GET @edit_support:/admin/support/edit/@id=Controller\Admin->support
POST @modify_support:/admin/support/edit=Controller\Admin->support
GET @invalidate_support:/admin/support/invalidate/@id=Controller\Admin->invalidate
GET @validate_support:/admin/support/validate/@id=Controller\Admin->validate
GET @recompute:/admin/recompute=Controller\Admin->recompute
GET|POST @admin_accounts:/admin/accounts=Controller\Admin->accounts
......@@ -46,7 +47,7 @@ POST @modify_user:/admin/users/@id=Controller\Admin->user
POST @adresse:/admin/adresses=Controller\Admin->adresse
GET @counterparts_dashboard:/admin/counterparts_dashboard=Controller\Admin->counterparts_dashboard
GET|POST @counterparts_dashboard:/admin/counterparts_dashboard=Controller\Admin->counterparts_dashboard
GET|POST @banque:/admin/banque=Controller\Admin->banque
......
......@@ -2,8 +2,8 @@
<h2>Gestion banque</h2>
<check if="{{@result}}"><p class="result">{{@result | raw}}</p></check>
<check if="{{@error}}"><p class="error">{{@error | raw}}</p></check>
<check if="{{@message}}"><p class="message">{{@message | raw}}</p></check>
<check if="{{@SESSION.error}}"><message messages="{{@SESSION.error}}" class="alert alert-danger"/></check>
<check if="{{@SESSION.message}}"><message messages="{{@SESSION.message}}" class="alert alert-danger" /></p></check>
<section id="cbs">
<h3 >Mise à jour des dates d'expiration des CB</h3>
......
<section>
<h2>Import des contreparties depuis un fichier csv</h2>
<p>Veuillez préparer un fichier csv du format : Mail;quoi;</p>
<form enctype="multipart/form-data" method=POST action="{{ 'counterparts_dashboard' | alias}}">
<input type="hidden" id="csrf" name="csrf" value="{{ @CSRF }}" />
<input type="file" id="file" name="file">
<br />
<input type="submit" value="Pousser le fichier">
</form>
{{ var_dump(@counterparts_import) }}
<message messages="{{@SESSION.error}}" class="alert alert-danger" />
</form>
</section>
<h2>Tableau de bord des contreparties</h2>
<table cellspacing="0" cellpadding="0">
<theader>
......@@ -19,8 +31,8 @@
</tr>
<tr>
<td>Hoodies</td>
<td style="text-align:right;"><b>{{ @hoodie_s1 }}</b></td>
<td style="text-align:right;">{{ @hoodie_s2 }}</td>
<td style="text-align:right;"><b>{{ @hoopie_s1 }}</b></td>
<td style="text-align:right;">{{ @hoopie_s2 }}</td>
</tr>
</tbody>
</table>
......
......@@ -52,9 +52,8 @@
<input type="submit" value="Voir ce don" />
</form>
<br />
<check if="{{ @msg }}">
<span class="error">{{ @msg }}</span>
</check>
<check if="{{ @SESSION.error }}"> <message messages="{{ @SESSION.error }}" class="alert alert-danger" /> </check>
<check if="{{ @SESSION.message }}"> <message messages="{{ @SESSION.message }}" class="alert alert-default" /> </check>
</section>
<script type="text/javascript">
......
......@@ -45,6 +45,8 @@
<input type="submit" value="Filtrer" />
</form>
<a href="{{ 'recompute' | alias }}">Recalculer les totaux et cumuls de toute la base de donnée</a>
<br />
<check if="{{ @row_count }}"><b>{{ @row_count }} résultats</b>
<br />
<table cellspacing="0" cellpadding="0">
......
......@@ -154,7 +154,7 @@
</nav>
</div>
<section id="messages">
<message messages="@SESSION.message" class="alert alert-default">
<message messages="@SESSION.error" class="alert alert-danger">
<message messages="{{ @SESSION.message }}" class="alert alert-default">
<message messages="{{ @SESSION.error }}" class="alert alert-danger">
</section>
......@@ -33,6 +33,24 @@ class CounterpartSeeder extends AbstractSeed
'status' => 2,
'adresse_id' => null,
),
array(
'id' => 3,
'datec' => '2016-06-22 12:34',
'user_id' => 2,
'quoi' => 'pibag', // [piplome|pibag|pishirt|hoodie]
'taille' => 2,
'status' => 2,
'adresse_id' => null,
),
array(
'id' => 4,
'datec' => '2016-06-22 12:34',
'user_id' => 2,
'quoi' => 'hoopie', // [piplome|pibag|pishirt|hoodie]
'taille' => 2,
'status' => 2,
'adresse_id' => null,
),
);
$this->table('contreparties')->insert($data)->save();
......
<?php
namespace LQDN\Command;
class AdminUpdateTotalUsersCommand
{
// There is no parameters for this command.
}
<?php
namespace LQDN\Command;
class DonationIncStatusCommand
{
private $donId;
public function __construct($donId)
{
$this->donId = $donId;
}
public function getId()
{
return $this->donId;
}
}
......@@ -7,6 +7,8 @@ class UserCreateCommand
private $email;
private $hash;
private $pseudo;
private $cumul;
private $total;
public function __construct($email, $hash, $pseudo, $cumul, $total)
{
......
......@@ -23,13 +23,7 @@ class DonationFinder
public function findByUserId($userId)
{
$userId = (int) $userId;
$donations = [];
$stmt = $this->connection->query("SELECT * FROM dons WHERE user_id='$userId'");
while ($donation = $stmt->fetch()) {
$donations[$donation['id']] = $donation;
}
return $donations;
return $this->connection->executeQuery("SELECT * FROM dons WHERE user_id=:userId", ["userId" => $userId])->fetchAll(\PDO::FETCH_ASSOC);
}
/**
......@@ -39,16 +33,9 @@ class DonationFinder
*
* @return []
*/
public function findById($donationId)
public function findById($did)
{
$donationId = (int) $donationId;
$donations = [];
$stmt = $this->connection->query("SELECT * FROM dons WHERE id='$donationId'");
while ($donation = $stmt->fetch()) {
$donations[$donationId] = $donation;
}
return $donations;
return $this->connection->executeQuery("SELECT * FROM dons WHERE id=:did", ["did" => $did])->fetch(\PDO::FETCH_ASSOC);
}
/**
* Return dons for admins.
......
......@@ -7,6 +7,7 @@ use LQDN\Command\DonationCreateCommand;
use LQDN\Command\DonationInvalidateCommand;
use LQDN\Command\DonationResetPdfCommand;
use LQDN\Command\DonationValidateCommand;
use LQDN\Command\DonationIncStatusCommand;
class DonationHandler
{
......@@ -67,4 +68,14 @@ EOF;
{
$this->connection->executeUpdate('UPDATE dons SET pdf = "" WHERE id = :id', ['id' => $command->getId()]);
}
/**
* Increase the status of a donation
*
* @param DonationIncStatusCommand $command
*/
public function handleDonationIncStatusCommand(DonationIncStatusCommand $command)
{
$this->connection->executeUpdate('UPDATE dons SET status = status + 1 WHERE id = :id', ['id' => $command->getId()]);
}
}
......@@ -7,6 +7,7 @@ use LQDN\Command\UserUpdateByAdminCommand;
use LQDN\Command\UserUpdateTotalCommand;
use LQDN\Command\UserUpdateCumulCommand;
use LQDN\Command\UserCreateCommand;
use LQDN\Command\AdminUpdateTotalUsersCommand;
class UserHandler
{
......@@ -39,13 +40,13 @@ class UserHandler
*/
public function handleUserCreateCommand(UserCreateCommand $command)
{
$stmt = $this->connection->prepare('INSERT INTO users(email, hash, pseudo, total, cumul) VALUES (:email, :hash, :pseudo, :total, :cumul)');
$stmt->bindValue('email', $command->getEmail());
$stmt->bindValue('hash', $command->getHash());
$stmt->bindValue('pseudo', $command->getPseudo());
$stmt->bindValue('total', $command->getTotal());
$stmt->bindValue('cumul', $command->getCumul());
$stmt->execute();
$this->connection->executeUpdate('INSERT INTO users(email, hash, pseudo, total, cumul) VALUES (:email, :hash, :pseudo, :total, :cumul)', [
'email'=> $command->getEmail(),
'hash'=> $command->getHash(),
'pseudo'=> $command->getPseudo(),
'total'=> $command->getTotal(),
'cumul'=> $command->getCumul(),
]);
}
/**
......@@ -79,4 +80,33 @@ class UserHandler
]
);
}
/**
* Get through all the users and databases to recompute all total from users.
*
* @param AdminUpdateTotalUsersCommand $command
*/
public function handleAdminUpdateTotalUsersCommand(AdminUpdateTotalUsersCommand $command)
{
// Let's get all users first
$user_ids = $this->connection->executeQuery('SELECT id FROM users')->fetchAll(\PDO::FETCH_ASSOC);
foreach ($user_ids as $user_id) {
$user_id = (int) $user_id;
$total = $this->connection->executeQuery('SELECT SUM(somme) AS total FROM dons WHERE user_id = :user_id AND STATUS IN (1, 102)', [
'user_id' => $user_id
])->fetchColumn();
// Let's compute the cumul too
// quoi = 'hoopie' somme = 250
// quoi = 'pishirt' somme = 100
// quoi = 'pibag' somme = 50
// quoi = 'piplome' somme = 30
$spent = $this->connection->executeQuery(
"SELECT sum(IF(quoi = 'hoopie',250,0)) + sum(IF(quoi = 'pishirt', 100, 0)) + sum(IF(quoi = 'pibag', 50, 0)) + sum(IF(quoi = 'piplome', 30, 0)) AS spent FROM contreparties WHERE user_id = :user_id",
[ 'user_id' => $user_id]
)->fetchColumn();
$this->connection->executeUpdate('UPDATE users SET total = :total, cumul = :cumul WHERE id = :user_id', ['total' => $total, 'cumul' => $total - $spent, 'user_id' => $user_id]);
}
}
}
......@@ -9,7 +9,7 @@ class CounterpartFinderTest extends FunctionalTest
public function testFindByUserId()
{
$counterparts = $this->container['counterpart_finder']->findByUserId(2);
$this->assertCount(1, $counterparts);
$this->assertCount(3, $counterparts);
$firstCounterpart = reset($counterparts);
......
......@@ -38,7 +38,7 @@ class DonationFinderTest extends FunctionalTest
'adresse_id' => '1',
'identifier' => 'id1',
];
$this->assertEquals($expectedDonation, $donations[1]);
$this->assertEquals($expectedDonation, $donations[0]);
}
public function testAdminSearchDonations()
......
......@@ -19,7 +19,7 @@ class CounterpartHandlerTest extends FunctionalTest
public function testCounterpartCreate()
{
$this->assertFalse($this->counterpartExists(3));
$this->assertFalse($this->counterpartExists(5));
$this->container['command_handler']->handle(new CounterpartCreateCommand(1, 1, 'pishirt', 4, 1, date("Y-m-d H:i:s"), ''));
}
......
......@@ -6,6 +6,7 @@ use LQDN\Command\DonationInvalidateCommand;
use LQDN\Command\DonationResetPdfCommand;
use LQDN\Command\DonationValidateCommand;
use LQDN\Command\DonationCreateCommand;
use LQDN\Command\DonationIncStatusCommand;
use LQDN\Tests\Functional\FunctionalTest;
class DonationHandlerTest extends FunctionalTest
......@@ -39,7 +40,21 @@ class DonationHandlerTest extends FunctionalTest
}
public function testDonationIncStatusCommand()
{
// Let's get the previous status
$don = $this->container['donation_finder']->findById(1);
$prev_status = $don['status'];
// Update
$this->container['command_handler']->handle(new DonationIncStatusCommand($don['id']));
$don = $this->container['donation_finder']->findById(1);
$this->assertEquals($prev_status + 1, $don['status']);
// Remise en état
$this->container['db']->executeUpdate("UPDATE dons SET status = status - 1 WHERE id = :id",
[ 'id' => $don['id']]);
}
/**
* Retrieve a donation
*
......
......@@ -6,10 +6,18 @@ use LQDN\Command\UserUpdateByAdminCommand;
use LQDN\Command\UserUpdateTotalCommand;
use LQDN\Command\UserUpdateCumulCommand;
use LQDN\Command\UserCreateCommand;
use LQDN\Command\AdminUpdateTotalUsersCommand;
use LQDN\Tests\Functional\FunctionalTest;
class UserHandlerTest extends FunctionalTest
{
public function testAdminUpdateTotalUsersCommand()
{
$this->container['command_handler']->handle(new AdminUpdateTotalUsersCommand());
$this->assertSame(1000, (int) $this->getUser(1)['total']);
$this->assertSame(900, (int) $this->getUser(1)['cumul']);
}
public function testUserUpdateFromAdmin()
{
$user = $this->getUser(1);
......@@ -28,6 +36,10 @@ class UserHandlerTest extends FunctionalTest
public function testUserCreateCommand()
{
$this->container['command_handler']->handle(new UserCreateCommand('eve@example.org', 'not a hash', 'Eve', 0, 0));
$last_id = $this->container['db']->lastInsertId();
$user = $this->getUser($last_id);
$this->assertSame('eve@example.org', $user['email']);
}
public function testUserUpdateTotal()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment