1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 13:12:50 +01:00

Merge pull request #8490 from turbo124/v5-develop

Add group setting filters
This commit is contained in:
David Bomba 2023-04-30 18:09:28 +10:00 committed by GitHub
commit e96a2a85f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 9668 additions and 6495 deletions

View File

@ -14,8 +14,9 @@ namespace App\DataMapper\Tax;
use App\Models\Client;
use App\Models\Invoice;
use App\Models\Product;
use App\DataMapper\Tax\ZipTax\Response;
use App\DataMapper\Tax\TaxData;
use App\DataProviders\USStates;
use App\DataMapper\Tax\ZipTax\Response;
class BaseRule implements RuleInterface
{
@ -148,7 +149,9 @@ class BaseRule implements RuleInterface
{
if(!array_key_exists($this->client->country->iso_3166_2, $this->region_codes)) {
throw new \Exception('Automatic tax calculations not supported for this country');
$this->client->country_id = $this->invoice->company->settings->country_id;
$this->client->saveQuietly();
nlog('Automatic tax calculations not supported for this country - defaulting to company country');
}
$this->client_region = $this->region_codes[$this->client->country->iso_3166_2];
@ -157,14 +160,17 @@ class BaseRule implements RuleInterface
return $this;
//determine if we are taxing locally or if we are taxing globally
$this->invoice->tax_data = $this->invoice->client->tax_data ?: new Response([]);
$tax_data = $this->invoice->client->tax_data ?? new Response([]);
if(strlen($this->invoice->tax_data?->originDestination) == 0 && $this->client->company->tax_data->seller_subregion != $this->client_subregion) {
$tax_data = $this->invoice->tax_data;
$tax_data->originDestination = "D";
$tax_data->geoState = $this->client_subregion;
$this->invoice->tax_data = $tax_data;
$this->invoice->saveQuietly();
if($this->invoice instanceof Invoice) {
$this->invoice->tax_data = $tax_data;
$this->invoice->saveQuietly();
}
}
return $this;
@ -217,9 +223,11 @@ class BaseRule implements RuleInterface
return $this;
}
$this->tax_rate1 = $this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_rate;
$this->tax_name1 = $this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_name;
if(isset($this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion})) {
$this->tax_rate1 = $this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_rate;
$this->tax_name1 = $this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_name;
}
return $this;
}

View File

