use Galette\Controllers\GaletteController;
use Galette\Controllers\Crud;
+use Galette\Controllers\CsvController;
use Galette\Controllers\PdfController;
use Galette\Entity\Contribution;
[Crud\ContributionsController::class, 'doEdit']
)->setName('doEditContribution')->add($authenticate);
+//Batch actions on contributions list
+$app->post(
+ '/{type:contributions|transactions}/batch',
+ [Crud\ContributionsController::class, 'handleBatch']
+)->setName('batch-contributionslist')->add($authenticate);
+
+//contributions list CSV export
+$app->map(
+ ['GET', 'POST'],
+ '/{type:contributions|transactions}/export/csv',
+ [CsvController::class, 'contributionsExport']
+)->setName('csv-contributionslist')->add($authenticate);
+
$app->get(
'/transaction/add',
[Crud\TransactionsController::class, 'add']
[Crud\ContributionsController::class, 'confirmDelete']
)->setName('removeContribution')->add($authenticate);
-$app->post(
+$app->get(
'/{type:contributions|transactions}/batch/remove',
[Crud\ContributionsController::class, 'confirmDelete']
)->setName('removeContributions')->add($authenticate);
namespace Galette\Controllers\Crud;
+use Galette\Filters\ContributionsList;
use Throwable;
use Analog\Analog;
use Galette\Controllers\CrudController;
*
* @param Request $request PSR Request
* @param Response $response PSR Response
- * @param string|null $type Contribution type
+ * @param string|null $type One of 'transactions' or 'contributions'
*
* @return Response
*/
public function filter(Request $request, Response $response, string $type = null): Response
{
- $raw_type = null;
- switch ($type) {
- case 'transactions':
- $raw_type = 'transactions';
- break;
- case 'contributions':
- $raw_type = 'contributions';
- break;
- }
-
- $type = 'filter_' . $raw_type;
+ $filter_name = 'filter_' . $type;
$post = $request->getParsedBody();
$error_detected = [];
- if ($this->session->$type !== null) {
- $filters = $this->session->$type;
+ if ($this->session->$filter_name !== null) {
+ $filters = $this->session->$filter_name;
} else {
- $filter_class = '\\Galette\\Filters\\' . ucwords($raw_type) . 'List';
+ $filter_class = '\\Galette\\Filters\\' . ucwords($type) . 'List';
$filters = new $filter_class();
}
}
}
- $this->session->$type = $filters;
+ $this->session->$filter_name = $filters;
if (count($error_detected) > 0) {
//report errors
return $response
->withStatus(301)
- ->withHeader('Location', $this->router->pathFor('contributions', ['type' => $raw_type]));
+ ->withHeader('Location', $this->router->pathFor('contributions', ['type' => $type]));
+ }
+
+ /**
+ * Batch actions handler
+ *
+ * @param Request $request PSR Request
+ * @param Response $response PSR Response
+ * @param string $type One of 'transactions' or 'contributions'
+ *
+ * @return Response
+ */
+ public function handleBatch(Request $request, Response $response, string $type): Response
+ {
+ $filter_name = 'filter_' . $type;
+ $post = $request->getParsedBody();
+
+ if (isset($post['contrib_sel'])) {
+ if (isset($this->session->$filter_name)) {
+ $filters = $this->session->$filter_name;
+ } else {
+ $filters = new ContributionsList();
+ }
+
+ $filters->selected = $post['contrib_sel'];
+ $this->session->$filter_name = $filters;
+
+ if (isset($post['csv'])) {
+ return $response
+ ->withStatus(301)
+ ->withHeader('Location', $this->router->pathFor('csv-contributionslist', ['type' => $type]));
+ }
+
+ if (isset($post['delete'])) {
+ return $response
+ ->withStatus(301)
+ ->withHeader('Location', $this->router->pathFor('removeContributions'));
+ }
+
+ throw new \RuntimeException('Does not know what to batch :(');
+ } else {
+ $this->flash->addMessage(
+ 'error_detected',
+ _T("No contribution was selected, please check at least one.")
+ );
+
+ return $response
+ ->withStatus(301)
+ ->withHeader('Location', $this->router->pathFor('contributions', ['type' => $type]));
+ }
}
// /CRUD - Read
namespace Galette\Controllers;
+use Galette\Filters\ContributionsList;
+use Galette\IO\ContributionsCsv;
use Slim\Http\Request;
use Slim\Http\Response;
use Galette\Entity\ImportModel;
return $this->sendResponse($response, $filepath, $filename);
}
+
+ /**
+ * Contributions CSV exports
+ *
+ * @param Request $request PSR Request
+ * @param Response $response PSR Response
+ * @param string $type One of 'contributions' or 'transactions'
+ *
+ * @return Response
+ */
+ public function contributionsExport(Request $request, Response $response, string $type): Response
+ {
+ $post = $request->getParsedBody();
+ $get = $request->getQueryParams();
+
+ $session_var = $post['session_var'] ?? $get['session_var'] ?? 'filter_' . $type;
+
+ if (isset($this->session->$session_var)) {
+ $filters = $this->session->$session_var;
+ } else {
+ $filters = new ContributionsList();
+ }
+
+ $csv = new ContributionsCsv(
+ $this->zdb,
+ $this->login,
+ $type
+ );
+ $csv->exportContributions($filters);
+
+ $filepath = $csv->getPath();
+ $filename = $csv->getFileName();
+
+ return $this->sendResponse($response, $filepath, $filename);
+ }
}
*/
$this->_fields = array(
'id_cotis' => array(
- 'label' => null, //not a field in the form
+ 'label' => _T('Contribution id'), //not a field in the form
'propname' => 'id'
),
Adherent::PK => array(
'propname' => 'info'
),
'date_enreg' => array(
- 'label' => null, //not a field in the form
+ 'label' => _T('Date'), //not a field in the form
'propname' => 'date'
),
'date_debut_cotis' => array(
'propname' => 'end_date'
),
Transaction::PK => array(
- 'label' => null, //not a field in the form
+ 'label' => _T('Transaction ID'), //not a field in the form
'propname' => 'transaction'
),
//this one is not really a field, but is required in some cases...
- //adding it here make simplier to check required fields
+ //adding it here make more simple to check required fields
'duree_mois_cotis' => array(
'label' => _T("Membership extension:"),
'propname' => 'extension'
//count days until end of membership date
$diff1 = (int)$bdate->diff($edate)->format('%a');
- //count days beetween end of membership date and offered months
+ //count days between end of membership date and offered months
$tdate = clone $edate;
$tdate->modify('-' . $preferences->pref_membership_offermonths . ' month');
$diff2 = (int)$edate->diff($tdate)->format('%a');
$this->_begin_date = $r->date_debut_cotis;
$enddate = $r->date_fin_cotis;
//do not work with knows bad dates...
- //the one with BC comes from 0.63/pgsl demo... Why the hell a so
+ //the one with BC comes from 0.63/pgsql demo... Why the hell a so
//strange date? don't know :(
if (
$enddate !== '0000-00-00'
}
break;
case 'spayment_type':
- if ($this->_payment_type === null) {
- return '-';
- }
-
- $ptype = new PaymentType($this->zdb, (int)$this->payment_type);
- return $ptype->getName();
-
+ return $this->getPaymentType();
break;
case 'model':
if ($this->_is_cotis === null) {
{
$res = $this->get($id);
if ($res === false) {
- //get() alred logged
+ //get() already logged
return self::ID_NOT_EXITS;
};
$field = $this->flabel;
--- /dev/null
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Contributions CSV exports
+ *
+ * PHP version 5
+ *
+ * Copyright © 2021 The Galette Team
+ *
+ * This file is part of Galette (http://galette.tuxfamily.org).
+ *
+ * Galette is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Galette is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Galette. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category IO
+ * @package Galette
+ *
+ * @author Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2019 The Galette Team
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link http://galette.tuxfamily.org
+ * @since Available since 0.9.6-dev - 2021-11-07
+ */
+
+namespace Galette\IO;
+
+use DateTime;
+use Galette\Core\Db;
+use Galette\Core\Login;
+use Galette\Core\Authentication;
+use Galette\Entity\Adherent;
+use Galette\Entity\Contribution;
+use Galette\Entity\ContributionsTypes;
+use Galette\Repository\Contributions;
+use Galette\Filters\ContributionsList;
+use Galette\Repository\PaymentTypes;
+
+/**
+ * Contributions CSV exports
+ *
+ * @category IO
+ * @name Csv
+ * @package Galette
+ * @author Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2021 The Galette Team
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link http://galette.tuxfamily.org
+ * @since Available since 0.9.6-dev - 2021-11-07
+ */
+
+class ContributionsCsv extends CsvOut
+{
+ private $filename;
+ private $path;
+ private $zdb;
+ private $login;
+ private $members_fields;
+ private $fields_config;
+ private $filters;
+ private $type;
+
+ /**
+ * Default constructor
+ *
+ * @param Db $zdb Db instance
+ * @param Login $login Login instance
+ * @param string $type One of 'contributions' or 'transactions'
+ */
+ public function __construct(Db $zdb, Login $login, string $type)
+ {
+ $this->filename = 'filtered_' . $type . 'list.csv';
+ $this->path = self::DEFAULT_DIRECTORY . $this->filename;
+ $this->zdb = $zdb;
+ $this->login = $login;
+ $this->type = $type;
+ parent::__construct();
+ }
+
+ /**
+ * Export members CSV
+ *
+ * @param ContributionsList $filters Current filters
+ *
+ * @return void
+ */
+ public function exportContributions(ContributionsList $filters)
+ {
+ $class = '\\Galette\\Entity\\' . ucwords(trim($this->type, 's'));
+ $contrib = new $class($this->zdb, $this->login);
+
+ $fields = $contrib->fields;
+ //not a real data
+ unset($fields['duree_mois_cotis']);
+ $labels = array();
+
+ foreach ($fields as $k => $f) {
+ $label = $f['label'];
+ if (isset($f['cotlabel'])) {
+ $label = $f['cotlabel'] . ' / ' . $label;
+ }
+ $labels[] = $label;
+ }
+
+ $contributions = new Contributions($this->zdb, $this->login, $filters);
+ $contributions_list = $contributions->getArrayList($filters->selected);
+
+ $ptypes = PaymentTypes::getAll();
+ $ctype = new ContributionsTypes($this->zdb);
+
+ foreach ($contributions_list as &$contribution) {
+ if (isset($contribution->type_paiement_cotis)) {
+ //add textual payment type
+ $contribution->type_paiement_cotis = $ptypes[$contribution->type_paiement_cotis];
+ }
+
+ //add textual type
+ $contribution->id_type_cotis = $ctype->getLabel($contribution->id_type_cotis);
+
+ //handle dates
+ if (isset($contribution->date)) {
+ if (
+ $contribution->date != ''
+ && $contribution->date != '1901-01-01'
+ ) {
+ $date = new DateTime($contribution->date);
+ $contribution->date = $date->format(__("Y-m-d"));
+ } else {
+ $contribution->date = '';
+ }
+ }
+
+ if (isset($contribution->date_debut_cotis)) {
+ if (
+ $contribution->date_debut_cotis != ''
+ && $contribution->date_debut_cotis != '1901-01-01'
+ ) {
+ $date = new DateTime($contribution->date_debut_cotis);
+ $contribution->date_debut_cotis = $date->format(__("Y-m-d"));
+ } else {
+ $contribution->date_debut_cotis = '';
+ }
+ }
+
+ if (isset($contribution->date_fin_cotis)) {
+ if (
+ $contribution->date_fin_cotis != ''
+ && $contribution->date_fin_cotis != '1901-01-01'
+ ) {
+ $date = new DateTime($contribution->date_fin_cotis);
+ $contribution->date_fin_cotis = $date->format(__("Y-m-d"));
+ } else {
+ $contribution->date_fin_cotis = '';
+ }
+ }
+
+ //member name
+ if (isset($contribution->{Adherent::PK})) {
+ $contribution->{Adherent::PK} = Adherent::getSName($this->zdb, $contribution->{Adherent::PK});
+ }
+
+ //handle booleans
+ if (isset($member->activite_adh)) {
+ $member->activite_adh
+ = ($member->activite_adh) ? _T("Yes") : _T("No");
+ }
+ /*if (isset($member->bool_admin_adh)) {
+ $member->bool_admin_adh
+ = ($member->bool_admin_adh) ? _T("Yes") : _T("No");
+ }
+ if (isset($member->bool_exempt_adh)) {
+ $member->bool_exempt_adh
+ = ($member->bool_exempt_adh) ? _T("Yes") : _T("No");
+ }
+ if (isset($member->bool_display_info)) {
+ $member->bool_display_info
+ = ($member->bool_display_info) ? _T("Yes") : _T("No");
+ }*/
+ }
+
+ $fp = fopen($this->path, 'w');
+ if ($fp) {
+ $this->export(
+ $contributions_list,
+ self::DEFAULT_SEPARATOR,
+ self::DEFAULT_QUOTE,
+ $labels,
+ $fp
+ );
+ fclose($fp);
+ }
+ }
+
+ /**
+ * Get file path on disk
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * Get file name
+ *
+ * @return string
+ */
+ public function getFileName()
+ {
+ return $this->filename;
+ }
+}
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
- * Memers CSV exports
+ * Members CSV exports
*
* PHP version 5
*
private $count = null;
private $sum;
+ private $current_selection;
/**
* Default constructor
return $this->getList(true);
}
+ /**
+ * Get contributions list for a specific transaction
+ *
+ * @param array $ids an array of members id that has been selected
+ * @param bool $as_contrib return the results as an array of
+ * @param array $fields field(s) name(s) to get. Should be a string or
+ * an array. If null, all fields will be
+ * returned
+ * @param boolean $count true if we want to count members
+ *
+ * @return Contribution[]
+ */
+ public function getArrayList(array $ids, bool $as_contrib = false, array $fields = null, bool $count = true)
+ {
+ if (count($ids) < 1) {
+ Analog::log('No contribution selected.', Analog::INFO);
+ return false;
+ }
+
+ $this->current_selection = $ids;
+ $list = $this->getList($as_contrib, $fields, $count);
+ $array_list = [];
+ foreach ($list as $entry) {
+ $array_list[] = $entry;
+ }
+ return $array_list;
+ }
+
/**
* Get contributions list
*
$select->join(
array('p' => PREFIX_DB . Adherent::TABLE),
- 'a.' . Adherent::PK . '= p.' . Adherent::PK
+ 'a.' . Adherent::PK . '= p.' . Adherent::PK,
+ array()
);
$this->buildWhereClause($select);
break;
}
+ if (isset($this->current_selection)) {
+ $select->where->in('a.' . self::PK, $this->current_selection);
+ }
+
try {
if ($this->filters->start_date_filter != null) {
$d = new \DateTime($this->filters->rstart_date_filter);
</div>
</div>
</form>
- <form action="" method="post" id="listform">
+ <form action="{path_for name="batch-contributionslist" data=["type" => "contributions"]}" method="post" id="listform">
<table class="listing">
<thead>
<tr>
<i class="fas fa-trash fa-fw"></i> {_T string="Delete"}
</button>
</li>
+ <li>
+ <button type="submit" id="csv" name="csv">
+ <i class="fas fa-file-csv fa-fw"></i> {_T string="Export as CSV"}
+ </button>
+ </li>
</ul>
{/if}
{/if}
_init_contribs_page();
{include file="js_removal.tpl"}
- {include file="js_removal.tpl" selector="#delete" deleteurl="'{path_for name="removeContributions" data=["type" => "contributions"]}'" extra_check="if (!_checkselection()) {ldelim}return false;{rdelim}" extra_data="delete: true, contrib_sel: $('#listform input[type=\"checkbox\"]:checked').map(function(){ return $(this).val(); }).get()" method="POST"}
+ {include file="js_removal.tpl" selector="#delete" deleteurl="'{path_for name="batch-contributionslist" data=["type" => "contributions"]}'" extra_check="if (!_checkselection()) {ldelim}return false;{rdelim}" extra_data="delete: true, contrib_sel: $('#listform input[type=\"checkbox\"]:checked').map(function(){ return $(this).val(); }).get()" method="POST"}
});
</script>
{/block}