Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(cleanup) Membership in months or by default #498

Merged
merged 2 commits into from May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions galette/docs/CHANGES
Expand Up @@ -29,6 +29,7 @@ Changes
- Menu entry was not always correctly selected
- Add payment type on transactions
- Remove non user related files from cofiguration folder
- Add monthly contribution membership

1.0.3 -> 1.0.4

Expand Down
2 changes: 1 addition & 1 deletion galette/install/scripts/mysql.sql
Expand Up @@ -100,7 +100,7 @@ CREATE TABLE galette_types_cotisation (
id_type_cotis int(10) unsigned NOT NULL auto_increment,
libelle_type_cotis varchar(255) NOT NULL default '',
amount decimal(15,2) NULL DEFAULT NULL,
cotis_extension tinyint(1) NOT NULL default 0,
cotis_extension tinyint NOT NULL default 0,
PRIMARY KEY (id_type_cotis)
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;

Expand Down
2 changes: 1 addition & 1 deletion galette/install/scripts/pgsql.sql
Expand Up @@ -255,7 +255,7 @@ CREATE TABLE galette_types_cotisation (
id_type_cotis integer DEFAULT nextval('galette_types_cotisation_id_seq'::text) NOT NULL,
libelle_type_cotis character varying(255) DEFAULT '' NOT NULL,
amount decimal(15,2) NULL DEFAULT NULL,
cotis_extension boolean DEFAULT FALSE,
cotis_extension integer DEFAULT 0,
PRIMARY KEY (id_type_cotis)
);

Expand Down
4 changes: 4 additions & 0 deletions galette/install/scripts/sql/upgrade-to-1.10-mysql.sql
Expand Up @@ -83,3 +83,7 @@ CREATE TABLE galette_payments_schedules (
FOREIGN KEY (id_cotis) REFERENCES galette_cotisations (id_cotis) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (id_paymenttype) REFERENCES galette_paymenttypes (type_id) ON DELETE CASCADE ON UPDATE CASCADE
);

ALTER TABLE galette_types_cotisation CHANGE cotis_extension cotis_extension TINYINT NOT NULL DEFAULT '0';
UPDATE galette_types_cotisation SET cotis_extension=-1 WHERE cotis_extension=1;

5 changes: 5 additions & 0 deletions galette/install/scripts/sql/upgrade-to-1.10-pgsql.sql
Expand Up @@ -70,3 +70,8 @@ CREATE TABLE galette_payments_schedules (
comment text,
PRIMARY KEY (id_schedule)
);

ALTER TABLE galette_types_cotisation ALTER COLUMN cotis_extension DROP DEFAULT;
ALTER TABLE galette_types_cotisation ALTER cotis_extension TYPE integer USING CASE WHEN cotis_extension=false THEN 0 ELSE -1 END;
ALTER TABLE galette_types_cotisation ALTER COLUMN cotis_extension SET DEFAULT 0;

Expand Up @@ -197,7 +197,7 @@ public function store(
$ctype = new ContributionsTypes($this->zdb);

$label = trim($post['libelle_type_cotis']);
$field = (bool)trim($post['cotis_extension'] ?? 0);
$field = (int)trim($post['cotis_extension'] ?? 0);
$amount = null;
if (isset($post['amount']) && $post['amount'] !== '') {
$amount = (float)$post['amount'];
Expand Down
39 changes: 20 additions & 19 deletions galette/lib/Galette/Entity/Contribution.php
Expand Up @@ -173,7 +173,7 @@ public function __construct(Db $zdb, Login $login, int|array|ArrayObject $args =
} else {
// Caution : the next_begin_date is the day after the due_date.
$next_begin_date = clone $due_date;
$next_begin_date->add(new \DateInterval('P1D'));
$next_begin_date->add(new DateInterval('P1D'));
$this->begin_date = $next_begin_date->format('Y-m-d');
}
}
Expand Down Expand Up @@ -249,7 +249,6 @@ protected function setFields(): self
return $this;
}


/**
* Sets end contribution date
*
Expand All @@ -261,12 +260,16 @@ private function retrieveEndDate(): void

$now = new \DateTime();
$begin_date = new \DateTime($this->begin_date);
if ($preferences->pref_beg_membership != '') {

if ($this->type->extension > ContributionsTypes::DONATION_TYPE) {
$dext = new DateInterval('P' . $this->type->extension . 'M');
$end_date = $begin_date->add($dext);
} elseif ($preferences->pref_beg_membership != '') {
//case beginning of membership
list($j, $m) = explode('/', $preferences->pref_beg_membership);
$next_begin_date = new DateTime($begin_date->format('Y') . '-' . $m . '-' . $j);
while ($next_begin_date <= $begin_date) {
$next_begin_date->add(new \DateInterval('P1Y'));
$next_begin_date->add(new DateInterval('P1Y'));
}

if ($preferences->pref_membership_offermonths > 0) {
Expand All @@ -275,35 +278,34 @@ private function retrieveEndDate(): void

//count days between next membership begin date and offered months
$tdate = clone $next_begin_date;
$tdate->sub(new \DateInterval('P' . $preferences->pref_membership_offermonths . 'M'));
$tdate->sub(new DateInterval('P' . $preferences->pref_membership_offermonths . 'M'));
$diff2 = (int)$next_begin_date->diff($tdate)->format('%a');

//when number of days until next membership begin date is less than or equal to the offered months, it's free :)
if ($diff1 <= $diff2) {
$next_begin_date->add(new \DateInterval('P1Y'));
$next_begin_date->add(new DateInterval('P1Y'));
}
}

// Caution : the end_date to retrieve is the day before the next_begin_date.
$end_date = clone $next_begin_date;
$end_date->sub(new \DateInterval('P1D'));
$this->end_date = $end_date->format('Y-m-d');
trasher marked this conversation as resolved.
Show resolved Hide resolved
} elseif ($preferences->pref_membership_ext != '') {
//case membership extension
if ($this->extension == null) {
$this->extension = $preferences->pref_membership_ext;
}
$dext = new \DateInterval('P' . $this->extension . 'M');
$dext = new DateInterval('P' . $this->extension . 'M');
// Caution : the end_date to retrieve is the day before the next_begin_date.
$next_begin_date = $begin_date->add($dext);
$end_date = clone $next_begin_date;
$end_date->sub(new \DateInterval('P1D'));
$this->end_date = $end_date->format('Y-m-d');
} else {
throw new \RuntimeException(
'Unable to define end date; none of pref_beg_membership nor pref_membership_ext are defined!'
);
}

// Caution : the end_date to retrieve is the day before the next_begin_date.
$end_date->sub(new DateInterval('P1D'));
$this->end_date = $end_date->format('Y-m-d');
}

/**
Expand Down Expand Up @@ -564,7 +566,7 @@ public function checkOverlap(): bool|string
'c.' . ContributionsTypes::PK . '=ct.' . ContributionsTypes::PK,
array()
)->where([Adherent::PK => $this->member])
->where(array('cotis_extension' => new Expression('true')))
->where->notEqualTo('cotis_extension', ContributionsTypes::DONATION_TYPE)
->where->nest->nest
->greaterThanOrEqualTo('date_debut_cotis', $this->begin_date)
->lessThanOrEqualTo('date_debut_cotis', $this->end_date)
Expand Down Expand Up @@ -861,9 +863,8 @@ public static function getDueDate(Db $zdb, ?int $member_id): ?string
array()
)->where(
[Adherent::PK => $member_id]
)->where(
array('cotis_extension' => new Expression('true'))
);
)
->where->notEqualTo('cotis_extension', ContributionsTypes::DONATION_TYPE);

$results = $zdb->execute($select);
$result = $results->current();
Expand Down Expand Up @@ -1375,10 +1376,10 @@ public function setContributionType(int $type): self
//set type
$this->type = new ContributionsTypes($this->zdb, $type);
//set is_cotis according to type
if ($this->type->extension == 1) {
$this->is_cotis = true;
} else {
if ($this->type->extension == ContributionsTypes::DONATION_TYPE) {
$this->is_cotis = false;
} else {
$this->is_cotis = true;
}

return $this;
Expand Down
49 changes: 25 additions & 24 deletions galette/lib/Galette/Entity/ContributionsTypes.php
Expand Up @@ -37,14 +37,16 @@
* @property string $label
* @property string $libelle
* @property ?float $amount
* @property boolean $extension
* @property int $extension
*/

class ContributionsTypes
{
use I18n;

public const DEFAULT_TYPE = 1;
public const DEFAULT_TYPE = -1;
public const DONATION_TYPE = 0;

public const TABLE = 'types_cotisation';
public const PK = 'id_type_cotis';

Expand All @@ -53,7 +55,7 @@ class ContributionsTypes
private int $id;
private string $label;
private ?float $amount;
private bool $is_extension = false;
private int $extension;

public const ID_NOT_EXITS = -1;

Expand All @@ -62,13 +64,13 @@ class ContributionsTypes

/** @var array<int, array<string, mixed>> */
protected static array $defaults = array(
array('id' => 1, 'libelle' => 'annual fee', 'extension' => '1'),
array('id' => 2, 'libelle' => 'reduced annual fee', 'extension' => '1'),
array('id' => 3, 'libelle' => 'company fee', 'extension' => '1'),
array('id' => 4, 'libelle' => 'donation in kind', 'extension' => 0),
array('id' => 5, 'libelle' => 'donation in money', 'extension' => 0),
array('id' => 6, 'libelle' => 'partnership', 'extension' => 0),
array('id' => 7, 'libelle' => 'annual fee (to be paid)', 'extension' => '1')
array('id' => 1, 'libelle' => 'annual fee', 'extension' => self::DEFAULT_TYPE),
array('id' => 2, 'libelle' => 'reduced annual fee', 'extension' => self::DEFAULT_TYPE),
array('id' => 3, 'libelle' => 'company fee', 'extension' => self::DEFAULT_TYPE),
array('id' => 4, 'libelle' => 'donation in kind', 'extension' => self::DONATION_TYPE),
array('id' => 5, 'libelle' => 'donation in money', 'extension' => self::DONATION_TYPE),
array('id' => 6, 'libelle' => 'partnership', 'extension' => self::DONATION_TYPE),
array('id' => 7, 'libelle' => 'annual fee (to be paid)', 'extension' => self::DEFAULT_TYPE)
);

/**
Expand All @@ -80,6 +82,7 @@ class ContributionsTypes
public function __construct(Db $zdb, int|ArrayObject $args = null)
{
$this->zdb = $zdb;
$this->extension = self::DEFAULT_TYPE;
if (is_int($args)) {
$this->load($args);
} elseif ($args instanceof ArrayObject) {
Expand Down Expand Up @@ -136,7 +139,7 @@ private function loadFromRS(ArrayObject $r): void
$this->id = $r->{self::PK};
$this->label = $r->libelle_type_cotis;
$this->amount = $r->amount;
$this->is_extension = (bool)$r->cotis_extension;
$this->extension = (int)$r->cotis_extension;
}

/**
Expand All @@ -146,7 +149,7 @@ private function loadFromRS(ArrayObject $r): void
*/
public function isExtension(): bool
{
return $this->is_extension;
return $this->extension !== self::DONATION_TYPE;
}

/**
Expand Down Expand Up @@ -234,9 +237,9 @@ public function getList(bool $extent = null): array
$select->order(self::PK);

if ($extent === true) {
$select->where(array('cotis_extension' => new Expression('true')));
$select->where->notEqualTo('cotis_extension', self::DONATION_TYPE);
} elseif ($extent === false) {
$select->where(array('cotis_extension' => new Expression('false')));
$select->where->equalTo('cotis_extension', self::DONATION_TYPE);
}

$results = $this->zdb->execute($select);
Expand Down Expand Up @@ -381,13 +384,13 @@ public function getIdByLabel(string $label): int|false
/**
* Add a new entry
*
* @param string $label The label
* @param ?float $amount The amount
* @param boolean $extension Extends membership?
* @param string $label The label
* @param ?float $amount The amount
* @param int $extension Membership extension in months, 0 for a donation or -1 for preferences default
*
* @return bool|integer -2 : label already exists
*/
public function add(string $label, ?float $amount, bool $extension): bool|int
public function add(string $label, ?float $amount, int $extension): bool|int
{
// Avoid duplicates.
$label = strip_tags($label);
Expand All @@ -406,7 +409,7 @@ public function add(string $label, ?float $amount, bool $extension): bool|int
$values = array(
'libelle_type_cotis' => $label,
'amount' => $amount ?? new Expression('NULL'),
'cotis_extension' => $extension ? true : ($this->zdb->isPostgres() ? 'false' : 0)
'cotis_extension' => $extension
);

$insert = $this->zdb->insert(self::TABLE);
Expand Down Expand Up @@ -446,11 +449,11 @@ public function add(string $label, ?float $amount, bool $extension): bool|int
* @param integer $id Entry ID
* @param string $label The label
* @param ?float $amount The amount
* @param boolean $extension Extends membership?
* @param int $extension Membership extension in months, 0 for a donation or -1 for preferences default
*
* @return self::ID_NOT_EXITS|boolean
*/
public function update(int $id, string $label, ?float $amount, bool $extension): int|bool
public function update(int $id, string $label, ?float $amount, int $extension): int|bool
{
$label = strip_tags($label);
$ret = $this->get($id);
Expand All @@ -465,7 +468,7 @@ public function update(int $id, string $label, ?float $amount, bool $extension):
$values = array(
'libelle_type_cotis' => $label,
'amount' => $amount ?? new Expression('NULL'),
'cotis_extension' => $extension ? true : ($this->zdb->isPostgres() ? 'false' : 0)
'cotis_extension' => $extension
);

$update = $this->zdb->update(self::TABLE);
Expand Down Expand Up @@ -593,8 +596,6 @@ public function __get(string $name): mixed
switch ($name) {
case 'libelle':
return _T($this->label);
case 'extension':
return $this->isExtension();
default:
return $this->$name;
}
Expand Down
2 changes: 1 addition & 1 deletion galette/templates/default/components/forms/input.html.twig
Expand Up @@ -28,7 +28,7 @@
{% endif %}
{% if type is defined and type == 'checkbox' %}
<div class="ui toggle{% if checked is defined and checked == true %} checked{% endif %} right aligned checkbox">
{% else %}
{% elseif nolabel is not defined or nolabel != true %}
{% block label %}
<label for="{{ id }}"{% if title is defined %} title="{{ title }}"{% endif %}{% if labelclass is defined %} class="{% if labelclass is defined %}{{ labelclass }}{% endif %}"{% endif %}>
{% if masschange ?? false %}
Expand Down
21 changes: 15 additions & 6 deletions galette/templates/default/pages/contribution_type_form.html.twig
Expand Up @@ -33,12 +33,21 @@
<label for="amount">{{ _T("Amount:") }}</label>
<input type="text" name="amount" id="amount" value="{{ entry.amount }}"/>
</div>
<div class="ui toggle checkbox">
<input type="checkbox" name="cotis_extension" id="cotis_extension" value="1"{% if entry.cotis_extension == 1 %} checked="checked"{% endif %} />
<label for="cotis_extension">
{{ _T("Extends membership?") }}
</label>
</div>
{% set cotisextensions = {
(constant("Galette\\Entity\\ContributionsTypes::DEFAULT_TYPE")): _T("Default"),
(constant("Galette\\Entity\\ContributionsTypes::DONATION_TYPE")): _T("No"),
(1): _Tn('%1$s month', '%1$s months', 1)|format(1)
} %}
{% for m in 2..11 %}
{% set cotisextensions = cotisextensions + {(m): _Tn('%1$s month', '%1$s months', m)|format(m)} %}
{% endfor %}
{% include "components/forms/select.html.twig" with {
id: 'cotis_extension',
value: entry.cotis_extension,
values: cotisextensions,
label: _T("Membership extension"),
component_class: 'field inline',
} %}
</div>

<input type="hidden" name="mod" id="mod" value="{{ entry.id_type_cotis }}"/>
Expand Down