1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-09-20 00:11:35 +02:00

validation rules for max amounts

This commit is contained in:
David Bomba 2024-05-06 11:47:20 +10:00
parent 6e5fb456c1
commit deab4b6ace
9 changed files with 305 additions and 9 deletions

View File

@ -0,0 +1,42 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Events\Statement;
use App\Models\Client;
use App\Models\Company;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* Class StatementWasEmailed.
*/
class StatementWasEmailed
{
use Dispatchable;
use InteractsWithSockets;
use SerializesModels;
public function __construct(public Client $client, public Company $company, public string $end_date, public array $event_vars)
{
}
// /**
// * Get the channels the event should broadcast on.
// *
// * @return Channel|array
// */
public function broadcastOn()
{
return [];
}
}

View File

@ -41,7 +41,7 @@ class StoreBankTransactionRequest extends Request
$rules = [];
$rules['bank_integration_id'] = 'bail|required|exists:bank_integrations,id,company_id,'.$user->company()->id.',is_deleted,0';
$rules['amount'] = ['sometimes', 'bail', 'numeric', 'nullable', 'max:99999999999999'];
return $rules;
}
@ -55,6 +55,7 @@ class StoreBankTransactionRequest extends Request
$input['bank_integration_id'] = $this->decodePrimaryKey($input['bank_integration_id']);
}
$this->replace($input);
}
}

View File

@ -44,9 +44,7 @@ class UpdateBankTransactionRequest extends Request
$rules['vendor_id'] = 'bail|required|exists:vendors,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
}
// if (isset($this->expense_id)) {
// $rules['expense_id'] = 'bail|required|exists:expenses,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
// }
$rules['amount'] = ['sometimes', 'bail', 'nullable', 'numeric', 'max:99999999999999'];
$rules['bank_integration_id'] = 'bail|required|exists:bank_integrations,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';

View File

@ -53,6 +53,7 @@ class StoreExpenseRequest extends Request
$rules['payment_date'] = 'bail|nullable|sometimes|date:Y-m-d';
$rules['date'] = 'bail|sometimes|date:Y-m-d';
$rules['documents'] = 'bail|sometimes|array';
$rules['amount'] = ['sometimes', 'bail', 'nullable', 'numeric', 'max:99999999999999'];
return $this->globalRules($rules);
}

View File

@ -55,7 +55,7 @@ class UpdateExpenseRequest extends Request
$rules['transaction_id'] = 'bail|sometimes|nullable|exists:bank_transactions,id,company_id,'.$user->company()->id;
$rules['invoice_id'] = 'bail|sometimes|nullable|exists:invoices,id,company_id,'.$user->company()->id;
$rules['documents'] = 'bail|sometimes|array';
$rules['amount'] = ['sometimes', 'bail', 'nullable', 'numeric', 'max:99999999999999'];
return $this->globalRules($rules);
}

View File

