Merge "Activate/Deactive Ticket"

This commit is contained in:
Zuul 2021-04-22 19:48:56 +00:00 committed by Gerrit Code Review
commit d4b350a5ad
13 changed files with 265 additions and 6 deletions

View File

@ -900,7 +900,8 @@ final class OAuth2SummitOrdersApiController
public function getTicketByHash($hash){
try {
$ticket = $this->service->getTicketByHash($hash);
if(is_null($ticket) || !$ticket->isActive())
throw new EntityNotFoundException();
return $this->ok(SerializerRegistry::getInstance()->getSerializer($ticket, ISummitAttendeeTicketSerializerTypes::PublicEdition)->serialize(Request::input('expand', '')));
}
catch (ValidationException $ex) {
@ -1207,4 +1208,65 @@ final class OAuth2SummitOrdersApiController
return $this->error500($ex);
}
}
/**
* @param $summit_id
* @param $order_id
* @param $ticket_id
* @return \Illuminate\Http\JsonResponse|mixed
*/
public function activateTicket($summit_id, $order_id, $ticket_id){
try {
$summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id);
if (is_null($summit)) return $this->error404();
$ticket = $this->service->activateTicket($summit, intval($order_id), intval($ticket_id));
return $this->updated(SerializerRegistry::getInstance()->getSerializer($ticket, ISummitAttendeeTicketSerializerTypes::AdminType)->serialize( Request::input('expand', '')));
}
catch(\InvalidArgumentException $ex){
Log::warning($ex);
return $this->error400();
}
catch (ValidationException $ex) {
Log::warning($ex);
return $this->error412($ex->getMessages());
}
catch(EntityNotFoundException $ex)
{
Log::warning($ex);
return $this->error404(array('message'=> $ex->getMessage()));
}
catch (Exception $ex) {
Log::error($ex);
return $this->error500($ex);
}
}
public function deActivateTicket($summit_id, $order_id, $ticket_id){
try {
$summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id);
if (is_null($summit)) return $this->error404();
$ticket = $this->service->deActivateTicket($summit, intval($order_id), intval($ticket_id));
return $this->updated(SerializerRegistry::getInstance()->getSerializer($ticket, ISummitAttendeeTicketSerializerTypes::AdminType)->serialize( Request::input('expand', '')));
}
catch(\InvalidArgumentException $ex){
Log::warning($ex);
return $this->error400();
}
catch (ValidationException $ex) {
Log::warning($ex);
return $this->error412($ex->getMessages());
}
catch(EntityNotFoundException $ex)
{
Log::warning($ex);
return $this->error404(array('message'=> $ex->getMessage()));
}
catch (Exception $ex) {
Log::error($ex);
return $this->error500($ex);
}
}
}

View File

@ -435,6 +435,7 @@ final class OAuth2SummitTicketApiController extends OAuth2ProtectedController
function($filter) use($owner){
if($filter instanceof Filter){
$filter->addFilterCondition(FilterElement::makeEqual('member_id', $owner->getId()));
$filter->addFilterCondition(FilterElement::makeEqual('is_active', true));
}
return $filter;
},

View File

@ -886,6 +886,10 @@ Route::group([
Route::post('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@addTicket']);
Route::group(['prefix' => '{ticket_id}'], function () {
Route::put('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@updateTicket']);
Route::group(['prefix' => 'activate'], function () {
Route::put('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@activateTicket']);
Route::delete('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@deActivateTicket']);
});
Route::get('pdf', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@getTicketPDFBySummit']);
});
});

View File

