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
31 changes: 31 additions & 0 deletions app/Events/Vouchers/VoucherSendToEmailBySponsorEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace App\Events\Vouchers;

use App\Models\Voucher;

class VoucherSendToEmailBySponsorEvent extends BaseVoucherEvent
{
protected ?string $email;

/**
* Create a new event instance.
*
* @param Voucher $voucher
* @param string|null $email
*/
public function __construct(Voucher $voucher, ?string $email)
{
parent::__construct($voucher);

$this->email = $email;
}

/**
* @return string|null
*/
public function getEmail(): ?string
{
return $this->email;
}
}
24 changes: 0 additions & 24 deletions app/Events/Vouchers/VoucherSendToEmailEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,6 @@

namespace App\Events\Vouchers;

use App\Models\Voucher;

class VoucherSendToEmailEvent extends BaseVoucherEvent
{
protected string $email;

/**
* Create a new event instance.
*
* @param Voucher $voucher
* @param string $email
*/
public function __construct(Voucher $voucher, string $email)
{
parent::__construct($voucher);

$this->email = $email;
}

/**
* @return string
*/
public function getEmail(): string
{
return $this->email;
}
}
15 changes: 15 additions & 0 deletions app/Helpers/Number.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace App\Helpers;

class Number extends \Illuminate\Support\Number
{
/**
* @param float $amount
* @return int
*/
public static function toCents(float $amount): int
{
return (int) round($amount * 100);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use App\Events\Funds\FundVouchersExportedEvent;
use App\Events\Vouchers\VoucherLimitUpdated;
use App\Events\Vouchers\VoucherSendToEmailBySponsorEvent;
use App\Exports\VoucherExport;
use App\Helpers\Arr;
use App\Http\Controllers\Controller;
Expand Down Expand Up @@ -481,7 +482,10 @@ public function sendByEmail(
$this->authorize('show', $organization);
$this->authorize('sendByEmailSponsor', [$voucher, $organization]);

$voucher->sendToEmail($request->post('email'));
Event::dispatch(new VoucherSendToEmailBySponsorEvent(
$voucher,
$voucher->granted ? null : $request->post('email')
));

return SponsorVoucherResource::create($voucher);
}
Expand Down
13 changes: 12 additions & 1 deletion app/Http/Controllers/Api/Platform/PayoutsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Http\Controllers\Api\Platform;

use App\Helpers\Number;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\Platform\Payouts\IndexPayoutsRequest;
use App\Http\Requests\Api\Platform\Payouts\StorePayoutRequest;
Expand Down Expand Up @@ -87,7 +88,17 @@ public function store(StorePayoutRequest $request): VoucherTransactionPayoutReso
}
}

