Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ jobs:
- name: CS
run: |
cd galette-core/galette/plugins/plugin-helloasso
../../vendor/bin/phpcs lib/ ./*.php
../../vendor/bin/phpcs lib/ tests/ ./*.php

- name: CS Fixer
if: matrix.php-is-min
Expand Down
29 changes: 19 additions & 10 deletions lib/GaletteHelloasso/Controllers/HelloassoController.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,15 @@ class HelloassoController extends AbstractPluginController
#[Inject("Plugin Galette Helloasso")]
protected array $module_info;

#[Inject]
protected Helloasso $helloasso;

/**
* Main form
*/
public function form(Response $response): Response
{
$helloasso = new Helloasso($this->zdb, $this->preferences);
$helloasso = $this->helloasso;

$current_url = $this->preferences->getURL();

Expand Down Expand Up @@ -90,7 +93,7 @@ public function form(Response $response): Response
public function formCheckout(Request $request, Response $response): Response
{
$helloasso_request = $request->getParsedBody();
$helloasso = new Helloasso($this->zdb, $this->preferences);
$helloasso = $this->helloasso;
$adherent = new Adherent($this->zdb);

// Only reasons proposed to the current user can be paid
Expand Down Expand Up @@ -188,7 +191,7 @@ public function logs(
$helloasso = $this->session->helloasso;
$this->session->helloasso = null;
} else {
$helloasso = new Helloasso($this->zdb, $this->preferences);
$helloasso = $this->helloasso;
}

$filters = [];
Expand Down Expand Up @@ -300,7 +303,7 @@ public function preferences(Request $request, Response $response): Response
$helloasso = $this->session->helloasso;
$this->session->helloasso = null;
} else {
$helloasso = new Helloasso($this->zdb, $this->preferences);
$helloasso = $this->helloasso;
}

$amounts = $helloasso->getAllAmounts();
Expand All @@ -312,6 +315,8 @@ public function preferences(Request $request, Response $response): Response
'webhook_url' => $this->preferences->getURL() . $this->routeparser->urlFor('helloasso_webhook'),
'amounts' => $amounts,
'tab' => $tab,
//one call to HelloAsso for the whole page
'organization' => $helloasso->getOrganization(),
'documentation' => 'https://galette-plugins.github.io/plugin-helloasso/documentation.html#pr%C3%A9f%C3%A9rences'
];