@ -100,7 +100,7 @@ class Response
public string $originDestination = ""; // defines if the client origin is the locale where the tax is remitted to
public function __construct($data)
public function __construct($data = null)
{
if($data) {

View File

@ -86,7 +86,7 @@ class BankIntegrationFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder
@ -103,7 +103,7 @@ class BankIntegrationFilters extends QueryFilters
/**
* Filters the query by the users company ID.
*
* @return Illuminate\Database\Query\Builder
* @return Builder
*/
public function entityFilter(): Builder
{

View File

@ -0,0 +1,79 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Filters;
use Illuminate\Database\Eloquent\Builder;
/**
* GroupSettingFilters.
*/
class GroupSettingFilters extends QueryFilters
{
/**
* Filter by name.
*
* @param string $name
* @return Builder
*/
public function name(string $name = ''): Builder
{nlog("filter");
if (strlen($name) == 0) {
return $this->builder;
}
return $this->builder->where('name', 'like', '%'.$name.'%');
}
/**
* Filter based on search text.
*
* @param string $filter
* @return Builder
*/
public function filter(string $filter = ''): Builder
{
if (strlen($filter) == 0) {
return $this->builder;
}
return $this->builder->where(function ($query) use ($filter) {
$query->where('name', 'like', '%'.$filter.'%');
});
}
/**
* Sorts the list based on $sort.
*
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder
{
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2) {
return $this->builder;
}
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
}
/**
* Filters the query by the users company ID.
*
* @return Builder
*/
public function entityFilter(): Builder
{
return $this->builder->company();
}
}

View File

@ -172,22 +172,16 @@ abstract class QueryFilters
switch ($operator) {
case 'lt':
return '<';
break;
case 'gt':
return '>';
break;
case 'lte':
return '<=';
break;
case 'gte':
return '>=';
break;
case 'eq':
return '=';
break;
default:
return '=';
break;
}
}

View File

@ -30,33 +30,33 @@ class InvoiceItemSum
use Taxer;
private array $tax_jurisdictions = [
'AT', // Austria
'BE', // Belgium
'BG', // Bulgaria
'CY', // Cyprus
'CZ', // Czech Republic
// 'AT', // Austria
// 'BE', // Belgium
// 'BG', // Bulgaria
// 'CY', // Cyprus
// 'CZ', // Czech Republic
'DE', // Germany
'DK', // Denmark
'EE', // Estonia
'ES', // Spain
'FI', // Finland
'FR', // France
'GR', // Greece
'HR', // Croatia
'HU', // Hungary
'IE', // Ireland
'IT', // Italy
'LT', // Lithuania
'LU', // Luxembourg
'LV', // Latvia
'MT', // Malta
'NL', // Netherlands
'PL', // Poland
'PT', // Portugal
'RO', // Romania
'SE', // Sweden
'SI', // Slovenia
'SK', // Slovakia
// 'DK', // Denmark
// 'EE', // Estonia
// 'ES', // Spain
// 'FI', // Finland
// 'FR', // France
// 'GR', // Greece
// 'HR', // Croatia
// 'HU', // Hungary
// 'IE', // Ireland
// 'IT', // Italy
// 'LT', // Lithuania
// 'LU', // Luxembourg
// 'LV', // Latvia
// 'MT', // Malta
// 'NL', // Netherlands
// 'PL', // Poland
// 'PT', // Portugal
// 'RO', // Romania
// 'SE', // Sweden
// 'SI', // Slovenia
// 'SK', // Slovakia
'US', // USA
@ -116,7 +116,6 @@ class InvoiceItemSum
{
if (!$this->invoice->line_items || !is_array($this->invoice->line_items)) {
$this->items = [];
return $this;
}
@ -146,8 +145,11 @@ class InvoiceItemSum
}
//should we be filtering by client country here? do we need to reflect at the company <=> client level?
if (in_array($this->client->country->iso_3166_2, $this->tax_jurisdictions)) { //only calculate for supported tax jurisdictions
// if (in_array($this->client->country->iso_3166_2, $this->tax_jurisdictions)) { //only calculate for supported tax jurisdictions
if (in_array($this->client->company->country()->iso_3166_2, $this->tax_jurisdictions)) { //only calculate for supported tax jurisdictions
nlog($this->client->company->country()->iso_3166_2);
$class = "App\DataMapper\Tax\\".$this->client->company->country()->iso_3166_2."\\Rule";
$this->rule = new $class();
@ -216,7 +218,12 @@ class InvoiceItemSum
return $this;
}
/**
* calcTaxes
*
* @return self
*/
private function calcTaxes()
{
if ($this->calc_tax) {

View File

@ -62,84 +62,6 @@ class AccountController extends BaseController
* @param CreateAccountRequest $request
* @return Response
*
* @OA\Post(
* path="/api/v1/signup",
* operationId="postSignup",
* tags={"signup"},
* summary="Attempts a new account signup",
* description="Attempts a new account signup and returns a CompanyUser object on success",
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(
* name="token_name",
* in="query",
* description="A custom name for the user company token",
* example="Daves iOS Device",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\RequestBody(
* description="Signup credentials",
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="email",
* description="The user email address",
* type="string",
* ),
* @OA\Property(
* property="first_name",
* description="The signup users first name",
* type="string",
* ),
* @OA\Property(
* property="last_name",
* description="The signup users last name",
* type="string",
* ),
* @OA\Property(
* property="terms_of_service",
* description="The user accepted the terms of service",
* type="boolean",
* ),
* @OA\Property(
* property="privacy_policy",
* description="The user accepted the privacy policy",
* type="boolean",
* ),
* @OA\Property(
* property="password",
* example="1234567",
* description="The user password must meet minimum criteria ~ >6 characters",
* type="string"
* )
* )
* )
* ),
* @OA\Response(
* response=200,
* description="The Company User response",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/CompanyUser"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function store(CreateAccountRequest $request)
{

View File

@ -68,39 +68,10 @@ class ClientController extends BaseController
}
/**
* @OA\Get(
* path="/api/v1/clients",
* operationId="getClients",
* tags={"clients"},
* summary="Gets a list of clients",
* description="Lists clients, search and filters allow fine grained lists to be generated.
* Query parameters can be added to performed more fine grained filtering of the clients, these are handled by the ClientFilters class which defines the methods available",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(ref="#/components/parameters/index"),
* @OA\Response(
* response=200,
* description="A list of clients",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/Client"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*
* @param ClientFilters $filters
* @return Response|mixed
* @return Response
*
*/
public function index(ClientFilters $filters)
{
@ -118,47 +89,6 @@ class ClientController extends BaseController
* @param Client $client
* @return Response
*
*
* @OA\Get(
* path="/api/v1/clients/{id}",
* operationId="showClient",
* tags={"clients"},
* summary="Shows a client",
* description="Displays a client by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Client Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the cl.ient object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/Client"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function show(ShowClientRequest $request, Client $client)
{
@ -172,47 +102,6 @@ class ClientController extends BaseController
* @param Client $client
* @return Response
*
*
* @OA\Get(
* path="/api/v1/clients/{id}/edit",
* operationId="editClient",
* tags={"clients"},
* summary="Shows a client for editting",
* description="Displays a client by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Client Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the client object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/Client"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function edit(EditClientRequest $request, Client $client)
{
@ -226,48 +115,6 @@ class ClientController extends BaseController
* @param Client $client
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/clients/{id}",
* operationId="updateClient",
* tags={"clients"},
* summary="Updates a client",
* description="Handles the updating of a client by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Client Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the client object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/Client"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function update(UpdateClientRequest $request, Client $client)
{
@ -290,37 +137,6 @@ class ClientController extends BaseController
* @param CreateClientRequest $request
* @return Response
*
*
*
* @OA\Get(
* path="/api/v1/clients/create",
* operationId="getClientsCreate",
* tags={"clients"},
* summary="Gets a new blank client object",
* description="Returns a blank object with default values",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Response(
* response=200,
* description="A blank client object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/Client"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function create(CreateClientRequest $request)
{
@ -335,37 +151,6 @@ class ClientController extends BaseController
* @param StoreClientRequest $request
* @return Response
*
*
*
* @OA\Post(
* path="/api/v1/clients",
* operationId="storeClient",
* tags={"clients"},
* summary="Adds a client",
* description="Adds an client to a company",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Response(
* response=200,
* description="Returns the saved client object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/Client"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function store(StoreClientRequest $request)
{
@ -392,47 +177,7 @@ class ClientController extends BaseController
* @param Client $client
* @return Response
*
*
* @throws \Exception
* @OA\Delete(
* path="/api/v1/clients/{id}",
* operationId="deleteClient",
* tags={"clients"},
* summary="Deletes a client",
* description="Handles the deletion of a client by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Client Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns a HTTP status",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function destroy(DestroyClientRequest $request, Client $client)
{
@ -446,61 +191,20 @@ class ClientController extends BaseController
*
* @return Response
*
*
* @OA\Post(
* path="/api/v1/clients/bulk",
* operationId="bulkClients",
* tags={"clients"},
* summary="Performs bulk actions on an array of clients",
* description="",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/index"),
* @OA\RequestBody(
* description="User credentials",
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="array",
* @OA\Items(
* type="integer",
* description="Array of hashed IDs to be bulk 'actioned",
* example="[0,1,2,3]",
* ),
* )
* )
* ),
* @OA\Response(
* response=200,
* description="The Client User response",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/Client"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function bulk(BulkClientRequest $request)
{
$action = $request->action;
/** @var \App\Models\User $user */
$user = auth()->user();
$clients = Client::withTrashed()
->company()
->whereIn('id', $request->ids)
->cursor()
->each(function ($client) use ($action) {
if (auth()->user()->can('edit', $client)) {
->each(function ($client) use ($action, $user) {
if ($user->can('edit', $client)) {
$this->client_repo->{$action}($client);
}
});
@ -515,48 +219,6 @@ class ClientController extends BaseController
* @param Client $client
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/clients/{id}/upload",
* operationId="uploadClient",
* tags={"clients"},
* summary="Uploads a document to a client",
* description="Handles the uploading of a document to a client",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Client Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the client object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/Client"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadClientRequest $request, Client $client)
{
@ -578,47 +240,6 @@ class ClientController extends BaseController
* @param Client $client
* @return Response
*
*
*
* @OA\Post(
* path="/api/v1/clients/{id}/purge",
* operationId="purgeClient",
* tags={"clients"},
* summary="Purges a client from the system",
* description="Handles purging a client",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Client Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the client object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function purge(PurgeClientRequest $request, Client $client)
{
@ -647,58 +268,6 @@ class ClientController extends BaseController
* @param string $mergeable_client
* @return Response
*
*
*
* @OA\Post(
* path="/api/v1/clients/{id}/{mergeable_client_hashed_id}/merge",
* operationId="mergeClient",
* tags={"clients"},
* summary="Merges two clients",
* description="Handles merging 2 clients",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Client Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Parameter(
* name="mergeable_client_hashed_id",
* in="path",
* description="The Mergeable Client Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the client object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function merge(PurgeClientRequest $request, Client $client, string $mergeable_client)

View File

@ -521,8 +521,11 @@ class DesignController extends BaseController
$designs = Design::withTrashed()->company()->whereIn('id', $this->transformKeys($ids));
$designs->each(function ($design, $key) use ($action) {
if (auth()->user()->can('edit', $design)) {
/** @var \App\Models\User $user */
$user = auth()->user();
$designs->each(function ($design, $key) use ($action, $user) {
if ($user->can('edit', $design)) {
$this->design_repo->{$action}($design);
}
});
@ -534,7 +537,11 @@ class DesignController extends BaseController
{
$design_id = $request->input('design_id');
$entity = $request->input('entity');
$company = auth()->user()->getCompany();
/** @var \App\Models\User $user */
$user = auth()->user();
$company = $user->getCompany();
$design = Design::where('company_id', $company->id)
->orWhereNull('company_id')

View File

@ -12,6 +12,7 @@
namespace App\Http\Controllers;
use App\Factory\GroupSettingFactory;
use App\Filters\GroupSettingFilters;
use App\Http\Requests\GroupSetting\CreateGroupSettingRequest;
use App\Http\Requests\GroupSetting\DestroyGroupSettingRequest;
use App\Http\Requests\GroupSetting\EditGroupSettingRequest;
@ -49,47 +50,17 @@ class GroupSettingController extends BaseController
$this->group_setting_repo = $group_setting_repo;
}
/**
* Display a listing of the resource.
* Show the form for creating a new resource.
*
* @param GroupSettingFilters $filters
* @return Response
*
*
* @OA\Get(
* path="/api/v1/group_settings",
* operationId="getGroupSettings",
* tags={"group_settings"},
* summary="Gets a list of group_settings",
* description="Lists group_settings, search and filters allow fine grained lists to be generated.
Query parameters can be added to performed more fine grained filtering of the group_settings, these are handled by the GroupSettingFilters class which defines the methods available",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Response(
* response=200,
* description="A list of group_settings",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/GroupSetting"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function index()
*/
public function index(GroupSettingFilters $filters)
{
$group_settings = GroupSetting::whereCompanyId(auth()->user()->company()->id);
$group_settings = GroupSetting::filter($filters);
return $this->listResponse($group_settings);
}
@ -100,41 +71,13 @@ class GroupSettingController extends BaseController
* @param CreateGroupSettingRequest $request
* @return Response
*
*
*
* @OA\Get(
* path="/api/v1/group_settings/create",
* operationId="getGroupSettingsCreate",
* tags={"group_settings"},
* summary="Gets a new blank GroupSetting object",
* description="Returns a blank object with default values",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Response(
* response=200,
* description="A blank GroupSetting object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/GroupSetting"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
*/
public function create(CreateGroupSettingRequest $request)
{
$group_setting = GroupSettingFactory::create(auth()->user()->company()->id, auth()->user()->id);
/** @var \App\Models\User $user */
$user = auth()->user();
$group_setting = GroupSettingFactory::create($user->company()->id, $user->id);
return $this->itemResponse($group_setting);
}
@ -145,44 +88,13 @@ class GroupSettingController extends BaseController
* @param StoreGroupSettingRequest $request
* @return Response
*
*
*
* @OA\Post(
* path="/api/v1/group_settings",
* operationId="storeGroupSetting",
* tags={"group_settings"},
* summary="Adds a GroupSetting",
* description="Adds an GroupSetting to the system",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Response(
* response=200,
* description="Returns the saved GroupSetting object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/GroupSetting"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function store(StoreGroupSettingRequest $request)
{
//need to be careful here as we may also receive some
//supporting attributes such as logo which need to be handled outside of the
//settings object
$group_setting = GroupSettingFactory::create(auth()->user()->company()->id, auth()->user()->id);
/** @var \App\Models\User $user */
$user = auth()->user();
$group_setting = GroupSettingFactory::create($user->company()->id, $user->id);
$group_setting = $this->group_setting_repo->save($request->all(), $group_setting);
@ -198,47 +110,6 @@ class GroupSettingController extends BaseController
* @param GroupSetting $group_setting
* @return Response
*
*
* @OA\Get(
* path="/api/v1/group_settings/{id}",
* operationId="showGroupSetting",
* tags={"group_settings"},
* summary="Shows an GroupSetting",
* description="Displays an GroupSetting by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The GroupSetting Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the GroupSetting object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/GroupSetting"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function show(ShowGroupSettingRequest $request, GroupSetting $group_setting)
{
@ -252,47 +123,6 @@ class GroupSettingController extends BaseController
* @param GroupSetting $group_setting
* @return Response
*
*
* @OA\Get(
* path="/api/v1/group_settings/{id}/edit",
* operationId="editGroupSetting",
* tags={"group_settings"},
* summary="Shows an GroupSetting for editting",
* description="Displays an GroupSetting by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The GroupSetting Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the GroupSetting object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/GroupSetting"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function edit(EditGroupSettingRequest $request, GroupSetting $group_setting)
{
@ -306,47 +136,6 @@ class GroupSettingController extends BaseController
* @param GroupSetting $group_setting
* @return Response
*
*
* @OA\Put(
* path="/api/v1/group_settings/{id}",
* operationId="updateGroupSetting",
* tags={"group_settings"},
* summary="Updates an GroupSetting",
* description="Handles the updating of an GroupSetting by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The GroupSetting Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the GroupSetting object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/GroupSetting"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function update(UpdateGroupSettingRequest $request, GroupSetting $group_setting)
{
@ -370,45 +159,6 @@ class GroupSettingController extends BaseController
*
*
* @throws \Exception
* @OA\Delete(
* path="/api/v1/group_settings/{id}",
* operationId="deleteGroupSetting",
* tags={"group_settings"},
* summary="Deletes a GroupSetting",
* description="Handles the deletion of an GroupSetting by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The GroupSetting Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns a HTTP status",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function destroy(DestroyGroupSettingRequest $request, GroupSetting $group_setting)
{
@ -420,51 +170,8 @@ class GroupSettingController extends BaseController
/**
* Perform bulk actions on the list view.
*
* @return Collection
* @return Response
*
* @OA\Post(
* path="/api/v1/group_settings/bulk",
* operationId="bulkGroupSettings",
* tags={"group_settings"},
* summary="Performs bulk actions on an array of group_settings",
* description="",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/index"),
* @OA\RequestBody(
* description="An array of group_settings ids",
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="array",
* @OA\Items(
* type="integer",
* description="Array of hashed IDs to be bulk 'actioned",
* example="[0,1,2,3]",
* ),
* )
* )
* ),
* @OA\Response(
* response=200,
* description="The Bulk Action response",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function bulk()
{
@ -472,17 +179,20 @@ class GroupSettingController extends BaseController
$ids = request()->input('ids');
$group_settings = GroupSetting::withTrashed()->whereIn('id', $this->transformKeys($ids))->company()->get();
$group_settings = GroupSetting::withTrashed()->whereIn('id', $this->transformKeys($ids))->company();
if (! $group_settings) {
if ($group_settings->count() == 0) {
return response()->json(['message' => ctrans('texts.no_group_settings_found')]);
}
/** @var \App\Models\User $user */
$user = auth()->user();
/*
* Send the other actions to the switch
*/
$group_settings->each(function ($group, $key) use ($action) {
if (auth()->user()->can('edit', $group)) {
$group_settings->cursor()->each(function ($group, $key) use ($action, $user) {
if ($user->can('edit', $group)) {
$this->group_setting_repo->{$action}($group);
}
});
@ -499,48 +209,6 @@ class GroupSettingController extends BaseController
* @param GroupSetting $group_setting
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/group_settings/{id}/upload",
* operationId="uploadGroupSetting",
* tags={"group_settings"},
* summary="Uploads a document to a group setting",
* description="Handles the uploading of a document to a group setting",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Group Setting Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the Group Setting object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/Invoice"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadGroupSettingRequest $request, GroupSetting $group_setting)
{

View File

@ -237,7 +237,7 @@ class PreviewController extends BaseController
$html = new HtmlEngine($entity_obj->invitations()->first());
$design = \App\Models\Design::find($entity_obj->design_id);
$design = \App\Models\Design::withTrashed()->find($entity_obj->design_id);
/* Catch all in case migration doesn't pass back a valid design */
if (! $design) {

View File

@ -196,7 +196,7 @@ class PreviewPurchaseOrderController extends BaseController
$html = new VendorHtmlEngine($entity_obj->invitations()->first());
$design = \App\Models\Design::find($entity_obj->design_id);
$design = \App\Models\Design::withTrashed()->find($entity_obj->design_id);
/* Catch all in case migration doesn't pass back a valid design */
if (!$design) {

View File

@ -69,37 +69,6 @@ class UserController extends BaseController
* @param UserFilters $filters
* @return Response
*
*
* @OA\Get(
* path="/api/v1/users",
* operationId="getUsers",
* tags={"users"},
* summary="Gets a list of users",
* description="Lists users, search and filters allow fine grained lists to be generated.
*
*Query parameters can be added to performed more fine grained filtering of the users, these are handled by the UserFilters class which defines the methods available",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Response(
* response=200,
* description="A list of users",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/User"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function index(UserFilters $filters)
{
@ -114,37 +83,6 @@ class UserController extends BaseController
* @param CreateUserRequest $request
* @return Response
*
*
*
* @OA\Get(
* path="/api/v1/users/create",
* operationId="getUsersCreate",
* tags={"users"},
* summary="Gets a new blank User object",
* description="Returns a blank object with default values",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Response(
* response=200,
* description="A blank User object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/User"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function create(CreateUserRequest $request)
{
@ -159,41 +97,13 @@ class UserController extends BaseController
* @param StoreUserRequest $request
* @return Response
*
*
*
* @OA\Post(
* path="/api/v1/users",
* operationId="storeUser",
* tags={"users"},
* summary="Adds a User",
* description="Adds an User to the system",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Response(
* response=200,
* description="Returns the saved User object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/User"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function store(StoreUserRequest $request)
{
$company = auth()->user()->company();
/** @var \App\Models\User $logged_in_user */
$logged_in_user = auth()->user();
$company = $logged_in_user->company();
$user = $this->user_repo->save($request->all(), $request->fetchUser());
@ -216,47 +126,6 @@ class UserController extends BaseController
* @param User $user
* @return Response
*
*
* @OA\Get(
* path="/api/v1/users/{id}",
* operationId="showUser",
* tags={"users"},
* summary="Shows an User",
* description="Displays an User by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The User Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the User object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/User"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function show(ShowUserRequest $request, User $user)
{
@ -270,47 +139,6 @@ class UserController extends BaseController
* @param User $user
* @return Response
*
*
* @OA\Get(
* path="/api/v1/users/{id}/edit",
* operationId="editUser",
* tags={"users"},
* summary="Shows an User for editting",
* description="Displays an User by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The User Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the User object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/User"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function edit(EditUserRequest $request, User $user)
{
@ -320,53 +148,16 @@ class UserController extends BaseController
/**
* Update the specified resource in storage.
*
* @OA\Put(
* path="/api/v1/users/{id}",
* operationId="updateUser",
* tags={"users"},
* summary="Updates an User",
* description="Handles the updating of an User by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The User Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the User object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/User"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
* @param UpdateUserRequest $request
* @param User $user
* @return Response|mixed
*/
public function update(UpdateUserRequest $request, User $user)
{
$old_company_user = $user->company_users()->where('company_id', auth()->user()->company()->id)->first();
/** @var \App\Models\User $logged_in_user */
$logged_in_user = auth()->user();
$old_company_user = $user->company_users()->where('company_id', $logged_in_user->company()->id)->first();
$old_user = json_encode($user);
$old_user_email = $user->getOriginal('email');
@ -384,10 +175,10 @@ class UserController extends BaseController
$user->oauth_user_refresh_token = null;
$user->oauth_user_token = null;
$user->save();
UserEmailChanged::dispatch($new_user, json_decode($old_user), auth()->user()->company());
UserEmailChanged::dispatch($new_user, json_decode($old_user), $logged_in_user->company());
}
event(new UserWasUpdated($user, auth()->user(), auth()->user()->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
event(new UserWasUpdated($user, $logged_in_user, $logged_in_user->company(), Ninja::eventVars($logged_in_user->id)));
return $this->itemResponse($user);
}
@ -397,59 +188,8 @@ class UserController extends BaseController
*
* @param DestroyUserRequest $request
* @param User $user
* @return Response
* @return JsonResponse | Response
*
*
* @OA\Delete(
* path="/api/v1/users/{id}",
* operationId="deleteUser",
* tags={"users"},
* summary="Deletes a User",
* description="Handles the deletion of an User by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="token_name",
* in="query",
* required=false,
* description="Customized name for the Users API Token",
* example="iOS Device 11 iPad",
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Parameter(
* name="id",
* in="path",
* description="The User Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns a HTTP status",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function destroy(DestroyUserRequest $request, User $user)
{
@ -460,7 +200,10 @@ class UserController extends BaseController
/* If the user passes the company user we archive the company user */
$user = $this->user_repo->delete($request->all(), $user);
event(new UserWasDeleted($user, auth()->user(), auth()->user()->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
/** @var \App\Models\User $logged_in_user */
$logged_in_user = auth()->user();
event(new UserWasDeleted($user, $logged_in_user, $logged_in_user->company(), Ninja::eventVars($logged_in_user->id)));
return $this->itemResponse($user->fresh());
}
@ -468,54 +211,8 @@ class UserController extends BaseController
/**
* Perform bulk actions on the list view.
*
* @return Collection
* @return Response
*
*
*
* @OA\Post(
* path="/api/v1/users/bulk",
* operationId="bulkUsers",
* tags={"users"},
* summary="Performs bulk actions on an array of users",
* description="",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/index"),
* @OA\RequestBody(
* description="Hashed ids",
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="array",
* @OA\Items(
* type="integer",
* description="Array of hashed IDs to be bulk 'actioned",
* example="[0,1,2,3]",
* ),
* )
* )
* ),
* @OA\Response(
* response=200,
* description="The User response",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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/User"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function bulk(BulkUserRequest $request)
{
@ -548,45 +245,6 @@ class UserController extends BaseController
/**
* Detach an existing user to a company.
*
* @OA\Delete(
* path="/api/v1/users/{user}/detach_from_company",
* operationId="detachUser",
* tags={"users"},
* summary="Detach an existing user to a company",
* description="Detach an existing user from a company",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="user",
* in="path",
* description="The user hashed_id",
* example="FD767dfd7",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Success response",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
* @param DetachCompanyUserRequest $request
* @param User $user
* @return \Illuminate\Http\JsonResponse
@ -622,52 +280,16 @@ class UserController extends BaseController
/**
* Invite an existing user to a company.
*
* @OA\Post(
* path="/api/v1/users/{user}/invite",
* operationId="inviteUser",
* tags={"users"},
* summary="Reconfirm an existing user to a company",
* description="Reconfirm an existing user from a company",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="user",
* in="path",
* description="The user hashed_id",
* example="FD767dfd7",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Success response",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
* @param ReconfirmUserRequest $request
* @param User $user
* @return \Illuminate\Http\JsonResponse
*/
public function invite(ReconfirmUserRequest $request, User $user)
{
$user->service()->invite($user->company());
/** @var \App\Models\User $logged_in_user */
$logged_in_user = auth()->user();
$user->service()->invite($logged_in_user->company());
return response()->json(['message' => ctrans('texts.confirmation_resent')], 200);
}
@ -676,52 +298,16 @@ class UserController extends BaseController
/**
* Invite an existing user to a company.
*
* @OA\Post(
* path="/api/v1/users/{user}/reconfirm",
* operationId="inviteUserReconfirm",
* tags={"users"},
* summary="Reconfirm an existing user to a company",
* description="Reconfirm an existing user from a company",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="user",
* in="path",
* description="The user hashed_id",
* example="FD767dfd7",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Success response",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-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\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
* @param ReconfirmUserRequest $request
* @param User $user
* @return \Illuminate\Http\JsonResponse
*/
public function reconfirm(ReconfirmUserRequest $request, User $user)
{
$user->service()->invite($user->company());
/** @var \App\Models\User $logged_in_user */
$logged_in_user = auth()->user();
$user->service()->invite($logged_in_user->company());
return response()->json(['message' => ctrans('texts.confirmation_resent')], 200);
}
@ -733,6 +319,18 @@ class UserController extends BaseController
$user->oauth_user_refresh_token = null;
$user->save();
/** @var \App\Models\User $logged_in_user */
$logged_in_user = auth()->user();
$company = $logged_in_user->company();
$settings = $company->settings;
$settings->email_sending_method = "default";
$settings->gmail_sending_user_id = "0";
$company->settings = $settings;
$company->save();
return $this->itemResponse($user->fresh());
}

View File

@ -400,7 +400,6 @@ class BillingPortalPurchase extends Component
$context = 'purchase';
// if(Ninja::isHosted() && $this->subscription->service()->recurring_products()->first()?->id == SubscriptionService::WHITE_LABEL) {
if (Ninja::isHosted() && $this->subscription->service()->recurring_products()->first()?->product_key == 'whitelabel') {
$context = 'whitelabel';
}
@ -444,13 +443,13 @@ class BillingPortalPurchase extends Component
return;
}
return $this->subscription->service()->handleNoPaymentRequired([
'email' => $this->email ?? $this->contact->email,
'quantity' => $this->quantity,
'contact_id' => $this->contact->id,
'client_id' => $this->contact->client->id,
'coupon' => $this->coupon,
'campaign' => $this->campaign,
]);
}

View File

@ -19,6 +19,7 @@ use App\Models\Invoice;
use League\Csv\Statement;
use App\Factory\QuoteFactory;
use App\Factory\ClientFactory;
use Illuminate\Support\Carbon;
use App\Factory\InvoiceFactory;
use App\Factory\PaymentFactory;
use App\Import\ImportException;
@ -495,7 +496,8 @@ class BaseImport
/* Make sure we don't apply any payments to invoices with a Zero Amount*/
if ($invoice->amount > 0) {
$payment_repository->save(
$payment = $payment_repository->save(
$payment_data,
PaymentFactory::create(
$this->company->id,
@ -503,6 +505,16 @@ class BaseImport
$invoice->client_id
)
);
$payment_date = Carbon::parse($payment->date);
if(!$payment_date->isToday())
{
$payment->paymentables()->update(['created_at' => $payment_date]);
}
}
}
}

View File

@ -47,9 +47,9 @@ class CreateAccount
public function handle()
{
if (config('ninja.environment') == 'selfhost' && Account::all()->count() == 0) {
if (config('ninja.environment') == 'selfhost' && Account::count() == 0) {
return $this->create();
} elseif (config('ninja.environment') == 'selfhost' && Account::all()->count() > 1) {
} elseif (config('ninja.environment') == 'selfhost' && Account::count() > 1) {
return response()->json(['message' => Ninja::selfHostedMessage()], 400);
} elseif (! Ninja::boot()) {
return response()->json(['message' => Ninja::parse()], 401);

View File

@ -135,7 +135,7 @@ class CreateEntityPdf implements ShouldQueue
$entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->client->getSetting($entity_design_id));
$design = Design::find($entity_design_id);
$design = Design::withTrashed()->find($entity_design_id);
/* Catch all in case migration doesn't pass back a valid design */
if (! $design) {

View File

@ -122,7 +122,7 @@ class CreateRawPdf implements ShouldQueue
$entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->entity->client->getSetting($entity_design_id));
$design = Design::find($entity_design_id);
$design = Design::withTrashed()->find($entity_design_id);
/* Catch all in case migration doesn't pass back a valid design */
if (! $design) {

View File

@ -120,7 +120,7 @@ class CreatePurchaseOrderPdf implements ShouldQueue
$entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey('Wpmbk5ezJn');
$design = Design::find($entity_design_id);
$design = Design::withTrashed()->find($entity_design_id);
/* Catch all in case migration doesn't pass back a valid design */
if (!$design) {

View File

@ -56,7 +56,7 @@ class MultiDB
public static function checkDomainAvailable($subdomain) : bool
{
if (! config('ninja.db.multi_db_enabled')) {
return Company::whereSubdomain($subdomain)->get()->count() == 0;
return Company::whereSubdomain($subdomain)->count() == 0;
}
$current_db = config('database.default');
@ -105,7 +105,7 @@ class MultiDB
* a new user request.
*
* @param string $email The user email
* @param stirng $company_key The company key
* @param string $company_key The company key
* @return bool True|False
*/
public static function checkUserAndCompanyCoExist($email, $company_key) :bool
@ -156,8 +156,8 @@ class MultiDB
}
/**
* @param array $data
* @return User|null
* @param string $email
* @return ClientContact|null
*/
public static function hasContact(string $email) : ?ClientContact
{
@ -183,8 +183,8 @@ class MultiDB
}
/**
* @param array $data
* @return User|null
* @param array $search
* @return ClientContact|null
*/
public static function findContact(array $search) : ?ClientContact
{
@ -456,8 +456,8 @@ class MultiDB
}
/**
* @param array $data
* @return User|null
* @param string $phone
* @return bool
*/
public static function hasPhoneNumber(string $phone) : bool
{
@ -482,7 +482,7 @@ class MultiDB
public static function randomSubdomainGenerator()
public static function randomSubdomainGenerator(): string
{
$current_db = config('database.default');
@ -509,6 +509,7 @@ class MultiDB
/**
* @param $database
* @return void
*/
public static function setDB(string $database) : void
{

View File

@ -68,7 +68,7 @@ use Laracasts\Presenter\PresentableTrait;
* @property int $is_verified_account
* @property string|null $account_sms_verification_code
* @property string|null $account_sms_verification_number
* @property int $account_sms_verified
* @property bool $account_sms_verified
* @property string|null $bank_integration_account_id
* @property int $is_trial
* @property-read int|null $bank_integrations_count
@ -128,6 +128,7 @@ use Laracasts\Presenter\PresentableTrait;
* @method static \Illuminate\Database\Eloquent\Builder|Account whereUtmTerm($value)
* @method static \Illuminate\Database\Eloquent\Builder|Account first()
* @method static \Illuminate\Database\Eloquent\Builder|Account with()
* @method static \Illuminate\Database\Eloquent\Builder|Account count()
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankIntegration> $bank_integrations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Company> $companies
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyUser> $company_users

View File

@ -65,26 +65,26 @@ use Laracasts\Presenter\PresentableTrait;
* @property bool $is_large
* @property int $enable_shop_api
* @property string $default_auto_bill
* @property int $mark_expenses_invoiceable
* @property int $mark_expenses_paid
* @property int $invoice_expense_documents
* @property int $auto_start_tasks
* @property int $invoice_task_timelog
* @property int $invoice_task_documents
* @property int $show_tasks_table
* @property int $is_disabled
* @property int $default_task_is_date_based
* @property int $enable_product_discount
* @property int $calculate_expense_tax_by_amount
* @property int $expense_inclusive_taxes
* @property bool $mark_expenses_invoiceable
* @property bool $mark_expenses_paid
* @property bool $invoice_expense_documents
* @property bool $auto_start_tasks
* @property bool $invoice_task_timelog
* @property bool $invoice_task_documents
* @property bool $show_tasks_table
* @property bool $is_disabled
* @property bool $default_task_is_date_based
* @property bool $enable_product_discount
* @property bool $calculate_expense_tax_by_amount
* @property bool $expense_inclusive_taxes
* @property int $session_timeout
* @property int $oauth_password_required
* @property bool $oauth_password_required
* @property int $invoice_task_datelog
* @property int $default_password_timeout
* @property int $show_task_end_date
* @property int $markdown_enabled
* @property int $use_comma_as_decimal_place
* @property int $report_include_drafts
* @property bool $show_task_end_date
* @property bool $markdown_enabled
* @property bool $use_comma_as_decimal_place
* @property bool $report_include_drafts
* @property array|null $client_registration_fields
* @property bool $convert_rate_to_client
* @property bool $markdown_email_enabled

View File

@ -11,10 +11,11 @@
namespace App\Models;
use App\Models\Filterable;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
/**
* App\Models\GroupSetting
@ -61,7 +62,8 @@ class GroupSetting extends StaticModel
{
use MakesHash;
use SoftDeletes;
use Filterable;
protected $casts = [
'settings' => 'object',
'updated_at' => 'timestamp',

View File

@ -11,24 +11,24 @@
namespace App\Models;
use App\Events\Invoice\InvoiceReminderWasEmailed;
use App\Events\Invoice\InvoiceWasEmailed;
use App\Helpers\Invoice\InvoiceSum;
use App\Helpers\Invoice\InvoiceSumInclusive;
use App\Jobs\Entity\CreateEntityPdf;
use App\Models\Presenters\InvoicePresenter;
use App\Services\Invoice\InvoiceService;
use App\Services\Ledger\LedgerService;
use App\Utils\Ninja;
use App\Utils\Traits\Invoice\ActionsInvoice;
use Illuminate\Support\Carbon;
use App\Utils\Traits\MakesDates;
use App\Utils\Traits\MakesInvoiceValues;
use App\Helpers\Invoice\InvoiceSum;
use App\Jobs\Entity\CreateEntityPdf;
use App\Utils\Traits\MakesReminders;
use App\Utils\Traits\NumberFormatter;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use App\Services\Ledger\LedgerService;
use Illuminate\Support\Facades\Storage;
use App\Services\Invoice\InvoiceService;
use App\Utils\Traits\MakesInvoiceValues;
use App\Events\Invoice\InvoiceWasEmailed;
use Laracasts\Presenter\PresentableTrait;
use App\Models\Presenters\InvoicePresenter;
use App\Helpers\Invoice\InvoiceSumInclusive;
use App\Utils\Traits\Invoice\ActionsInvoice;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Events\Invoice\InvoiceReminderWasEmailed;
/**
* App\Models\Invoice

View File

@ -381,7 +381,6 @@ class BaseDriver extends AbstractPaymentDriver
* When a successful payment is made, we need to append the gateway fee
* to an invoice.
*
* @param PaymentResponseRequest $request The incoming payment request
* @return void Success/Failure
*/
public function confirmGatewayFee() :void
@ -395,7 +394,7 @@ class BaseDriver extends AbstractPaymentDriver
/*Hydrate invoices*/
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payment_invoices, 'invoice_id')))->withTrashed()->get();
$invoices->each(function ($invoice) use ($fee_total) {
$invoices->each(function ($invoice) {
if (collect($invoice->line_items)->contains('type_id', '3')) {
$invoice->service()->toggleFeesPaid()->save();
}
@ -421,7 +420,6 @@ class BaseDriver extends AbstractPaymentDriver
/**
* Return the contact if possible.
*
* @return ClientContact The ClientContact object
*/
public function getContact()
{

View File

@ -128,7 +128,7 @@ class ActivityRepository extends BaseRepository
$entity_design_id = $entity->design_id ? $entity->design_id : $this->decodePrimaryKey($entity->client->getSetting($entity_design_id));
$design = Design::find($entity_design_id);
$design = Design::withTrashed()->find($entity_design_id);
if (! $entity->invitations()->exists() || ! $design) {
nlog("No invitations for entity {$entity->id} - {$entity->number}");

View File

@ -23,6 +23,33 @@ class DesignRepository extends BaseRepository
{
$design->name = $design->name.'_deleted_'.Str::random(5);
/** Make sure this design was not a default design - if it is, set the Clean template as the default */
/** @var \App\Models\User $user */
$user = auth()->user();
$company = $user->company();
$settings = $company->settings;
if ($settings->invoice_design_id == $design->hashed_id) {
$settings->invoice_design_id = 'Wpmbk5ezJn';
}
if ($settings->quote_design_id == $design->hashed_id) {
$settings->quote_design_id = 'Wpmbk5ezJn';
}
if ($settings->credit_design_id == $design->hashed_id) {
$settings->credit_design_id = 'Wpmbk5ezJn';
}
if ($settings->purchase_order_design_id == $design->hashed_id) {
$settings->purchase_order_design_id = 'Wpmbk5ezJn';
}
$company->settings = $settings;
$company->save();
parent::delete($design);
return $design;

View File

@ -201,7 +201,7 @@ class PaymentRepository extends BaseRepository
* the company currency, we need to set a record.
* @param $data
* @param $payment
* @return
* @return Payment $payment
*/
public function processExchangeRates($data, $payment)
{

View File

@ -411,6 +411,6 @@ class Statement
$id = (int) $this->client->getSetting('entity_design_id');
}
return Design::find($id);
return Design::withTrashed()->find($id);
}
}

View File

@ -104,16 +104,6 @@ class ApplyPayment extends AbstractService
$this->invoice->service()->applyNumber()->workFlow()->touchPdf()->save();
$transaction = [
'invoice' => $this->invoice->transaction_event(),
'payment' => $this->payment->transaction_event(),
'client' => $this->invoice->client->transaction_event(),
'credit' => [],
'metadata' => [],
];
// TransactionLog::dispatch(TransactionEvent::INVOICE_PAYMENT_APPLIED, $transaction, $this->invoice->company->db);
return $this->invoice;
}
}

View File

@ -66,7 +66,7 @@ class GenerateDeliveryNote
return (new Phantom)->generate($this->invoice->invitations->first());
}
$design = Design::find($design_id);
$design = Design::withTrashed()->find($design_id);
$html = new HtmlEngine($invitation);
if ($design->is_custom) {

View File

@ -272,7 +272,7 @@ class PdfConfiguration
{
$design_id = $this->entity->design_id ? : $this->decodePrimaryKey($this->settings_object->getSetting($this->entity_design_id));
$this->design = Design::find($design_id ?: 2);
$this->design = Design::withTrashed()->find($design_id ?: 2);
return $this;
}

View File

@ -64,7 +64,7 @@ class PdfMock
$pdf_config->setPdfVariables();
$pdf_config->setCurrency(Currency::find($this->settings->currency_id));
$pdf_config->setCountry(Country::find($this->settings->country_id ?: 840));
$pdf_config->design = Design::find($this->decodePrimaryKey($pdf_config->entity_design_id));
$pdf_config->design = Design::withTrashed()->find($this->decodePrimaryKey($pdf_config->entity_design_id));
$pdf_config->currency_entity = $this->mock->client;
$pdf_service->config = $pdf_config;

View File

@ -121,6 +121,10 @@ class SubscriptionService
'account_key' => $recurring_invoice->client->custom_value2,
];
if (property_exists($payment_hash->data->billing_context, 'campaign')) {
$context['campaign'] = $payment_hash->data->billing_context->campaign;
}
$response = $this->triggerWebhook($context);
return $this->handleRedirect('/client/recurring_invoices/'.$recurring_invoice->hashed_id);

View File

@ -22,12 +22,12 @@ class ZeroCostProduct extends AbstractService
private $data;
/**
$data = [
'email' => $this->email ?? $this->contact->email,
'quantity' => $this->quantity,
'contact_id' => $this->contact->id,
'client_id' => $this->contact->client->id,
];
* $data = [
* 'email' => $this->email ?? $this->contact->email,
* 'quantity' => $this->quantity,
* 'contact_id' => $this->contact->id,
* 'client_id' => $this->contact->client->id,
* ];
*/
public function __construct(Subscription $subscription, array $data)
{
@ -79,6 +79,9 @@ class ZeroCostProduct extends AbstractService
'redirect_url' => "/client/recurring_invoices/{$recurring_invoice->hashed_id}",
];
if(isset($this->data['campaign']))
$context['campaign'] = $this->data['campaign'];
return $context;
}

View File

@ -190,7 +190,7 @@ class Phantom
$design_id = $entity_obj->design_id ? $entity_obj->design_id : $this->decodePrimaryKey($entity_obj->client->getSetting($entity_design_id));
$design = Design::find($design_id);
$design = Design::withTrashed()->find($design_id);
$html = new HtmlEngine($invitation);
if ($design->is_custom) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,7 @@
name: X-API-PASSWORD
in: header
description: 'The login password when challenged on certain protected routes'
required: false
required: true
schema:
type: string
example: supersecretpassword

View File

@ -0,0 +1,6 @@
400:
description: 'Invalid user input'
content:
application/json:
schema:
$ref: '#components/schemas/InvalidInputError'

View File

@ -0,0 +1,6 @@
429:
description: 'Rate Limit Exceeded'
content:
application/json:
schema:
$ref: '#/components/schemas/RateLimiterError'

View File

@ -247,8 +247,34 @@
type: string
type: object
type: object
RateLimiterError:
properties:
message:
description: 'Rate limit exceeded.'
type: string
example: 'Rate limit exceeded.'
errors:
properties:
value:
type: array
items:
type: string
type: object
type: object
InvalidInputError:
properties:
message:
description: 'Invalid input'
type: string
example: 'Invalid input'
errors:
properties:
value:
type: array
items:
type: string
type: object
type: object
Webhook:
properties:
id:

View File

@ -4,18 +4,25 @@
description: 'The unique identifier of the client'
type: string
example: Opnel5aKBz
readOnly: true
contacts:
type: array
items:
$ref: '#/components/schemas/ClientContact'
user_id:
description: 'The unique identifier of the user who created the client'
type: string
example: Ua6Rw4pVbS
readOnly: true
assigned_user_id:
description: 'The unique identifier of the user who has been assigned the client'
type: string
example: Ua6Rw4pVbS
company_id:
description: 'The unique identifier of the company the client belongs to'
type: string
example: Co7Vn3yLmW
contacts:
type: array
items:
$ref: '#/components/schemas/ClientContact'
readOnly: true
name:
description: 'The name of the client company or organization'
type: string
@ -32,6 +39,7 @@
description: 'A unique hash value for the client'
type: string
example: asdfkjhk342hjhbfdvmnfb1
readOnly: true
industry_id:
description: 'The unique identifier of the industry the client operates in'
type: number
@ -125,36 +133,65 @@
description: 'A boolean value indicating whether the client has been deleted or not'
type: boolean
example: false
readOnly: true
balance:
description: 'The outstanding balance the client owes'
type: number
format: float
example: '500.00'
readOnly: true
paid_to_date:
description: 'The total amount the client has paid to date'
type: number
format: float
example: '2000.00'
readOnly: true
credit_balance:
description: 'The available credit balance for the client to use on future purchases'
type: number
format: float
example: '100.00'
readOnly: true
last_login:
description: "The timestamp of the client's last login"
type: number
format: integer
example: '1628686031'
readOnly: true
created_at:
description: 'The timestamp when the client was created'
type: number
format: integer
example: '1617629031'
readOnly: true
updated_at:
description: 'The timestamp when the client was last updated'
type: number
format: integer
example: '1628445631'
readOnly: true
group_settings_id:
description: 'The group settings assigned to the client'
type: string
example: Opnel5aKBz
routing_id:
description: 'The routing address id for e-invoicing for this client'
type: string
example: Opnel5aKBz3489-dfkiu-2239-sdsd
is_tax_exempt:
description: 'Flag which defines if the client is exempt from taxes'
type: boolean
example: false
has_valid_vat_number:
description: 'Flag which defines if the client has a valid VAT number'
type: boolean
example: false
readOnly: true
payment_balance:
description: 'Defines the payment balance the client has on file (pre payments / over payments / unapplied amounts)'
type: number
example: 100
readOnly: true
settings:
$ref: '#/components/schemas/CompanySettings'
$ref: '#/components/schemas/ClientSettings'
type: object

View File

@ -0,0 +1,48 @@
ClientContactRequest:
properties:
id:
description: 'The hashed if of the contact'
type: string
example: Opnel5aKBz
readOnly: true
first_name:
description: 'The first name of the contact'
type: string
example: John
last_name:
description: 'The last name of the contact'
type: string
example: Doe
phone:
description: 'The phone number of the contact'
type: string
example: 555-152-4524
custom_value1:
description: 'A Custom field value'
type: string
example: ''
custom_value2:
description: 'A Custom field value'
type: string
example: ''
custom_value3:
description: 'A Custom field value'
type: string
example: ''
custom_value4:
description: 'A Custom field value'
type: string
example: ''
email:
description: 'The email of the contact'
type: string
example: ''
password:
description: 'The hashed password of the contact'
type: string
example: '*****'
send_email:
description: 'Boolean value determines is this contact should receive emails'
type: boolean
example: true
type: object

View File

@ -0,0 +1,141 @@
ClientRequest:
required:
- contacts
- country_id
properties:
id:
description: 'The unique identifier of the client'
type: string
example: Opnel5aKBz
readOnly: true
contacts:
type: array
description: 'A list of contacts associated with the client'
items:
$ref: '#/components/schemas/ClientContactRequest'
name:
description: 'The name of the client company or organization'
type: string
example: "Jim's Housekeeping"
website:
description: 'The website URL of the client company or organization'
type: string
example: 'https://www.jims-housekeeping.com'
private_notes:
description: 'Notes that are only visible to the user who created the client'
type: string
example: 'Client prefers email communication over phone calls'
industry_id:
description: 'The unique identifier of the industry the client operates in'
type: number
example: '5'
size_id:
description: 'The unique identifier for the size category of the client company or organization'
type: number
example: '2'
address1:
description: "First line of the client's address"
type: string
example: '123 Main St'
address2:
description: "Second line of the client's address, if needed"
type: string
example: 'Apt 4B'
city:
description: 'The city the client is located in'
type: string
example: 'Beverly Hills'
state:
description: 'The state, province, or locality the client is located in'
type: string
example: 'California'
postal_code:
description: 'The postal code or ZIP code of the client'
type: string
example: '90210'
phone:
description: "The client's phone number"
type: string
example: '555-3434-3434'
country_id:
description: "The unique identifier of the client's country"
type: number
format: integer
example: '1'
custom_value1:
description: 'A custom field for storing additional information'
type: string
example: 'Preferred contact: Email'
custom_value2:
description: 'A custom field for storing additional information'
type: string
example: 'Account manager: John Doe'
custom_value3:
description: 'A custom field for storing additional information'
type: string
example: 'VIP client: Yes'
custom_value4:
description: 'A custom field for storing additional information'
type: string
example: 'Annual contract value: $50,000'
vat_number:
description: "The client's VAT (Value Added Tax) number, if applicable"
type: string
example: 'VAT123456'
id_number:
description: 'A unique identification number for the client, such as a tax ID or business registration number'
type: string
number:
description: 'A system-assigned unique number for the client, typically used for invoicing purposes'
type: string
example: 'CL-0001'
shipping_address1:
description: "First line of the client's shipping address"
type: string
example: '5 Wallaby Way'
shipping_address2:
description: "Second line of the client's shipping address, if needed"
type: string
example: 'Suite 5'
shipping_city:
description: "The city of the client's shipping address"
type: string
example: 'Perth'
shipping_state:
description: "The state, province, or locality of the client's shipping address"
type: string
example: 'Western Australia'
shipping_postal_code:
description: "The postal code or ZIP code of the client's shipping address"
type: string
example: '6110'
shipping_country_id:
description: "The unique identifier of the country for the client's shipping address"
type: number
format: integer
example: '4'
is_deleted:
description: 'A boolean value indicating whether the client has been deleted or not'
type: boolean
example: false
readOnly: true
group_settings_id:
description: 'The group settings assigned to the client'
type: string
example: Opnel5aKBz
routing_id:
description: 'The routing address id for e-invoicing for this client'
type: string
example: Opnel5aKBz3489-dfkiu-2239-sdsd
is_tax_exempt:
description: 'Flag which defines if the client is exempt from taxes'
type: boolean
example: false
has_valid_vat_number:
description: 'Flag which defines if the client has a valid VAT number'
type: boolean
example: false
readOnly: true
settings:
$ref: '#/components/schemas/ClientSettings'
type: object

View File

@ -0,0 +1,834 @@
ClientSettings:
required:
- currency_id
properties:
currency_id:
description: 'The default currency id'
type: string
example: true
timezone_id:
description: 'The timezone id'
type: string
example: '15'
date_format_id:
description: 'The date format id'
type: string
example: '15'
military_time:
description: 'Toggles 12/24 hour time'
type: boolean
example: true
language_id:
description: 'The language id'
type: string
example: '1'
show_currency_code:
description: 'Toggles whether the currency symbol or code is shown'
type: boolean
example: true
payment_terms:
description: '-1 sets no payment term, 0 sets payment due immediately, positive integers indicates payment terms in days'
type: integer
example: '1'
company_gateway_ids:
description: 'A commad separate list of available gateways'
type: string
example: '1,2,3,4'
custom_value1:
description: 'A Custom Label'
type: string
example: 'Custom Label'
custom_value2:
description: 'A Custom Label'
type: string
example: 'Custom Label'
custom_value3:
description: 'A Custom Label'
type: string
example: 'Custom Label'
custom_value4:
description: 'A Custom Label'
type: string
example: 'Custom Label'
default_task_rate:
description: 'The default task rate'
type: number
format: float
example: '10.00'
send_reminders:
description: 'Toggles whether reminders are sent'
type: boolean
example: true
enable_client_portal_tasks:
description: 'Show/hide the tasks panel in the client portal'
type: boolean
example: true
email_style:
description: 'options include plain,light,dark,custom'
type: string
example: light
reply_to_email:
description: 'The reply to email address'
type: string
example: email@gmail.com
bcc_email:
description: 'A comma separate list of BCC emails'
type: string
example: 'email@gmail.com, contact@gmail.com'
pdf_email_attachment:
description: 'Toggles whether to attach PDF as attachment'
type: boolean
example: true
ubl_email_attachment:
description: 'Toggles whether to attach UBL as attachment'
type: boolean
example: true
email_style_custom:
description: 'The custom template'
type: string
example: '<HTML></HTML>'
counter_number_applied:
description: 'enum when the invoice number counter is set, ie when_saved, when_sent, when_paid'
type: string
example: when_sent
quote_number_applied:
description: 'enum when the quote number counter is set, ie when_saved, when_sent'
type: string
example: when_sent
custom_message_dashboard:
description: 'A custom message which is displayed on the dashboard'
type: string
example: 'Please pay invoices immediately'
custom_message_unpaid_invoice:
description: 'A custom message which is displayed in the client portal when a client is viewing a unpaid invoice.'
type: string
example: 'Please pay invoices immediately'
custom_message_paid_invoice:
description: 'A custom message which is displayed in the client portal when a client is viewing a paid invoice.'
type: string
example: 'Thanks for paying this invoice!'
custom_message_unapproved_quote:
description: 'A custom message which is displayed in the client portal when a client is viewing a unapproved quote.'
type: string
example: 'Please approve quote'
lock_invoices:
description: 'Toggles whether invoices are locked once sent and cannot be modified further'
type: boolean
example: true
auto_archive_invoice:
description: 'Toggles whether a invoice is archived immediately following payment'
type: boolean
example: true
auto_archive_quote:
description: 'Toggles whether a quote is archived after being converted to a invoice'
type: boolean
example: true
auto_convert_quote:
description: 'Toggles whether a quote is converted to a invoice when approved'
type: boolean
example: true
inclusive_taxes:
description: 'Boolean flag determining whether inclusive or exclusive taxes are used'
type: boolean
example: true
task_number_pattern:
description: 'Allows customisation of the task number pattern'
type: string
example: '{$year}-{$counter}'
task_number_counter:
description: 'The incrementing counter for tasks'
type: integer
example: '1'
reminder_send_time:
description: 'Time from UTC +0 when the email will be sent to the client'
type: integer
example: '32400'
expense_number_pattern:
description: 'Allows customisation of the expense number pattern'
type: string
example: '{$year}-{$counter}'
expense_number_counter:
description: 'The incrementing counter for expenses'
type: integer
example: '1'
vendor_number_pattern:
description: 'Allows customisation of the vendor number pattern'
type: string
example: '{$year}-{$counter}'
vendor_number_counter:
description: 'The incrementing counter for vendors'
type: integer
example: '1'
ticket_number_pattern:
description: 'Allows customisation of the ticket number pattern'
type: string
example: '{$year}-{$counter}'
ticket_number_counter:
description: 'The incrementing counter for tickets'
type: integer
example: '1'
payment_number_pattern:
description: 'Allows customisation of the payment number pattern'
type: string
example: '{$year}-{$counter}'
payment_number_counter:
description: 'The incrementing counter for payments'
type: integer
example: '1'
invoice_number_pattern:
description: 'Allows customisation of the invoice number pattern'
type: string
example: '{$year}-{$counter}'
invoice_number_counter:
description: 'The incrementing counter for invoices'
type: integer
example: '1'
quote_number_pattern:
description: 'Allows customisation of the quote number pattern'
type: string
example: '{$year}-{$counter}'
quote_number_counter:
description: 'The incrementing counter for quotes'
type: integer
example: '1'
client_number_pattern:
description: 'Allows customisation of the client number pattern'
type: string
example: '{$year}-{$counter}'
client_number_counter:
description: 'The incrementing counter for clients'
type: integer
example: '1'
credit_number_pattern:
description: 'Allows customisation of the credit number pattern'
type: string
example: '{$year}-{$counter}'
credit_number_counter:
description: 'The incrementing counter for credits'
type: integer
example: '1'
recurring_invoice_number_prefix:
description: 'This string is prepended to the recurring invoice number'
type: string
example: R
reset_counter_frequency_id:
description: 'CONSTANT which is used to apply the frequency which the counters are reset'
type: integer
example: '1'
reset_counter_date:
description: 'The explicit date which is used to reset counters'
type: string
example: '2019-01-01'
counter_padding:
description: 'Pads the counter with leading zeros'
type: integer
example: '1'
shared_invoice_quote_counter:
description: 'Flags whether to share the counter for invoices and quotes'
type: boolean
example: true
update_products:
description: 'Determines if client fields are updated from third party APIs'
type: boolean
example: true
convert_products:
description: ''
type: boolean
example: true
fill_products:
description: 'Automatically fill products based on product_key'
type: boolean
example: true
invoice_terms:
description: 'The default invoice terms'
type: string
example: 'Invoice Terms are...'
quote_terms:
description: 'The default quote terms'
type: string
example: 'Quote Terms are...'
invoice_taxes:
description: 'Taxes can be applied to the invoice'
type: number
example: '1'
invoice_design_id:
description: 'The default design id (invoice, quote etc)'
type: string
example: '1'
quote_design_id:
description: 'The default design id (invoice, quote etc)'
type: string
example: '1'
invoice_footer:
description: 'The default invoice footer'
type: string
example: '1'
invoice_labels:
description: 'JSON string of invoice labels'
type: string
example: '1'
tax_rate1:
description: 'The tax rate (float)'
type: number
example: '10'
tax_name1:
description: 'The tax name'
type: string
example: GST
tax_rate2:
description: 'The tax rate (float)'
type: number
example: '10'
tax_name2:
description: 'The tax name'
type: string
example: GST
tax_rate3:
description: 'The tax rate (float)'
type: number
example: '10'
tax_name3:
description: 'The tax name'
type: string
example: GST
payment_type_id:
description: 'The default payment type id'
type: string
example: '1'
custom_fields:
description: 'JSON string of custom fields'
type: string
example: '{}'
email_footer:
description: 'The default email footer'
type: string
example: 'A default email footer'
email_sending_method:
description: 'The email driver to use to send email, options include default, gmail'
type: string
example: default
gmail_sending_user_id:
description: 'The hashed_id of the user account to send email from'
type: string
example: F76sd34D
email_subject_invoice:
description: ''
type: string
example: 'Your Invoice Subject'
email_subject_quote:
description: ''
type: string
example: 'Your Quote Subject'
email_subject_payment:
description: ''
type: string
example: 'Your Payment Subject'
email_template_invoice:
description: 'The full template for invoice emails'
type: string
example: '<HTML></HTML>'
email_template_quote:
description: 'The full template for quote emails'
type: string
example: '<HTML></HTML>'
email_template_payment:
description: 'The full template for payment emails'
type: string
example: '<HTML></HTML>'
email_subject_reminder1:
description: 'Email subject for Reminder'
type: string
example: '<HTML></HTML>'
email_subject_reminder2:
description: 'Email subject for Reminder'
type: string
example: '<HTML></HTML>'
email_subject_reminder3:
description: 'Email subject for Reminder'
type: string
example: '<HTML></HTML>'
email_subject_reminder_endless:
description: 'Email subject for endless reminders'
type: string
example: '<HTML></HTML>'
email_template_reminder1:
description: 'The full template for Reminder 1'
type: string
example: '<HTML></HTML>'
email_template_reminder2:
description: 'The full template for Reminder 2'
type: string
example: '<HTML></HTML>'
email_template_reminder3:
description: 'The full template for Reminder 3'
type: string
example: '<HTML></HTML>'
email_template_reminder_endless:
description: 'The full template for enless reminders'
type: string
example: '<HTML></HTML>'
enable_portal_password:
description: 'Toggles whether a password is required to log into the client portal'
type: boolean
example: true
show_accept_invoice_terms:
description: 'Toggles whether the terms dialogue is shown to the client'
type: boolean
example: true
show_accept_quote_terms:
description: 'Toggles whether the terms dialogue is shown to the client'
type: boolean
example: true
require_invoice_signature:
description: 'Toggles whether a invoice signature is required'
type: boolean
example: true
require_quote_signature:
description: 'Toggles whether a quote signature is required'
type: boolean
example: true
name:
description: 'The company name'
type: string
example: 'Acme Co'
company_logo:
description: 'The company logo file'
type: object
example: logo.png
website:
description: 'The company website URL'
type: string
example: www.acme.com
address1:
description: 'The company address line 1'
type: string
example: 'Suite 888'
address2:
description: 'The company address line 2'
type: string
example: '5 Jimbo Way'
city:
description: 'The company city'
type: string
example: Sydney
state:
description: 'The company state'
type: string
example: Florisa
postal_code:
description: 'The company zip/postal code'
type: string
example: '90210'
phone:
description: 'The company phone'
type: string
example: 555-213-3948
email:
description: 'The company email'
type: string
example: joe@acme.co
country_id:
description: 'The country ID'
type: string
example: '1'
vat_number:
description: 'The company VAT/TAX ID number'
type: string
example: '32 120 377 720'
page_size:
description: 'The default page size'
type: string
example: A4
font_size:
description: 'The font size'
type: number
example: '9'
primary_font:
description: 'The primary font'
type: string
example: roboto
secondary_font:
description: 'The secondary font'
type: string
example: roboto
hide_paid_to_date:
description: 'Flags whether to hide the paid to date field'
type: boolean
example: false
embed_documents:
description: 'Toggled whether to embed documents in the PDF'
type: boolean
example: false
all_pages_header:
description: 'The header for the PDF'
type: boolean
example: false
all_pages_footer:
description: 'The footer for the PDF'
type: boolean
example: false
document_email_attachment:
description: 'Toggles whether to attach documents in the email'
type: boolean
example: false
enable_client_portal_password:
description: 'Toggles password protection of the client portal'
type: boolean
example: false
enable_email_markup:
description: 'Toggles the use of markdown in emails'
type: boolean
example: false
enable_client_portal_dashboard:
description: 'Toggles whether the client dashboard is shown in the client portal'
type: boolean
example: false
enable_client_portal:
description: 'Toggles whether the entire client portal is displayed to the client, or only the context'
type: boolean
example: false
email_template_statement:
description: 'The body of the email for statements'
type: string
example: 'template matter'
email_subject_statement:
description: 'The subject of the email for statements'
type: string
example: 'subject matter'
signature_on_pdf:
description: 'Toggles whether the signature (if available) is displayed on the PDF'
type: boolean
example: false
quote_footer:
description: 'The default quote footer'
type: string
example: 'the quote footer'
email_subject_custom1:
description: 'Custom reminder template subject'
type: string
example: 'Custom Subject 1'
email_subject_custom2:
description: 'Custom reminder template subject'
type: string
example: 'Custom Subject 2'
email_subject_custom3:
description: 'Custom reminder template subject'
type: string
example: 'Custom Subject 3'
email_template_custom1:
description: 'Custom reminder template body'
type: string
example: '<HTML>'
email_template_custom2:
description: 'Custom reminder template body'
type: string
example: '<HTML>'
email_template_custom3:
description: 'Custom reminder template body'
type: string
example: '<HTML>'
enable_reminder1:
description: 'Toggles whether this reminder is enabled'
type: boolean
example: false
enable_reminder2:
description: 'Toggles whether this reminder is enabled'
type: boolean
example: false
enable_reminder3:
description: 'Toggles whether this reminder is enabled'
type: boolean
example: false
num_days_reminder1:
description: 'The Reminder interval'
type: number
example: '9'
num_days_reminder2:
description: 'The Reminder interval'
type: number
example: '9'
num_days_reminder3:
description: 'The Reminder interval'
type: number
example: '9'
schedule_reminder1:
description: '(enum: after_invoice_date, before_due_date, after_due_date)'
type: string
example: after_invoice_date
schedule_reminder2:
description: '(enum: after_invoice_date, before_due_date, after_due_date)'
type: string
example: after_invoice_date
schedule_reminder3:
description: '(enum: after_invoice_date, before_due_date, after_due_date)'
type: string
example: after_invoice_date
late_fee_amount1:
description: 'The late fee amount for reminder 1'
type: number
example: 10
late_fee_amount2:
description: 'The late fee amount for reminder 2'
type: number
example: 20
late_fee_amount3:
description: 'The late fee amount for reminder 2'
type: number
example: 100
endless_reminder_frequency_id:
description: 'The frequency id of the endless reminder'
type: string
example: '1'
client_online_payment_notification:
description: 'Determines if a client should receive the notification for a online payment'
type: boolean
example: false
client_manual_payment_notification:
description: 'Determines if a client should receive the notification for a manually entered payment'
type: boolean
example: false
enable_e_invoice:
description: 'Determines if e-invoicing is enabled'
type: boolean
example: false
default_expense_payment_type_id:
description: 'The default payment type for expenses'
type: string
example: '0'
e_invoice_type:
description: 'The e-invoice type'
type: string
example: 'EN16931'
mailgun_endpoint:
description: 'The mailgun endpoint - used to determine whether US or EU endpoints are used'
type: string
example: 'api.mailgun.net or api.eu.mailgun.net'
client_initiated_payments:
description: 'Determines if clients can initiate payments directly from the client portal'
type: boolean
example: false
client_initiated_payments_minimum:
description: 'The minimum amount a client can pay'
type: number
example: 10
sync_invoice_quote_columns:
description: 'Determines if invoice and quote columns are synced for the PDF rendering, or if they use their own columns'
type: boolean
example: false
show_task_item_description:
description: 'Determines if the task item description is shown on the invoice'
type: boolean
example: false
allow_billable_task_items:
description: 'Determines if task items can be marked as billable'
type: boolean
example: false
accept_client_input_quote_approval:
description: 'Determines if clients can approve quotes and also pass through a PO Number reference'
type: boolean
example: false
custom_sending_email:
description: 'When using Mailgun or Postmark, the FROM email address can be customized using this setting.'
type: string
example: 'bob@gmail.com'
show_paid_stamp:
description: 'Determines if the PAID stamp is shown on the invoice'
type: boolean
example: false
show_shipping_address:
description: 'Determines if the shipping address is shown on the invoice'
type: boolean
example: false
company_logo_size:
description: 'The size of the company logo on the PDF - percentage value between 0 and 100'
type: number
example: 100
show_email_footer:
description: 'Determines if the email footer is shown on emails'
type: boolean
example: false
email_alignment:
description: 'The alignment of the email body text, options include left / center / right'
type: string
example: 'left'
auto_bill_standard_invoices:
description: 'Determines if standard invoices are automatically billed when they are created or due'
type: boolean
example: false
postmark_secret:
description: 'The Postmark secret API key'
type: string
example: '123456'
mailgun_secret:
description: 'The Mailgun secret API key'
type: string
example: '123456'
mailgun_domain:
description: 'The Mailgun domain'
type: string
example: 'sandbox123456.mailgun.org'
send_email_on_mark_paid:
description: 'Determines if an email is sent when an invoice is marked as paid'
type: boolean
example: false
vendor_portal_enable_uploads:
description: 'Determines if vendors can upload files to the portal'
type: boolean
example: false
besr_id:
description: 'The BESR ID'
type: string
example: '123456'
qr_iban:
description: 'The IBAN for the QR code'
type: string
example: 'CH123456'
email_subject_purchase_order:
description: 'The email subject for purchase orders'
type: string
example: 'Purchase Order'
email_template_purchase_order:
description: 'The email template for purchase orders'
type: string
example: 'Please see attached your purchase order.'
require_purchase_order_signature:
description: 'Determines if a signature is required on purchase orders'
type: boolean
example: false
purchase_order_public_notes:
description: 'The public notes for purchase orders'
type: string
example: 'Please see attached your purchase order.'
purchase_order_terms:
description: 'The terms for purchase orders'
type: string
example: 'Please see attached your purchase order.'
purchase_order_footer:
description: 'The footer for purchase orders'
type: string
example: 'Please see attached your purchase order.'
purchase_order_design_id:
description: 'The design id for purchase orders'
type: string
example: 'hd677df'
purchase_order_number_pattern:
description: 'The pattern for purchase order numbers'
type: string
example: 'PO-000000'
purchase_order_number_counter:
description: 'The counter for purchase order numbers'
type: number
example: 1
page_numbering_alignment:
description: 'The alignment for page numbering: options include left / center / right'
type: string
example: 'left'
page_numbering:
description: 'Determines if page numbering is enabled on Document PDFs'
type: boolean
example: false
auto_archive_invoice_cancelled:
description: 'Determines if invoices are automatically archived when they are cancelled'
type: boolean
example: false
email_from_name:
description: 'The FROM name for emails when using Custom emailers'
type: string
example: 'Bob Smith'
show_all_tasks_client_portal:
description: 'Determines if all tasks are shown on the client portal'
type: boolean
example: false
entity_send_time:
description: 'The time that emails are sent. The time is localized to the clients locale, integer values from 1 - 24'
type: integer
example: 9
shared_invoice_credit_counter:
description: 'Determines if the invoice and credit counter are shared'
type: boolean
example: false
reply_to_name:
description: 'The reply to name for emails'
type: string
example: 'Bob Smith'
hide_empty_columns_on_pdf:
description: 'Determines if empty columns are hidden on PDFs'
type: boolean
example: false
enable_reminder_endless:
description: 'Determines if endless reminders are enabled'
type: boolean
example: false
use_credits_payment:
description: 'Determines if credits can be used as a payment method'
type: boolean
example: false
recurring_invoice_number_pattern:
description: 'The pattern for recurring invoice numbers'
type: string
example: 'R-000000'
recurring_invoice_number_counter:
description: 'The counter for recurring invoice numbers'
type: number
example: 1
client_portal_under_payment_minimum:
description: 'The minimum payment payment'
type: number
example: 10
auto_bill_date:
description: 'Determines when the invoices are auto billed, options are on_send_date (when the invoice is sent) or on_due_date (when the invoice is due))'
type: string
example: 'on_send_date'
primary_color:
description: 'The primary color for the client portal / document highlights'
type: string
example: '#ffffff'
secondary_color:
description: 'The secondary color for the client portal / document highlights'
type: string
example: '#ffffff'
client_portal_allow_under_payment:
description: 'Determines if clients can pay invoices under the invoice amount due'
type: boolean
example: false
client_portal_allow_over_payment:
description: 'Determines if clients can pay invoices over the invoice amount'
type: boolean
example: false
auto_bill:
description: 'Determines how autobilling is applied for recurring invoices. off (no auto billed), always (always auto bill), optin (The user must opt in to auto billing), optout (The user must opt out of auto billing'
type: string
example: 'off'
client_portal_terms:
description: 'The terms which are displayed on the client portal'
type: string
example: 'Please see attached your invoice.'
client_portal_privacy_policy:
description: 'The privacy policy which is displayed on the client portal'
type: string
example: 'These are the terms of use for using the client portal.'
client_can_register:
description: 'Determines if clients can register on the client portal'
type: boolean
example: false
portal_design_id:
description: 'The design id for the client portal'
type: string
example: 'hd677df'
late_fee_endless_percent:
description: 'The late fee percentage for endless late fees'
type: number
example: 10
late_fee_endless_amount:
description: 'The late fee amount for endless late fees'
type: number
example: 10
auto_email_invoice:
description: 'Determines if invoices are automatically emailed when they are created'
type: boolean
example: false
email_signature:
description: 'The email signature for emails'
type: string
example: 'Bob Smith'
type: object

View File

@ -1,5 +1,11 @@
CompanySettings:
required:
- currency_id
properties:
currency_id:
description: 'The default currency id'
type: string
example: true
timezone_id:
description: 'The timezone id'
type: string
@ -20,10 +26,6 @@
description: 'Toggles whether the currency symbol or code is shown'
type: boolean
example: true
currency_id:
description: 'The default currency id'
type: string
example: true
payment_terms:
description: '-1 sets no payment term, 0 sets payment due immediately, positive integers indicates payment terms in days'
type: integer
@ -306,7 +308,7 @@
type: string
example: 'A default email footer'
email_sending_method:
description: 'The email driver to use to send email, options include default, gmail'
description: 'The email driver to use to send email, options include default, gmail, client_postmark, client_mailgun, office365'
type: string
example: default
gmail_sending_user_id:
@ -589,4 +591,248 @@
description: 'Determines if a client should receive the notification for a manually entered payment'
type: boolean
example: false
enable_e_invoice:
description: 'Determines if e-invoicing is enabled'
type: boolean
example: false
default_expense_payment_type_id:
description: 'The default payment type for expenses'
type: string
example: '0'
e_invoice_type:
description: 'The e-invoice type'
type: string
example: 'EN16931'
mailgun_endpoint:
description: 'The mailgun endpoint - used to determine whether US or EU endpoints are used'
type: string
example: 'api.mailgun.net or api.eu.mailgun.net'
client_initiated_payments:
description: 'Determines if clients can initiate payments directly from the client portal'
type: boolean
example: false
client_initiated_payments_minimum:
description: 'The minimum amount a client can pay'
type: number
example: 10
sync_invoice_quote_columns:
description: 'Determines if invoice and quote columns are synced for the PDF rendering, or if they use their own columns'
type: boolean
example: false
show_task_item_description:
description: 'Determines if the task item description is shown on the invoice'
type: boolean
example: false
allow_billable_task_items:
description: 'Determines if task items can be marked as billable'
type: boolean
example: false
accept_client_input_quote_approval:
description: 'Determines if clients can approve quotes and also pass through a PO Number reference'
type: boolean
example: false
custom_sending_email:
description: 'When using Mailgun or Postmark, the FROM email address can be customized using this setting.'
type: string
example: 'bob@gmail.com'
show_paid_stamp:
description: 'Determines if the PAID stamp is shown on the invoice'
type: boolean
example: false
show_shipping_address:
description: 'Determines if the shipping address is shown on the invoice'
type: boolean
example: false
company_logo_size:
description: 'The size of the company logo on the PDF - percentage value between 0 and 100'
type: number
example: 100
show_email_footer:
description: 'Determines if the email footer is shown on emails'
type: boolean
example: false
email_alignment:
description: 'The alignment of the email body text, options include left / center / right'
type: string
example: 'left'
auto_bill_standard_invoices:
description: 'Determines if standard invoices are automatically billed when they are created or due'
type: boolean
example: false
postmark_secret:
description: 'The Postmark secret API key'
type: string
example: '123456'
mailgun_secret:
description: 'The Mailgun secret API key'
type: string
example: '123456'
mailgun_domain:
description: 'The Mailgun domain'
type: string
example: 'sandbox123456.mailgun.org'
send_email_on_mark_paid:
description: 'Determines if an email is sent when an invoice is marked as paid'
type: boolean
example: false
vendor_portal_enable_uploads:
description: 'Determines if vendors can upload files to the portal'
type: boolean
example: false
besr_id:
description: 'The BESR ID'
type: string
example: '123456'
qr_iban:
description: 'The IBAN for the QR code'
type: string
example: 'CH123456'
email_subject_purchase_order:
description: 'The email subject for purchase orders'
type: string
example: 'Purchase Order'
email_template_purchase_order:
description: 'The email template for purchase orders'
type: string
example: 'Please see attached your purchase order.'
require_purchase_order_signature:
description: 'Determines if a signature is required on purchase orders'
type: boolean
example: false
purchase_order_public_notes:
description: 'The public notes for purchase orders'
type: string
example: 'Please see attached your purchase order.'
purchase_order_terms:
description: 'The terms for purchase orders'
type: string
example: 'Please see attached your purchase order.'
purchase_order_footer:
description: 'The footer for purchase orders'
type: string
example: 'Please see attached your purchase order.'
purchase_order_design_id:
description: 'The design id for purchase orders'
type: string
example: 'hd677df'
purchase_order_number_pattern:
description: 'The pattern for purchase order numbers'
type: string
example: 'PO-000000'
purchase_order_number_counter:
description: 'The counter for purchase order numbers'
type: number
example: 1
page_numbering_alignment:
description: 'The alignment for page numbering: options include left / center / right'
type: string
example: 'left'
page_numbering:
description: 'Determines if page numbering is enabled on Document PDFs'
type: boolean
example: false
auto_archive_invoice_cancelled:
description: 'Determines if invoices are automatically archived when they are cancelled'
type: boolean
example: false
email_from_name:
description: 'The FROM name for emails when using Custom emailers'
type: string
example: 'Bob Smith'
show_all_tasks_client_portal:
description: 'Determines if all tasks are shown on the client portal'
type: boolean
example: false
entity_send_time:
description: 'The time that emails are sent. The time is localized to the clients locale, integer values from 1 - 24'
type: integer
example: 9
shared_invoice_credit_counter:
description: 'Determines if the invoice and credit counter are shared'
type: boolean
example: false
reply_to_name:
description: 'The reply to name for emails'
type: string
example: 'Bob Smith'
hide_empty_columns_on_pdf:
description: 'Determines if empty columns are hidden on PDFs'
type: boolean
example: false
enable_reminder_endless:
description: 'Determines if endless reminders are enabled'
type: boolean
example: false
use_credits_payment:
description: 'Determines if credits can be used as a payment method'
type: boolean
example: false
recurring_invoice_number_pattern:
description: 'The pattern for recurring invoice numbers'
type: string
example: 'R-000000'
recurring_invoice_number_counter:
description: 'The counter for recurring invoice numbers'
type: number
example: 1
client_portal_under_payment_minimum:
description: 'The minimum payment payment'
type: number
example: 10
auto_bill_date:
description: 'Determines when the invoices are auto billed, options are on_send_date (when the invoice is sent) or on_due_date (when the invoice is due))'
type: string
example: 'on_send_date'
primary_color:
description: 'The primary color for the client portal / document highlights'
type: string
example: '#ffffff'
secondary_color:
description: 'The secondary color for the client portal / document highlights'
type: string
example: '#ffffff'
client_portal_allow_under_payment:
description: 'Determines if clients can pay invoices under the invoice amount due'
type: boolean
example: false
client_portal_allow_over_payment:
description: 'Determines if clients can pay invoices over the invoice amount'
type: boolean
example: false
auto_bill:
description: 'Determines how autobilling is applied for recurring invoices. off (no auto billed), always (always auto bill), optin (The user must opt in to auto billing), optout (The user must opt out of auto billing'
type: string
example: 'off'
client_portal_terms:
description: 'The terms which are displayed on the client portal'
type: string
example: 'Please see attached your invoice.'
client_portal_privacy_policy:
description: 'The privacy policy which is displayed on the client portal'
type: string
example: 'These are the terms of use for using the client portal.'
client_can_register:
description: 'Determines if clients can register on the client portal'
type: boolean
example: false
portal_design_id:
description: 'The design id for the client portal'
type: string
example: 'hd677df'
late_fee_endless_percent:
description: 'The late fee percentage for endless late fees'
type: number
example: 10
late_fee_endless_amount:
description: 'The late fee amount for endless late fees'
type: number
example: 10
auto_email_invoice:
description: 'Determines if invoices are automatically emailed when they are created'
type: boolean
example: false
email_signature:
description: 'The email signature for emails'
type: string
example: 'Bob Smith'
type: object

View File

@ -0,0 +1,15 @@
GenericBulkAction:
properties:
action:
type: string
example: archive
description: 'The action to perform ie. archive / restore / delete'
ids:
type: array
items:
format: string
type: string
example: 2J234DFA,D2J234DFA,D2J234DFA
description: string array of client hashed ids
type: object

View File

@ -5,14 +5,17 @@
type: string
description: 'The hashed product ID.'
example: eP01N
readOnly: true
company_id:
type: string
description: 'The hashed ID of the company that owns this product.'
example: eP01N
readOnly: true
user_id:
type: string
description: 'The hashed ID of the user that created this product.'
example: n30m4
readOnly: true
assigned_user_id:
type: string
description: 'The hashed ID of the user assigned to this product.'
@ -51,17 +54,17 @@
example: 'These are some notes about the product.'
cost:
type: number
format: float
format: double
description: 'The cost of the product.'
example: 10.0
price:
type: number
format: float
format: double
description: 'The price of the product.'
example: 20.0
quantity:
type: number
format: float
format: double
description: 'The quantity of the product.'
example: 5.0
tax_name1:
@ -70,7 +73,7 @@
example: 'Tax 1'
tax_rate1:
type: number
format: float
format: double
description: 'The rate of tax 1.'
example: 10.0
tax_name2:
@ -79,7 +82,7 @@
example: 'Tax 2'
tax_rate2:
type: number
format: float
format: double
description: 'The rate of tax 2.'
example: 5.0
tax_name3:
@ -88,7 +91,7 @@
example: 'Tax 3'
tax_rate3:
type: number
format: float
format: double
description: 'The rate of tax 3.'
example: 0.0
archived_at:
@ -96,43 +99,63 @@
format: timestamp
description: 'The timestamp when the product was archived.'
example: '2022-03-18T15:00:00Z'
readOnly: true
created_at:
type: integer
format: timestamp
description: 'The timestamp when the product was created.'
example: '2022-03-18T15:00:00Z'
readOnly: true
updated_at:
description: Timestamp
type: integer
format: timestamp
example: '2022-03-18T12:34:56.789Z'
readOnly: true
is_deleted:
type: boolean
description: 'Boolean flag determining if the product has been deleted'
example: false
readOnly: true
in_stock_quantity:
type: integer
format: int32
description: The quantity of the product that is currently in stock
default: 0
stock_notification:
type: boolean
description: Indicates whether stock notifications are enabled for this product
default: true
stock_notification_threshold:
type: integer
format: int32
description: The minimum quantity threshold for which stock notifications will be triggered
default: 0
max_quantity:
type: integer
format: int32
description: The maximum quantity that can be ordered for this product
product_image:
type: string
description: The URL of the product image
format: uri-reference
tax_id:
type: string
default: '1'
description: |
The tax category id for this product.'
The following constants are available (default = '1')
```
PRODUCT_TYPE_PHYSICAL = '1'
PRODUCT_TYPE_SERVICE = '2'
PRODUCT_TYPE_DIGITAL = '3'
PRODUCT_TYPE_SHIPPING = '4'
PRODUCT_TYPE_EXEMPT = '5'
PRODUCT_TYPE_REDUCED_TAX = '6'
PRODUCT_TYPE_OVERRIDE_TAX = '7'
PRODUCT_TYPE_ZERO_RATED = '8'
PRODUCT_TYPE_REVERSE_TAX = '9'
```
example: '1'

View File

@ -0,0 +1,37 @@
ProductBulkAction:
required:
- action
- ids
properties:
action:
type: string
example: archive
description: 'The action to perform ie. archive / restore / delete / set_tax_id'
ids:
type: array
items:
format: string
type: string
example: 2J234DFA,D2J234DFA,D2J234DFA
description: string array of client hashed ids
tax_id:
type: string
example: '1'
description: |
The tax rate id to set on the list of products
The following constants are available (default = '1')
```
PRODUCT_TYPE_PHYSICAL = '1'
PRODUCT_TYPE_SERVICE = '2'
PRODUCT_TYPE_DIGITAL = '3'
PRODUCT_TYPE_SHIPPING = '4'
PRODUCT_TYPE_EXEMPT = '5'
PRODUCT_TYPE_REDUCED_TAX = '6'
PRODUCT_TYPE_OVERRIDE_TAX = '7'
PRODUCT_TYPE_ZERO_RATED = '8'
PRODUCT_TYPE_REVERSE_TAX = '9'
```
type: object

View File

@ -0,0 +1,159 @@
ProductRequest:
type: object
properties:
id:
type: string
description: 'The hashed product ID.'
example: eP01N
readOnly: true
assigned_user_id:
type: string
description: 'The hashed ID of the user assigned to this product.'
example: pR0j3
required: false
project_id:
type: string
description: 'The hashed ID of the project that this product is associated with.'
example: pR0j3
required: false
vendor_id:
type: string
description: 'The hashed ID of the vendor that this product is associated with.'
example: pR0j3
required: false
custom_value1:
type: string
description: 'Custom value field 1.'
example: 'Custom value 1'
required: false
custom_value2:
type: string
description: 'Custom value field 2.'
example: 'Custom value 2'
required: false
custom_value3:
type: string
description: 'Custom value field 3.'
example: 'Custom value 3'
required: false
custom_value4:
type: string
description: 'Custom value field 4.'
example: 'Custom value 4'
required: false
product_key:
type: string
description: 'The product key.'
example: '1234'
required: false
notes:
type: string
description: 'Notes about the product.'
example: 'These are some notes about the product.'
required: false
cost:
type: number
format: double
description: 'The cost of the product.'
example: 10.0
required: false
price:
type: number
format: double
description: 'The price of the product.'
example: 20.0
required: false
quantity:
type: number
format: double
description: 'The quantity of the product.'
example: 5.0
required: false
default: 1
tax_name1:
type: string
description: 'The name of tax 1.'
example: 'Tax 1'
required: false
tax_rate1:
type: number
format: double
description: 'The rate of tax 1.'
example: 10.0
required: false
tax_name2:
type: string
description: 'The name of tax 2.'
example: 'Tax 2'
required: false
tax_rate2:
type: number
format: double
description: 'The rate of tax 2.'
example: 5.0
required: false
tax_name3:
type: string
description: 'The name of tax 3.'
example: 'Tax 3'
required: false
tax_rate3:
type: number
format: double
description: 'The rate of tax 3.'
example: 0.0
required: false
in_stock_quantity:
type: integer
format: int32
description: |
The quantity of the product that is currently in stock.
**note** this field is not mutable without passing an extra query parameter which will allow modification of this value.
The query parameter ?update_in_stock_quantity=true **MUST** be passed if you wish to update this value manually.
default: 0
required: false
stock_notification:
type: boolean
description: Indicates whether stock notifications are enabled for this product
default: true
required: false
stock_notification_threshold:
type: integer
format: int32
description: The minimum quantity threshold for which stock notifications will be triggered
default: 0
required: false
max_quantity:
type: integer
format: int32
description: The maximum quantity that can be ordered for this product
required: false
product_image:
type: string
description: The URL of the product image
format: uri-reference
required: false
tax_id:
type: string
default: '1'
required: false
description: |
The tax category id for this product.'
The following constants are available (default = '1')
```
PRODUCT_TYPE_PHYSICAL = '1'
PRODUCT_TYPE_SERVICE = '2'
PRODUCT_TYPE_DIGITAL = '3'
PRODUCT_TYPE_SHIPPING = '4'
PRODUCT_TYPE_EXEMPT = '5'
PRODUCT_TYPE_REDUCED_TAX = '6'
PRODUCT_TYPE_OVERRIDE_TAX = '7'
PRODUCT_TYPE_ZERO_RATED = '8'
PRODUCT_TYPE_REVERSE_TAX = '9'
```
example: '1'

View File

@ -128,6 +128,8 @@ paths:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
5XX:
$ref: "#/components/responses/5XX"
default:
$ref: "#/components/responses/default"
/api/v1/refresh:

View File

@ -4,7 +4,38 @@
- clients
summary: 'List clients'
description: |
Lists clients. Fine grained filtering is also available using query parameters.
When retrieving a list of clients you can also chain query parameters in order to filter the dataset that is returned. For example, you can send a request to the following URL to retrieve clients that have a balance greater than 1000:\
```
/api/v1/clients?balance=gt:1000
```
You can also sort the results by adding a sort parameter. The following example will sort the results by the client name in descending order:\
```
/api/v1/clients?sort=name|desc
```
You can also combine multiple filters together. The following example will return clients that have a balance greater than 1000 and are not deleted and have a name that starts with "Bob":\
```
/api/v1/clients?balance=gt:1000&name=Bob*
```
If you wish to retrieve child relations, you can also combine the query parameter `?include=` with a comma separated list of relationships:\
```
/api/v1/clients?include=activities,ledger,system_logs'
```
The per_page and page variables allow pagination of the list of clients. The following example will return the second page of clients with 15 clients per page:\
```
/api/v1/clients?per_page=15&page=2
```
The default per_page value is 20.
operationId: getClients
parameters:
- $ref: '#/components/parameters/X-API-TOKEN'
@ -94,18 +125,31 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
default:
$ref: '#/components/responses/default'
post:
tags:
- clients
summary: 'Create client'
description: 'Adds a client to a company'
description: |
Adds a client to a company
When creating (or updating) a client you must include the child contacts with all mutating requests. Client contacts cannot be modified in isolation.
operationId: storeClient
parameters:
- $ref: '#/components/parameters/X-API-TOKEN'
- $ref: '#/components/parameters/X-Requested-With'
- $ref: '#/components/parameters/client_include'
requestBody:
description: Client object that needs to be added to the company
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ClientRequest'
responses:
200:
description: 'Returns the saved client object'
@ -126,6 +170,8 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
default:
$ref: '#/components/responses/default'
'/api/v1/clients/{id}':
@ -167,6 +213,8 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
default:
$ref: '#/components/responses/default'
put:
@ -187,6 +235,13 @@
type: string
format: string
example: D2J234DFA
requestBody:
description: Client object that needs to be updated
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ClientRequest'
responses:
200:
description: 'Returns the client object'
@ -207,6 +262,8 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
default:
$ref: '#/components/responses/default'
delete:
@ -243,6 +300,8 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
default:
$ref: '#/components/responses/default'
'/api/v1/clients/{id}/edit':
@ -250,7 +309,7 @@
tags:
- clients
summary: 'Edit Client'
description: 'Displays a client by id'
description: 'Displays a client by id, essentially an alias of the show route'
operationId: editClient
parameters:
- $ref: '#/components/parameters/X-API-TOKEN'
@ -284,6 +343,8 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
default:
$ref: '#/components/responses/default'
/api/v1/clients/create:
@ -317,6 +378,8 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
default:
$ref: '#/components/responses/default'
/api/v1/clients/bulk:
@ -331,19 +394,16 @@
- $ref: '#/components/parameters/X-Requested-With'
- $ref: '#/components/parameters/index'
requestBody:
description: 'User credentials'
description: 'Bulk action array'
required: true
content:
application/json:
schema:
type: array
items:
description: 'Array of hashed IDs to be bulk ''actioned'
type: integer
example: '[0,1,2,3]'
$ref: '#/components/schemas/GenericBulkAction'
responses:
200:
description: 'The Client User response'
description: 'The Client listresponse'
headers:
X-MINIMUM-CLIENT-VERSION:
$ref: '#/components/headers/X-MINIMUM-CLIENT-VERSION'
@ -361,6 +421,8 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
default:
$ref: '#/components/responses/default'
'/api/v1/clients/{id}/upload':
@ -416,6 +478,8 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
default:
$ref: '#/components/responses/default'
'/api/v1/clients/{id}/purge':
@ -423,11 +487,17 @@
tags:
- clients
summary: 'Purge client'
description: 'Handles purging a client'
description: |
Handles purging a clients.
Please note this is a destructive action.
This action will remove all data associated with the client and cannot be undone.
operationId: purgeClient
parameters:
- $ref: '#/components/parameters/X-API-TOKEN'
- $ref: '#/components/parameters/X-Requested-With'
- $ref: '#/components/parameters/X-API-PASSWORD'
- $ref: '#/components/parameters/client_include'
- name: id
in: path
@ -453,6 +523,8 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
default:
$ref: '#/components/responses/default'
'/api/v1/clients/{id}/{mergeable_client_hashed_id}/merge':
@ -460,12 +532,18 @@
tags:
- clients
summary: 'Merge client'
description: 'Handles merging 2 clients'
description: |
Handles merging 2 clients
The id parameter is the client that will be the primary client after the merge has completed.
The mergeable_client_hashed_id is the client that will be merged into the primary client, this clients records will be updated and associated with the primary client.
operationId: mergeClient
parameters:
- $ref: '#/components/parameters/X-API-TOKEN'
- $ref: '#/components/parameters/X-Requested-With'
- $ref: '#/components/parameters/client_include'
- $ref: '#/components/parameters/X-API-PASSWORD'
- name: id
in: path
description: 'The Client Hashed ID'
@ -498,6 +576,8 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
default:
$ref: '#/components/responses/default'
/api/v1/client_statement:
@ -512,7 +592,7 @@
- $ref: '#/components/parameters/X-Requested-With'
- $ref: '#/components/parameters/include'
requestBody:
description: 'Statment Options'
description: 'Statement Options'
required: true
content:
application/json:
@ -530,6 +610,9 @@
show_payments_table:
description: 'Flag which determines if the payments table is shown'
type: boolean
show_credits_table:
description: 'Flag which determines if the credits table is shown'
type: boolean
show_aging_table:
description: 'Flag which determines if the aging table is shown'
type: boolean
@ -554,5 +637,9 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: '#/components/responses/default'

View File

@ -27,9 +27,12 @@
$ref: "#/components/responses/401"
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
post:
@ -62,7 +65,11 @@
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
@ -105,7 +112,11 @@
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
put:
@ -146,7 +157,11 @@
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
delete:
@ -183,7 +198,11 @@
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/credits/{id}/edit":
@ -225,7 +244,11 @@
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/credits/create:
@ -259,7 +282,11 @@
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/credits/bulk:
@ -282,8 +309,8 @@
type: array
items:
description: "Array of hashed IDs to be bulk 'actioned"
type: integer
example: "[0,1,2,3]"
type: string
example: '[D2J234DFA,D2J234DFA,D2J234DFA]'
responses:
200:
description: "The Bulk Action response"
@ -300,7 +327,11 @@
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/credit/{invitation_key}/download":
@ -338,7 +369,11 @@
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/credits/{id}/upload":
@ -379,6 +414,10 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"

View File

@ -113,7 +113,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
post:
@ -151,7 +155,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
@ -193,7 +201,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
@ -234,7 +246,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
delete:
@ -270,7 +286,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/invoices/{id}/edit":
@ -311,7 +331,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
@ -345,7 +369,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
@ -428,7 +456,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
@ -490,7 +522,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/invoice/{invitation_key}/download":
@ -527,7 +563,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/invoices/{id}/delivery_note":
@ -564,7 +604,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/invoices/{id}/upload":
@ -622,6 +666,10 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"

View File

@ -64,7 +64,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
post:
@ -103,7 +107,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
@ -145,7 +153,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
put:
@ -185,7 +197,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
delete:
@ -221,7 +237,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/payments/{id}/edit":
@ -262,7 +282,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/payments/create:
@ -295,7 +319,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/payments/refund:
@ -335,7 +363,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/payments/bulk:
@ -379,7 +411,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/payments/{id}/{action}":
@ -429,7 +465,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
@ -471,6 +511,10 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"

View File

@ -60,6 +60,10 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: '#/components/responses/default'
post:
@ -72,6 +76,13 @@
- $ref: "#/components/parameters/X-API-TOKEN"
- $ref: "#/components/parameters/X-Requested-With"
- $ref: "#/components/parameters/include"
requestBody:
description: Product object that needs to be added to the company
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProductRequest'
responses:
200:
description: "Returns the saved product object"
@ -92,6 +103,10 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: '#/components/responses/default'
"/api/v1/products/{id}":
@ -133,6 +148,10 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: '#/components/responses/default'
put:
@ -153,6 +172,13 @@
type: string
format: string
example: D2J234DFA
requestBody:
description: Product object that needs to be added to the company
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProductRequest'
responses:
200:
description: "Returns the Product object"
@ -173,6 +199,10 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: '#/components/responses/default'
delete:
@ -209,6 +239,10 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: '#/components/responses/default'
"/api/v1/products/{id}/edit":
@ -250,6 +284,10 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: '#/components/responses/default'
"/api/v1/products/create":
@ -283,6 +321,10 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: '#/components/responses/default'
@ -291,23 +333,19 @@
tags:
- products
summary: "Bulk product actions"
description: "Archive / Restore / Delete in bulk"
description: "Archive / Restore / Delete / Set tax id in bulk"
operationId: bulkProducts
parameters:
- $ref: "#/components/parameters/X-API-TOKEN"
- $ref: "#/components/parameters/X-Requested-With"
- $ref: "#/components/parameters/index"
requestBody:
description: "Hashed IDs"
description: 'Bulk action array'
required: true
content:
application/json:
schema:
type: array
items:
description: "Array of hashed IDs to be bulk 'actioned"
type: integer
example: "[0,1,2,3]"
$ref: '#/components/schemas/ProductBulkAction'
responses:
200:
description: "The Product response"
@ -328,6 +366,10 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: '#/components/responses/default'
@ -384,5 +426,9 @@
$ref: '#/components/responses/403'
422:
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: '#/components/responses/default'

View File

@ -29,7 +29,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
post:
@ -61,7 +65,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/projects/{id}":
@ -102,7 +110,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
put:
@ -142,7 +154,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
delete:
@ -178,7 +194,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/projects/{id}/edit":
@ -219,7 +239,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/projects/create:
@ -252,7 +276,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/projects/bulk:
@ -296,7 +324,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/projects/{id}/upload":
@ -337,6 +369,10 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"

View File

@ -28,7 +28,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
post:
@ -60,7 +64,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
@ -102,7 +110,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/purchase_order/{id}":
@ -143,7 +155,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
delete:
@ -179,7 +195,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/purchase_orders/{id}/edit":
@ -220,7 +240,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
@ -254,7 +278,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/purchase_orders/bulk:
@ -294,7 +322,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/purchase_orders/{id}/{action}":
@ -344,7 +376,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/purchase_orders/{id}/upload":
@ -385,7 +421,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/purchase_order/{invitation_key}/download":
@ -422,6 +462,10 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"

View File

@ -77,7 +77,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
post:
@ -109,7 +113,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/quotes/{id}":
@ -150,7 +158,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
put:
@ -190,7 +202,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
delete:
@ -226,7 +242,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/quotes/{id}/edit":
@ -267,7 +287,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/quotes/create:
@ -300,7 +324,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/quotes/bulk:
@ -344,7 +372,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/quotes/{id}/{action}":
@ -394,7 +426,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/quote/{invitation_key}/download":
@ -431,7 +467,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/quotes/{id}/upload":
@ -472,6 +512,10 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"

View File

@ -67,7 +67,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
post:
@ -99,7 +103,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
@ -141,7 +149,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
put:
@ -181,7 +193,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
delete:
@ -217,7 +233,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/recurring_invoices/{id}/edit":
@ -258,7 +278,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
@ -292,7 +316,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/recurring_invoices/bulk:
@ -360,7 +388,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/recurring_invoices/{id}/{action}":
@ -410,7 +442,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/recurring_invoice/{invitation_key}/download":
@ -447,7 +483,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/recurring_invoices/{id}/upload":
@ -488,6 +528,10 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"

View File

@ -29,7 +29,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
post:
@ -61,7 +65,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/tasks/{id}":
@ -102,7 +110,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
put:
@ -142,7 +154,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
delete:
@ -178,7 +194,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/tasks/{id}/edit":
@ -219,7 +239,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/tasks/create:
@ -252,7 +276,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/tasks/bulk:
@ -296,7 +324,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/tasks/{id}/upload":
@ -337,7 +369,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/tasks/sort:
@ -366,6 +402,10 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"

View File

@ -29,7 +29,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
post:
@ -61,7 +65,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/vendors/{id}":
@ -102,7 +110,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
put:
@ -142,7 +154,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
delete:
@ -178,7 +194,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/vendors/{id}/edit":
@ -219,7 +239,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/vendors/create:
@ -252,7 +276,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
/api/v1/vendors/bulk:
@ -296,7 +324,11 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"
"/api/v1/vendors/{id}/upload":
@ -337,6 +369,10 @@
403:
$ref: "#/components/responses/403"
422:
$ref: "#/components/responses/422"
$ref: '#/components/responses/422'
429:
$ref: '#/components/responses/429'
5XX:
description: 'Server error'
default:
$ref: "#/components/responses/default"

View File

@ -38,6 +38,43 @@ class GroupSettingTest extends TestCase
$this->makeTestData();
}
public function testAddGroupFilters()
{
$settings = new \stdClass;
$settings->currency_id = '1';
$data = [
'name' => 'testX',
'settings' => $settings,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/group_settings', $data);
$response->assertStatus(200);
$arr = $response->json();
$this->assertEquals('testX', $arr['data']['name']);
$this->assertEquals(0, $arr['data']['archived_at']);
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->get('/api/v1/group_settings?name=fdfdfd');
$response->assertStatus(200);
$arr = $response->json();
$this->assertCount(0, $arr['data']);
}
public function testAddGroupSettings()
{
$settings = new \stdClass;
@ -79,10 +116,13 @@ class GroupSettingTest extends TestCase
$response->assertStatus(200);
$arr = $response->json();
$id = $arr['data']['id'];
$this->assertEquals(0, $arr['data']['archived_at']);
$data = [
'action' => 'archive',
'ids' => [$arr['data']['id']],
'ids' => [$id],
];
$response = $this->withHeaders([
@ -95,5 +135,41 @@ class GroupSettingTest extends TestCase
$arr = $response->json();
$this->assertNotNull($arr['data'][0]['archived_at']);
$data = [
'action' => 'restore',
'ids' => [$id],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/group_settings/bulk', $data);
$response->assertStatus(200);
$arr = $response->json();
$this->assertEquals(0, $arr['data'][0]['archived_at']);
$data = [
'action' => 'delete',
'ids' => [$id],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/group_settings/bulk', $data);
$response->assertStatus(200);
$arr = $response->json();
$this->assertNotNull($arr['data'][0]['archived_at']);
$this->assertTrue($arr['data'][0]['is_deleted']);
}
}

View File

@ -31,6 +31,8 @@ class ReminderTest extends TestCase
use DatabaseTransactions;
use MockAccountData;
public $faker;
protected function setUp() :void
{
parent::setUp();
@ -49,6 +51,49 @@ class ReminderTest extends TestCase
}
public function testForSingleEndlessReminder()
{
$this->invoice->next_send_date = null;
$this->invoice->date = now()->format('Y-m-d');
$this->invoice->last_sent_date = now();
$this->invoice->due_date = Carbon::now()->addDays(5)->format('Y-m-d');
$this->invoice->save();
$settings = $this->company->settings;
$settings->enable_reminder1 = false;
$settings->schedule_reminder1 = '';
$settings->num_days_reminder1 = 0;
$settings->enable_reminder2 = false;
$settings->schedule_reminder2 = '';
$settings->num_days_reminder2 = 0;
$settings->enable_reminder3 = false;
$settings->schedule_reminder3 = '';
$settings->num_days_reminder3 = 0;
$settings->timezone_id = '5';
$settings->entity_send_time = 8;
$settings->endless_reminder_frequency_id = '5';
$settings->enable_reminder_endless = true;
$this->client->company->settings = $settings;
$this->client->push();
$client_settings = $settings;
$client_settings->timezone_id = '5';
$client_settings->entity_send_time = 8;
$this->invoice->client->settings = $client_settings;
$this->invoice->push();
$this->invoice = $this->invoice->service()->markSent()->save();
$this->invoice->service()->setReminder($client_settings)->save();
$this->invoice = $this->invoice->fresh();
$this->assertEquals(now()->addMonth()->format('Y-m-d'), Carbon::parse($this->invoice->next_send_date)->format('Y-m-d'));
}
public function testForClientTimezoneEdges()
{
$this->invoice->next_send_date = null;

View File

@ -11,19 +11,18 @@
namespace Tests\Feature;
use App\Factory\InvoiceFactory;
use App\Helpers\Invoice\InvoiceSum;
use Carbon\Carbon;
use Tests\TestCase;
use App\Models\Client;
use App\Models\Invoice;
use App\Models\Payment;
use Tests\MockAccountData;
use App\Factory\InvoiceFactory;
use App\Utils\Traits\MakesHash;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutEvents;
use Illuminate\Routing\Middleware\ThrottleRequests;
use App\Helpers\Invoice\InvoiceSum;
use Illuminate\Support\Facades\Session;
use Illuminate\Validation\ValidationException;
use Tests\MockAccountData;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithoutEvents;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Foundation\Testing\DatabaseTransactions;
/**
* @test
@ -36,6 +35,8 @@ class UpdatePaymentTest extends TestCase
use MockAccountData;
use WithoutEvents;
public $faker;
protected function setUp() :void
{
parent::setUp();
@ -50,6 +51,37 @@ class UpdatePaymentTest extends TestCase
$this->withoutMiddleware(
ThrottleRequests::class
);
}
public function testUpdatingPaymentableDates()
{
$this->invoice = $this->invoice->service()->markPaid()->save();
$payment = $this->invoice->payments->first();
$this->assertNotNull($payment);
$payment->paymentables()->each(function ($pivot){
$this->assertTrue(Carbon::createFromTimestamp($pivot->created_at)->isToday());
});
$payment->paymentables()->each(function ($pivot) {
$pivot->created_at = now()->startOfDay()->subMonth();
$pivot->save();
});
$payment->paymentables()->each(function ($pivot) {
$this->assertTrue(Carbon::createFromTimestamp($pivot->created_at)->eq(now()->startOfDay()->subMonth()));
});
}
public function testUpdatePaymentClientPaidToDate()