Skip to content

Commit

Permalink
Merge branch 'develop' into feature/add-template-to-voucher-set
Browse files Browse the repository at this point in the history
  • Loading branch information
ok200paul committed Sep 24, 2024
2 parents f801505 + 19412e5 commit 4a9fb86
Show file tree
Hide file tree
Showing 116 changed files with 2,560 additions and 1,047 deletions.
2 changes: 2 additions & 0 deletions app/Enums/ApiResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/
enum ApiResponse: string
{
case RESPONSE_ALREADY_EXISTS = 'Already exists';
case RESPONSE_DELETED = 'Deleted';
case RESPONSE_ERROR = 'Error';
case RESPONSE_FILE_TYPE_NOT_ALLOWED = 'File type not allowed';
Expand Down Expand Up @@ -34,4 +35,5 @@ enum ApiResponse: string
case RESPONSE_REDEMPTION_TEST_REDEMPTION = 'Please provide the customer with their goods / services to the value of XXX.';
case RESPONSE_REDEMPTION_SUCCESSFUL = 'Redemption successful.';
case RESPONSE_UPDATED = 'Updated';
case RESPONSE_VOUCHER_BENEFICIARY_DISTRIBUTION_SENT_ELSEWHERE = 'This voucher has been previously sent to a different beneficiary.';
}
25 changes: 16 additions & 9 deletions app/Enums/PersonalAccessTokenAbility.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,18 @@ enum PersonalAccessTokenAbility: string
case SYSTEM_STATISTICS_READ = 'system-statistics-read';
case SYSTEM_STATISTICS_UPDATE = 'system-statistics-update';
case SYSTEM_STATISTICS_DELETE = 'system-statistics-delete';
case VOUCHER_REDEMPTIONS_CREATE = 'voucher-redemptions-create';
case VOUCHER_REDEMPTIONS_READ = 'voucher-redemptions-read';
case VOUCHER_REDEMPTIONS_UPDATE = 'voucher-redemptions-update';
case VOUCHER_REDEMPTIONS_DELETE = 'voucher-redemptions-delete';
case VOUCHER_BENEFICIARY_DISTRIBUTION_CREATE = 'voucher-beneficiary-distributions-create';
case VOUCHER_BENEFICIARY_DISTRIBUTION_READ = 'voucher-beneficiary-distributions-read';
case VOUCHER_BENEFICIARY_DISTRIBUTION_UPDATE = 'voucher-beneficiary-distributions-update';
case VOUCHER_BENEFICIARY_DISTRIBUTION_DELETE = 'voucher-beneficiary-distributions-delete';
case VOUCHER_SET_MERCHANT_TEAM_APPROVAL_REQUESTS_CREATE = 'voucher-set-merchant-team-approval-requests-create';
case VOUCHER_SET_MERCHANT_TEAM_APPROVAL_REQUESTS_READ = 'voucher-set-merchant-team-approval-requests-read';
case VOUCHER_SET_MERCHANT_TEAM_APPROVAL_REQUESTS_UPDATE = 'voucher-set-merchant-team-approval-requests-update';
case VOUCHER_SET_MERCHANT_TEAM_APPROVAL_REQUESTS_DELETE = 'voucher-set-merchant-team-approval-requests-delete';
case VOUCHER_REDEMPTIONS_CREATE = 'voucher-redemptions-create';
case VOUCHER_REDEMPTIONS_READ = 'voucher-redemptions-read';
case VOUCHER_REDEMPTIONS_UPDATE = 'voucher-redemptions-update';
case VOUCHER_REDEMPTIONS_DELETE = 'voucher-redemptions-delete';
case MY_TEAM_SEARCH_CREATE = 'my-team-search-create';
case MY_TEAM_SEARCH_READ = 'my-team-search-read';
case MY_TEAM_SEARCH_UPDATE = 'my-team-search-update';
Expand Down Expand Up @@ -94,15 +98,18 @@ public static function abilityLabels(): array
self::SYSTEM_STATISTICS_READ->value => 'System Statistics Read',
self::SYSTEM_STATISTICS_UPDATE->value => 'System Statistics Update',
self::SYSTEM_STATISTICS_DELETE->value => 'System Statistics Delete',
self::VOUCHER_REDEMPTIONS_CREATE->value => 'Voucher Redemptions Create',
self::VOUCHER_REDEMPTIONS_READ->value => 'Voucher Redemptions Read',
self::VOUCHER_REDEMPTIONS_UPDATE->value => 'Voucher Redemptions Update',
self::VOUCHER_REDEMPTIONS_DELETE->value => 'Voucher Redemptions Delete',
self::VOUCHER_BENEFICIARY_DISTRIBUTION_CREATE->value => 'Voucher Beneficiary Distribution Create',
self::VOUCHER_BENEFICIARY_DISTRIBUTION_READ->value => 'Voucher Beneficiary Distribution Read',
self::VOUCHER_BENEFICIARY_DISTRIBUTION_UPDATE->value => 'Voucher Beneficiary Distribution Update',
self::VOUCHER_BENEFICIARY_DISTRIBUTION_DELETE->value => 'Voucher Beneficiary Distribution Delete',
self::VOUCHER_SET_MERCHANT_TEAM_APPROVAL_REQUESTS_CREATE->value => 'Voucher Set Merchant Team Approval Request Create',
self::VOUCHER_SET_MERCHANT_TEAM_APPROVAL_REQUESTS_READ->value => 'Voucher Set Merchant Team Approval Request Read',
self::VOUCHER_SET_MERCHANT_TEAM_APPROVAL_REQUESTS_UPDATE->value => 'Voucher Set Merchant Team Approval Request Update',
self::VOUCHER_SET_MERCHANT_TEAM_APPROVAL_REQUESTS_DELETE->value => 'Voucher Set Merchant Team Approval Request Delete',