@ -67,9 +67,8 @@ class RefundPaymentRequest extends Request
$input = $this->all();
$rules = [
'id' => 'bail|required', //@phpstan-ignore-line
'id' => new ValidRefundableRequest($input),
'amount' => 'numeric',
'id' => ['bail','required', new ValidRefundableRequest($input)],
'amount' => ['numeric', 'max:99999999999999'],
'date' => 'required',
'invoices.*.invoice_id' => 'required',
'invoices.*.amount' => 'required',

View File

@ -50,7 +50,7 @@ class StorePaymentRequest extends Request
'invoices.*.invoice_id' => ['bail','required','distinct', new ValidInvoicesRules($this->all()),Rule::exists('invoices','id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)],
'credits.*.credit_id' => ['bail','required','distinct', new ValidCreditsRules($this->all()),Rule::exists('credits','id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)],
'credits.*.amount' => ['bail','required', new CreditsSumRule($this->all())],
'amount' => ['bail', 'numeric', new PaymentAmountsBalanceRule()],
'amount' => ['bail', 'numeric', new PaymentAmountsBalanceRule(), 'max:99999999999999'],
'number' => ['bail', 'nullable', Rule::unique('payments')->where('company_id', $user->company()->id)],
'idempotency_key' => ['nullable', 'bail', 'string','max:64', Rule::unique('payments')->where('company_id', $user->company()->id)],
];

View File

@ -0,0 +1,56 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Listeners\Statement;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use stdClass;
class StatementEmailedActivity implements ShouldQueue
{
protected $activityRepo;
/**
* Create the event listener.
*
* @param ActivityRepository $activityRepo
*/
public function __construct(ActivityRepository $activityRepo)
{
$this->activityRepo = $activityRepo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$fields = new stdClass();
$user_id = isset($event->event_vars['user_id']) ? $event->event_vars['user_id'] : $event->client->id;
$fields->user_id = $user_id;
$fields->client_id = $event->client->id;
$fields->notes = $event->end_date;
$fields->company_id = $event->company->id;
$fields->activity_type_id = Activity::EMAIL_STATEMENT;
$this->activityRepo->save($fields, $event->client, $event->event_vars);
}
}

View File

@ -0,0 +1,199 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace Tests\Feature;
use Tests\TestCase;
use App\Models\Quote;
use App\Models\Credit;
use App\Models\Invoice;
use Tests\MockAccountData;
use App\Models\PurchaseOrder;
use App\DataMapper\InvoiceItem;
use App\Models\RecurringInvoice;
use Illuminate\Validation\ValidationException;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Foundation\Testing\DatabaseTransactions;
/**
* @test
* @covers App\Http\Controllers\ActivityController
*/
class MaxAmountTest extends TestCase
{
use DatabaseTransactions;
use MockAccountData;
protected function setUp() :void
{
parent::setUp();
$this->makeTestData();
$this->withoutMiddleware(
ThrottleRequests::class
);
}
public function testInvoiceMaxAmount()
{
$item = new InvoiceItem();
$item->cost = 10000000000000000;
$item->quantity = 100;
$data = [
'user_id' => $this->user->id,
'client_id' => $this->client->id,
'company_id' => $this->company->id,
'line_items' => [$item]
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/invoices', $data);
$response->assertStatus(422);
$i = Invoice::factory()->create($data);
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->putJson("/api/v1/invoices/{$i->hashed_id}", $data);
$response->assertStatus(422);
}
public function testCreditMaxAmount()
{
$item = new InvoiceItem();
$item->cost = 10000000000000000;
$item->quantity = 100;
$data = [
'user_id' => $this->user->id,
'client_id' => $this->client->id,
'company_id' => $this->company->id,
'line_items' => [$item]
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/credits', $data);
$response->assertStatus(422);
$i = Credit::factory()->create($data);
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->putJson("/api/v1/credits/{$i->hashed_id}", $data);
$response->assertStatus(422);
}
public function testQuoteMaxAmount()
{
$item = new InvoiceItem();
$item->cost = 10000000000000000;
$item->quantity = 100;
$data = [
'user_id' => $this->user->id,
'client_id' => $this->client->id,
'company_id' => $this->company->id,
'line_items' => [$item]
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/quotes', $data);
$response->assertStatus(422);
$i = Quote::factory()->create($data);
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->putJson("/api/v1/quotes/{$i->hashed_id}", $data);
$response->assertStatus(422);
}
public function testPurchaseOrderMaxAmount()
{
$item = new InvoiceItem();
$item->cost = 10000000000000000;
$item->quantity = 100;
$data = [
'user_id' => $this->user->id,
'vendor_id' => $this->vendor->id,
'company_id' => $this->company->id,
'line_items' => [$item]
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/purchase_orders', $data);
$response->assertStatus(422);
$i = PurchaseOrder::factory()->create($data);
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->putJson("/api/v1/purchase_orders/{$i->hashed_id}", $data);
$response->assertStatus(422);
}
public function testRecurringInvoiceMaxAmount()
{
$item = new InvoiceItem();
$item->cost = 10000000000000000;
$item->quantity = 100;
$data = [
'user_id' => $this->user->id,
'client_id' => $this->client->id,
'company_id' => $this->company->id,
'line_items' => [$item],
'frequency_id' => 5
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/recurring_invoices', $data);
$response->assertStatus(422);
$i = RecurringInvoice::factory()->create($data);
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->putJson("/api/v1/recurring_invoices/{$i->hashed_id}", $data);
$response->assertStatus(422);
}
}