@ -37,6 +37,7 @@ class BaseSummitAttendeeTicketSerializer extends SilverStripeSerializer
'Discount' => 'discount:json_float',
'RefundedAmount' => 'refunded_amount:json_float',
'Currency' => 'currency:json_string',
'Active' => 'is_active:json_bool',
];
protected static $allowed_relations = [

View File

@ -46,6 +46,7 @@ final class SummitAttendeeTicketCSVSerializer extends SilverStripeSerializer
'Currency' => 'currency:json_string',
'BadgeTypeId' => 'badge_type_id:json_int',
'BadgeTypeName' => 'badge_type_name:json_string',
'Active' => 'is_active:json_bool',
];
/**

View File

@ -1805,7 +1805,7 @@ LEFT JOIN Member ON Member.ID = SummitAttendee.MemberID
WHERE
( Member.ID = :member_id OR SummitAttendee.Email = :member_email) AND
SummitAttendee.SummitID = :summit_id AND
SummitAttendeeTicket.Status = :ticket_status
SummitAttendeeTicket.Status = :ticket_status AND SummitAttendeeTicket.IsActive = 1
SQL;
$stmt = $this->prepareRawSQL($sql);
@ -1841,13 +1841,14 @@ SQL;
JOIN o.summit su
WHERE su.id = :summit_id
and ( m.id = :member_id or o.email = :member_email)
and t.status = :ticket_status");
and t.status = :ticket_status and t.is_active = :active");
return $query
->setParameter('member_id', $this->getId())
->setParameter('member_email', $this->email)
->setParameter('ticket_status', IOrderConstants::PaidStatus)
->setParameter('summit_id', $summit->getId())
->setParameter('active', true)
->getResult();
}

View File

@ -369,6 +369,10 @@ class SummitAttendee extends SilverstripeBaseModel
public function sendInvitationEmail(SummitAttendeeTicket $ticket, bool $overrideTicketOwnerIsSameAsOrderOwnerRule = false){
Log::debug(sprintf("SummitAttendee::sendInvitationEmail attendee %s", $this->getEmail()));
if($ticket->getOwnerEmail() != $this->getEmail()) return;
if(!$ticket->isActive()){
Log::warning(sprintf("SummitAttendee::sendInvitationEmail attendee %s ticket is not active", $this->getEmail()));
return;
}
$this->updateStatus();
if($this->isComplete()) {
Log::debug(sprintf("SummitAttendee::sendInvitationEmail attendee %s is complete", $this->getEmail()));

View File

@ -159,6 +159,12 @@ class SummitAttendeeTicket extends SilverstripeBaseModel
*/
private $former_hashes;
/**
* @ORM\Column(name="IsActive", type="boolean")
* @var bool
*/
private $is_active;
/**
* SummitAttendeeTicket constructor.
*/
@ -172,6 +178,7 @@ class SummitAttendeeTicket extends SilverstripeBaseModel
$this->raw_cost = 0.0;
$this->discount = 0.0;
$this->refunded_amount = 0.0;
$this->is_active = true;
}
/**
@ -936,4 +943,23 @@ class SummitAttendeeTicket extends SilverstripeBaseModel
// i am order owner
if($this->order->getOwnerEmail() == $member->getEmail()) return true;
}
/**
* @return bool
*/
public function isActive(): bool
{
return $this->is_active;
}
public function activate(): void
{
$this->is_active = true;
}
public function deActivate(): void
{
$this->is_active = false;
}
}

View File