self::VOUCHER_REDEMPTIONS_CREATE->value => 'Voucher Redemptions Create',
self::VOUCHER_REDEMPTIONS_READ->value => 'Voucher Redemptions Read',
self::VOUCHER_REDEMPTIONS_UPDATE->value => 'Voucher Redemptions Update',
self::VOUCHER_REDEMPTIONS_DELETE->value => 'Voucher Redemptions Delete',
];
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace App\Events\VoucherBeneficiaryDistributions;

use App\Models\VoucherBeneficiaryDistribution;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class VoucherBeneficiaryDistributionCreated
{
use Dispatchable, InteractsWithSockets, SerializesModels;

/**
* Create a new event instance.
*
* @param VoucherBeneficiaryDistribution $voucherBeneficiaryDistribution
*/
public function __construct(public VoucherBeneficiaryDistribution $voucherBeneficiaryDistribution) {}

/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('channel-name'),
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class ApiMyTeamVouchersController extends Controller
* Set the related data the GET request is allowed to ask for
*/
public array $availableRelations = [
'voucherBeneficiaryDistributions',
'voucherRedemptions.redeemedByUser',
'voucherRedemptions.redeemedByTeam',
'createdByTeam',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
<?php

/** @noinspection PhpUnusedParameterInspection */

namespace App\Http\Controllers\Api\V1;

use App\Enums\ApiResponse;
use App\Http\Controllers\Api\HandlesAPIRequests;
use App\Http\Controllers\Controller;
use App\Models\Voucher;
use App\Models\VoucherBeneficiaryDistribution;
use App\Models\VoucherSet;
use Crypt;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Knuckles\Scribe\Attributes\Authenticated;
use Knuckles\Scribe\Attributes\BodyParam;
use Knuckles\Scribe\Attributes\Endpoint;
use Knuckles\Scribe\Attributes\Group;
use Knuckles\Scribe\Attributes\Response;
use Knuckles\Scribe\Attributes\Subgroup;

#[Group('App Endpoints')]
#[Subgroup('/voucher-beneficiary-distribution', 'API for create voucher beneficiary distributions')]
class ApiVoucherBeneficiaryDistributionController extends Controller
{
use HandlesAPIRequests;

/**
* Set the related data the GET request is allowed to ask for
*/
public array $availableRelations = [];

public static array $searchableFields = [
];

/**
* @hideFromAPIDocumentation
*/
public function index(): JsonResponse
{
$this->responseCode = 403;
$this->message = ApiResponse::RESPONSE_METHOD_NOT_ALLOWED->value;

return $this->respond();
}

#[Endpoint(
title : 'POST /',
description : 'Create a new beneficiary distribution.',
authenticated: true
)]
#[Authenticated]
#[BodyParam(
name : 'voucher_id',
type : 'uuid',
description: 'The UUID of the voucher to be distributed. required_without:resend_beneficiary_distribution_id',
required : false
)]
#[BodyParam(
name : 'beneficiary_email',
type : 'email',
description: 'The email for the voucher beneficiary. required_without:resend_beneficiary_distribution_id',
required : false
)]
#[BodyParam(
name : 'resend_beneficiary_distribution_id',
type : 'integer',
description: 'The database ID for a beneficiary distribution that you would like to resend. Must belong to your team. required_without:beneficiary_email,voucher_id',
required : false
)]
#[Response(
content : '{"meta":{"responseCode":200,"limit":50,"offset":0,"message":"Saved.","cached":false,"availableRelations":[]},"data":{"id": "1234"}}',
status : 200,
description: '',
)]
public function store(): JsonResponse
{
/**
* The validation array.
*/
$validationArray = [
'voucher_id' => [
'required_without:resend_beneficiary_distribution_id',
'string',
Rule::exists('vouchers', 'id'),
],
'beneficiary_email' => [
'required_without:resend_beneficiary_distribution_id',
'email',
],
'resend_beneficiary_distribution_id' => [
'sometimes',
Rule::exists('voucher_beneficiary_distributions', 'id'),
],
];

$validator = Validator::make($this->request->all(), $validationArray);

if ($validator->fails()) {

$this->responseCode = 400;
$this->message = $validator->errors()->first();

return $this->respond();
}

try {

$voucherId = $this->request->get('voucher_id');
$beneficiaryEmail = $this->request->get('beneficiary_email');

/**
* Ensure the authenticated user team owns the voucher
*/
$voucher = Voucher::where('created_by_team_id', Auth::user()->current_team_id)
->orWhere('allocated_to_service_team_id', Auth::user()->current_team_id)
->find($voucherId);

if (!$voucher) {
$this->responseCode = 404;
$this->message = ApiResponse::RESPONSE_NOT_FOUND->value;

return $this->respond();
}

/**
* The client is re-sending an existing distribution.
*/
if ($this->request->has('resend_beneficiary_distribution_id')) {

$id = $this->request->get('resend_beneficiary_distribution_id');

$voucherBeneficiaryDistribution = VoucherBeneficiaryDistribution::find($id);

if (!$voucherBeneficiaryDistribution) {
$this->responseCode = 404;
$this->message = ApiResponse::RESPONSE_NOT_FOUND->value;

return $this->respond();
}

/**
* Ensure the voucher set belongs to the user's current team
*/
$voucherSet = VoucherSet::where('created_by_team_id', Auth::user()->current_team_id)
->orWhere('allocated_to_service_team_id', Auth::user()->current_team_id)
->find($voucherBeneficiaryDistribution->voucher_set_id);
if (!$voucherSet) {
$this->responseCode = 404;
$this->message = ApiResponse::RESPONSE_NOT_FOUND->value;

return $this->respond();
}

$decryptedEmail = Crypt::decrypt($voucherBeneficiaryDistribution->beneficiary_email_encrypted);

$model = new VoucherBeneficiaryDistribution();
$model->voucher_id = $voucherBeneficiaryDistribution->voucher_id;
$model->voucher_set_id = $voucherBeneficiaryDistribution->voucher_set_id;
$model->beneficiary_email_encrypted = Crypt::encrypt($decryptedEmail);
$model->created_by_user_id = Auth::id();
$model->save();

$this->data = $model;

return $this->respond();

}

/**
* Ensure this voucher has not been sent to someone else.
*/
$numExistingDistributionsForThisVoucher = VoucherBeneficiaryDistribution::where('voucher_id', $voucherId)
->count();

if ($numExistingDistributionsForThisVoucher > 0) {
$this->responseCode = 400;
$this->message = ApiResponse::RESPONSE_ALREADY_EXISTS->value;

return $this->respond();
}

/**
* This voucher has not been sent to anybody else.
*/
$model = new VoucherBeneficiaryDistribution();
$model->voucher_id = $voucher->id;
$model->voucher_set_id = $voucher->voucher_set_id;
$model->beneficiary_email_encrypted = Crypt::encrypt($beneficiaryEmail);
$model->created_by_user_id = Auth::id();
$model->save();

$this->data = $model;

}
catch (Exception $e) {

$this->responseCode = 500;
$this->message = ApiResponse::RESPONSE_ERROR->value . ': "' . $e->getMessage() . '".';

}

return $this->respond();
}

