Fixes for Vendor Contacts (#3227)

* bug Fixes

* Working on Vendor GET route

* Fixes for vendor contacts
This commit is contained in:
David Bomba 2020-01-20 15:53:40 +11:00 committed by GitHub
parent 84642bf035
commit 0e9d098049
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 327 additions and 91 deletions

View File

@ -300,12 +300,6 @@ class CreateTestData extends Command
'is_primary' => 0
]);
factory(\App\Models\Vendor::class, rand(10, 50))->create([
'user_id' => $client->user->id,
'company_id' => $client->company->id
]);
}
private function createInvoice($client)

View File

@ -0,0 +1,158 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Filters;
use App\Models\Expense;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
/**
* ExpenseFilters
*/
class ExpenseFilters extends QueryFilters
{
/**
* Filter based on search text
*
* @param string query filter
* @return Illuminate\Database\Query\Builder
* @deprecated
*
*/
public function filter(string $filter = '') : Builder
{
if (strlen($filter) == 0) {
return $this->builder;
}
return $this->builder->where(function ($query) use ($filter) {
$query->where('expenses.name', 'like', '%'.$filter.'%')
->orWhere('expenses.id_number', 'like', '%'.$filter.'%')
->orWhere('expense_contacts.first_name', 'like', '%'.$filter.'%')
->orWhere('expense_contacts.last_name', 'like', '%'.$filter.'%')
->orWhere('expense_contacts.email', 'like', '%'.$filter.'%')
->orWhere('expenses.custom_value1', 'like', '%'.$filter.'%')
->orWhere('expenses.custom_value2', 'like', '%'.$filter.'%')
->orWhere('expenses.custom_value3', 'like', '%'.$filter.'%')
->orWhere('expenses.custom_value4', 'like', '%'.$filter.'%');
});
}
/**
* Filters the list based on the status
* archived, active, deleted
*
* @param string filter
* @return Illuminate\Database\Query\Builder
*/
public function status(string $filter = '') : Builder
{
if (strlen($filter) == 0) {
return $this->builder;
}
$table = 'expenses';
$filters = explode(',', $filter);
return $this->builder->where(function ($query) use ($filters, $table) {
$query->whereNull($table . '.id');
if (in_array(parent::STATUS_ACTIVE, $filters)) {
$query->orWhereNull($table . '.deleted_at');
}
if (in_array(parent::STATUS_ARCHIVED, $filters)) {
$query->orWhere(function ($query) use ($table) {
$query->whereNotNull($table . '.deleted_at');
if (! in_array($table, ['users'])) {
$query->where($table . '.is_deleted', '=', 0);
}
});
}
if (in_array(parent::STATUS_DELETED, $filters)) {
$query->orWhere($table . '.is_deleted', '=', 1);
}
});
}
/**
* Sorts the list based on $sort
*
* @param string sort formatted as column|asc
* @return Illuminate\Database\Query\Builder
*/
public function sort(string $sort) : Builder
{
$sort_col = explode("|", $sort);
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
}
/**
* Returns the base query
*
* @param int company_id
* @return Illuminate\Database\Query\Builder
* @deprecated
*/
public function baseQuery(int $company_id, User $user) : Builder
{
$query = DB::table('expenses')
->join('companies', 'companies.id', '=', 'expenses.company_id')
->where('expenses.company_id', '=', $company_id)
//->whereRaw('(expenses.name != "" or contacts.first_name != "" or contacts.last_name != "" or contacts.email != "")') // filter out buy now invoices
->select(
// DB::raw('COALESCE(expenses.currency_id, companies.currency_id) currency_id'),
DB::raw('COALESCE(expenses.country_id, companies.country_id) country_id'),
DB::raw("CONCAT(COALESCE(expense_contacts.first_name, ''), ' ', COALESCE(expense_contacts.last_name, '')) contact"),
'expenses.id',
'expenses.private_notes',
'expenses.custom_value1',
'expenses.custom_value2',
'expenses.custom_value3',
'expenses.custom_value4',
'expenses.created_at',
'expenses.created_at as expense_created_at',
'expenses.deleted_at',
'expenses.is_deleted',
'expenses.user_id',
);
/**
* If the user does not have permissions to view all invoices
* limit the user to only the invoices they have created
*/
if (Gate::denies('view-list', Expense::class)) {
$query->where('expenses.user_id', '=', $user->id);
}
return $query;
}
/**
* Filters the query by the users company ID
*
* @param $company_id The company Id
* @return Illuminate\Database\Query\Builder
*/
public function entityFilter()
{
//return $this->builder->whereCompanyId(auth()->user()->company()->id);
return $this->builder->company();
}
}

View File

