From: Johan Cwiklinski Date: Thu, 30 Sep 2021 06:00:22 +0000 (+0200) Subject: Massive add contributions; closes #1381 X-Git-Tag: 0.9.5.1~82 X-Git-Url: https://git.agnieray.net/?a=commitdiff_plain;h=a9b7715a88a1b3929de1583afff918e5959d78f8;p=galette.git Massive add contributions; closes #1381 --- diff --git a/galette/includes/routes/contributions.routes.php b/galette/includes/routes/contributions.routes.php index 10ee7f96f..eab836cc0 100644 --- a/galette/includes/routes/contributions.routes.php +++ b/galette/includes/routes/contributions.routes.php @@ -136,3 +136,18 @@ $app->post( '/document/{hash}', [PdfController::class, 'directlinkDocument'] )->setName('get-directlink'); + +$app->get( + '/contribution/mass-add/choose-type', + [Crud\ContributionsController::class, 'massAddChooseType'] +)->setName('massAddContributionsChooseType')->add($authenticate); + +$app->post( + '/contribution/mass-add', + [Crud\ContributionsController::class, 'massAddContributions'] +)->setName('massAddContributions')->add($authenticate); + +$app->post( + '/contribution/do-mass-add', + [Crud\ContributionsController::class, 'doMassAddContributions'] +)->setName('doMassAddContributions')->add($authenticate); diff --git a/galette/lib/Galette/Controllers/Crud/ContributionsController.php b/galette/lib/Galette/Controllers/Crud/ContributionsController.php index 974346b24..fc7d0303e 100644 --- a/galette/lib/Galette/Controllers/Crud/ContributionsController.php +++ b/galette/lib/Galette/Controllers/Crud/ContributionsController.php @@ -43,14 +43,9 @@ use Slim\Http\Response; use Galette\Entity\Adherent; use Galette\Entity\Contribution; use Galette\Entity\Transaction; -use Galette\Repository\Contributions; -use Galette\Repository\Transactions; use Galette\Repository\Members; use Galette\Entity\ContributionsTypes; -use Galette\Core\GaletteMail; -use Galette\IO\PdfMembersCards; use Galette\Repository\PaymentTypes; -use Analog\Analog; /** * Galette contributions controller @@ -92,13 +87,6 @@ class ContributionsController extends CrudController $ct = new ContributionsTypes($this->zdb); $contributions_types = $ct->getList($type === 'fee'); - $disabled = array(); - - if (!is_int($contrib->id)) { - // initialiser la structure contribution à vide (nouvelle contribution) - $contribution['duree_mois_cotis'] = $this->preferences->pref_membership_ext; - } - // template variable declaration $title = null; if ($type === 'fee') { @@ -113,20 +101,9 @@ class ContributionsController extends CrudController $title .= ' (' . _T("creation") . ')'; } - // required fields - $required = [ - 'id_type_cotis' => 1, - 'id_adh' => 1, - 'date_enreg' => 1, - 'date_debut_cotis' => 1, - 'date_fin_cotis' => $contrib->isCotis(), - 'montant_cotis' => $contrib->isCotis() ? 1 : 0 - ]; - $params = [ 'page_title' => $title, - 'required' => $required, - 'disabled' => $disabled, + 'required' => $contrib->getRequired(), 'contribution' => $contrib, 'adh_selected' => $contrib->member, 'type' => $type @@ -139,7 +116,7 @@ class ContributionsController extends CrudController $m = new Members(); $members = $m->getSelectizedMembers( $this->zdb, - isset($contrib) && $contrib->member > 0 ? $contrib->member : null + $contrib->member > 0 ? $contrib->member : null ); $params['members'] = [ @@ -152,7 +129,7 @@ class ContributionsController extends CrudController } $ext_membership = ''; - if (isset($contrib) && $contrib->isCotis() || !isset($contrib) && $type === 'fee') { + if ($contrib->isCotis() || !isset($contrib) && $type === 'fee') { $ext_membership = $this->preferences->pref_membership_ext; } $params['pref_membership_ext'] = $ext_membership; @@ -170,9 +147,9 @@ class ContributionsController extends CrudController /** * Add page * - * @param Request $request PSR Request - * @param Response $response PSR Response - * @param string $type Contribution type + * @param Request $request PSR Request + * @param Response $response PSR Response + * @param string|null $type Contribution type * * @return Response */ @@ -231,6 +208,157 @@ class ContributionsController extends CrudController return $this->store($request, $response, 'add', $type); } + /** + * Choose contribution type to mass add contribution + * + * @param Request $request PSR Request + * @param Response $response PSR Response + * + * @return Response + */ + public function massAddChooseType(Request $request, Response $response): Response + { + $filters = $this->session->filter_members; + $data = [ + 'id' => $filters->selected, + 'redirect_uri' => $this->router->pathFor('members') + ]; + + // display page + $this->view->render( + $response, + 'mass_choose_type.tpl', + array( + 'mode' => $request->isXhr() ? 'ajax' : '', + 'page_title' => str_replace( + '%count', + count($data['id']), + _T('Mass add contribution on %count members') + ), + 'data' => $data, + 'form_url' => $this->router->pathFor('massAddContributions'), + 'cancel_uri' => $this->router->pathFor('members') + ) + ); + return $response; + } + + /** + * Massive change page + * + * @param Request $request PSR Request + * @param Response $response PSR Response + * + * @return Response + */ + public function massAddContributions(Request $request, Response $response): Response + { + $post = $request->getParsedBody(); + $filters = $this->session->filter_members; + $contribution = new Contribution($this->zdb, $this->login); + + $type = $post['type']; + $data = [ + 'id' => $filters->selected, + 'redirect_uri' => $this->router->pathFor('members'), + 'type' => $type + ]; + + // contribution types + $ct = new ContributionsTypes($this->zdb); + $contributions_types = $ct->getList($type === 'fee'); + + // display page + $this->view->render( + $response, + 'mass_add_contribution.tpl', + array( + 'mode' => $request->isXhr() ? 'ajax' : '', + 'page_title' => str_replace( + '%count', + count($data['id']), + _T('Mass add contribution on %count members') + ), + 'form_url' => $this->router->pathFor('doMassAddContributions'), + 'cancel_uri' => $this->router->pathFor('members'), + 'data' => $data, + 'contribution' => $contribution, + 'type' => $type, + 'require_mass' => true, + 'required' => $contribution->getRequired(), + 'type_cotis_options' => $contributions_types + ) + ); + return $response; + } + + /** + * Do massive contribution add + * + * @param Request $request PSR Request + * @param Response $response PSR Response + * + * @return Response + */ + public function doMassAddContributions(Request $request, Response $response): Response + { + $post = $request->getParsedBody(); + $members_ids = $post['id']; + unset($post['id']); + + $error_detected = []; + + // flagging required fields for first step only + $disabled = []; + $success = 0; + $errors = 0; + + foreach ($members_ids as $member_id) { + $post[Adherent::PK] = (int)$member_id; + $contrib = new Contribution($this->zdb, $this->login); + + // regular fields + $valid = $contrib->check($post, $contrib->getRequired(), $disabled); + if ($valid !== true) { + $error_detected = array_merge($error_detected, $valid); + } + + //all goes well, we can proceed + if (count($error_detected) == 0) { + $store = $contrib->store(); + if ($store === true) { + ++$success; + $files_res = $contrib->handleFiles($_FILES); + if (is_array($files_res)) { + $error_detected = array_merge($error_detected, $files_res); + } + } else { + ++$errors; + } + } + } + + if (count($error_detected) == 0) { + $redirect_url = $this->router->pathFor('members'); + } else { + //something went wrong. + //store entity in session + $redirect_url = $this->router->pathFor('massAddContributions'); + //report errors + foreach ($error_detected as $error) { + $this->flash->addMessage( + 'error_detected', + $error + ); + } + } + + //redirect to calling action + return $response + ->withStatus(301) + ->withHeader('Location', $redirect_url); + } + // /CRUD - Create // CRUD - Read @@ -549,19 +677,10 @@ class ContributionsController extends CrudController } } - // flagging required fields for first step only - $required = [ - 'id_type_cotis' => 1, - 'id_adh' => 1, - 'date_enreg' => 1, - 'montant_cotis' => 1, //TODO: not always required, see #196 - 'date_debut_cotis' => 1, - 'date_fin_cotis' => ($type === 'fee') - ]; $disabled = []; // regular fields - $valid = $contrib->check($post, $required, $disabled); + $valid = $contrib->check($post, $contrib->getRequired(), $disabled); if ($valid !== true) { $error_detected = array_merge($error_detected, $valid); } diff --git a/galette/lib/Galette/Controllers/Crud/MembersController.php b/galette/lib/Galette/Controllers/Crud/MembersController.php index b9ae30824..38ce68c60 100644 --- a/galette/lib/Galette/Controllers/Crud/MembersController.php +++ b/galette/lib/Galette/Controllers/Crud/MembersController.php @@ -1029,6 +1029,12 @@ class MembersController extends CrudController ->withHeader('Location', $this->router->pathFor('masschangeMembers')); } + if (isset($post['masscontributions'])) { + return $response + ->withStatus(301) + ->withHeader('Location', $this->router->pathFor('massAddContributionsChooseType')); + } + throw new \RuntimeException('Does not know what to batch :('); } else { $this->flash->addMessage( diff --git a/galette/lib/Galette/Entity/Contribution.php b/galette/lib/Galette/Entity/Contribution.php index 000c0daf2..aa7a433f3 100644 --- a/galette/lib/Galette/Entity/Contribution.php +++ b/galette/lib/Galette/Entity/Contribution.php @@ -1365,4 +1365,23 @@ class Contribution return true; } } + + /** + * Get required fields list + * + * @return array + */ + public function getRequired(): array + { + // required fields + $required = [ + 'id_type_cotis' => 1, + 'id_adh' => 1, + 'date_enreg' => 1, + 'date_debut_cotis' => 1, + 'date_fin_cotis' => $this->isCotis(), + 'montant_cotis' => $this->isCotis() ? 1 : 0 + ]; + return $required; + } } diff --git a/galette/templates/default/ajouter_contribution.tpl b/galette/templates/default/ajouter_contribution.tpl index b7e2b84b1..531bdb03d 100644 --- a/galette/templates/default/ajouter_contribution.tpl +++ b/galette/templates/default/ajouter_contribution.tpl @@ -1,7 +1,12 @@ -{extends file="page.tpl"} +{if isset($mode) && $mode eq 'ajax'} + {assign var="extend" value='ajax.tpl'} +{else} + {assign var="extend" value='page.tpl'} +{/if} +{extends file=$extend} {block name="content"} -{if isset($members.list)} +{if isset($members.list) || $require_mass}
$type, "id" => $contribution->id]}{else}{path_for name="doAddContribution" data=["type" => $type]}{/if}" enctype="multipart/form-data" method="post">
{if $contribution->isTransactionPart()} @@ -64,9 +69,10 @@ {/if} + {if !$require_mass}