/**
* @hideFromAPIDocumentation
*
* @param int $id
*/
public function show(int $id)
{
$this->responseCode = 403;
$this->message = ApiResponse::RESPONSE_METHOD_NOT_ALLOWED->value;

return $this->respond();
}

/**
* @hideFromAPIDocumentation
*
* @param string $id
*/
public function update(string $id)
{
$this->responseCode = 403;
$this->message = ApiResponse::RESPONSE_METHOD_NOT_ALLOWED->value;

return $this->respond();
}

/**
* @hideFromAPIDocumentation
*
* @param string $id
*/
public function destroy(string $id)
{
$this->responseCode = 403;
$this->message = ApiResponse::RESPONSE_METHOD_NOT_ALLOWED->value;

return $this->respond();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace App\Jobs\VoucherBeneficiaryDistributions;

use App\Models\VoucherBeneficiaryDistribution;
use App\Notifications\VoucherBeneficiaryDistributions\BeneficiaryVoucherDistributionEmail;
use Crypt;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Notification;

class SendVoucherToBeneficiary implements ShouldQueue
{
use Queueable;

/**
* Create a new job instance.
*
* @param VoucherBeneficiaryDistribution $voucherBeneficiaryDistribution
*/
public function __construct(public VoucherBeneficiaryDistribution $voucherBeneficiaryDistribution) {}

/**
* Execute the job.
*/
public function handle(): void
{
if (env('APP_ENV') != 'testing') {

$address = Crypt::decrypt($this->voucherBeneficiaryDistribution->beneficiary_email_encrypted);

Notification::route('mail', $address)
->notify(new BeneficiaryVoucherDistributionEmail($this->voucherBeneficiaryDistribution));
}
}
}
Loading

0 comments on commit 4a9fb86

Please sign in to comment.