Skip to content

Commit 7b06860

Browse files
committed
3893: Created pretix orders in public meeting fixture
1 parent bfbbe6c commit 7b06860

File tree

5 files changed

+211
-9
lines changed

5 files changed

+211
-9
lines changed

.github/workflows/pr.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ jobs:
177177
run: |
178178
docker network create frontend
179179
docker compose pull
180-
docker compose up --detach
180+
docker compose --profile pretix up --detach
181181
182182
# Important: Use --no-interaction to make https://getcomposer.org/doc/06-config.md#discard-changes have effect.
183183
docker compose exec phpfpm composer install --no-interaction
@@ -275,7 +275,7 @@ jobs:
275275
run: |
276276
docker network create frontend
277277
docker compose pull
278-
docker compose up --detach
278+
docker compose --profile pretix up --detach
279279
280280
# Important: Use --no-interaction to make https://getcomposer.org/doc/06-config.md#discard-changes have effect.
281281
docker compose exec phpfpm composer install --no-interaction

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ Versioning](https://semver.org/spec/v2.0.0.html).
99
* [PR-463](https://github.com/itk-dev/hoeringsportal/pull/463)
1010
3893: Avoid `<strong>` in translation
1111
* [PR-451](https://github.com/itk-dev/hoeringsportal/pull/451)
12-
3893: Enabled multiple pretix dates on public meetings
12+
* Enabled multiple pretix dates on public meetings
13+
* Updated fixtures with multipe date examples (and pretix orders)
1314
* [PR-472](https://github.com/itk-dev/hoeringsportal/pull/472)
1415
* Translated search page to Danish
1516
* Updated custom Danish translations (exported from production site)

Taskfile.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ tasks:
237237
- task drush -- --yes pm:uninstall content_fixtures
238238
# Update states on public meetings.
239239
- task drush -- --yes hoeringsportal:public_meeting:state-update
240+
- task drush -- --yes cache:rebuild
240241
silent: true
241242

242243
translations:import:

web/modules/custom/hoeringsportal_base_fixtures/hoeringsportal_base_fixtures.info.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ core_version_requirement: ^9 || ^10
55
package: ITK
66
dependencies:
77
- content_fixtures:content_fixtures
8+
- itk_pretix:itk_pretix

web/modules/custom/hoeringsportal_base_fixtures/src/Fixture/PublicMeetingFixture.php

Lines changed: 205 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@
77
use Drupal\content_fixtures\Fixture\FixtureGroupInterface;
88
use Drupal\Core\Session\AccountInterface;
99
use Drupal\Core\Session\AccountSwitcherInterface;
10+
use Drupal\Core\Site\Settings;
1011
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
12+
use Drupal\itk_pretix\Pretix\EventHelper as PretixEventHelper;
13+
use Drupal\itk_pretix\Pretix\OrderHelper as PretixOrderHelper;
1114
use Drupal\node\Entity\Node;
1215
use Drupal\node\NodeInterface;
16+
use Symfony\Component\Console\Output\ConsoleOutput;
17+
use Symfony\Component\Console\Output\NullOutput;
1318

1419
/**
1520
* Page fixture.
@@ -20,6 +25,8 @@ final class PublicMeetingFixture extends AbstractFixture implements DependentFix
2025

2126
public function __construct(
2227
private readonly AccountSwitcherInterface $accountSwitcher,
28+
private readonly PretixEventHelper $pretixEventHelper,
29+
private readonly PretixOrderHelper $pretixOrderHelper,
2330
) {
2431
}
2532

@@ -49,9 +56,9 @@ public function load() {
4956
'field_content_state' => 'active',
5057
'field_email_address' => '[email protected]',
5158
'field_first_meeting_time' => date('Y-m-d', 1283166912),
52-
'field_media_document' => [[$this->getReference('media_library:Fil:MTM')]],
59+
'field_media_document' => [[$this->getReference('media_library:Fil:MTM')]],
5360
'field_media_image_single' => [
54-
['target_id' => $this->getReference('media:Large1')->id()],
61+
['target_id' => $this->getReference('media:Large1')->id()],
5562
],
5663
'field_pretix_event_settings' => [
5764
'template_event' => 'template-series',
@@ -145,17 +152,209 @@ public function load() {
145152
$node = $node->createDuplicate();
146153
$node->setTitle('Public meeting with pretix signup and monthly occurrences');
147154
$node->set('field_pretix_dates', array_map(
148-
static fn (int $offset) => [
155+
static fn(int $offset) => [
149156
'location' => sprintf('Location %d', $offset + 1),
150157
'address' => 'Hack Kampmanns Plads 2, 8000 Aarhus C',
151-
'registration_deadline_value' => (new \DateTimeImmutable(sprintf('10:00 first day of %d month', $offset - 1)))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
152-
'time_from_value' => (new \DateTimeImmutable(sprintf('12:00 first day of %d month', $offset - 1)))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
153-
'time_to_value' => (new \DateTimeImmutable(sprintf('13:00 first day of %d month', $offset - 1)))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
158+
'registration_deadline_value' => (new \DateTimeImmutable(sprintf('10:00 first day of %d month',
159+
$offset - 1)))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
160+
'time_from_value' => (new \DateTimeImmutable(sprintf('12:00 first day of %d month',
161+
$offset - 1)))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
162+
'time_to_value' => (new \DateTimeImmutable(sprintf('13:00 first day of %d month',
163+
$offset - 1)))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
154164
'spots' => 10 * $offset + 7,
155165
],
156166
range(0, 12)
157167
));
158168
$node->save();
169+
170+
$node = $node->createDuplicate();
171+
$node->setTitle('Public meeting with pretix signup and daily occurrences');
172+
$node->set('field_pretix_dates', array_map(
173+
static fn(int $offset) => [
174+
'location' => sprintf('Location %d', $offset),
175+
'address' => 'Hack Kampmanns Plads 2, 8000 Aarhus C',
176+
'registration_deadline_value' => (new \DateTimeImmutable('10:00 first day of this month'))->modify(sprintf('+%d day',
177+
$offset - 1))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
178+
'time_from_value' => (new \DateTimeImmutable('12:00 first day of this month'))->modify(sprintf('+%d day',
179+
$offset - 1))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
180+
'time_to_value' => (new \DateTimeImmutable('13:00 first day of this month'))->modify(sprintf('+%d day',
181+
$offset - 1))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
182+
'spots' => 87,
183+
],
184+
range(1, (int) (new \DateTimeImmutable('this month'))->format('t')),
185+
));
186+
$node->save();
187+
188+
$node = $node->createDuplicate();
189+
$node->setTitle('Public meeting with orders');
190+
$node->set('field_pretix_dates', [
191+
[
192+
'location' => 'The location',
193+
'address' => 'Hack Kampmanns Plads 2, 8000 Aarhus C',
194+
'registration_deadline_value' => (new \DateTimeImmutable('2024-12-31T00:00:00+0100'))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
195+
'time_from_value' => (new \DateTimeImmutable('2025-01-01T19:00:00+0100'))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
196+
'time_to_value' => (new \DateTimeImmutable('2025-01-01T21:00:00+0100'))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
197+
'spots' => 10,
198+
],
199+
[
200+
'location' => 'Another location',
201+
'address' => 'Rådhuspladsen 1, 8000 Aarhus C',
202+
'registration_deadline_value' => (new \DateTimeImmutable('2025-11-30T00:00:00+0100'))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
203+
'time_from_value' => (new \DateTimeImmutable('2025-12-01T15:00:00+0100'))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
204+
'time_to_value' => (new \DateTimeImmutable('2025-12-01T16:30:00+0100'))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
205+
'spots' => 10,
206+
],
207+
[
208+
'location' => 'The location',
209+
'address' => 'Hack Kampmanns Plads 2, 8000 Aarhus C',
210+
'registration_deadline_value' => (new \DateTimeImmutable('2025-11-30T00:00:00+0100'))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
211+
'time_from_value' => (new \DateTimeImmutable('2025-12-02T15:00:00+0100'))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
212+
'time_to_value' => (new \DateTimeImmutable('2025-12-02T16:30:00+0100'))->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
213+
'spots' => 10,
214+
],
215+
]);
216+
$node->save();
217+
218+
$this->createOrders($node,
219+
[
220+
'lines' => [
221+
[
222+
'dates_delta' => 0,
223+
],
224+
],
225+
],
226+
[
227+
'email' => '[email protected]',
228+
'lines' => [
229+
[
230+
'dates_delta' => 1,
231+
'quantity' => 7,
232+
],
233+
],
234+
],
235+
236+
// Sell out.
237+
[
238+
'lines' => [
239+
[
240+
'dates_delta' => 2,
241+
'quantity' => 10,
242+
],
243+
],
244+
],
245+
);
246+
}
247+
248+
/**
249+
* Create orders in pretix.
250+
*
251+
* @param \Drupal\node\NodeInterface $node
252+
* The public meeting node.
253+
* @param array ...$specs
254+
* Order specs, e.g.
255+
*
256+
* <code>
257+
* [
258+
* [
259+
* // Optional email; defaults to '[email protected]'.
260+
* 'email' => '[email protected]',
261+
* 'lines' => [
262+
* [
263+
* // The date to create an order line for
264+
* 'dates_delta' => 0,
265+
* // The quantity; defaults to 1.
266+
* 'quantity' => 9,
267+
* ],
268+
* ],
269+
* ],
270+
* [
271+
* 'lines' => [
272+
* [
273+
* 'dates_delta' => 1,
274+
* ],
275+
* ],
276+
* ],
277+
*
278+
* // Sell out.
279+
* [
280+
* 'lines' => [
281+
* [
282+
* 'dates_delta' => 2,
283+
* 'quantity' => 10,
284+
* ],
285+
* ],
286+
* ],
287+
* ]
288+
* </code>.
289+
*/
290+
public function createOrders(NodeInterface $node, array ...$specs): void {
291+
$output = 'cli' === PHP_SAPI ? new ConsoleOutput() : new NullOutput();
292+
293+
if (empty($specs)) {
294+
throw new \InvalidArgumentException('Missing specs');
295+
}
296+
297+
$output->writeln(sprintf('Creating orders for %s (#%d)', $node->label(),
298+
$node->id()));
299+
300+
$client = $this->pretixEventHelper->getPretixClient($node);
301+
$request = new \ReflectionMethod($client, 'request');
302+
303+
// Add setting to create a proper webhook in pretix
304+
// (http://pretix.hoeringsportal.local.itkdev.dk/control/organizer/hoeringsportal/webhooks)
305+
// (see PretixOrderHelper::ensureWebhook() for details).
306+
$settings = Settings::getAll();
307+
if (!isset($settings['itk_pretix']['drupal_base_url'])) {
308+
$settings['itk_pretix']['drupal_base_url'] = 'http://hoeringsportal.local.itkdev.dk:8080';
309+
}
310+
new Settings($settings);
311+
$output->writeln(sprintf('Ensuring that webhook (%s) exists in pretix',
312+
$settings['itk_pretix']['drupal_base_url']));
313+
$this->pretixOrderHelper->ensureWebhook($client);
314+
315+
$eventInfo = $this->pretixEventHelper->loadPretixEventInfo($node);
316+
/** @var \Drupal\Core\Field\FieldItemListInterface $dates */
317+
$dates = $node->get('field_pretix_dates');
318+
foreach ($specs as $spec) {
319+
$lines = $spec['lines'] ?? NULL;
320+
if (!is_array($lines)) {
321+
continue;
322+
}
323+
foreach ($spec['lines'] as $line) {
324+
$date = $dates[$line['dates_delta']] ?? NULL;
325+
if (!$date) {
326+
continue;
327+
}
328+
329+
$subEventInfo = $this->pretixEventHelper->loadPretixSubEventInfo($date);
330+
// https://docs.pretix.eu/dev/api/resources/orders.html#creating-orders
331+
$path = sprintf(
332+
'organizers/%s/events/%s/orders/',
333+
$eventInfo['pretix_organizer_slug'],
334+
$eventInfo['pretix_event_slug'],
335+
);
336+
$payload = [
337+
'json' => [
338+
'email' => $spec['email'] ?? '[email protected]',
339+
'positions' => array_map(
340+
static fn(int $index) => [
341+
'subevent' => $subEventInfo['pretix_subevent_id'],
342+
'attendee_name' => sprintf('Attendee %d', $index),
343+
'attendee_email' => sprintf('test%[email protected]', $index),
344+
'item' => reset($subEventInfo['data']['subevent']['item_price_overrides'])['item'],
345+
],
346+
range(1, $line['quantity'] ?? 1),
347+
),
348+
],
349+
];
350+
351+
$output->writeln(sprintf('POST\'ing %s to %s', json_encode($payload, JSON_PRETTY_PRINT), $path));
352+
/** @var \Psr\Http\Message\ResponseInterface $response */
353+
$response = $request->invoke($client, 'POST', $path, $payload);
354+
355+
$output->writeln(sprintf('Response: %d', $response->getStatusCode()));
356+
}
357+
}
159358
}
160359

161360
/**

0 commit comments

Comments
 (0)