@ -11,16 +11,17 @@
namespace App\Http\Controllers;
use App\Filters\VendorFilters;
use App\Filters\ExpenseFilters;
use App\Jobs\Entity\ActionEntity;
use App\Jobs\Util\ProcessBulk;
use App\Jobs\Util\UploadAvatar;
use App\Models\Country;
use App\Models\Currency;
use App\Models\Expense;
use App\Models\Size;
use App\Models\Vendor;
use App\Repositories\BaseRepository;
use App\Transformers\VendorTransformer;
use App\Repositories\ExpenseRepository;
use App\Transformers\ExpenseTransformer;
use App\Utils\Traits\BulkOptions;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Uploadable;
@ -29,45 +30,45 @@ use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
/**
* Class VendorController
* Class ExpenseController
* @package App\Http\Controllers
* @covers App\Http\Controllers\VendorController
* @covers App\Http\Controllers\ExpenseController
*/
class VendorController extends BaseController
class ExpenseController extends BaseController
{
use MakesHash;
use Uploadable;
use BulkOptions;
protected $entity_type = Vendor::class;
protected $entity_type = Expense::class;
protected $entity_transformer = VendorTransformer::class;
protected $entity_transformer = ExpenseTransformer::class;
/**
* @var Vendorepository
* @var Expenseepository
*/
protected $vendor_repo;
protected $expense_repo;
/**
* VendorController constructor.
* @param VendorRepository $vendorRepo
* ExpenseController constructor.
* @param ExpenseRepository $expenseRepo
*/
public function __construct(VendorRepository $vendor_repo)
public function __construct(ExpenseRepository $expense_repo)
{
parent::__construct();
$this->vendor_repo = $vendor_repo;
$this->expense_repo = $expense_repo;
}
/**
* @OA\Get(
* path="/api/v1/vendors",
* operationId="getVendors",
* tags={"vendors"},
* summary="Gets a list of vendors",
* description="Lists vendors, search and filters allow fine grained lists to be generated.
* path="/api/v1/expenses",
* operationId="getExpenses",
* tags={"expenses"},
* summary="Gets a list of expenses",
* description="Lists expenses, search and filters allow fine grained lists to be generated.
Query parameters can be added to performed more fine grained filtering of the vendors, these are handled by the VendorFilters class which defines the methods available",
Query parameters can be added to performed more fine grained filtering of the expenses, these are handled by the ExpenseFilters class which defines the methods available",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
@ -75,11 +76,11 @@ class VendorController extends BaseController
* @OA\Parameter(ref="#/components/parameters/index"),
* @OA\Response(
* response=200,
* description="A list of vendors",
* description="A list of expenses",
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Vendor"),
* @OA\JsonContent(ref="#/components/schemas/Expense"),
* ),
* @OA\Response(
* response=422,
@ -95,11 +96,11 @@ class VendorController extends BaseController
* )
*
*/
public function index(VendorFilters $filters)
public function index(ExpenseFilters $filters)
{
$vendors = Vendor::filter($filters);
$expenses = Expense::filter($filters);
return $this->listResponse($vendors);
return $this->listResponse($expenses);
}
/**
@ -110,9 +111,9 @@ class VendorController extends BaseController
*
*
* @OA\Get(
* path="/api/v1/vendors/{id}",
* operationId="showVendor",
* tags={"vendors"},
* path="/api/v1/expenses/{id}",
* operationId="showExpense",
* tags={"expenses"},
* summary="Shows a client",
* description="Displays a client by id",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
@ -122,7 +123,7 @@ class VendorController extends BaseController
* @OA\Parameter(
* name="id",
* in="path",
* description="The Vendor Hashed ID",
* description="The Expense Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
@ -132,11 +133,11 @@ class VendorController extends BaseController
* ),
* @OA\Response(
* response=200,
* description="Returns the vendor object",
* description="Returns the expense object",
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Vendor"),
* @OA\JsonContent(ref="#/components/schemas/Expense"),
* ),
* @OA\Response(
* response=422,
@ -152,9 +153,9 @@ class VendorController extends BaseController
* )
*
*/
public function show(ShowVendorRequest $request, Vendor $vendor)
public function show(ShowExpenseRequest $request, Expense $expense)
{
return $this->itemResponse($vendor);
return $this->itemResponse($expense);
}
/**
@ -165,9 +166,9 @@ class VendorController extends BaseController
*
*
* @OA\Get(
* path="/api/v1/vendors/{id}/edit",
* operationId="editVendor",
* tags={"vendors"},
* path="/api/v1/expenses/{id}/edit",
* operationId="editExpense",
* tags={"expenses"},
* summary="Shows a client for editting",
* description="Displays a client by id",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
@ -177,7 +178,7 @@ class VendorController extends BaseController
* @OA\Parameter(
* name="id",
* in="path",
* description="The Vendor Hashed ID",
* description="The Expense Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
@ -191,7 +192,7 @@ class VendorController extends BaseController
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Vendor"),
* @OA\JsonContent(ref="#/components/schemas/Expense"),
* ),
* @OA\Response(
* response=422,
@ -207,24 +208,24 @@ class VendorController extends BaseController
* )
*
*/
public function edit(EditVendorRequest $request, Vendor $vendor)
public function edit(EditExpenseRequest $request, Expense $expense)
{
return $this->itemResponse($vendor);
return $this->itemResponse($expense);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param App\Models\Vendor $vendor
* @param App\Models\Expense $expense
* @return \Illuminate\Http\Response
*
*
*
* @OA\Put(
* path="/api/v1/vendors/{id}",
* operationId="updateVendor",
* tags={"vendors"},
* path="/api/v1/expenses/{id}",
* operationId="updateExpense",
* tags={"expenses"},
* summary="Updates a client",
* description="Handles the updating of a client by id",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
@ -234,7 +235,7 @@ class VendorController extends BaseController
* @OA\Parameter(
* name="id",
* in="path",
* description="The Vendor Hashed ID",
* description="The Expense Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
@ -248,7 +249,7 @@ class VendorController extends BaseController
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Vendor"),
* @OA\JsonContent(ref="#/components/schemas/Expense"),
* ),
* @OA\Response(
* response=422,
@ -264,16 +265,16 @@ class VendorController extends BaseController
* )
*
*/
public function update(UpdateVendorRequest $request, Vendor $vendor)
public function update(UpdateExpenseRequest $request, Expense $expense)
{
if($request->entityIsDeleted($vendor))
if($request->entityIsDeleted($expense))
return $request->disallowUpdate();
$vendor = $this->client_repo->save($request->all(), $vendor);
$expense = $this->client_repo->save($request->all(), $expense);
$this->uploadLogo($request->file('company_logo'), $vendor->company, $vendor);
$this->uploadLogo($request->file('company_logo'), $expense->company, $expense);
return $this->itemResponse($vendor->fresh());
return $this->itemResponse($expense->fresh());
}
/**
@ -284,9 +285,9 @@ class VendorController extends BaseController
*
*
* @OA\Get(
* path="/api/v1/vendors/create",
* operationId="getVendorsCreate",
* tags={"vendors"},
* path="/api/v1/expenses/create",
* operationId="getExpensesCreate",
* tags={"expenses"},
* summary="Gets a new blank client object",
* description="Returns a blank object with default values",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
@ -299,7 +300,7 @@ class VendorController extends BaseController
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Vendor"),
* @OA\JsonContent(ref="#/components/schemas/Expense"),
* ),
* @OA\Response(
* response=422,
@ -315,11 +316,11 @@ class VendorController extends BaseController
* )
*
*/
public function create(CreateVendorRequest $request)
public function create(CreateExpenseRequest $request)
{
$vendor = VendorFactory::create(auth()->user()->company()->id, auth()->user()->id);
$expense = ExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id);
return $this->itemResponse($vendor);
return $this->itemResponse($expense);
}
/**
@ -331,9 +332,9 @@ class VendorController extends BaseController
*
*
* @OA\Post(
* path="/api/v1/vendors",
* operationId="storeVendor",
* tags={"vendors"},
* path="/api/v1/expenses",
* operationId="storeExpense",
* tags={"expenses"},
* summary="Adds a client",
* description="Adds an client to a company",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
@ -346,7 +347,7 @@ class VendorController extends BaseController
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Vendor"),
* @OA\JsonContent(ref="#/components/schemas/Expense"),
* ),
* @OA\Response(
* response=422,
@ -362,15 +363,15 @@ class VendorController extends BaseController
* )
*
*/
public function store(StoreVendorRequest $request)
public function store(StoreExpenseRequest $request)
{
$vendor = $this->client_repo->save($request->all(), VendorFactory::create(auth()->user()->company()->id, auth()->user()->id));
$expense = $this->client_repo->save($request->all(), ExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id));
$vendor->load('contacts', 'primary_contact');
$expense->load('contacts', 'primary_contact');
$this->uploadLogo($request->file('company_logo'), $vendor->company, $vendor);
$this->uploadLogo($request->file('company_logo'), $expense->company, $expense);
return $this->itemResponse($vendor);
return $this->itemResponse($expense);
}
/**
@ -381,9 +382,9 @@ class VendorController extends BaseController
*
*
* @OA\Delete(
* path="/api/v1/vendors/{id}",
* operationId="deleteVendor",
* tags={"vendors"},
* path="/api/v1/expenses/{id}",
* operationId="deleteExpense",
* tags={"expenses"},
* summary="Deletes a client",
* description="Handles the deletion of a client by id",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
@ -393,7 +394,7 @@ class VendorController extends BaseController
* @OA\Parameter(
* name="id",
* in="path",
* description="The Vendor Hashed ID",
* description="The Expense Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
@ -422,10 +423,10 @@ class VendorController extends BaseController
* )
*
*/
public function destroy(DestroyVendorRequest $request, Vendor $vendor)
public function destroy(DestroyExpenseRequest $request, Expense $expense)
{
//may not need these destroy routes as we are using actions to 'archive/delete'
$vendor->delete();
$expense->delete();
return response()->json([], 200);
}
@ -433,15 +434,15 @@ class VendorController extends BaseController
/**
* Perform bulk actions on the list view
*
* @param BulkVendorRequest $request
* @param BulkExpenseRequest $request
* @return \Illuminate\Http\Response
*
*
* @OA\Post(
* path="/api/v1/vendors/bulk",
* operationId="bulkVendors",
* tags={"vendors"},
* summary="Performs bulk actions on an array of vendors",
* path="/api/v1/expenses/bulk",
* operationId="bulkExpenses",
* tags={"expenses"},
* summary="Performs bulk actions on an array of expenses",
* description="",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
@ -464,11 +465,11 @@ class VendorController extends BaseController
* ),
* @OA\Response(
* response=200,
* description="The Vendor User response",
* description="The Expense User response",
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Vendor"),
* @OA\JsonContent(ref="#/components/schemas/Expense"),
* ),
* @OA\Response(
* response=422,
@ -487,15 +488,15 @@ class VendorController extends BaseController
$action = request()->input('action');
$ids = request()->input('ids');
$vendors = Vendor::withTrashed()->find($this->transformKeys($ids));
$expenses = Expense::withTrashed()->find($this->transformKeys($ids));
$vendors->each(function ($vendor, $key) use ($action) {
if (auth()->user()->can('edit', $vendor)) {
$this->client_repo->{$action}($vendor);
$expenses->each(function ($expense, $key) use ($action) {
if (auth()->user()->can('edit', $expense)) {
$this->client_repo->{$action}($expense);
}
});
return $this->listResponse(Vendor::withTrashed()->whereIn('id', $this->transformKeys($ids)));
return $this->listResponse(Expense::withTrashed()->whereIn('id', $this->transformKeys($ids)));
}
/**

View File

@ -20,6 +20,8 @@ use App\Models\Currency;
use App\Models\Size;
use App\Models\Vendor;
use App\Repositories\BaseRepository;
use App\Repositories\VendorRepository;
use App\Transformers\VendorTransformer;
use App\Utils\Traits\BulkOptions;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Uploadable;

View File

@ -11,6 +11,7 @@
namespace App\Models;
use App\Models\Filterable;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
@ -18,6 +19,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
class Expense extends BaseModel
{
use SoftDeletes;
use Filterable;
protected $fillable = [
'client_id',

View File

@ -11,6 +11,8 @@
namespace App\Models;
use App\Models\Filterable;
use App\Models\VendorContact;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
@ -18,6 +20,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
class Vendor extends BaseModel
{
use SoftDeletes;
use Filterable;
protected $fillable = [
'name',

View File

@ -0,0 +1,75 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Repositories;
use App\Factory\ExpenseFactory;
use App\Models\Expense;
use App\Repositories\VSendorContactRepository;
use App\Utils\Traits\GeneratesCounter;
use Illuminate\Http\Request;
/**
* ExpenseRepository
*/
class ExpenseRepository extends BaseRepository
{
use GeneratesCounter;
public function __construct()
{
}
/**
* Gets the class name.
*
* @return string The class name.
*/
public function getClassName()
{
return Expense::class;
}
/**
* Saves the expense and its contacts
*
* @param array $data The data
* @param \App\Models\expense $expense The expense
*
* @return expense|\App\Models\expense|null expense Object
*/
public function save(array $data, Expense $expense) : ?Expense
{
$expense->fill($data);
$expense->save();
// if ($expense->id_number == "" || !$expense->id_number) {
// $expense->id_number = $this->getNextExpenseNumber($expense);
// } //todo write tests for this and make sure that custom expense numbers also works as expected from here
return $expense;
}
/**
* Store expenses in bulk.
*
* @param array $expense
* @return expense|null
*/
public function create($expense): ?Expense
{
return $this->save(
$expense,
ExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id)
);
}
}

View File

@ -16,6 +16,7 @@ use App\Models\Vendor;
use App\Models\VendorContact;
use App\Models\VendorGatewayToken;
use App\Transformers\ActivityTransformer;
use App\Transformers\VendorContactTransformer;
use App\Transformers\VendorGatewayTokenTransformer;
use App\Utils\Traits\MakesHash;