diff --git a/app/Http/Controllers/ExpenseController.php b/app/Http/Controllers/ExpenseController.php index ce66ddb296..8827cbc470 100644 --- a/app/Http/Controllers/ExpenseController.php +++ b/app/Http/Controllers/ExpenseController.php @@ -497,11 +497,6 @@ class ExpenseController extends BaseController $expenses = Expense::withTrashed()->find($request->ids); - if ($request->action == 'bulk_categorize' && $user->can('edit', $expenses->first())) { - $this->expense_repo->categorize($expenses, $request->category_id); - $expenses = collect([]); - } - if ($request->action == 'bulk_update' && $user->can('edit', $expenses->first())) { $expenses = Expense::withTrashed() @@ -514,7 +509,10 @@ class ExpenseController extends BaseController } - + if ($request->action == 'bulk_categorize' && $user->can('edit', $expenses->first())) { + $this->expense_repo->categorize($expenses, $request->category_id); + $expenses = collect([]); + } $expenses->each(function ($expense) use ($request, $user) { if ($user->can('edit', $expense)) { diff --git a/app/Http/Controllers/RecurringInvoiceController.php b/app/Http/Controllers/RecurringInvoiceController.php index 9a064edd12..82f867071c 100644 --- a/app/Http/Controllers/RecurringInvoiceController.php +++ b/app/Http/Controllers/RecurringInvoiceController.php @@ -423,7 +423,18 @@ class RecurringInvoiceController extends BaseController } $recurring_invoices = RecurringInvoice::withTrashed()->find($request->ids); + + if ($request->action == 'bulk_update' && $user->can('edit', $recurring_invoices->first())) { + $recurring_invoices = RecurringInvoice::withTrashed() + ->company() + ->whereIn('id', $request->ids); + + $this->recurring_invoice_repo->bulkUpdate($recurring_invoices, $request->column, $request->new_value); + + return $this->listResponse(RecurringInvoice::query()->withTrashed()->company()->whereIn('id', $request->ids)); + + } if($request->action == 'set_payment_link' && $request->has('subscription_id')) { diff --git a/app/Http/Requests/RecurringInvoice/BulkRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/BulkRecurringInvoiceRequest.php index 8d0e7e2163..7177766009 100644 --- a/app/Http/Requests/RecurringInvoice/BulkRecurringInvoiceRequest.php +++ b/app/Http/Requests/RecurringInvoice/BulkRecurringInvoiceRequest.php @@ -36,9 +36,11 @@ class BulkRecurringInvoiceRequest extends Request return [ 'ids' => ['required','bail','array', Rule::exists('recurring_invoices', 'id')->where('company_id', $user->company()->id)], - 'action' => 'in:archive,restore,delete,increase_prices,update_prices,start,stop,send_now,set_payment_link', + 'action' => 'in:archive,restore,delete,increase_prices,update_prices,start,stop,send_now,set_payment_link,bulk_update', 'percentage_increase' => 'required_if:action,increase_prices|numeric|min:0|max:100', - 'subscription_id' => 'sometimes|string' + 'subscription_id' => 'sometimes|string', + 'column' => ['required_if:action,bulk_update', 'string', Rule::in(\App\Models\RecurringInvoice::$bulk_update_columns)], + 'new_value' => ['required_if:action,bulk_update|string'], ]; } diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index 03bea605ef..07972881e0 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -246,6 +246,24 @@ class RecurringInvoice extends BaseModel protected $touches = []; + public static array $bulk_update_columns = [ + 'tax_rate1', + 'tax_name1', + 'tax_rate2', + 'tax_name2', + 'tax_rate3', + 'tax_name3', + 'custom_value1', + 'custom_value2', + 'custom_value3', + 'custom_value4', + 'uses_inclusive_taxes', + 'private_notes', + 'public_notes', + 'terms', + 'footer', + ]; + public function getEntityType() { return self::class; diff --git a/app/Repositories/BaseRepository.php b/app/Repositories/BaseRepository.php index 1102764f44..4071b8cd07 100644 --- a/app/Repositories/BaseRepository.php +++ b/app/Repositories/BaseRepository.php @@ -395,6 +395,29 @@ class BaseRepository public function bulkUpdate(\Illuminate\Database\Eloquent\Builder $model, string $column, mixed $new_value): void { + /** Handle taxes being updated */ + if(in_array($column, ['tax_name1','tax_name2','tax_name3'])) { + + $parts = explode("||", $new_value); + + if (count($parts) !== 2) + return; + + $tax_name = trim($parts[0]); + $rate = filter_var($parts[1], FILTER_VALIDATE_FLOAT); + + if ($rate === false) + return; + + $taxrate_column = str_replace("name", "rate", $column); + + $model->update([ + $column => $tax_name, + $taxrate_column => $rate, + ]); + return; + } + $model->update([$column => $new_value]); } } diff --git a/app/Repositories/ExpenseRepository.php b/app/Repositories/ExpenseRepository.php index 0c2484dd99..54feb00958 100644 --- a/app/Repositories/ExpenseRepository.php +++ b/app/Repositories/ExpenseRepository.php @@ -205,25 +205,4 @@ class ExpenseRepository extends BaseRepository }); } - - public function bulkUpdate(\Illuminate\Database\Eloquent\Builder $model, string $column, mixed $new_value): void - { - if(in_array($column, ['tax_name1','tax_name2','tax_name3'])) { - - $parts = explode("||", $new_value); - - $tax_name = $parts[0]; - $rate = $parts[1]; - - $taxrate_column = str_replace("name", "rate", $column); - - $model->update([ - $column => $tax_name, - $taxrate_column => $rate, - ]); - return; - } - - $model->update([$column => $new_value]); - } } diff --git a/tests/Feature/RecurringInvoiceTest.php b/tests/Feature/RecurringInvoiceTest.php index 184a2206a4..9571a213b6 100644 --- a/tests/Feature/RecurringInvoiceTest.php +++ b/tests/Feature/RecurringInvoiceTest.php @@ -61,6 +61,142 @@ class RecurringInvoiceTest extends TestCase $this->makeTestData(); } +public function testBulkUpdatesTaxes() + { + RecurringInvoice::factory(5)->create([ + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'client_id' => $this->client->id, + 'vendor_id' => $this->vendor->id, + ]); + + $ri = RecurringInvoice::query() + ->where('company_id', $this->company->id) + ->where('client_id', $this->client->id) + ->where('vendor_id', $this->vendor->id); + + $this->assertCount(5, $ri->get()); + + $data = [ + 'action' => 'bulk_update', + 'ids' => $ri->get()->pluck('hashed_id'), + 'column' => 'tax_name1', + 'new_value' => 'GST||10', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson('/api/v1/recurring_invoices/bulk', $data); + + $response->assertStatus(200); + + + $ri->cursor()->each(function ($e){ + $this->assertEquals('GST', $e->tax_name1); + $this->assertEquals(10, $e->tax_rate1); + }); + + $data = [ + 'action' => 'bulk_update', + 'ids' => $ri->get()->pluck('hashed_id'), + 'column' => 'custom_value1', + 'new_value' => 'CUSTOMCUSTOM123', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson('/api/v1/recurring_invoices/bulk', $data); + + $response->assertStatus(200); + + $ri->cursor()->each(function ($e) { + $this->assertEquals('CUSTOMCUSTOM123', $e->custom_value1); + }); + + + $data = [ + 'action' => 'bulk_update', + 'ids' => $ri->get()->pluck('hashed_id'), + 'column' => 'footer', + 'new_value' => 'testfooter', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson('/api/v1/recurring_invoices/bulk', $data); + + $response->assertStatus(200); + + $ri->cursor()->each(function ($e) { + $this->assertEquals('testfooter', $e->footer); + }); + + $data = [ + 'action' => 'bulk_update', + 'ids' => $ri->get()->pluck('hashed_id'), + 'column' => 'uses_inclusive_taxes', + 'new_value' => true, + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson('/api/v1/recurring_invoices/bulk', $data); + + $response->assertStatus(200); + + $ri->cursor()->each(function ($e) { + $this->assertTrue((bool)$e->uses_inclusive_taxes); + }); + + $data = [ + 'action' => 'bulk_update', + 'ids' => $ri->get()->pluck('hashed_id'), + 'column' => 'private_notes', + 'new_value' => 'TESTEST123', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson('/api/v1/recurring_invoices/bulk', $data); + + $response->assertStatus(200); + + $ri->cursor()->each(function ($e) { + $this->assertEquals('TESTEST123', $e->private_notes); + }); + + $data = [ + 'action' => 'bulk_update', + 'ids' => $ri->get()->pluck('hashed_id'), + 'column' => 'public_notes', + 'new_value' => 'TESTEST123', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson('/api/v1/recurring_invoices/bulk', $data); + + $response->assertStatus(200); + + $ri->cursor()->each(function ($e) { + $this->assertEquals('TESTEST123', $e->private_notes); + }); + + + + } + + + + + + public function testDateValidations() { $data = [