if (VoucherPayoutAmountRule::exceedsBalance($amount, (float) $voucher->amount_available)) {
$partialAmounts = $voucher->getPayoutPartialAmounts();

if (is_array($partialAmounts)) {
$allowedCents = array_map(fn (string $amount) => Number::toCents((float) $amount), $partialAmounts);

if (!in_array(Number::toCents($amount), $allowedCents, true)) {
throw ValidationException::withMessages([
'amount' => [trans('validation.payout.amount_partial')],
]);
}
} elseif (VoucherPayoutAmountRule::exceedsBalance($amount, (float) $voucher->amount_available)) {
throw ValidationException::withMessages([
'amount' => [VoucherPayoutAmountRule::balanceExceededMessage($voucher)],
]);
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/Api/Platform/VouchersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public function sendEmail(Voucher $voucher): JsonResponse
{
$this->authorize('sendEmail', $voucher);

$voucher->sendToEmail($voucher->identity->email);
$voucher->sendToEmail();

return new JsonResponse([]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ public function authorize(): bool
{
return
$this->organization->identityCan($this->identity(), Permission::MANAGE_VOUCHERS) &&
$this->voucher->fund->organization_id === $this->organization->id &&
!$this->voucher->granted;
$this->voucher->fund->organization_id === $this->organization->id;
}

/**
Expand All @@ -36,7 +35,7 @@ public function rules(): array
{
return [
'email' => [
'required',
$this->voucher->granted ? 'nullable' : 'required',
new IdentityEmailExistsRule(),
...$this->emailRules(),
],
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Resources/FundResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ protected function getFundConfigData(Fund $fund, bool $isDashboard): array
'key', 'allow_fund_requests', 'allow_fund_request_prefill', 'allow_prevalidations',
'allow_direct_requests', 'allow_blocking_vouchers', 'backoffice_fallback', 'is_configured',
'email_required', 'contact_info_enabled', 'contact_info_required', 'allow_reimbursements',
'allow_voucher_payouts', 'allow_voucher_payout_count',
'allow_voucher_payouts', 'allow_voucher_payouts_partial', 'allow_voucher_payout_count',
'contact_info_message_custom', 'contact_info_message_text', 'bsn_confirmation_time',
'auth_2fa_policy', 'auth_2fa_remember_ip', 'auth_2fa_restrict_reimbursements',
'auth_2fa_restrict_auth_sessions', 'auth_2fa_restrict_emails',
Expand Down
1 change: 1 addition & 0 deletions app/Http/Resources/Sponsor/SponsorVoucherResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public function toArray(Request $request): array
'url_webshop' => $voucher->fund->fund_config->implementation->url_webshop ?? null,
'show_subsidies' => $voucher->fund->fund_config->show_subsidies ?? false,
'show_qr_limits' => $voucher->fund->fund_config->show_qr_limits ?? false,
'show_qr_code' => $voucher->fund->fund_config->show_qr_code ?? false,
'show_requester_limits' => $voucher->fund->fund_config->show_requester_limits ?? false,
'allow_physical_cards' => $voucher->fund->fund_config->allow_physical_cards ?? false,
'allow_voucher_records' => $voucher->fund->fund_config->allow_voucher_records ?? false,
Expand Down
3 changes: 2 additions & 1 deletion app/Http/Resources/VoucherResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public function toArray(Request $request): array
'iban' => $voucher->fund_request->getIban(false),
'iban_name' => $voucher->fund_request->getIbanName(false),
] : null,
'voucher_payout_partial_amounts' => $voucher->getPayoutPartialAmounts(),
...$this->getRecords($voucher),
...$this->timestamps($voucher, 'created_at'),
];
Expand Down Expand Up @@ -274,7 +275,7 @@ protected function getFundResource(Voucher $voucher): array
'fund_physical_card_types' => FundPhysicalCardTypeResource::collection($fund->fund_physical_card_types),
...$fund->fund_config->only([
'allow_reimbursements', 'allow_reservations', 'key', 'show_qr_code',
'allow_voucher_payouts', 'allow_voucher_payout_count',
'allow_voucher_payouts', 'allow_voucher_payouts_partial', 'allow_voucher_payout_count',
]),
'voucher_payout_fixed_amount' => $payoutAmount === null ? null : currency_format($payoutAmount),
];
Expand Down
54 changes: 44 additions & 10 deletions app/Listeners/VoucherSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
use App\Events\Vouchers\VoucherExpireSoon;
use App\Events\Vouchers\VoucherLimitUpdated;
use App\Events\Vouchers\VoucherPhysicalCardRequestedEvent;
use App\Events\Vouchers\VoucherSendToEmailBySponsorEvent;
use App\Events\Vouchers\VoucherSendToEmailEvent;
use App\Mail\Vouchers\SendVoucherMail;
use App\Models\Voucher;
use App\Models\VoucherToken;
use App\Notifications\Identities\Voucher\IdentityProductVoucherAddedNotification;
use App\Notifications\Identities\Voucher\IdentityProductVoucherExpiredNotification;
use App\Notifications\Identities\Voucher\IdentityProductVoucherReservedNotification;
use App\Notifications\Identities\Voucher\IdentityProductVoucherSharedByEmailNotification;
use App\Notifications\Identities\Voucher\IdentityProductVoucherSharedNotification;
use App\Notifications\Identities\Voucher\IdentitySponsorProductVoucherSharedByEmailNotification;
use App\Notifications\Identities\Voucher\IdentitySponsorVoucherSharedByEmailNotification;
use App\Notifications\Identities\Voucher\IdentityVoucherAddedBudgetNotification;
use App\Notifications\Identities\Voucher\IdentityVoucherAssignedBudgetNotification;
use App\Notifications\Identities\Voucher\IdentityVoucherAssignedProductNotification;
Expand Down Expand Up @@ -271,31 +274,61 @@ public function onVoucherDeactivated(VoucherDeactivated $voucherDeactivated): vo
}

/**
* @param VoucherSendToEmailEvent $event
* @param VoucherSendToEmailBySponsorEvent $event
* @noinspection PhpUnused
*/
public function onVoucherSendToEmail(VoucherSendToEmailEvent $event): void
public function onVoucherSendToEmailBySponsor(VoucherSendToEmailBySponsorEvent $event): void
{
$email = $event->getEmail();
$voucher = $event->getVoucher();

$eventLog = $voucher->log($voucher::EVENT_SHARED_BY_EMAIL, [
'fund' => $voucher->fund,
'voucher' => $voucher,
'product' => $voucher->product,
'sponsor' => $voucher->fund->organization,
'provider' => $voucher->product?->organization,
'implementation' => $voucher->fund->getImplementation(),
], [
'email' => $email,
'qr_token' => $voucher->fund->fund_config->show_qr_code
? $voucher->token_without_confirmation->address
: null,
'voucher_product_or_fund_name' => $voucher->product->name ?? $voucher->fund->name,
'expiration_date' => format_date_locale($voucher->last_active_day),
]);

IdentityVoucherSharedByEmailNotification::send($eventLog);
if ($voucher->product) {
IdentitySponsorProductVoucherSharedByEmailNotification::send($eventLog);
} else {
IdentitySponsorVoucherSharedByEmailNotification::send($eventLog);
}
}

/**
* @param VoucherSendToEmailEvent $event
* @noinspection PhpUnused
*/
public function onVoucherSendToEmailByIdentity(VoucherSendToEmailEvent $event): void
{
$voucher = $event->getVoucher();

$eventLog = $voucher->log($voucher::EVENT_SHARED_BY_EMAIL, [
'fund' => $voucher->fund,
'product' => $voucher->product,
'sponsor' => $voucher->fund->organization,
'provider' => $voucher->product?->organization,
'implementation' => $voucher->fund->getImplementation(),
], [
'qr_token' => $voucher->fund->fund_config->show_qr_code
? $voucher->token_without_confirmation->address
: null,
]);

resolve('forus.services.notification')->sendSystemMail($email, new SendVoucherMail(
$eventLog->data,
$voucher->fund->getEmailFrom()
));
if ($voucher->product) {
IdentityProductVoucherSharedByEmailNotification::send($eventLog);
} else {
IdentityVoucherSharedByEmailNotification::send($eventLog);
}
}

/**
Expand Down Expand Up @@ -350,7 +383,8 @@ public function subscribe(Dispatcher $events): void
$events->listen(VoucherExpireSoon::class, "$class@onVoucherExpireSoon");
$events->listen(VoucherExpired::class, "$class@onVoucherExpired");
$events->listen(VoucherDeactivated::class, "$class@onVoucherDeactivated");
$events->listen(VoucherSendToEmailEvent::class, "$class@onVoucherSendToEmail");
$events->listen(VoucherSendToEmailEvent::class, "$class@onVoucherSendToEmailByIdentity");
$events->listen(VoucherSendToEmailBySponsorEvent::class, "$class@onVoucherSendToEmailBySponsor");
$events->listen(VoucherPhysicalCardRequestedEvent::class, "$class@onVoucherPhysicalCardRequested");
}
}
2 changes: 1 addition & 1 deletion app/Mail/Funds/FundRequests/FundRequestApprovedMail.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ protected function getMailExtraData(array $data): array
return [
'app_link' => $this->makeLink($data['app_link'], 'download de Me-app'),
'webshop_link' => $this->makeLink($data['webshop_link'], 'hier'),
'webshop_button' => $this->makeButton($data['webshop_link'], 'Activeer tegoed'),
'webshop_button' => $this->makeButton($data['webshop_link'], 'Ga naar webshop'),
];
}
}
2 changes: 1 addition & 1 deletion app/Mail/Reimbursements/ReimbursementApprovedMail.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ protected function getMailExtraData(array $data): array
return [
'app_link' => $this->makeLink($data['app_link'], 'download de Me-app'),
'webshop_link' => $this->makeLink($data['webshop_link'], 'hier'),
'webshop_button' => $this->makeButton($data['webshop_link'], 'Activeer tegoed'),
'webshop_button' => $this->makeButton($data['webshop_link'], 'Ga naar webshop'),
];
}
}
32 changes: 32 additions & 0 deletions app/Mail/Vouchers/SendProductVoucherBySponsorMail.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace App\Mail\Vouchers;

use App\Mail\ImplementationMail;
use Illuminate\Mail\Mailable;
use League\CommonMark\Exception\CommonMarkException;

class SendProductVoucherBySponsorMail extends ImplementationMail
{
public ?string $notificationTemplateKey = 'notifications_identities.sponsor_product_voucher_shared_by_email';

/**
* @throws CommonMarkException
* @return Mailable
*/
public function build(): Mailable
{
return $this->buildNotificationTemplatedMail();
}

/**
* @param array $data
* @return array
*/
protected function getMailExtraData(array $data): array
{
return [
...$data['qr_token'] ? ['qr_token' => $this->makeQrCode($data['qr_token'])] : [],
];
}
}
32 changes: 32 additions & 0 deletions app/Mail/Vouchers/SendProductVoucherMail.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace App\Mail\Vouchers;

use App\Mail\ImplementationMail;
use Illuminate\Mail\Mailable;
use League\CommonMark\Exception\CommonMarkException;

class SendProductVoucherMail extends ImplementationMail
{
public ?string $notificationTemplateKey = 'notifications_identities.product_voucher_shared_by_email';

/**
* @throws CommonMarkException
* @return Mailable
*/
public function build(): Mailable
{
return $this->buildNotificationTemplatedMail();
}

/**
* @param array $data
* @return array
*/
protected function getMailExtraData(array $data): array
{
return [
...$data['qr_token'] ? ['qr_token' => $this->makeQrCode($data['qr_token'])] : [],
];
}
}
Loading
Loading