mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-31 12:34:35 -04:00
Add bulk categorization:
This commit is contained in:
parent
d26e5f05c3
commit
79e9c516fd
@ -11,27 +11,28 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Events\Expense\ExpenseWasCreated;
|
use App\Utils\Ninja;
|
||||||
use App\Events\Expense\ExpenseWasUpdated;
|
use App\Models\Account;
|
||||||
|
use App\Models\Expense;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
use App\Factory\ExpenseFactory;
|
use App\Factory\ExpenseFactory;
|
||||||
use App\Filters\ExpenseFilters;
|
use App\Filters\ExpenseFilters;
|
||||||
use App\Http\Requests\Expense\CreateExpenseRequest;
|
use App\Utils\Traits\MakesHash;
|
||||||
use App\Http\Requests\Expense\DestroyExpenseRequest;
|
use App\Utils\Traits\Uploadable;
|
||||||
|
use App\Utils\Traits\BulkOptions;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
|
use App\Repositories\ExpenseRepository;
|
||||||
|
use App\Transformers\ExpenseTransformer;
|
||||||
|
use App\Events\Expense\ExpenseWasCreated;
|
||||||
|
use App\Events\Expense\ExpenseWasUpdated;
|
||||||
|
use App\Http\Requests\Expense\BulkExpenseRequest;
|
||||||
use App\Http\Requests\Expense\EditExpenseRequest;
|
use App\Http\Requests\Expense\EditExpenseRequest;
|
||||||
use App\Http\Requests\Expense\ShowExpenseRequest;
|
use App\Http\Requests\Expense\ShowExpenseRequest;
|
||||||
use App\Http\Requests\Expense\StoreExpenseRequest;
|
use App\Http\Requests\Expense\StoreExpenseRequest;
|
||||||
|
use App\Http\Requests\Expense\CreateExpenseRequest;
|
||||||
use App\Http\Requests\Expense\UpdateExpenseRequest;
|
use App\Http\Requests\Expense\UpdateExpenseRequest;
|
||||||
use App\Http\Requests\Expense\UploadExpenseRequest;
|
use App\Http\Requests\Expense\UploadExpenseRequest;
|
||||||
use App\Models\Account;
|
use App\Http\Requests\Expense\DestroyExpenseRequest;
|
||||||
use App\Models\Expense;
|
|
||||||
use App\Repositories\ExpenseRepository;
|
|
||||||
use App\Transformers\ExpenseTransformer;
|
|
||||||
use App\Utils\Ninja;
|
|
||||||
use App\Utils\Traits\BulkOptions;
|
|
||||||
use App\Utils\Traits\MakesHash;
|
|
||||||
use App\Utils\Traits\SavesDocuments;
|
|
||||||
use App\Utils\Traits\Uploadable;
|
|
||||||
use Illuminate\Http\Response;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ExpenseController.
|
* Class ExpenseController.
|
||||||
@ -321,7 +322,10 @@ class ExpenseController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function create(CreateExpenseRequest $request)
|
public function create(CreateExpenseRequest $request)
|
||||||
{
|
{
|
||||||
$expense = ExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id);
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
$expense = ExpenseFactory::create($user->company()->id, $user->id);
|
||||||
|
|
||||||
return $this->itemResponse($expense);
|
return $this->itemResponse($expense);
|
||||||
}
|
}
|
||||||
@ -366,9 +370,12 @@ class ExpenseController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function store(StoreExpenseRequest $request)
|
public function store(StoreExpenseRequest $request)
|
||||||
{
|
{
|
||||||
$expense = $this->expense_repo->save($request->all(), ExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id));
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
event(new ExpenseWasCreated($expense, $expense->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
$expense = $this->expense_repo->save($request->all(), ExpenseFactory::create($user->company()->id, $user->id));
|
||||||
|
|
||||||
|
event(new ExpenseWasCreated($expense, $expense->company, Ninja::eventVars($user ? $user->id : null)));
|
||||||
|
|
||||||
event('eloquent.created: App\Models\Expense', $expense);
|
event('eloquent.created: App\Models\Expense', $expense);
|
||||||
|
|
||||||
@ -481,20 +488,25 @@ class ExpenseController extends BaseController
|
|||||||
* ),
|
* ),
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
public function bulk()
|
public function bulk(BulkExpenseRequest $request)
|
||||||
{
|
{
|
||||||
$action = request()->input('action');
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
$ids = request()->input('ids');
|
$expenses = Expense::withTrashed()->find($request->ids);
|
||||||
$expenses = Expense::withTrashed()->find($this->transformKeys($ids));
|
|
||||||
|
|
||||||
$expenses->each(function ($expense, $key) use ($action) {
|
if($request->action == 'bulk_categorize' && $user->can('edit', $expenses->first())) {
|
||||||
if (auth()->user()->can('edit', $expense)) {
|
$this->expense_repo->categorize($expenses, $request->category_id);
|
||||||
$this->expense_repo->{$action}($expense);
|
$expenses = collect([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$expenses->each(function ($expense) use ($request, $user) {
|
||||||
|
if ($user->can('edit', $expense)) {
|
||||||
|
$this->expense_repo->{$request->action}($expense);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return $this->listResponse(Expense::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
return $this->listResponse(Expense::withTrashed()->whereIn('id', $request->ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,13 +12,10 @@
|
|||||||
namespace App\Http\Requests\Expense;
|
namespace App\Http\Requests\Expense;
|
||||||
|
|
||||||
use App\Http\Requests\Request;
|
use App\Http\Requests\Request;
|
||||||
use App\Models\Expense;
|
use Illuminate\Validation\Rule;
|
||||||
use App\Utils\Traits\BulkOptions;
|
|
||||||
|
|
||||||
class BulkExpenseRequest extends Request
|
class BulkExpenseRequest extends Request
|
||||||
{
|
{
|
||||||
use BulkOptions;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the user is authorized to make this request.
|
* Determine if the user is authorized to make this request.
|
||||||
*
|
*
|
||||||
@ -26,15 +23,7 @@ class BulkExpenseRequest extends Request
|
|||||||
*/
|
*/
|
||||||
public function authorize()
|
public function authorize()
|
||||||
{
|
{
|
||||||
if (! $this->has('action')) {
|
return true;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! in_array($this->action, $this->getBulkOptions(), true)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return auth()->user()->can(auth()->user()->isAdmin(), Expense::class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,13 +33,30 @@ class BulkExpenseRequest extends Request
|
|||||||
*/
|
*/
|
||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
$rules = $this->getGlobalRules();
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
/* We don't require IDs on bulk storing. */
|
return [
|
||||||
if ($this->action !== self::$STORE_METHOD) {
|
'ids' => ['required','bail','array', Rule::exists('expenses', 'id')->where('company_id', $user->company()->id)],
|
||||||
$rules['ids'] = ['required'];
|
'category_id' => ['sometimes', 'bail', Rule::exists('expense_categories', 'id')->where('company_id', $user->company()->id)],
|
||||||
|
'action' => 'in:archive,restore,delete,bulk_categorize',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepareForValidation()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
if (isset($input['ids'])) {
|
||||||
|
$input['ids'] = $this->transformKeys($input['ids']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $rules;
|
if (isset($input['category_id'])) {
|
||||||
|
$input['category_id'] = $this->transformKeys($input['category_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,14 @@
|
|||||||
|
|
||||||
namespace App\Repositories;
|
namespace App\Repositories;
|
||||||
|
|
||||||
use App\Factory\ExpenseFactory;
|
|
||||||
use App\Libraries\Currency\Conversion\CurrencyApi;
|
|
||||||
use App\Models\Expense;
|
use App\Models\Expense;
|
||||||
use App\Utils\Traits\GeneratesCounter;
|
|
||||||
use Carbon\Exceptions\InvalidFormatException;
|
|
||||||
use Illuminate\Database\QueryException;
|
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
use App\Factory\ExpenseFactory;
|
||||||
|
use App\Models\ExpenseCategory;
|
||||||
|
use App\Utils\Traits\GeneratesCounter;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
use Carbon\Exceptions\InvalidFormatException;
|
||||||
|
use App\Libraries\Currency\Conversion\CurrencyApi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ExpenseRepository.
|
* ExpenseRepository.
|
||||||
@ -158,4 +159,25 @@ class ExpenseRepository extends BaseRepository
|
|||||||
|
|
||||||
return $expense;
|
return $expense;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Categorize Expenses in bulk
|
||||||
|
*
|
||||||
|
* @param Collection $expenses
|
||||||
|
* @param int $category_id
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function categorize($expenses, $category_id): void
|
||||||
|
{
|
||||||
|
$ec = ExpenseCategory::withTrashed()->find($category_id);
|
||||||
|
|
||||||
|
$expenses->when($ec)
|
||||||
|
->each(function ($expense) use($ec){
|
||||||
|
|
||||||
|
$expense->category_id = $ec->id;
|
||||||
|
$expense->save();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,12 @@
|
|||||||
|
|
||||||
namespace Tests\Feature;
|
namespace Tests\Feature;
|
||||||
|
|
||||||
use App\Models\BankIntegration;
|
|
||||||
use App\Models\BankTransaction;
|
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
use App\Models\Expense;
|
use App\Models\Expense;
|
||||||
use Tests\MockAccountData;
|
use Tests\MockAccountData;
|
||||||
|
use App\Models\BankIntegration;
|
||||||
|
use App\Models\BankTransaction;
|
||||||
|
use App\Models\ExpenseCategory;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
@ -232,6 +233,42 @@ class ExpenseApiTest extends TestCase
|
|||||||
$this->assertTrue($arr['data'][0]['is_deleted']);
|
$this->assertTrue($arr['data'][0]['is_deleted']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testExpenseBulkCategorize()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
$e = Expense::factory()->create([
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
$ec = ExpenseCategory::factory()->create([
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'name' => 'Test Category',
|
||||||
|
]);
|
||||||
|
|
||||||
|
nlog("expense category id = {$ec->hashed_id}");
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'category_id' => $ec->hashed_id,
|
||||||
|
'action' => 'bulk_categorize',
|
||||||
|
'ids' => [$this->encodePrimaryKey($e->id)],
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/expenses/bulk', $data);
|
||||||
|
|
||||||
|
$arr = $response->json();
|
||||||
|
nlog($arr);
|
||||||
|
|
||||||
|
$this->assertEquals($ec->hashed_id, $arr['data'][0]['category_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testAddingExpense()
|
public function testAddingExpense()
|
||||||
{
|
{
|
||||||
$data = [
|
$data = [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user