mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Enhancements to API (#3088)
* working on email throttling * Fixes for invitaiton links * pass custom fields as object * Add user agent to company token * Update company token transformer * Remove prefix setting from CompanySettings * Implement user agent on company token & provide better error handling for undefined relationships includes * Fix bulk actions * Working on updating/creating a company user * Fixes for tests
This commit is contained in:
parent
170340cdfa
commit
69efd4d574
@ -71,37 +71,28 @@ class CompanySettings extends BaseSettings
|
||||
/* Counters */
|
||||
public $invoice_number_pattern = '';
|
||||
public $invoice_number_counter = 1;
|
||||
public $invoice_number_prefix = '';
|
||||
|
||||
public $quote_number_prefix = '';
|
||||
public $quote_number_pattern = '';
|
||||
public $quote_number_counter = 1;
|
||||
|
||||
public $client_number_prefix = '';
|
||||
public $client_number_pattern = '';
|
||||
public $client_number_counter = 1;
|
||||
|
||||
public $credit_number_prefix = '';
|
||||
public $credit_number_pattern = '';
|
||||
public $credit_number_counter = 1;
|
||||
|
||||
public $task_number_prefix = '';
|
||||
public $task_number_pattern = '';
|
||||
public $task_number_counter = 1;
|
||||
|
||||
public $expense_number_prefix = '';
|
||||
public $expense_number_pattern = '';
|
||||
public $expense_number_counter = 1;
|
||||
|
||||
public $vendor_number_prefix = '';
|
||||
public $vendor_number_pattern = '';
|
||||
public $vendor_number_counter = 1;
|
||||
|
||||
public $ticket_number_prefix = '';
|
||||
public $ticket_number_pattern = '';
|
||||
public $ticket_number_counter = 1;
|
||||
|
||||
public $payment_number_prefix = '';
|
||||
public $payment_number_pattern = '';
|
||||
public $payment_number_counter = 1;
|
||||
|
||||
@ -260,19 +251,14 @@ class CompanySettings extends BaseSettings
|
||||
'embed_documents' => 'bool',
|
||||
'all_pages_header' => 'bool',
|
||||
'all_pages_footer' => 'bool',
|
||||
'task_number_prefix' => 'string',
|
||||
'task_number_pattern' => 'string',
|
||||
'task_number_counter' => 'int',
|
||||
'expense_number_prefix' => 'string',
|
||||
'expense_number_pattern' => 'string',
|
||||
'expense_number_counter' => 'int',
|
||||
'vendor_number_prefix' => 'string',
|
||||
'vendor_number_pattern' => 'string',
|
||||
'vendor_number_counter' => 'int',
|
||||
'ticket_number_prefix' => 'string',
|
||||
'ticket_number_pattern' => 'string',
|
||||
'ticket_number_counter' => 'int',
|
||||
'payment_number_prefix' => 'string',
|
||||
'payment_number_pattern' => 'string',
|
||||
'payment_number_counter' => 'int',
|
||||
'reply_to_email' => 'string',
|
||||
@ -287,10 +273,8 @@ class CompanySettings extends BaseSettings
|
||||
'city' => 'string',
|
||||
'company_logo' => 'string',
|
||||
'country_id' => 'string',
|
||||
'client_number_prefix' => 'string',
|
||||
'client_number_pattern' => 'string',
|
||||
'client_number_counter' => 'integer',
|
||||
'credit_number_prefix' => 'string',
|
||||
'credit_number_pattern' => 'string',
|
||||
'credit_number_counter' => 'integer',
|
||||
'currency_id' => 'string',
|
||||
@ -320,7 +304,6 @@ class CompanySettings extends BaseSettings
|
||||
'email_template_reminder_endless' => 'string',
|
||||
'enable_client_portal_password' => 'bool',
|
||||
'inclusive_taxes' => 'bool',
|
||||
'invoice_number_prefix' => 'string',
|
||||
'invoice_number_pattern' => 'string',
|
||||
'invoice_number_counter' => 'integer',
|
||||
'invoice_design_id' => 'string',
|
||||
@ -336,7 +319,6 @@ class CompanySettings extends BaseSettings
|
||||
'phone' => 'string',
|
||||
'postal_code' => 'string',
|
||||
'quote_design_id' => 'string',
|
||||
'quote_number_prefix' => 'string',
|
||||
'quote_number_pattern' => 'string',
|
||||
'quote_number_counter' => 'integer',
|
||||
'quote_terms' => 'string',
|
||||
|
@ -22,6 +22,7 @@ use Illuminate\Validation\ValidationException;
|
||||
use Symfony\Component\Debug\Exception\FatalThrowableError;
|
||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Illuminate\Database\Eloquent\RelationNotFoundException;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
@ -70,15 +71,15 @@ class Handler extends ExceptionHandler
|
||||
public function render($request, Exception $exception)
|
||||
{
|
||||
|
||||
if ($exception instanceof ModelNotFoundException)
|
||||
if ($exception instanceof ModelNotFoundException && $request->expectsJson())
|
||||
{
|
||||
return response()->json(['message'=>'Record not found'],400);
|
||||
}
|
||||
else if($exception instanceof ThrottleRequestsException)
|
||||
else if($exception instanceof ThrottleRequestsException && $request->expectsJson())
|
||||
{
|
||||
return response()->json(['message'=>'Too many requests'],429);
|
||||
}
|
||||
else if($exception instanceof FatalThrowableError)
|
||||
else if($exception instanceof FatalThrowableError && $request->expectsJson())
|
||||
{
|
||||
return response()->json(['message'=>'Fatal error'], 500);
|
||||
}
|
||||
@ -95,15 +96,18 @@ class Handler extends ExceptionHandler
|
||||
'message' => ctrans('texts.token_expired'),
|
||||
'message-type' => 'danger']);
|
||||
}
|
||||
else if ($exception instanceof NotFoundHttpException) {
|
||||
else if ($exception instanceof NotFoundHttpException && $request->expectsJson()) {
|
||||
return response()->json(['message'=>'Route does not exist'],404);
|
||||
}
|
||||
else if($exception instanceof MethodNotAllowedHttpException){
|
||||
else if($exception instanceof MethodNotAllowedHttpException && $request->expectsJson()){
|
||||
return response()->json(['message'=>'Method not support for this route'],404);
|
||||
}
|
||||
else if ($exception instanceof ValidationException && $request->expectsJson()) {
|
||||
return response()->json(['message' => 'The given data was invalid.', 'errors' => $exception->validator->getMessageBag()], 422);
|
||||
}
|
||||
else if ($exception instanceof RelationNotFoundException && $request->expectsJson()) {
|
||||
return response()->json(['message' => $exception->getMessage()], 400);
|
||||
}
|
||||
|
||||
return parent::render($request, $exception);
|
||||
|
||||
|
@ -28,6 +28,7 @@ class CompanyFactory
|
||||
$company->company_key = $this->createHash();
|
||||
$company->settings = CompanySettings::defaults();
|
||||
$company->db = config('database.default');
|
||||
$company->custom_fields = (object) ['custom1' => '1', 'custom2' => '2', 'custom3'=>3];
|
||||
$company->domain = '';
|
||||
|
||||
return $company;
|
||||
|
30
app/Factory/CompanyUserFactory.php
Normal file
30
app/Factory/CompanyUserFactory.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Factory;
|
||||
|
||||
use App\Models\CompanyUser;
|
||||
|
||||
class CompanyUserFactory
|
||||
{
|
||||
|
||||
public static function create($user_id, $company_id, $account_id) :CompanyUser
|
||||
{
|
||||
|
||||
$company_user = new CompanyUser;
|
||||
$company_user->user_id = $user_id;
|
||||
$company_user->company_id = $company_id;
|
||||
$company_user->account_id = $account_id;
|
||||
|
||||
return $company_user;
|
||||
|
||||
}
|
||||
}
|
@ -139,6 +139,7 @@ class AccountController extends BaseController
|
||||
$account = CreateAccount::dispatchNow($request->all());
|
||||
|
||||
$ct = CompanyUser::whereUserId(auth()->user()->id);
|
||||
|
||||
return $this->listResponse($ct);
|
||||
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ class InvitationController extends Controller
|
||||
public function router(string $entity, string $invitation_key)
|
||||
{
|
||||
$key = $entity.'_id';
|
||||
$entity_obj = ucfirst($entity).'Invitation';
|
||||
$entity_obj = 'App\Models\\'.ucfirst($entity).'Invitation';
|
||||
|
||||
$invitation = $entity_obj::whereRaw("BINARY `key`= ?", [$invitation_key])->first();
|
||||
|
||||
@ -40,7 +40,9 @@ class InvitationController extends Controller
|
||||
|
||||
if((bool)$invitation->contact->client->getSetting('enable_client_portal_password') !== false)
|
||||
$this->middleware('auth:contact');
|
||||
|
||||
else
|
||||
auth()->guard('contact')->login($invitation->contact, false);
|
||||
|
||||
$invitation->markViewed();
|
||||
|
||||
return redirect()->route('client.'.$entity.'.show', [$entity => $this->encodePrimaryKey($invitation->{$key})]);
|
||||
|
@ -228,7 +228,7 @@ class CompanyController extends BaseController
|
||||
/*
|
||||
* Create token
|
||||
*/
|
||||
$company_token = CreateCompanyToken::dispatchNow($company, auth()->user());
|
||||
$company_token = CreateCompanyToken::dispatchNow($company, auth()->user(), request()->server('HTTP_USER_AGENT'));
|
||||
|
||||
$this->entity_transformer = CompanyUserTransformer::class;
|
||||
$this->entity_type = CompanyUser::class;
|
||||
|
@ -519,7 +519,7 @@ class InvoiceController extends BaseController
|
||||
|
||||
$ids = request()->input('ids');
|
||||
|
||||
$invoices = Invoice::withTrashed()->find($ids);
|
||||
$invoices = Invoice::withTrashed()->find($this->transformKeys($ids));
|
||||
|
||||
$invoices->each(function ($invoice, $key) use($action){
|
||||
|
||||
@ -528,8 +528,7 @@ class InvoiceController extends BaseController
|
||||
|
||||
});
|
||||
|
||||
//todo need to return the updated dataset
|
||||
return $this->listResponse(Invoice::withTrashed()->whereIn('id', $ids));
|
||||
return $this->listResponse(Invoice::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
||||
|
||||
}
|
||||
|
||||
|
@ -7,9 +7,11 @@
|
||||
* @OA\Property(property="size_id", type="string", example="1", description="The company size ID"),
|
||||
* @OA\Property(property="industry_id", type="string", example="1", description="The company industry ID"),
|
||||
* @OA\Property(property="portal_mode", type="string", example="subdomain", description="Determines the client facing urls ie: subdomain,domain,iframe"),
|
||||
* @OA\Property(property="domain", type="string", example="http://acmeco.invoicing.co", description="Determines the client facing url "),
|
||||
* @OA\Property(property="portal_domain", type="string", example="https://subdomain.invoicing.co", description="The fully qualified domain for client facing URLS"),
|
||||
* @OA\Property(property="enabled_tax_rates", type="integer", example="1", description="Number of taxes rates used per entity"),
|
||||
* @OA\Property(property="fill_products", type="boolean", example=true, description="Toggles filling a product description based on product key"),
|
||||
* @OA\Property(property="enable_invoice_quantity", type="boolean", example=true, description="Toggles filling a product description based on product key"),
|
||||
* @OA\Property(property="convert_products", type="boolean", example=true, description="___________"),
|
||||
* @OA\Property(property="update_products", type="boolean", example=true, description="Toggles updating a product description which description changes"),
|
||||
* @OA\Property(property="custom_fields", type="object", description="Custom fields map"),
|
||||
|
@ -35,32 +35,23 @@
|
||||
* @OA\Property(property="auto_convert_quote", type="boolean", example=true, description="____________"),
|
||||
* @OA\Property(property="inclusive_taxes", type="boolean", example=true, description="____________"),
|
||||
* @OA\Property(property="translations", type="object", example="", description="JSON payload of customized translations"),
|
||||
* @OA\Property(property="task_number_prefix", type="string", example="R", description="This string is prepended to the task number"),
|
||||
* @OA\Property(property="task_number_pattern", type="string", example="{$year}-{$counter}", description="Allows customisation of the task number pattern"),
|
||||
* @OA\Property(property="task_number_counter", type="integer", example="1", description="____________"),
|
||||
* @OA\Property(property="expense_number_prefix", type="string", example="R", description="This string is prepended to the expense number"),
|
||||
* @OA\Property(property="expense_number_pattern", type="string", example="{$year}-{$counter}", description="Allows customisation of the expense number pattern"),
|
||||
* @OA\Property(property="expense_number_counter", type="integer", example="1", description="____________"),
|
||||
* @OA\Property(property="vendor_number_prefix", type="string", example="R", description="This string is prepended to the vendor number"),
|
||||
* @OA\Property(property="vendor_number_pattern", type="string", example="{$year}-{$counter}", description="Allows customisation of the vendor number pattern"),
|
||||
* @OA\Property(property="vendor_number_counter", type="integer", example="1", description="____________"),
|
||||
* @OA\Property(property="ticket_number_prefix", type="string", example="R", description="This string is prepended to the ticket number"),
|
||||
* @OA\Property(property="ticket_number_pattern", type="string", example="{$year}-{$counter}", description="Allows customisation of the ticket number pattern"),
|
||||
* @OA\Property(property="ticket_number_counter", type="integer", example="1", description="____________"),
|
||||
*
|
||||
* @OA\Property(property="payment_number_prefix", type="string", example="R", description="This string is prepended to the payment number"),
|
||||
* @OA\Property(property="payment_number_pattern", type="string", example="{$year}-{$counter}", description="Allows customisation of the payment number pattern"),
|
||||
* @OA\Property(property="payment_number_counter", type="integer", example="1", description="____________"),
|
||||
* @OA\Property(property="invoice_number_prefix", type="string", example="R", description="This string is prepended to the invoice number"),
|
||||
* @OA\Property(property="invoice_number_pattern", type="string", example="{$year}-{$counter}", description="Allows customisation of the invoice number pattern"),
|
||||
* @OA\Property(property="invoice_number_counter", type="integer", example="1", description="____________"),
|
||||
* @OA\Property(property="quote_number_prefix", type="string", example="R", description="This string is prepended to the quote number"),
|
||||
* @OA\Property(property="quote_number_pattern", type="string", example="{$year}-{$counter}", description="Allows customisation of the quote number pattern"),
|
||||
* @OA\Property(property="quote_number_counter", type="integer", example="1", description="____________"),
|
||||
* @OA\Property(property="client_number_prefix", type="string", example="R", description="This string is prepended to the client number"),
|
||||
* @OA\Property(property="client_number_pattern", type="string", example="{$year}-{$counter}", description="Allows customisation of the client number pattern"),
|
||||
* @OA\Property(property="client_number_counter", type="integer", example="1", description="____________"),
|
||||
* @OA\Property(property="credit_number_prefix", type="string", example="R", description="This string is prepended to the credit number"),
|
||||
* @OA\Property(property="credit_number_pattern", type="string", example="{$year}-{$counter}", description="Allows customisation of the credit number pattern"),
|
||||
* @OA\Property(property="credit_number_counter", type="integer", example="1", description="____________"),
|
||||
* @OA\Property(property="recurring_invoice_number_prefix", type="string", example="R", description="This string is prepended to the recurring invoice number"),
|
||||
|
@ -554,7 +554,7 @@ class PaymentController extends BaseController
|
||||
|
||||
$ids = request()->input('ids');
|
||||
|
||||
$payments = Payment::withTrashed()->find($ids);
|
||||
$payments = Payment::withTrashed()->find($this->transformKeys($ids));
|
||||
|
||||
$payments->each(function ($payment, $key) use($action){
|
||||
|
||||
@ -563,8 +563,7 @@ class PaymentController extends BaseController
|
||||
|
||||
});
|
||||
|
||||
//todo need to return the updated dataset
|
||||
return $this->listResponse(Payment::withTrashed()->whereIn('id', $ids));
|
||||
return $this->listResponse(Payment::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
||||
|
||||
}
|
||||
|
||||
|
@ -470,17 +470,16 @@ class ProductController extends BaseController
|
||||
|
||||
$ids = request()->input('ids');
|
||||
|
||||
$products = Product::withTrashed()->find($ids);
|
||||
$products = Product::withTrashed()->find($this->transformKeys($ids));
|
||||
|
||||
$products->each(function ($product, $key) use($action){
|
||||
|
||||
if(auth()->user()->can('edit', $product))
|
||||
ActionEntity::dispatchNow($product, $action);
|
||||
$this->product_repo->{$action}($product);
|
||||
|
||||
});
|
||||
|
||||
//todo need to return the updated dataset
|
||||
return response()->json([], 200);
|
||||
return $this->listResponse(Product::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -507,17 +507,16 @@ class QuoteController extends BaseController
|
||||
|
||||
$ids = request()->input('ids');
|
||||
|
||||
$quotes = Quote::withTrashed()->find($ids);
|
||||
$quotes = Quote::withTrashed()->find($this->transformKeys($ids));
|
||||
|
||||
$quotes->each(function ($quote, $key) use($action){
|
||||
|
||||
if(auth()->user()->can('edit', $quote))
|
||||
$this->quote_repo->{$action}($quote);
|
||||
$this->product_repo->{$action}($quote);
|
||||
|
||||
});
|
||||
|
||||
//todo need to return the updated dataset
|
||||
return $this->listResponse(Quote::withTrashed()->whereIn('id', $ids));
|
||||
return $this->listResponse(Quote::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
||||
|
||||
}
|
||||
|
||||
|
@ -517,7 +517,7 @@ class RecurringInvoiceController extends BaseController
|
||||
|
||||
$ids = request()->input('ids');
|
||||
|
||||
$recurring_invoices = RecurringInvoice::withTrashed()->find($ids);
|
||||
$recurring_invoices = RecurringInvoice::withTrashed()->find($this->transformKeys($ids));
|
||||
|
||||
$recurring_invoices->each(function ($recurring_invoice, $key) use($action){
|
||||
|
||||
@ -526,8 +526,7 @@ class RecurringInvoiceController extends BaseController
|
||||
|
||||
});
|
||||
|
||||
//todo need to return the updated dataset
|
||||
return $this->listResponse(RecurringInvoice::withTrashed()->whereIn('id', $ids));
|
||||
return $this->listResponse(RecurringInvoice::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
||||
|
||||
}
|
||||
|
||||
@ -610,7 +609,7 @@ class RecurringInvoiceController extends BaseController
|
||||
// return $this->itemResponse($recurring_invoice);
|
||||
break;
|
||||
case 'clone_to_quote':
|
||||
// $quote = CloneRecurringInvoiceToQuoteFactory::create($recurring_invoice, auth()->user()->id);
|
||||
// $recurring_invoice = CloneRecurringInvoiceToQuoteFactory::create($recurring_invoice, auth()->user()->id);
|
||||
// todo build the quote transformer and return response here
|
||||
break;
|
||||
case 'history':
|
||||
|
@ -515,7 +515,7 @@ class RecurringQuoteController extends BaseController
|
||||
|
||||
$ids = request()->input('ids');
|
||||
|
||||
$recurring_quotes = RecurringQuote::withTrashed()->find($ids);
|
||||
$recurring_quotes = RecurringQuote::withTrashed()->find($this->transformKeys($ids));
|
||||
|
||||
$recurring_quotes->each(function ($recurring_quote, $key) use($action){
|
||||
|
||||
@ -524,8 +524,7 @@ class RecurringQuoteController extends BaseController
|
||||
|
||||
});
|
||||
|
||||
//todo need to return the updated dataset
|
||||
return $this->listResponse(RecurringQuote::withTrashed()->whereIn('id', $ids));
|
||||
return $this->listResponse(RecurringQuote::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
||||
|
||||
}
|
||||
|
||||
|
@ -213,7 +213,7 @@ class UserController extends BaseController
|
||||
'settings' => $request->input('settings'),
|
||||
]);
|
||||
|
||||
CreateCompanyToken::dispatchNow($company, $user);
|
||||
CreateCompanyToken::dispatchNow($company, $user, request()->server('HTTP_USER_AGENT'));
|
||||
|
||||
$user->load('companies');
|
||||
|
||||
@ -514,9 +514,7 @@ class UserController extends BaseController
|
||||
|
||||
$ids = request()->input('ids');
|
||||
|
||||
$ids = $this->transformKeys($ids);
|
||||
|
||||
$users = User::withTrashed()->find($ids);
|
||||
$users = User::withTrashed()->find($this->transformKeys($ids));
|
||||
|
||||
$users->each(function ($user, $key) use($action){
|
||||
|
||||
@ -525,8 +523,7 @@ class UserController extends BaseController
|
||||
|
||||
});
|
||||
|
||||
//todo need to return the updated dataset
|
||||
return $this->listResponse(User::withTrashed()->whereIn('id', $ids));
|
||||
return $this->listResponse(User::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
||||
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ class StoreUserRequest extends Request
|
||||
public function authorize() : bool
|
||||
{
|
||||
|
||||
return auth()->user()->can('create', User::class);
|
||||
return auth()->user()->isAdmin();
|
||||
|
||||
}
|
||||
|
||||
@ -40,7 +40,6 @@ class StoreUserRequest extends Request
|
||||
'first_name' => 'required|string|max:100',
|
||||
'last_name' => 'required|string:max:100',
|
||||
'email' => new NewUniqueUserRule(),
|
||||
'is_admin' => 'required',
|
||||
];
|
||||
|
||||
}
|
||||
@ -49,16 +48,34 @@ class StoreUserRequest extends Request
|
||||
{
|
||||
$input = $this->all();
|
||||
|
||||
if(!isset($input['is_admin']))
|
||||
$input['is_admin'] = null;
|
||||
if(isset($input['company_user']))
|
||||
{
|
||||
|
||||
if(!isset($input['permissions']))
|
||||
$input['permissions'] = json_encode([]);
|
||||
if(!isset($input['company_user']['permissions']))
|
||||
$input['company_user']['permissions'] = '';
|
||||
|
||||
if(!isset($input['settings']))
|
||||
$input['settings'] = json_encode(DefaultSettings::userSettings());
|
||||
if(!isset($input['company_user']['settings']))
|
||||
$input['company_user']['settings'] = json_encode(DefaultSettings::userSettings());
|
||||
|
||||
}
|
||||
else{
|
||||
$input['company_user'] = [
|
||||
'settings' => json_encode(DefaultSettings::userSettings()),
|
||||
'permissions' => '',
|
||||
];
|
||||
}
|
||||
|
||||
$this->replace($input);
|
||||
|
||||
return $this->all();
|
||||
|
||||
}
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'company_user' => 'T',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
@ -80,7 +80,7 @@ class CreateAccount
|
||||
/*
|
||||
* Create token
|
||||
*/
|
||||
$company_token = CreateCompanyToken::dispatchNow($company, $user);
|
||||
$company_token = CreateCompanyToken::dispatchNow($company, $user, $this->request['user_agent']);
|
||||
/*
|
||||
* Login user
|
||||
*/
|
||||
|
@ -29,16 +29,19 @@ class CreateCompanyToken implements ShouldQueue
|
||||
|
||||
protected $user;
|
||||
|
||||
protected $user_agent;
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Company $company, User $user)
|
||||
public function __construct(Company $company, User $user, string $user_agent)
|
||||
{
|
||||
$this->company = $company;
|
||||
|
||||
$this->user = $user;
|
||||
|
||||
$this->user_agent = $user_agent;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,6 +58,7 @@ class CreateCompanyToken implements ShouldQueue
|
||||
'token' => Str::random(64),
|
||||
'name' => $this->user->first_name. ' '. $this->user->last_name,
|
||||
'company_id' => $this->company->id,
|
||||
'user_agent' => $this->user_agent,
|
||||
]);
|
||||
|
||||
return $ct;
|
||||
|
@ -70,7 +70,7 @@ class CreateUser
|
||||
'is_owner' => $this->company_owner,
|
||||
'is_admin' => 1,
|
||||
'is_locked' => 0,
|
||||
'permissions' => json_encode([]),
|
||||
'permissions' => '',
|
||||
'settings' => json_encode(DefaultSettings::userSettings()),
|
||||
]);
|
||||
|
||||
|
@ -178,11 +178,12 @@ class MultiDB
|
||||
|
||||
public static function findAndSetDbByInvitation($entity, $invitation_key)
|
||||
{
|
||||
$entity.'Invitation';
|
||||
|
||||
$class = 'App\Models\\'.ucfirst($entity).'Invitation';
|
||||
|
||||
foreach (self::$dbs as $db)
|
||||
{
|
||||
if($invite = $entity::on($db)->whereKey($invitation_key)->first())
|
||||
if($invite = $class::on($db)->whereRaw("BINARY `key`= ?",[$invitation_key])->first())
|
||||
{
|
||||
self::setDb($db);
|
||||
return true;
|
||||
|
@ -59,6 +59,7 @@ class Client extends BaseModel
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'currency_id',
|
||||
'name',
|
||||
'website',
|
||||
'private_notes',
|
||||
|
@ -53,6 +53,17 @@ class Company extends BaseModel
|
||||
'enable_product_cost',
|
||||
'enable_product_quantity',
|
||||
'default_quantity',
|
||||
'enable_invoice_quantity',
|
||||
'enabled_tax_rates',
|
||||
'portal_mode',
|
||||
'portal_domain',
|
||||
'convert_products',
|
||||
'update_products',
|
||||
'custom_surcharge_taxes1',
|
||||
'custom_surcharge_taxes2',
|
||||
'custom_surcharge_taxes3',
|
||||
'custom_surcharge_taxes4',
|
||||
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
|
@ -23,12 +23,20 @@ class CompanyUser extends Pivot
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'permissions' => 'object',
|
||||
'updated_at' => 'timestamp',
|
||||
'created_at' => 'timestamp',
|
||||
'deleted_at' => 'timestamp',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'account_id',
|
||||
'permissions',
|
||||
'settings',
|
||||
'is_admin',
|
||||
'is_owner',
|
||||
'is_locked'
|
||||
];
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->belongsTo(Account::class);
|
||||
|
@ -73,7 +73,7 @@ class ClientRepository extends BaseRepository
|
||||
$contacts = $this->contact_repo->save($data['contacts'], $client);
|
||||
|
||||
|
||||
if($data['name'] == '')
|
||||
if(empty($data['name']))
|
||||
$data['name'] = $client->present()->name();
|
||||
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\CompanyUser;
|
||||
use App\Factory\CompanyUserFactory;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
@ -50,9 +52,24 @@ class UserRepository extends BaseRepository
|
||||
{
|
||||
|
||||
$user->fill($data);
|
||||
|
||||
$user->save();
|
||||
|
||||
if($data['company_user'])
|
||||
{
|
||||
|
||||
$company = auth()->user()->company();
|
||||
$account_id = $company->account->id;
|
||||
|
||||
$cu = CompanyUser::whereUserId($user->id)->whereCompanyId($company->id)->first();
|
||||
|
||||
if(!$cu)
|
||||
$cu = CompanyUserFactory::create($user->id, $company->id, $account_id);
|
||||
|
||||
$cu->fill($data['company_user']);
|
||||
$cu->save();
|
||||
|
||||
}
|
||||
|
||||
return $user;
|
||||
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ class CompanyTokenTransformer extends EntityTransformer
|
||||
return [
|
||||
'token' => $company_token->token,
|
||||
'name' => $company_token->name ?: '',
|
||||
'user_agent' => $company_token->user_agent ?: 'Unidentified',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,8 @@ class CompanyTransformer extends EntityTransformer
|
||||
*/
|
||||
public function transform(Company $company)
|
||||
{
|
||||
$std = new \stdClass;
|
||||
|
||||
return [
|
||||
'id' => (string)$this->encodePrimaryKey($company->id),
|
||||
'company_key' => (string)$company->company_key ?: '',
|
||||
@ -81,7 +83,7 @@ class CompanyTransformer extends EntityTransformer
|
||||
'enable_product_cost' => (bool)$company->enable_product_cost,
|
||||
'enable_product_quantity' => (bool)$company->enable_product_quantity,
|
||||
'default_quantity' => (bool)$company->default_quantity,
|
||||
'custom_fields' => (string) $company->custom_fields,
|
||||
'custom_fields' => $company->custom_fields ?: $std,
|
||||
'size_id' => (string) $company->size_id ?: '',
|
||||
'industry_id' => (string) $company->industry_id ?: '',
|
||||
'first_month_of_year' => (string) $company->first_month_of_year ?: '',
|
||||
|
@ -61,10 +61,9 @@ trait GeneratesCounter
|
||||
|
||||
//Return a valid counter
|
||||
$pattern = $client->getSetting('invoice_number_pattern');
|
||||
$prefix = $client->getSetting('invoice_number_prefix');
|
||||
$padding = $client->getSetting('counter_padding');
|
||||
|
||||
$invoice_number = $this->checkEntityNumber(Invoice::class, $client, $counter, $padding, $prefix, $pattern);
|
||||
$invoice_number = $this->checkEntityNumber(Invoice::class, $client, $counter, $padding, $pattern);
|
||||
|
||||
$this->incrementCounter($counter_entity, 'invoice_number_counter');
|
||||
|
||||
@ -126,9 +125,9 @@ trait GeneratesCounter
|
||||
|
||||
//Return a valid counter
|
||||
$pattern = '';
|
||||
$prefix = $client->company->settings->recurring_invoice_number_prefix;
|
||||
$padding = $client->company->settings->counter_padding;
|
||||
$invoice_number = $this->checkEntityNumber(Invoice::class, $client, $counter, $padding, $prefix, $pattern);
|
||||
$padding = $client->getSetting('counter_padding');
|
||||
$invoice_number = $this->checkEntityNumber(Invoice::class, $client, $counter, $padding, $pattern);
|
||||
$invoice_number = $this->prefixCounter($invoice_number, $client->getSetting('recurring_number_prefix'));
|
||||
|
||||
//increment the correct invoice_number Counter (company vs client)
|
||||
if($is_client_counter)
|
||||
@ -155,7 +154,7 @@ trait GeneratesCounter
|
||||
$counter = $client->getSetting('client_number_counter' );
|
||||
$setting_entity = $client->getSettingEntity('client_number_counter');
|
||||
|
||||
$client_number = $this->checkEntityNumber(Client::class, $client, $counter, $client->getSetting('counter_padding'), $client->getSetting('client_number_prefix'), $client->getSetting('client_number_pattern'));
|
||||
$client_number = $this->checkEntityNumber(Client::class, $client, $counter, $client->getSetting('counter_padding'), $client->getSetting('client_number_pattern'));
|
||||
|
||||
$this->incrementCounter($setting_entity, 'client_number_counter');
|
||||
|
||||
@ -183,11 +182,10 @@ trait GeneratesCounter
|
||||
* @param Collection $entity The entity ie App\Models\Client, Invoice, Quote etc
|
||||
* @param integer $counter The counter
|
||||
* @param integer $padding The padding
|
||||
* @param string $prefix The prefix
|
||||
*
|
||||
*
|
||||
* @return string The padded and prefixed invoice number
|
||||
*/
|
||||
private function checkEntityNumber($class, $client, $counter, $padding, $prefix, $pattern)
|
||||
private function checkEntityNumber($class, $client, $counter, $padding, $pattern)
|
||||
{
|
||||
$check = false;
|
||||
|
||||
@ -195,10 +193,7 @@ trait GeneratesCounter
|
||||
|
||||
$number = $this->padCounter($counter, $padding);
|
||||
|
||||
if(isset($prefix) && strlen($prefix) >= 1)
|
||||
$number = $this->prefixCounter($number, $prefix);
|
||||
else
|
||||
$number = $this->applyNumberPattern($client, $number, $pattern);
|
||||
$number = $this->applyNumberPattern($client, $number, $pattern);
|
||||
|
||||
if($class == Invoice::class || $class == RecurringInvoice::class)
|
||||
$check = $class::whereCompanyId($client->company_id)->whereInvoiceNumber($number)->withTrashed()->first();
|
||||
|
@ -52,14 +52,14 @@ trait Inviteable
|
||||
|
||||
switch ($this->company->portal_mode) {
|
||||
case 'subdomain':
|
||||
return $domain . $entity_type .'/'. $this->key;
|
||||
return $domain .'client/'. $entity_type .'/'. $this->key;
|
||||
break;
|
||||
case 'iframe':
|
||||
return $domain . $entity_type .'/'. $this->key;
|
||||
return $domain .'client/'. $entity_type .'/'. $this->key;
|
||||
//return $domain . $entity_type .'/'. $this->contact->client->client_hash .'/'. $this->key;
|
||||
break;
|
||||
case 'domain':
|
||||
return $domain . $entity_type .'/'. $this->key;
|
||||
return $domain .'client/'. $entity_type .'/'. $this->key;
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ $factory->define(App\Models\Company::class, function (Faker $faker) {
|
||||
'ip' => $faker->ipv4,
|
||||
'db' => config('database.default'),
|
||||
'settings' => CompanySettings::defaults(),
|
||||
'custom_fields' => (object) ['custom1' => '1', 'custom2' => '2', 'custom3'=>3],
|
||||
|
||||
// 'address1' => $faker->secondaryAddress,
|
||||
// 'address2' => $faker->address,
|
||||
// 'city' => $faker->city,
|
||||
|
@ -152,6 +152,7 @@ class CreateUsersTable extends Migration
|
||||
$table->boolean('custom_surcharge_taxes2')->default(false);
|
||||
$table->boolean('custom_surcharge_taxes3')->default(false);
|
||||
$table->boolean('custom_surcharge_taxes4')->default(false);
|
||||
$table->boolean('enable_invoice_quantity')->default(true);
|
||||
$table->boolean('show_product_cost')->default(false);
|
||||
$table->unsignedInteger('enabled_tax_rates')->default(1);
|
||||
|
||||
@ -195,6 +196,7 @@ class CreateUsersTable extends Migration
|
||||
$table->boolean('is_owner')->default(false);
|
||||
$table->boolean('is_admin')->default(false);
|
||||
$table->boolean('is_locked')->default(false); // locks user out of account
|
||||
$table->timestamps(6);
|
||||
|
||||
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
|
||||
@ -271,7 +273,8 @@ class CreateUsersTable extends Migration
|
||||
$table->unsignedInteger('user_id');
|
||||
$table->string('token')->nullable();
|
||||
$table->string('name')->nullable();
|
||||
|
||||
$table->string('user_agent')->nullable();
|
||||
|
||||
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
|
@ -66,7 +66,7 @@ class PaymentLibrariesSeeder extends Seeder
|
||||
['name' => 'GoCardless', 'provider' => 'GoCardlessV2\Redirect', 'sort_order' => 9, 'is_offsite' => true, 'key' => 'b9886f9257f0c6ee7c302f1c74475f6c', 'fields' => '{"accessToken":"","webhookSecret":"","testMode":true}'],
|
||||
['name' => 'PagSeguro', 'provider' => 'PagSeguro', 'key' => 'ef498756b54db63c143af0ec433da803', 'fields' => '{"email":"","token":"","sandbox":false}'],
|
||||
['name' => 'PAYMILL', 'provider' => 'Paymill', 'key' => 'ca52f618a39367a4c944098ebf977e1c', 'fields' => '{"apiKey":""}'],
|
||||
['name' => 'Custom', 'provider' => 'Custom2', 'is_offsite' => true, 'sort_order' => 21, 'key' => '54faab2ab6e3223dbe848b1686490baa', 'fields' => '{"text":"","name":""}'],
|
||||
['name' => 'Custom', 'provider' => 'Custom', 'is_offsite' => true, 'sort_order' => 21, 'key' => '54faab2ab6e3223dbe848b1686490baa', 'fields' => '{"name":"","text":""}'],
|
||||
];
|
||||
|
||||
foreach ($gateways as $gateway) {
|
||||
|
@ -93,7 +93,7 @@ class RandomDataSeeder extends Seeder
|
||||
]);
|
||||
|
||||
|
||||
factory(\App\Models\Client::class, 20)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company){
|
||||
factory(\App\Models\Client::class, 10)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company){
|
||||
|
||||
factory(\App\Models\ClientContact::class,1)->create([
|
||||
'user_id' => $user->id,
|
||||
@ -102,7 +102,7 @@ class RandomDataSeeder extends Seeder
|
||||
'is_primary' => 1
|
||||
]);
|
||||
|
||||
factory(\App\Models\ClientContact::class,10)->create([
|
||||
factory(\App\Models\ClientContact::class,5)->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $c->id,
|
||||
'company_id' => $company->id
|
||||
@ -111,10 +111,10 @@ class RandomDataSeeder extends Seeder
|
||||
});
|
||||
|
||||
/** Product Factory */
|
||||
factory(\App\Models\Product::class,50)->create(['user_id' => $user->id, 'company_id' => $company->id]);
|
||||
factory(\App\Models\Product::class,20)->create(['user_id' => $user->id, 'company_id' => $company->id]);
|
||||
|
||||
/** Invoice Factory */
|
||||
factory(\App\Models\Invoice::class,50)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]);
|
||||
factory(\App\Models\Invoice::class,20)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]);
|
||||
|
||||
$invoices = Invoice::cursor();
|
||||
$invoice_repo = new InvoiceRepository();
|
||||
@ -162,7 +162,7 @@ class RandomDataSeeder extends Seeder
|
||||
});
|
||||
|
||||
/** Recurring Invoice Factory */
|
||||
factory(\App\Models\RecurringInvoice::class,20)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]);
|
||||
factory(\App\Models\RecurringInvoice::class,10)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]);
|
||||
|
||||
// factory(\App\Models\Payment::class,20)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id, 'settings' => ClientSettings::buildClientSettings($company->settings, $client->settings)]);
|
||||
|
||||
|
@ -239,9 +239,7 @@ class PaymentTest extends TestCase
|
||||
|
||||
}
|
||||
catch(ValidationException $e) {
|
||||
\Log::error('in the validator');
|
||||
$message = json_decode($e->validator->getMessageBag(),1);
|
||||
\Log::error($message);
|
||||
$this->assertNotNull($message);
|
||||
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\DataMapper\DefaultSettings;
|
||||
use App\Factory\ClientFactory;
|
||||
use App\Factory\CompanyUserFactory;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Factory\InvoiceToRecurringInvoiceFactory;
|
||||
@ -103,6 +104,11 @@ trait MockAccountData
|
||||
]);
|
||||
}
|
||||
|
||||
$cu = CompanyUserFactory::create($this->user->id, $this->company->id, $this->account->id);
|
||||
$cu->is_owner = true;
|
||||
$cu->is_admin = true;
|
||||
$cu->save();
|
||||
|
||||
$this->token = \Illuminate\Support\Str::random(64);
|
||||
|
||||
$company_token = CompanyToken::create([
|
||||
@ -113,14 +119,14 @@ trait MockAccountData
|
||||
'token' => $this->token,
|
||||
]);
|
||||
|
||||
$this->user->companies()->attach($this->company->id, [
|
||||
'account_id' => $this->account->id,
|
||||
'is_owner' => 1,
|
||||
'is_admin' => 1,
|
||||
'is_locked' => 0,
|
||||
'permissions' => json_encode([]),
|
||||
'settings' => json_encode(DefaultSettings::userSettings()),
|
||||
]);
|
||||
// $this->user->companies()->attach($this->company->id, [
|
||||
// 'account_id' => $this->account->id,
|
||||
// 'is_owner' => 1,
|
||||
// 'is_admin' => 1,
|
||||
// 'is_locked' => 0,
|
||||
// 'permissions' => '',
|
||||
// 'settings' => json_encode(DefaultSettings::userSettings()),
|
||||
// ]);
|
||||
|
||||
$this->client = ClientFactory::create($this->company->id, $this->user->id);
|
||||
$this->client->save();
|
||||
|
@ -66,7 +66,6 @@ class GeneratesCounterTest extends TestCase
|
||||
public function testInvoiceNumberPattern()
|
||||
{
|
||||
$settings = $this->client->company->settings;
|
||||
$settings->invoice_number_prefix = '';
|
||||
$settings->invoice_number_counter = 1;
|
||||
$settings->invoice_number_pattern = '{$year}-{$counter}';
|
||||
|
||||
@ -89,7 +88,6 @@ class GeneratesCounterTest extends TestCase
|
||||
public function testInvoiceClientNumberPattern()
|
||||
{
|
||||
$settings = $this->company->settings;
|
||||
$settings->client_number_prefix = '';
|
||||
$settings->client_number_pattern = '{$year}-{$clientCounter}';
|
||||
$settings->client_number_counter = 10;
|
||||
|
||||
@ -155,7 +153,6 @@ class GeneratesCounterTest extends TestCase
|
||||
public function testInvoicePrefix()
|
||||
{
|
||||
$settings = $this->company->settings;
|
||||
$settings->invoice_number_prefix = 'X';
|
||||
$this->company->settings = $settings;
|
||||
$this->company->save();
|
||||
|
||||
@ -165,11 +162,11 @@ class GeneratesCounterTest extends TestCase
|
||||
|
||||
$invoice_number = $this->getNextInvoiceNumber($cliz);
|
||||
|
||||
$this->assertEquals($invoice_number, 'X0001');
|
||||
$this->assertEquals($invoice_number, '0007');
|
||||
|
||||
$invoice_number = $this->getNextInvoiceNumber($cliz);
|
||||
|
||||
$this->assertEquals($invoice_number, 'X0002');
|
||||
$this->assertEquals($invoice_number, '0008');
|
||||
|
||||
|
||||
}
|
||||
@ -190,7 +187,6 @@ class GeneratesCounterTest extends TestCase
|
||||
public function testClientNumberPrefix()
|
||||
{
|
||||
$settings = $this->company->settings;
|
||||
$settings->client_number_prefix = 'C';
|
||||
$this->company->settings = $settings;
|
||||
$this->company->save();
|
||||
|
||||
@ -200,11 +196,11 @@ class GeneratesCounterTest extends TestCase
|
||||
|
||||
$client_number = $this->getNextClientNumber($cliz);
|
||||
|
||||
$this->assertEquals($client_number, 'C0001');
|
||||
$this->assertEquals($client_number, '0001');
|
||||
|
||||
$client_number = $this->getNextClientNumber($cliz);
|
||||
|
||||
$this->assertEquals($client_number, 'C0002');
|
||||
$this->assertEquals($client_number, '0002');
|
||||
|
||||
|
||||
}
|
||||
@ -212,7 +208,6 @@ class GeneratesCounterTest extends TestCase
|
||||
public function testClientNumberPattern()
|
||||
{
|
||||
$settings = $this->company->settings;
|
||||
$settings->client_number_prefix = '';
|
||||
$settings->client_number_pattern = '{$year}-{$user_id}-{$counter}';
|
||||
$this->company->settings = $settings;
|
||||
$this->company->save();
|
||||
|
Loading…
x
Reference in New Issue
Block a user