@ -39,6 +39,7 @@ final class DoctrineSummitAttendeeTicketRepository
{
return [
'number' => 'e.number:json_string',
'is_active' => 'e.is_active',
'order_number' => 'o.number:json_string',
'owner_name' => [
"concat(m.first_name, ' ', m.last_name) :operator :value",

View File

@ -113,6 +113,25 @@ interface ISummitOrderService extends IProcessPaymentService
*/
public function updateTicket(Summit $summit, int $order_id, int $ticket_id, array $payload):SummitAttendeeTicket;
/**
* @param Summit $summit
* @param int $order_id
* @param int $ticket_id
* @return SummitAttendeeTicket
* @throws EntityNotFoundException
* @throws ValidationException
*/
public function activateTicket(Summit $summit, int $order_id, int $ticket_id):SummitAttendeeTicket;
/**
* @param Summit $summit
* @param int $order_id
* @param int $ticket_id
* @return SummitAttendeeTicket
* @throws EntityNotFoundException
* @throws ValidationException
*/
public function deActivateTicket(Summit $summit, int $order_id, int $ticket_id):SummitAttendeeTicket;
/**
* @param Member $current_user
* @param int $order_id

View File

@ -2473,7 +2473,7 @@ final class SummitOrderService
$ticket = $this->ticket_repository->getByHashExclusiveLock($hash);
if (is_null($ticket))
if (is_null($ticket) && !$ticket->isActive())
throw new EntityNotFoundException("ticket not found");
if (!$ticket->isPaid())
@ -2532,7 +2532,7 @@ final class SummitOrderService
return $this->tx_service->transaction(function () use ($current_user, $ticket_id, $payload) {
$ticket = $this->ticket_repository->getByIdExclusiveLock($ticket_id);
if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket)
if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket || !$ticket->isActive())
throw new EntityNotFoundException("ticket not found");
if (!$ticket->canEditTicket($current_user)) {
@ -2796,7 +2796,12 @@ final class SummitOrderService
}
if (!is_null($ticket) && !$ticket->isPaid()) {
Log::debug("SummitOrderService::processTicketData - ticket is not paid");
Log::warning("SummitOrderService::processTicketData - ticket is not paid");
return;
}
if (!is_null($ticket) && !$ticket->isActive()) {
Log::warning("SummitOrderService::processTicketData - ticket is not active");
return;
}
}
@ -3063,6 +3068,10 @@ final class SummitOrderService
}
foreach ($order->getTickets() as $ticket) {
try {
if(!$ticket->isActive()){
Log::warning(sprintf("SummitOrderService::processSummitOrderReminders - summit %s order %s skipping ticket %s ( not active)", $summit->getId(), $order->getId(), $ticket->getId()));
continue;
}
$this->processTicketReminder($ticket);
} catch (\Exception $ex) {
Log::error($ex);
@ -3097,6 +3106,10 @@ final class SummitOrderService
$needs_action = false;
foreach ($order->getTickets() as $ticket) {
if(!$ticket->isActive()){
Log::warning(sprintf("SummitOrderService::processOrderReminder - order %s skipping ticket %s ( NOT ACTIVE ).", $order->getId(), $ticket->getId()));
continue;
}
if (!$ticket->hasOwner()) {
$needs_action = true;
break;
@ -3373,4 +3386,50 @@ final class SummitOrderService
}
});
}
/**
* @inheritDoc
*/
public function activateTicket(Summit $summit, int $order_id, int $ticket_id): SummitAttendeeTicket
{
return $this->tx_service->transaction(function() use($summit, $order_id, $ticket_id){
// lock and get the order
$order = $this->order_repository->getByIdExclusiveLock($order_id);
if (is_null($order) || !$order instanceof SummitOrder)
throw new EntityNotFoundException("order not found");
$ticket = $order->getTicketById($ticket_id);
if (is_null($ticket))
throw new EntityNotFoundException("ticket not found");
$ticket->activate();
return $ticket;
});
}
/**
* @inheritDoc
*/
public function deActivateTicket(Summit $summit, int $order_id, int $ticket_id): SummitAttendeeTicket
{
return $this->tx_service->transaction(function() use($summit, $order_id, $ticket_id){
// lock and get the order
$order = $this->order_repository->getByIdExclusiveLock($order_id);
if (is_null($order) || !$order instanceof SummitOrder)
throw new EntityNotFoundException("order not found");
$ticket = $order->getTicketById($ticket_id);
if (is_null($ticket))
throw new EntityNotFoundException("ticket not found");
$ticket->deActivate();
return $ticket;
});
}
}

View File

@ -0,0 +1,50 @@
<?php namespace Database\Migrations\Model;
/**
* Copyright 2019 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use Doctrine\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema as Schema;
use LaravelDoctrine\Migrations\Schema\Builder;
use LaravelDoctrine\Migrations\Schema\Table;
/**
* Class Version20210422150202
* @package Database\Migrations\Model
*/
final class Version20210422150202 extends AbstractMigration
{
/**
* @param Schema $schema
*/
public function up(Schema $schema):void
{
$builder = new Builder($schema);
if($schema->hasTable("SummitAttendeeTicket")) {
$builder->table('SummitAttendeeTicket', function (Table $table) {
$table->boolean("IsActive")->setDefault(true)->setNotnull(true);
});
}
}
/**
* @param Schema $schema
*/
public function down(Schema $schema):void
{
$builder = new Builder($schema);
if($schema->hasTable("SummitAttendeeTicket")) {
$builder->table('SummitAttendeeTicket', function (Table $table) {
$table->dropColumn("IsActive");
});
}
}
}

View File

@ -615,6 +615,36 @@ class ApiEndpointsSeeder extends Seeder
IGroup::SummitRegistrationAdmins
]
],
[
'name' => 'activate-ticket',
'route' => '/api/v1/summits/{id}/orders/{order_id}/tickets/{ticket_id}/activate',
'http_method' => 'PUT',
'scopes' => [
sprintf(SummitScopes::WriteSummitData, $current_realm),
sprintf(SummitScopes::UpdateRegistrationOrders, $current_realm),
],
'authz_groups' => [
IGroup::SuperAdmins,
IGroup::Administrators,
IGroup::SummitAdministrators,
IGroup::SummitRegistrationAdmins
]
],
[
'name' => 'deactivate-ticket',
'route' => '/api/v1/summits/{id}/orders/{order_id}/tickets/{ticket_id}/activate',
'http_method' => 'DELETE',
'scopes' => [
sprintf(SummitScopes::WriteSummitData, $current_realm),
sprintf(SummitScopes::UpdateRegistrationOrders, $current_realm),
],
'authz_groups' => [
IGroup::SuperAdmins,
IGroup::Administrators,
IGroup::SummitAdministrators,
IGroup::SummitRegistrationAdmins
]
],
[
'name' => 'add-ticket-2-order',
'route' => '/api/v1/summits/{id}/orders/{order_id}/tickets',