Expand All @@ -330,7 +335,7 @@ public function preferences(Request $request, Response $response): Response
public function storePreferences(Request $request, Response $response): Response
{
$post = $request->getParsedBody();
$helloasso = new Helloasso($this->zdb, $this->preferences);
$helloasso = $this->helloasso;

if ($this->login->isAdmin()) {
if (array_key_exists('helloasso_test_mode', $post)) {
Expand Down Expand Up @@ -392,7 +397,7 @@ public function webhook(Request $request, Response $response): Response
{
$body = $request->getBody();
$post = json_decode($body->getContents(), true);
$helloasso = new Helloasso($this->zdb, $this->preferences);
$helloasso = $this->helloasso;

// Verify notification authenticity
// https://dev.helloasso.com/docs/secure-webhook
Expand Down Expand Up @@ -421,7 +426,10 @@ public function webhook(Request $request, Response $response): Response
&& $post['metadata']['item_id']
) {
$hh = new HelloassoHistory($this->zdb, $this->login, $this->preferences);
$hh->add($post);
if (!$hh->add($post)) {
//HelloAsso will send it again
return $response->withStatus(500, 'Internal error');
}

// are we working on a real contribution?
$real_contrib = false;
Expand Down Expand Up @@ -541,7 +549,7 @@ public function returnUrl(Request $request, Response $response): Response
}

try {
$helloasso = new Helloasso($this->zdb, $this->preferences);
$helloasso = $this->helloasso;
$tokens = $helloasso->getTokens();

$client = $helloasso->setupClient();
Expand All @@ -552,15 +560,16 @@ public function returnUrl(Request $request, Response $response): Response
]
];

$request = $client->get(
$api_response = $client->request(
'GET',
$helloasso->getApiRoute()
. 'v5/organizations/'
. $helloasso->getOrganizationSlug()
. '/checkout-intents/'
. $checkout_id,
$headers
);
$checkout = json_decode($request->getBody()->getContents(), true);
$checkout = json_decode($api_response->getBody()->getContents(), true);

$details = [
'amount' => $checkout['order']['amount']['total'] / 100,
Expand Down
22 changes: 14 additions & 8 deletions lib/GaletteHelloasso/Helloasso.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Galette\Core\Preferences;
use Galette\Entity\ContributionsTypes;
use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface;

/**
* Preferences for helloasso
Expand All @@ -34,6 +35,7 @@ class Helloasso

private Db $zdb;
private Preferences $preferences;
private ?ClientInterface $client;

/** @var array<int, array<string,mixed>> */
private array $prices;
Expand Down Expand Up @@ -64,13 +66,15 @@ class Helloasso
/**
* Default constructor
*
* @param Db $zdb Database instance
* @param Preferences $preferences Preferences
* @param Db $zdb Database instance
* @param Preferences $preferences Preferences
* @param ?ClientInterface $client HTTP client, a default one is built if null
*/
public function __construct(Db $zdb, Preferences $preferences)
public function __construct(Db $zdb, Preferences $preferences, ?ClientInterface $client = null)
{
$this->zdb = $zdb;
$this->preferences = $preferences;
$this->client = $client;
$this->loaded = false;
$this->prices = [];
$this->inactives = [];
Expand Down Expand Up @@ -341,9 +345,11 @@ public function checkout(array $metadata, float $amount, ?bool $contains_donatio

try {
$tokens = $this->getTokens();
//19.99 * 100 is 1998.9999999999998
$amount = (int)round($amount);
$data = [
'totalAmount' => (int)$amount,
'initialAmount' => (int)$amount,
'totalAmount' => $amount,
'initialAmount' => $amount,
'itemName' => $metadata['item_name'],
'backUrl' => $this->preferences->getURL() . $routeparser->urlFor('helloasso_back'),
'errorUrl' => $this->preferences->getURL() . $routeparser->urlFor('helloasso_error'),
Expand Down Expand Up @@ -372,7 +378,7 @@ public function checkout(array $metadata, float $amount, ?bool $contains_donatio
],
'json' => $data,
];
$request = $client->post($this->getApiRoute() . 'v5/organizations/' . $this->getOrganizationSlug() . '/checkout-intents', $headers);
$request = $client->request('POST', $this->getApiRoute() . 'v5/organizations/' . $this->getOrganizationSlug() . '/checkout-intents', $headers);
$contents = $request->getBody()->getContents();

return json_decode($contents, true);
Expand All @@ -389,9 +395,9 @@ public function checkout(array $metadata, float $amount, ?bool $contains_donatio
/**
* Setup Guzzle client
*/
public function setupClient(): Client
public function setupClient(): ClientInterface
{
return new Client(
return $this->client ??= new Client(
$this->getClientOptions()
);
}
Expand Down
10 changes: 7 additions & 3 deletions lib/GaletteHelloasso/HelloassoHistory.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@ public function add(array|string $action, string $argument = '', string $query =
$insert = $this->zdb->insert($this->getTableName());
$insert->values($values);
$this->zdb->execute($insert);
$this->id = (int)$this->zdb->driver->getLastGeneratedValue();
//without the sequence name, pgsql gives no value
$this->id = (int)$this->zdb->connection->getLastGeneratedValue(
$this->zdb->isPostgres() ? $this->zdb->getSequenceName($this->getTableName(), 'id', prefixed: true) : null
);

Analog::log(
'An entry has been added in helloasso history',
Expand Down Expand Up @@ -143,12 +146,13 @@ public function getHelloassoHistory(): array
foreach ($orig as $o) {
try {
if (Galette::isSerialized($o['request'])) {
$oa = unserialize($o['request']);
//legacy entries: only plain data is expected
$oa = unserialize($o['request'], ['allowed_classes' => false]);
} else {
$oa = Galette::jsonDecode($o['request']);
}

$o['member_fullname'] = $this->getMemberFullName($o['member_id']);
$o['member_fullname'] = $this->getMemberFullName((int)$o['member_id']);
$o['raw_request'] = print_r($oa, true);
$o['request'] = $oa;

Expand Down
13 changes: 13 additions & 0 deletions lib/GaletteHelloasso/PluginGaletteHelloasso.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Galette\Core\Plugins\MenuProviderInterface;
use Galette\Core\Preferences;
use Galette\Core\GalettePlugin;
use Laminas\Db\Metadata\Source\Factory;

/**
* Galette HelloAsso plugin
Expand Down Expand Up @@ -132,4 +133,16 @@ public function isInstalled(): bool
&& $this->zdb->tableExists(HELLOASSO_PREFIX . HelloassoHistory::TABLE)
;
}

/**
* Database version of tables installed before versions tracking
*
* Payer, member, method and receipt are history columns since 1.1.0.
*/
public function getLegacyDbVersion(): ?float
{
$metadata = Factory::createSourceFromAdapter($this->zdb->db);
$columns = $metadata->getColumnNames(PREFIX_DB . HELLOASSO_PREFIX . HelloassoHistory::TABLE);
return in_array('payer_name', $columns, true) ? null : 1.0;
}
}
1 change: 1 addition & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ parameters:
level: 6
paths:
- lib/
- tests/
scanFiles:
- _config.inc.php
- ../../includes/sys_config/paths.inc.php
Expand Down
4 changes: 2 additions & 2 deletions scripts/pgsql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ CREATE SEQUENCE galette_helloasso_history_id_seq
DROP TABLE IF EXISTS galette_helloasso_history;
CREATE TABLE galette_helloasso_history (
id_helloasso integer DEFAULT nextval('galette_helloasso_history_id_seq'::text) NOT NULL,
history_date date NOT NULL,
history_date timestamp NOT NULL,
checkout_id character varying(255),
amount real NOT NULL,
amount numeric(15,2) NOT NULL,
comments character varying(255),
request text,
state smallint DEFAULT 0 NOT NULL,
Expand Down
22 changes: 13 additions & 9 deletions scripts/upgrade-to-1.1.0-mysql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,35 @@

INSERT INTO galette_helloasso_preferences (nom_pref, val_pref) VALUES ('helloasso_sepa_option', '');

-- without collation, columns get the one of the table
ALTER TABLE galette_helloasso_history
MODIFY checkout_id varchar(255) COLLATE utf8mb4_unicode_520_ci,
MODIFY comments varchar(255) COLLATE utf8mb4_unicode_520_ci,
MODIFY request text COLLATE utf8mb4_unicode_520_ci;
MODIFY checkout_id varchar(255),
MODIFY comments varchar(255),
MODIFY request text;

ALTER TABLE galette_helloasso_history
ADD COLUMN payer_name VARCHAR(255) NOT NULL,
ADD COLUMN member_id INT(10) NOT NULL,
ADD COLUMN method VARCHAR(10) NOT NULL,
ADD COLUMN receipt_url VARCHAR(255) NOT NULL;

-- 1.0.0 states were 0 (public donation), 1 (processed), 2 (error), 3 (incomplete)
-- and 4 (already done); incomplete payments did not create any contribution
Comment thread
gagnieray marked this conversation as resolved.
UPDATE galette_helloasso_history
SET
state = CASE
WHEN state = 0 THEN 3
state = CASE state
WHEN 0 THEN 3
WHEN 3 THEN 2
Comment thread
gagnieray marked this conversation as resolved.
ELSE state
END,
payer_name = CONCAT(
payer_name = COALESCE(CONCAT(
UPPER(JSON_UNQUOTE(JSON_EXTRACT(request, '$.data.payer.lastName'))),
' ',
JSON_UNQUOTE(JSON_EXTRACT(request, '$.data.payer.firstName'))
),
), ''),
member_id = COALESCE(
CAST(JSON_UNQUOTE(JSON_EXTRACT(request, '$.metadata.member_id')) AS UNSIGNED),
0
),
method = JSON_UNQUOTE(JSON_EXTRACT(request, '$.data.paymentMeans')),
receipt_url = JSON_UNQUOTE(JSON_EXTRACT(request, '$.data.paymentReceiptUrl'));
method = COALESCE(JSON_UNQUOTE(JSON_EXTRACT(request, '$.data.paymentMeans')), ''),
receipt_url = COALESCE(JSON_UNQUOTE(JSON_EXTRACT(request, '$.data.paymentReceiptUrl')), '');
40 changes: 24 additions & 16 deletions scripts/upgrade-to-1.1.0-pgsql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,34 @@

INSERT INTO galette_helloasso_preferences (nom_pref, val_pref) VALUES ('helloasso_sepa_option', '');

-- Keep time of payments, and do not store amounts as floating point numbers
ALTER TABLE galette_helloasso_history
ADD COLUMN payer_name character varying(255) NOT NULL,
ADD COLUMN member_id integer NOT NULL,
ADD COLUMN method character varying(10) NOT NULL,
ADD COLUMN receipt_url character varying(255) NOT NULL;
ALTER COLUMN history_date TYPE timestamp,
ALTER COLUMN amount TYPE numeric(15,2),
ADD COLUMN payer_name character varying(255) DEFAULT '' NOT NULL,
ADD COLUMN member_id integer DEFAULT 0 NOT NULL,
ADD COLUMN method character varying(10) DEFAULT '' NOT NULL,
ADD COLUMN receipt_url character varying(255) DEFAULT '' NOT NULL;
ALTER TABLE galette_helloasso_history
ALTER COLUMN payer_name DROP DEFAULT,
ALTER COLUMN member_id DROP DEFAULT,
ALTER COLUMN method DROP DEFAULT,
ALTER COLUMN receipt_url DROP DEFAULT;

-- 1.0.0 states were 0 (public donation), 1 (processed), 2 (error), 3 (incomplete)
-- and 4 (already done); incomplete payments did not create any contribution
Comment thread
gagnieray marked this conversation as resolved.
UPDATE galette_helloasso_history
SET
state = CASE
WHEN state = 0 THEN 3
state = CASE state
WHEN 0 THEN 3
WHEN 3 THEN 2
Comment thread
gagnieray marked this conversation as resolved.
ELSE state
END,
payer_name = CONCAT(
UPPER((request->'data'->'payer'->>'lastName')),
payer_name = TRIM(CONCAT(
UPPER(request::json->'data'->'payer'->>'lastName'),
' ',
(request->'data'->'payer'->>'firstName')
),
member_id = COALESCE(
(request->'metadata'->>'member_id')::int,
0
),
method = request->'data'->>'paymentMeans',
receipt_url = request->'data'->>'paymentReceiptUrl';
request::json->'data'->'payer'->>'firstName'
)),
member_id = COALESCE((request::json->'metadata'->>'member_id')::integer, 0),
method = COALESCE(request::json->'data'->>'paymentMeans', ''),
receipt_url = COALESCE(request::json->'data'->>'paymentReceiptUrl', '');
4 changes: 3 additions & 1 deletion templates/default/helloasso_error.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
{{ _T("Your Helloasso payment has failed for technical reasons.", "helloasso") }}
{% if error %}
<ul class="list">
<li>{{ _T("Payment nb.", "helloasso") }} : <code>{{ error.checkoutIntentId }}</code></li>
{% if error.checkoutIntentId is defined %}
<li>{{ _T("Payment nb.", "helloasso") }} : <code>{{ error.checkoutIntentId }}</code></li>
{% endif %}
{% if error.error is defined %}
<li>{{ _T("Error", "helloasso") }} : <code>{{ error.error }}</code></li>
{% endif %}
Expand Down
Loading
Loading