- {if $adh_selected eq 0} {/if} @@ -75,9 +81,10 @@ {/foreach}

+ {/if}

- {if $contribution->type} {assign var="selectedid" value=$contribution->type->id} {else} @@ -99,7 +106,7 @@ {if $type eq "fee"}{_T string="Details of membership fee"}{else}{_T string="Details of donation"}{/if}

- +

{* payment type *} {assign var="ptype" value=$contribution->payment_type} @@ -111,7 +118,7 @@ - + {_T string="(yyyy-mm-dd format)"}

@@ -123,18 +130,18 @@ {_T string="Date of contribution:"} {/if} - + {_T string="(yyyy-mm-dd format)"}

{if $type eq "fee"}

- {if $pref_membership_ext != ""} + {if $preferences->pref_membership_ext != ""} - + {_T string="months"} {else} - + {_T string="(yyyy-mm-dd format)"} {/if}

@@ -158,13 +165,16 @@ {/if} {include file="edit_dynamic_fields.tpl" object=$contribution} {if not $contribution->id and $pref_mail_method neq constant('Galette\Core\GaletteMail::METHOD_DISABLED')} + {if !$require_mass}

pref_bool_mailowner || isset($smarty.post.mail_confirm) and $smarty.post.mail_confirm != ""}checked="checked"{/if}/>
{_T string="Member will receive a notification by email, if he has an address."}

+ {/if} {/if}
+ {if !$require_mass}
+ {/if}
{else} {* No members *}
diff --git a/galette/templates/default/gestion_adherents.tpl b/galette/templates/default/gestion_adherents.tpl index 28f6ad702..6cdb3345e 100644 --- a/galette/templates/default/gestion_adherents.tpl +++ b/galette/templates/default/gestion_adherents.tpl @@ -308,6 +308,11 @@ We have to use a template file, so Smarty will do its work (like replacing varia {_T string="Mass change"} +
  • + +
  • {if $pref_mail_method neq constant('Galette\Core\GaletteMail::METHOD_DISABLED')}