feat(tenant): add master toggle for ticket refunds
This commit is contained in:
@@ -52,6 +52,7 @@ use Illuminate\Support\Facades\Schema;
|
||||
'checkout_editing_policy',
|
||||
'display_cart_item_images',
|
||||
'scanner_category_validation_enabled',
|
||||
'allow_ticket_refund',
|
||||
'allow_ticket_total_refund',
|
||||
'allow_ticket_partial_refund',
|
||||
'ticket_partial_refund_percentage',
|
||||
@@ -75,6 +76,7 @@ class Tenant extends Model
|
||||
'checkout_editing_policy' => CartEditingPolicy::Disabled->value,
|
||||
'display_cart_item_images' => true,
|
||||
'scanner_category_validation_enabled' => true,
|
||||
'allow_ticket_refund' => false,
|
||||
'allow_ticket_total_refund' => false,
|
||||
'allow_ticket_partial_refund' => false,
|
||||
'ticket_partial_refund_percentage' => 0,
|
||||
@@ -114,12 +116,14 @@ class Tenant extends Model
|
||||
|
||||
public function allow_refund(): bool
|
||||
{
|
||||
return (bool) $this->allow_ticket_total_refund || $this->allow_partial_refund();
|
||||
return (bool) $this->allow_ticket_refund
|
||||
&& ((bool) $this->allow_ticket_total_refund || $this->allow_partial_refund());
|
||||
}
|
||||
|
||||
public function allow_partial_refund(): bool
|
||||
{
|
||||
return (bool) $this->allow_ticket_partial_refund
|
||||
return (bool) $this->allow_ticket_refund
|
||||
&& (bool) $this->allow_ticket_partial_refund
|
||||
&& $this->ticket_partial_refund_percentage !== null
|
||||
&& (float) $this->ticket_partial_refund_percentage > 0;
|
||||
}
|
||||
@@ -157,6 +161,7 @@ class Tenant extends Model
|
||||
'checkout_editing_policy' => CartEditingPolicy::class,
|
||||
'display_cart_item_images' => 'boolean',
|
||||
'scanner_category_validation_enabled' => 'boolean',
|
||||
'allow_ticket_refund' => 'boolean',
|
||||
'allow_ticket_total_refund' => 'boolean',
|
||||
'allow_ticket_partial_refund' => 'boolean',
|
||||
'ticket_partial_refund_percentage' => 'decimal:2',
|
||||
|
||||
@@ -117,6 +117,7 @@ class StoreTenantRequest extends FormRequest
|
||||
],
|
||||
'display_cart_item_images' => ['sometimes', 'boolean'],
|
||||
'scanner_category_validation_enabled' => ['sometimes', 'boolean'],
|
||||
'allow_ticket_refund' => ['sometimes', 'boolean'],
|
||||
'allow_ticket_total_refund' => ['sometimes', 'boolean'],
|
||||
'allow_ticket_partial_refund' => ['sometimes', 'boolean'],
|
||||
'ticket_partial_refund_percentage' => [
|
||||
|
||||
@@ -138,6 +138,7 @@ class UpdateTenantRequest extends FormRequest
|
||||
],
|
||||
'display_cart_item_images' => ['sometimes', 'boolean'],
|
||||
'scanner_category_validation_enabled' => ['sometimes', 'boolean'],
|
||||
'allow_ticket_refund' => ['sometimes', 'boolean'],
|
||||
'allow_ticket_total_refund' => ['sometimes', 'boolean'],
|
||||
'allow_ticket_partial_refund' => ['sometimes', 'boolean'],
|
||||
'ticket_partial_refund_percentage' => [
|
||||
|
||||
@@ -87,6 +87,7 @@ class TenantResource extends JsonResource
|
||||
'checkout_editing_policy' => CartEditingPolicyResource::make($this->checkout_editing_policy),
|
||||
'display_cart_item_images' => $this->display_cart_item_images,
|
||||
'scanner_category_validation_enabled' => $this->scanner_category_validation_enabled,
|
||||
'allow_ticket_refund' => $this->allow_ticket_refund,
|
||||
'allow_ticket_total_refund' => $this->allow_ticket_total_refund,
|
||||
'allow_ticket_partial_refund' => $this->allow_ticket_partial_refund,
|
||||
'ticket_partial_refund_percentage' => $this->ticket_partial_refund_percentage,
|
||||
|
||||
@@ -141,12 +141,12 @@ class AdminAppTicketService
|
||||
$remainingItemAmount = max(0.0, round($itemTotal - $itemRefundedAmount, 2));
|
||||
|
||||
$total = null;
|
||||
if ($tenant->allow_ticket_total_refund && $unitPrice <= $remainingItemAmount) {
|
||||
if ($tenant->allow_refund() && $tenant->allow_ticket_total_refund && $unitPrice <= $remainingItemAmount) {
|
||||
$total = number_format($unitPrice, 2, '.', '');
|
||||
}
|
||||
|
||||
$partial = null;
|
||||
if ($tenant->allow_partial_refund()) {
|
||||
if ($tenant->allow_refund() && $tenant->allow_partial_refund()) {
|
||||
$partialAmount = $this->refundAmount($purchaseItem, $tenant, 'partial');
|
||||
if ($partialAmount <= $remainingItemAmount) {
|
||||
$partial = number_format($partialAmount, 2, '.', '');
|
||||
@@ -214,8 +214,8 @@ class AdminAppTicketService
|
||||
private function ensureRefundIsAllowed(Tenant $tenant, string $refundType): void
|
||||
{
|
||||
$isAllowed = match ($refundType) {
|
||||
'partial' => $tenant->allow_partial_refund(),
|
||||
'total' => (bool) $tenant->allow_ticket_total_refund,
|
||||
'partial' => $tenant->allow_refund() && $tenant->allow_partial_refund(),
|
||||
'total' => $tenant->allow_refund() && (bool) $tenant->allow_ticket_total_refund,
|
||||
};
|
||||
|
||||
if (! $isAllowed) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('tenants', function (Blueprint $table): void {
|
||||
$table->boolean('allow_ticket_refund')
|
||||
->default(false)
|
||||
->after('scanner_category_validation_enabled');
|
||||
});
|
||||
|
||||
DB::table('tenants')
|
||||
->where('allow_ticket_total_refund', true)
|
||||
->orWhere(function ($query): void {
|
||||
$query
|
||||
->where('allow_ticket_partial_refund', true)
|
||||
->where('ticket_partial_refund_percentage', '>', 0);
|
||||
})
|
||||
->update(['allow_ticket_refund' => true]);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('tenants', function (Blueprint $table): void {
|
||||
$table->dropColumn('allow_ticket_refund');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -18,12 +18,14 @@ class TenantRefundConfigurationTest extends TestCase
|
||||
{
|
||||
$tenant = $this->createTenant('refund-defaults');
|
||||
|
||||
$this->assertFalse($tenant->allow_ticket_refund);
|
||||
$this->assertFalse($tenant->allow_ticket_total_refund);
|
||||
$this->assertFalse($tenant->allow_ticket_partial_refund);
|
||||
$this->assertSame('0.00', $tenant->ticket_partial_refund_percentage);
|
||||
|
||||
$this->getJson("/api/tenants/{$tenant->codigo}")
|
||||
->assertOk()
|
||||
->assertJsonPath('data.allow_ticket_refund', false)
|
||||
->assertJsonPath('data.allow_ticket_total_refund', false)
|
||||
->assertJsonPath('data.allow_ticket_partial_refund', false)
|
||||
->assertJsonPath('data.ticket_partial_refund_percentage', '0.00');
|
||||
@@ -34,17 +36,20 @@ class TenantRefundConfigurationTest extends TestCase
|
||||
$tenant = $this->createTenant('refund-update');
|
||||
|
||||
$this->putJson("/api/tenants/{$tenant->codigo}", [
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
'allow_ticket_partial_refund' => true,
|
||||
'ticket_partial_refund_percentage' => 25.50,
|
||||
])
|
||||
->assertOk()
|
||||
->assertJsonPath('data.allow_ticket_refund', true)
|
||||
->assertJsonPath('data.allow_ticket_total_refund', true)
|
||||
->assertJsonPath('data.allow_ticket_partial_refund', true)
|
||||
->assertJsonPath('data.ticket_partial_refund_percentage', '25.50');
|
||||
|
||||
$this->assertDatabaseHas('tenants', [
|
||||
'id' => $tenant->id,
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
'allow_ticket_partial_refund' => true,
|
||||
'ticket_partial_refund_percentage' => 25.50,
|
||||
@@ -64,6 +69,7 @@ class TenantRefundConfigurationTest extends TestCase
|
||||
public function test_tenant_allow_refund_logic(): void
|
||||
{
|
||||
$tenant = new Tenant([
|
||||
'allow_ticket_refund' => false,
|
||||
'allow_ticket_total_refund' => false,
|
||||
'allow_ticket_partial_refund' => false,
|
||||
'ticket_partial_refund_percentage' => 0,
|
||||
@@ -83,6 +89,10 @@ class TenantRefundConfigurationTest extends TestCase
|
||||
|
||||
// Partial refund enabled and percentage is set
|
||||
$tenant->ticket_partial_refund_percentage = 25.50;
|
||||
$this->assertFalse($tenant->allow_refund());
|
||||
$this->assertFalse($tenant->allow_partial_refund());
|
||||
|
||||
$tenant->allow_ticket_refund = true;
|
||||
$this->assertTrue($tenant->allow_refund());
|
||||
$this->assertTrue($tenant->allowRefund());
|
||||
$this->assertTrue($tenant->allow_refund);
|
||||
@@ -101,6 +111,13 @@ class TenantRefundConfigurationTest extends TestCase
|
||||
$tenant->ticket_partial_refund_percentage = 50.00;
|
||||
$this->assertTrue($tenant->allow_refund());
|
||||
$this->assertTrue($tenant->allow_partial_refund());
|
||||
|
||||
$tenant->allow_ticket_refund = false;
|
||||
$this->assertFalse($tenant->allow_refund());
|
||||
$this->assertFalse($tenant->allow_partial_refund());
|
||||
$this->assertTrue($tenant->allow_ticket_total_refund);
|
||||
$this->assertTrue($tenant->allow_ticket_partial_refund);
|
||||
$this->assertSame('50.00', $tenant->ticket_partial_refund_percentage);
|
||||
}
|
||||
|
||||
private function createTenant(string $code): Tenant
|
||||
|
||||
@@ -100,7 +100,10 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
->assertJsonPath('data.0.can_refund', false);
|
||||
|
||||
// Total refund allowed
|
||||
$tenant->update(['allow_ticket_total_refund' => true]);
|
||||
$tenant->update([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
]);
|
||||
$this->getJson('/api/v1/adminapp/tenant/tickets')
|
||||
->assertOk()
|
||||
->assertJsonPath('data.0.allow_refund', true)
|
||||
@@ -108,6 +111,7 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
|
||||
// Partial refund allowed with percentage set
|
||||
$tenant->update([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => false,
|
||||
'allow_ticket_partial_refund' => true,
|
||||
'ticket_partial_refund_percentage' => 20.00,
|
||||
@@ -117,6 +121,17 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
->assertJsonPath('data.0.allow_refund', true)
|
||||
->assertJsonPath('data.0.can_refund', true);
|
||||
|
||||
// Master toggle disabled while preserving the partial refund preference
|
||||
$tenant->update(['allow_ticket_refund' => false]);
|
||||
$this->getJson('/api/v1/adminapp/tenant/tickets')
|
||||
->assertOk()
|
||||
->assertJsonPath('data.0.allow_refund', false)
|
||||
->assertJsonPath('data.0.can_refund', false);
|
||||
$this->assertTrue($tenant->fresh()->allow_ticket_partial_refund);
|
||||
$this->assertSame('20.00', $tenant->fresh()->ticket_partial_refund_percentage);
|
||||
|
||||
$tenant->update(['allow_ticket_refund' => true]);
|
||||
|
||||
// Partial refund enabled but percentage is 0
|
||||
$tenant->update([
|
||||
'ticket_partial_refund_percentage' => 0,
|
||||
@@ -162,7 +177,10 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
public function test_it_totally_refunds_a_ticket_when_the_tenant_allows_it(): void
|
||||
{
|
||||
$tenant = $this->createTenant('ticket-total-refund');
|
||||
$tenant->update(['allow_ticket_total_refund' => true]);
|
||||
$tenant->update([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
]);
|
||||
$admin = $this->createAdminAppUser($tenant);
|
||||
$this->grantTicketsMenu($tenant);
|
||||
Sanctum::actingAs($admin);
|
||||
@@ -184,6 +202,7 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
{
|
||||
$tenant = $this->createTenant('ticket-partial-refund');
|
||||
$tenant->update([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_partial_refund' => true,
|
||||
'ticket_partial_refund_percentage' => 25.50,
|
||||
]);
|
||||
@@ -239,6 +258,7 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
{
|
||||
$tenant = $this->createTenant('ticket-calc-both');
|
||||
$tenant->update([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
'allow_ticket_partial_refund' => true,
|
||||
'ticket_partial_refund_percentage' => 30.00,
|
||||
@@ -258,6 +278,7 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
{
|
||||
$tenant = $this->createTenant('ticket-calc-total');
|
||||
$tenant->update([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
'allow_ticket_partial_refund' => false,
|
||||
]);
|
||||
@@ -276,6 +297,7 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
{
|
||||
$tenant = $this->createTenant('ticket-calc-insufficient');
|
||||
$tenant->update([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
'allow_ticket_partial_refund' => true,
|
||||
'ticket_partial_refund_percentage' => 50.00,
|
||||
@@ -299,7 +321,10 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
public function test_it_fails_calculating_refund_if_ticket_is_not_active(): void
|
||||
{
|
||||
$tenant = $this->createTenant('ticket-calc-inactive');
|
||||
$tenant->update(['allow_ticket_total_refund' => true]);
|
||||
$tenant->update([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
]);
|
||||
$admin = $this->createAdminAppUser($tenant);
|
||||
$this->grantTicketsMenu($tenant);
|
||||
Sanctum::actingAs($admin);
|
||||
@@ -316,8 +341,14 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
{
|
||||
$tenantA = $this->createTenant('ticket-calc-a');
|
||||
$tenantB = $this->createTenant('ticket-calc-b');
|
||||
$tenantA->update(['allow_ticket_total_refund' => true]);
|
||||
$tenantB->update(['allow_ticket_total_refund' => true]);
|
||||
$tenantA->update([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
]);
|
||||
$tenantB->update([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
]);
|
||||
|
||||
$adminA = $this->createAdminAppUser($tenantA);
|
||||
$adminB = $this->createAdminAppUser($tenantB);
|
||||
|
||||
@@ -67,6 +67,7 @@ class TicketTest extends TestCase
|
||||
public function test_it_exposes_admin_action_capabilities(): void
|
||||
{
|
||||
$tenant = new Tenant([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
]);
|
||||
$active = (new Ticket)->setRelation('tenant', $tenant);
|
||||
|
||||
Reference in New Issue
Block a user