mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 21:22:58 +01:00
Merge branch 'v2' of https://github.com/turbo124/invoiceninja into v2
This commit is contained in:
commit
68e2e2c8f4
@ -286,6 +286,7 @@ class CreateTestData extends Command
|
||||
$company = factory(\App\Models\Company::class)->create([
|
||||
'account_id' => $account->id,
|
||||
'slack_webhook_url' => config('ninja.notification.slack'),
|
||||
'is_large' => true,
|
||||
]);
|
||||
|
||||
$account->default_company_id = $company->id;
|
||||
|
@ -101,6 +101,8 @@ class DemoMode extends Command
|
||||
'account_id' => $account->id,
|
||||
'slack_webhook_url' => config('ninja.notification.slack'),
|
||||
'enabled_modules' => 32767,
|
||||
'company_key' => 'demo',
|
||||
'enable_shop_api' => true
|
||||
]);
|
||||
|
||||
$settings = $company->settings;
|
||||
|
@ -121,7 +121,6 @@ class EmailTemplateDefaults
|
||||
|
||||
return $converter->convertToHtml(self::transformText('invoice_message'));
|
||||
|
||||
//return Parsedown::instance()->line(self::transformText('invoice_message'));
|
||||
}
|
||||
|
||||
public static function emailQuoteSubject()
|
||||
|
@ -33,8 +33,8 @@ class ClientFactory
|
||||
$client->client_hash = Str::random(40);
|
||||
$client->settings = ClientSettings::defaults();
|
||||
|
||||
$client_contact = ClientContactFactory::create($company_id, $user_id);
|
||||
$client->contacts->add($client_contact);
|
||||
// $client_contact = ClientContactFactory::create($company_id, $user_id);
|
||||
// $client->contacts->add($client_contact);
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
@ -70,9 +70,9 @@ class InvoiceFilters extends QueryFilters
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
public function invoice_number(string $invoice_number):Builder
|
||||
public function number(string $number) :Builder
|
||||
{
|
||||
return $this->builder->where('number', $invoice_number);
|
||||
return $this->builder->where('number', $number);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -270,7 +270,7 @@ class BaseController extends Controller
|
||||
|
||||
$query->with($includes);
|
||||
|
||||
if (!auth()->user()->hasPermission('view_'.lcfirst(class_basename($this->entity_type)))) {
|
||||
if (auth()->user() && !auth()->user()->hasPermission('view_'.lcfirst(class_basename($this->entity_type)))) {
|
||||
$query->where('user_id', '=', auth()->user()->id);
|
||||
}
|
||||
|
||||
@ -346,7 +346,7 @@ class BaseController extends Controller
|
||||
|
||||
$data = $this->createItem($item, $transformer, $this->entity_type);
|
||||
|
||||
if (request()->include_static) {
|
||||
if (auth()->user() && request()->include_static) {
|
||||
$data['static'] = Statics::company(auth()->user()->getCompany()->getLocale());
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ class InvitationController extends Controller
|
||||
|
||||
event(new InvitationWasViewed($invitation->{$entity}, $invitation, $invitation->{$entity}->company, Ninja::eventVars()));
|
||||
|
||||
$this->fireEntityViewedEvent($invitation->{$entity}, $entity);
|
||||
$this->fireEntityViewedEvent($invitation, $entity);
|
||||
}
|
||||
|
||||
return redirect()->route('client.'.$entity.'.show', [$entity => $this->encodePrimaryKey($invitation->{$key})]);
|
||||
|
91
app/Http/Controllers/Shop/ClientController.php
Normal file
91
app/Http/Controllers/Shop/ClientController.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Shop;
|
||||
|
||||
use App\Events\Client\ClientWasCreated;
|
||||
use App\Factory\ClientFactory;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Http\Requests\Client\StoreClientRequest;
|
||||
use App\Http\Requests\Shop\StoreShopClientRequest;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Repositories\ClientRepository;
|
||||
use App\Transformers\ClientTransformer;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\Uploadable;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ClientController extends BaseController
|
||||
{
|
||||
use MakesHash;
|
||||
use Uploadable;
|
||||
|
||||
protected $entity_type = Client::class;
|
||||
|
||||
protected $entity_transformer = ClientTransformer::class;
|
||||
|
||||
/**
|
||||
* @var ClientRepository
|
||||
*/
|
||||
protected $client_repo;
|
||||
|
||||
/**
|
||||
* ClientController constructor.
|
||||
* @param ClientRepository $clientRepo
|
||||
*/
|
||||
public function __construct(ClientRepository $client_repo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->client_repo = $client_repo;
|
||||
}
|
||||
|
||||
public function show(Request $request, string $contact_key)
|
||||
{
|
||||
$company = Company::where('company_key', $request->header('X-API-COMPANY-KEY'))->first();
|
||||
|
||||
if(!$company->enable_shop_api)
|
||||
return response()->json(['message' => 'Shop is disabled', 'errors' => []],403);
|
||||
|
||||
$contact = ClientContact::with('client')
|
||||
->where('company_id', $company->id)
|
||||
->where('contact_key', $contact_key)
|
||||
->firstOrFail();
|
||||
|
||||
return $this->itemResponse($contact->client);
|
||||
}
|
||||
|
||||
public function store(StoreShopClientRequest $request)
|
||||
{
|
||||
$company = Company::where('company_key', $request->header('X-API-COMPANY-KEY'))->first();
|
||||
|
||||
if(!$company->enable_shop_api)
|
||||
return response()->json(['message' => 'Shop is disabled', 'errors' => []],403);
|
||||
|
||||
app('queue')->createPayloadUsing(function () use ($company) {
|
||||
return ['db' => $company->db];
|
||||
});
|
||||
|
||||
$client = $this->client_repo->save($request->all(), ClientFactory::create($company->id, $company->owner()->id));
|
||||
|
||||
$client->load('contacts', 'primary_contact');
|
||||
|
||||
$this->uploadLogo($request->file('company_logo'), $company, $client);
|
||||
|
||||
event(new ClientWasCreated($client, $company, Ninja::eventVars()));
|
||||
|
||||
return $this->itemResponse($client);
|
||||
}
|
||||
}
|
94
app/Http/Controllers/Shop/InvoiceController.php
Normal file
94
app/Http/Controllers/Shop/InvoiceController.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Shop;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasCreated;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Http\Requests\Invoice\StoreInvoiceRequest;
|
||||
use App\Http\Requests\Shop\StoreShopInvoiceRequest;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Transformers\InvoiceTransformer;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class InvoiceController extends BaseController
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
protected $entity_type = Invoice::class;
|
||||
|
||||
protected $entity_transformer = InvoiceTransformer::class;
|
||||
|
||||
/**
|
||||
* @var InvoiceRepository
|
||||
*/
|
||||
protected $invoice_repo;
|
||||
|
||||
/**
|
||||
* InvoiceController constructor.
|
||||
*
|
||||
* @param \App\Repositories\InvoiceRepository $invoice_repo The invoice repo
|
||||
*/
|
||||
public function __construct(InvoiceRepository $invoice_repo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->invoice_repo = $invoice_repo;
|
||||
}
|
||||
|
||||
public function show(Request $request, string $invitation_key)
|
||||
{
|
||||
$company = Company::where('company_key', $request->header('X-API-COMPANY-KEY'))->first();
|
||||
|
||||
if(!$company->enable_shop_api)
|
||||
return response()->json(['message' => 'Shop is disabled', 'errors' => []],403);
|
||||
|
||||
$invitation = InvoiceInvitation::with(['invoice'])
|
||||
->where('company_id', $company->id)
|
||||
->where('key',$invitation_key)
|
||||
->firstOrFail();
|
||||
|
||||
return $this->itemResponse($invitation->invoice);
|
||||
}
|
||||
|
||||
|
||||
public function store(StoreShopInvoiceRequest $request)
|
||||
{
|
||||
|
||||
$company = Company::where('company_key', $request->header('X-API-COMPANY-KEY'))->first();
|
||||
|
||||
if(!$company->enable_shop_api)
|
||||
return response()->json(['message' => 'Shop is disabled', 'errors' => []],403);
|
||||
|
||||
app('queue')->createPayloadUsing(function () use ($company) {
|
||||
return ['db' => $company->db];
|
||||
});
|
||||
|
||||
$client = Client::find($request->input('client_id'));
|
||||
|
||||
$invoice = $this->invoice_repo->save($request->all(), InvoiceFactory::create($company->id, $company->owner()->id));
|
||||
|
||||
event(new InvoiceWasCreated($invoice, $company, Ninja::eventVars()));
|
||||
|
||||
$invoice = $invoice->service()->triggeredActions($request)->save();
|
||||
|
||||
return $this->itemResponse($invoice);
|
||||
}
|
||||
|
||||
}
|
60
app/Http/Controllers/Shop/ProductController.php
Normal file
60
app/Http/Controllers/Shop/ProductController.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Shop;
|
||||
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\Product;
|
||||
use App\Transformers\ProductTransformer;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductController extends BaseController
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
protected $entity_type = Product::class;
|
||||
|
||||
protected $entity_transformer = ProductTransformer::class;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$company = Company::where('company_key', $request->header('X-API-COMPANY-KEY'))->first();
|
||||
|
||||
if(!$company->enable_shop_api)
|
||||
return response()->json(['message' => 'Shop is disabled', 'errors' => []],403);
|
||||
|
||||
$products = Product::where('company_id', $company->id);
|
||||
|
||||
return $this->listResponse($products);
|
||||
}
|
||||
|
||||
public function show(Request $request, string $product_key)
|
||||
{
|
||||
$company = Company::where('company_key', $request->header('X-API-COMPANY-KEY'))->first();
|
||||
|
||||
if(!$company->enable_shop_api)
|
||||
return response()->json(['message' => 'Shop is disabled', 'errors' => []],403);
|
||||
|
||||
$product = Product::where('company_id', $company->id)
|
||||
->where('product_key', $product_key)
|
||||
->first();
|
||||
|
||||
return $this->itemResponse($product);
|
||||
}
|
||||
}
|
@ -73,6 +73,11 @@ class Kernel extends HttpKernel
|
||||
\App\Http\Middleware\StartupCheck::class,
|
||||
\App\Http\Middleware\QueryLogging::class,
|
||||
],
|
||||
'shop' => [
|
||||
'throttle:60,1',
|
||||
'bindings',
|
||||
'query_logging',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
@ -106,7 +111,10 @@ class Kernel extends HttpKernel
|
||||
'url_db' => \App\Http\Middleware\UrlSetDb::class,
|
||||
'web_db' => \App\Http\Middleware\SetWebDb::class,
|
||||
'api_db' => \App\Http\Middleware\SetDb::class,
|
||||
'company_key_db' => \App\Http\Middleware\SetDbByCompanyKey::class,
|
||||
'locale' => \App\Http\Middleware\Locale::class,
|
||||
'contact.register' => \App\Http\Middleware\ContactRegister::class,
|
||||
'shop_token_auth' => \App\Http\Middleware\Shop\ShopTokenAuth::class,
|
||||
|
||||
];
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ class Cors
|
||||
// ALLOW OPTIONS METHOD
|
||||
$headers = [
|
||||
'Access-Control-Allow-Methods'=> 'POST, GET, OPTIONS, PUT, DELETE',
|
||||
'Access-Control-Allow-Headers'=> 'X-API-SECRET,X-API-TOKEN,X-API-PASSWORD,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
||||
'Access-Control-Allow-Headers'=> 'X-API-COMPANY-KEY,X-API-SECRET,X-API-TOKEN,X-API-PASSWORD,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
||||
];
|
||||
|
||||
return Response::make('OK', 200, $headers);
|
||||
@ -36,7 +36,7 @@ class Cors
|
||||
|
||||
$response->headers->set('Access-Control-Allow-Origin', '*');
|
||||
$response->headers->set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
||||
$response->headers->set('Access-Control-Allow-Headers', 'X-API-SECRET,X-API-TOKEN,X-API-PASSWORD,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range');
|
||||
$response->headers->set('Access-Control-Allow-Headers', 'X-API-COMPANY-KEY,X-API-SECRET,X-API-TOKEN,X-API-PASSWORD,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range');
|
||||
$response->headers->set('Access-Control-Expose-Headers', 'X-APP-VERSION,X-MINIMUM-CLIENT-VERSION');
|
||||
$response->headers->set('X-APP-VERSION', config('ninja.app_version'));
|
||||
$response->headers->set('X-MINIMUM-CLIENT-VERSION', config('ninja.minimum_client_version'));
|
||||
|
48
app/Http/Middleware/SetDbByCompanyKey.php
Normal file
48
app/Http/Middleware/SetDbByCompanyKey.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\CompanyToken;
|
||||
use Closure;
|
||||
|
||||
class SetDbByCompanyKey
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$error = [
|
||||
'message' => 'Invalid Token',
|
||||
'errors' => []
|
||||
];
|
||||
|
||||
|
||||
if ($request->header('X-API-COMPANY-KEY') && config('ninja.db.multi_db_enabled')) {
|
||||
if (! MultiDB::findAndSetDbByCompanyKey($request->header('X-API-COMPANY-KEY'))) {
|
||||
return response()->json($error, 403);
|
||||
}
|
||||
} elseif (!config('ninja.db.multi_db_enabled')) {
|
||||
return $next($request);
|
||||
} else {
|
||||
return response()->json($error, 403);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ class TokenAuth
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if ($request->header('X-API-TOKEN') && ($company_token = CompanyToken::with(['user','company'])->whereRaw("BINARY `token`= ?", [$request->header('X-API-TOKEN')])->first())) {
|
||||
|
||||
$user = $company_token->user;
|
||||
|
||||
$error = [
|
||||
|
@ -94,4 +94,11 @@ class UpdateInvoiceRequest extends Request
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'id' => ctrans('text.locked_invoice'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
183
app/Http/Requests/Shop/StoreShopClientRequest.php
Normal file
183
app/Http/Requests/Shop/StoreShopClientRequest.php
Normal file
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\Shop;
|
||||
|
||||
use App\DataMapper\ClientSettings;
|
||||
use App\Http\Requests\Request;
|
||||
use App\Http\ValidationRules\Ninja\CanStoreClientsRule;
|
||||
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\GroupSetting;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreShopClientRequest extends Request
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private $company;
|
||||
|
||||
public function authorize() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
|
||||
if ($this->input('documents') && is_array($this->input('documents'))) {
|
||||
$documents = count($this->input('documents'));
|
||||
|
||||
foreach (range(0, $documents) as $index) {
|
||||
$rules['documents.' . $index] = 'file|mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
|
||||
}
|
||||
} elseif ($this->input('documents')) {
|
||||
$rules['documents'] = 'file|mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
|
||||
}
|
||||
|
||||
/* Ensure we have a client name, and that all emails are unique*/
|
||||
//$rules['name'] = 'required|min:1';
|
||||
$rules['id_number'] = 'unique:clients,id_number,' . $this->id . ',id,company_id,' . $this->company_id;
|
||||
$rules['settings'] = new ValidClientGroupSettingsRule();
|
||||
$rules['contacts.*.email'] = 'nullable|distinct';
|
||||
$rules['contacts.*.password'] = [
|
||||
'nullable',
|
||||
'sometimes',
|
||||
'string',
|
||||
'min:7', // must be at least 10 characters in length
|
||||
'regex:/[a-z]/', // must contain at least one lowercase letter
|
||||
'regex:/[A-Z]/', // must contain at least one uppercase letter
|
||||
'regex:/[0-9]/', // must contain at least one digit
|
||||
//'regex:/[@$!%*#?&.]/', // must contain a special character
|
||||
];
|
||||
|
||||
if($this->company->account->isFreeHostedClient())
|
||||
$rules['hosted_clients'] = new CanStoreClientsRule($this->company->id);
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->company = Company::where('company_key', request()->header('X-API-COMPANY-KEY'))->firstOrFail();
|
||||
|
||||
$input = $this->all();
|
||||
|
||||
//@todo implement feature permissions for > 100 clients
|
||||
//
|
||||
$settings = ClientSettings::defaults();
|
||||
|
||||
if (array_key_exists('settings', $input) && !empty($input['settings'])) {
|
||||
foreach ($input['settings'] as $key => $value) {
|
||||
$settings->{$key} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('assigned_user_id', $input) && is_string($input['assigned_user_id'])) {
|
||||
$input['assigned_user_id'] = $this->decodePrimaryKey($input['assigned_user_id']);
|
||||
}
|
||||
|
||||
//is no settings->currency_id is set then lets dive in and find either a group or company currency all the below may be redundant!!
|
||||
if (!property_exists($settings, 'currency_id') && isset($input['group_settings_id'])) {
|
||||
$input['group_settings_id'] = $this->decodePrimaryKey($input['group_settings_id']);
|
||||
$group_settings = GroupSetting::find($input['group_settings_id']);
|
||||
|
||||
if ($group_settings && property_exists($group_settings->settings, 'currency_id') && isset($group_settings->settings->currency_id)) {
|
||||
$settings->currency_id = (string)$group_settings->settings->currency_id;
|
||||
} else {
|
||||
$settings->currency_id = (string)$this->company->settings->currency_id;
|
||||
}
|
||||
} elseif (!property_exists($settings, 'currency_id')) {
|
||||
$settings->currency_id = (string)$this->company->settings->currency_id;
|
||||
}
|
||||
|
||||
if (isset($input['currency_code'])) {
|
||||
$settings->currency_id = $this->getCurrencyCode($input['currency_code']);
|
||||
}
|
||||
|
||||
$input['settings'] = $settings;
|
||||
|
||||
if (isset($input['contacts'])) {
|
||||
foreach ($input['contacts'] as $key => $contact) {
|
||||
if (array_key_exists('id', $contact) && is_numeric($contact['id'])) {
|
||||
unset($input['contacts'][$key]['id']);
|
||||
} elseif (array_key_exists('id', $contact) && is_string($contact['id'])) {
|
||||
$input['contacts'][$key]['id'] = $this->decodePrimaryKey($contact['id']);
|
||||
}
|
||||
|
||||
|
||||
//Filter the client contact password - if it is sent with ***** we should ignore it!
|
||||
if (isset($contact['password'])) {
|
||||
if (strlen($contact['password']) == 0) {
|
||||
$input['contacts'][$key]['password'] = '';
|
||||
} else {
|
||||
$contact['password'] = str_replace("*", "", $contact['password']);
|
||||
|
||||
if (strlen($contact['password']) == 0) {
|
||||
unset($input['contacts'][$key]['password']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($input['country_code'])) {
|
||||
$input['country_id'] = $this->getCountryCode($input['country_code']);
|
||||
}
|
||||
|
||||
if(isset($input['shipping_country_code'])) {
|
||||
$input['shipping_country_id'] = $this->getCountryCode($input['shipping_country_code']);
|
||||
}
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'unique' => ctrans('validation.unique', ['attribute' => 'email']),
|
||||
//'required' => trans('validation.required', ['attribute' => 'email']),
|
||||
'contacts.*.email.required' => ctrans('validation.email', ['attribute' => 'email']),
|
||||
];
|
||||
}
|
||||
|
||||
private function getCountryCode($country_code)
|
||||
{
|
||||
$countries = Cache::get('countries');
|
||||
|
||||
$country = $countries->filter(function ($item) use($country_code) {
|
||||
return $item->iso_3166_2 == $country_code || $item->iso_3166_3 == $country_code;
|
||||
})->first();
|
||||
|
||||
return (string) $country->id;
|
||||
}
|
||||
|
||||
private function getCurrencyCode($code)
|
||||
{
|
||||
$currencies = Cache::get('currencies');
|
||||
|
||||
$currency = $currencies->filter(function ($item) use($code){
|
||||
return $item->code == $code;
|
||||
})->first();
|
||||
|
||||
return (string) $currency->id;
|
||||
}
|
||||
|
||||
}
|
109
app/Http/Requests/Shop/StoreShopInvoiceRequest.php
Normal file
109
app/Http/Requests/Shop/StoreShopInvoiceRequest.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\Shop;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Http\ValidationRules\Invoice\UniqueInvoiceNumberRule;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Utils\Traits\CleanLineItems;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
||||
class StoreShopInvoiceRequest extends Request
|
||||
{
|
||||
use MakesHash;
|
||||
use CleanLineItems;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
private $company;
|
||||
|
||||
public function authorize() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
$rules = [];
|
||||
|
||||
if ($this->input('documents') && is_array($this->input('documents'))) {
|
||||
$documents = count($this->input('documents'));
|
||||
|
||||
foreach (range(0, $documents) as $index) {
|
||||
$rules['documents.' . $index] = 'file|mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
|
||||
}
|
||||
} elseif ($this->input('documents')) {
|
||||
$rules['documents'] = 'file|mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
|
||||
}
|
||||
|
||||
$rules['client_id'] = 'required|exists:clients,id,company_id,'.$this->company->id;
|
||||
|
||||
$rules['invitations.*.client_contact_id'] = 'distinct';
|
||||
|
||||
$rules['number'] = new UniqueInvoiceNumberRule($this->all());
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->company = Company::where('company_key', request()->header('X-API-COMPANY-KEY'))->firstOrFail();
|
||||
|
||||
$input = $this->all();
|
||||
|
||||
if (array_key_exists('design_id', $input) && is_string($input['design_id'])) {
|
||||
$input['design_id'] = $this->decodePrimaryKey($input['design_id']);
|
||||
}
|
||||
|
||||
if (array_key_exists('client_id', $input) && is_string($input['client_id'])) {
|
||||
$input['client_id'] = $this->decodePrimaryKey($input['client_id']);
|
||||
}
|
||||
|
||||
if (array_key_exists('assigned_user_id', $input) && is_string($input['assigned_user_id'])) {
|
||||
$input['assigned_user_id'] = $this->decodePrimaryKey($input['assigned_user_id']);
|
||||
}
|
||||
|
||||
if (isset($input['client_contacts'])) {
|
||||
foreach ($input['client_contacts'] as $key => $contact) {
|
||||
if (!array_key_exists('send_email', $contact) || !array_key_exists('id', $contact)) {
|
||||
unset($input['client_contacts'][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($input['invitations'])) {
|
||||
foreach ($input['invitations'] as $key => $value) {
|
||||
if (isset($input['invitations'][$key]['id']) && is_numeric($input['invitations'][$key]['id'])) {
|
||||
unset($input['invitations'][$key]['id']);
|
||||
}
|
||||
|
||||
if (isset($input['invitations'][$key]['id']) && is_string($input['invitations'][$key]['id'])) {
|
||||
$input['invitations'][$key]['id'] = $this->decodePrimaryKey($input['invitations'][$key]['id']);
|
||||
}
|
||||
|
||||
if (is_string($input['invitations'][$key]['client_contact_id'])) {
|
||||
$input['invitations'][$key]['client_contact_id'] = $this->decodePrimaryKey($input['invitations'][$key]['client_contact_id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
|
||||
//$input['line_items'] = json_encode($input['line_items']);
|
||||
$this->replace($input);
|
||||
}
|
||||
}
|
@ -180,6 +180,17 @@ class MultiDB
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function findAndSetDbByCompanyKey($company_key) :bool
|
||||
{
|
||||
foreach (self::$dbs as $db) {
|
||||
if ($company = Company::on($db)->where('company_key', $company_key)->first()) {
|
||||
self::setDb($company->db);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function findAndSetDbByDomain($subdomain) :bool
|
||||
{
|
||||
foreach (self::$dbs as $db) {
|
||||
|
@ -46,14 +46,14 @@ class InvoiceViewedActivity implements ShouldQueue
|
||||
|
||||
$fields = new \stdClass;
|
||||
|
||||
$fields->user_id = $event->invoice->user_id;
|
||||
$fields->company_id = $event->invoice->company_id;
|
||||
$fields->user_id = $event->invitation->user_id;
|
||||
$fields->company_id = $event->invitation->company_id;
|
||||
$fields->activity_type_id = Activity::VIEW_INVOICE;
|
||||
$fields->client_id = $event->invitation->client_id;
|
||||
$fields->client_id = $event->invitation->invoice->client_id;
|
||||
$fields->client_contact_id = $event->invitation->client_contact_id;
|
||||
$fields->invitation_id = $event->invitation->id;
|
||||
$fields->invoice_id = $event->invitation->invoice_id;
|
||||
|
||||
$this->activity_repo->save($fields, $event->invoice, $event->event_vars);
|
||||
$this->activity_repo->save($fields, $event->invitation->invoice, $event->event_vars);
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ class BouncedEmail extends Mailable implements ShouldQueue
|
||||
//->bcc('')
|
||||
->queue(new BouncedEmail($invitation));
|
||||
|
||||
return $this->from('turbo124@gmail.com') //todo
|
||||
return $this->from('x@gmail.com') //todo
|
||||
->subject(ctrans('texts.confirmation_subject'))
|
||||
->markdown('email.auth.verify', ['user' => $this->user])
|
||||
->text('email.auth.verify_text');
|
||||
|
@ -39,7 +39,7 @@ class VerifyUser extends Mailable implements ShouldQueue
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->from('turbo124@gmail.com') //todo
|
||||
return $this->from('x@gmail.com') //todo
|
||||
->subject(ctrans('texts.confirmation_subject'))
|
||||
->markdown('email.auth.verify', ['user' => $this->user])
|
||||
->text('email.auth.verify_text');
|
||||
|
@ -109,6 +109,7 @@ class Company extends BaseModel
|
||||
'slack_webhook_url',
|
||||
'google_analytics_key',
|
||||
'client_can_register',
|
||||
'enable_shop_api',
|
||||
];
|
||||
|
||||
|
||||
|
@ -46,6 +46,7 @@ class CompanyUser extends Pivot
|
||||
'is_owner',
|
||||
'is_locked',
|
||||
'slack_webhook_url',
|
||||
'shop_restricted'
|
||||
];
|
||||
|
||||
protected $touches = [];
|
||||
|
@ -103,7 +103,7 @@ class BaseNotification extends Notification implements ShouldQueue
|
||||
$email_style_custom = $this->settings->email_style_custom;
|
||||
$body = strtr($email_style_custom, "$body", $body);
|
||||
}
|
||||
|
||||
|
||||
$data = [
|
||||
'body' => $body,
|
||||
'design' => $design_style,
|
||||
@ -120,4 +120,22 @@ class BaseNotification extends Notification implements ShouldQueue
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getTemplateView()
|
||||
{
|
||||
|
||||
switch ($this->settings->email_style) {
|
||||
case 'plain':
|
||||
return 'email.template.plain';
|
||||
break;
|
||||
case 'custom':
|
||||
return 'email.template.custom';
|
||||
break;
|
||||
default:
|
||||
return 'email.admin.generic_email';
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -73,14 +73,17 @@ class SendGenericNotification extends BaseNotification implements ShouldQueue
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
|
||||
$mail_message = (new MailMessage)
|
||||
->withSwiftMessage(function ($message) {
|
||||
$message->getHeaders()->addTextHeader('Tag', $this->invitation->company->company_key);
|
||||
})->markdown('email.admin.generic_email', $this->buildMailMessageData());
|
||||
//})->markdown($this->getTemplateView(), $this->buildMailMessageData());
|
||||
})->markdown('email.template.plain', $this->buildMailMessageData());
|
||||
|
||||
$mail_message = $this->buildMailMessageSettings($mail_message);
|
||||
|
||||
return $mail_message;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,6 +57,8 @@ class RouteServiceProvider extends ServiceProvider
|
||||
$this->mapContactApiRoutes();
|
||||
|
||||
$this->mapClientApiRoutes();
|
||||
|
||||
$this->mapShopApiRoutes();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -117,4 +119,12 @@ class RouteServiceProvider extends ServiceProvider
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/client.php'));
|
||||
}
|
||||
|
||||
protected function mapShopApiRoutes()
|
||||
{
|
||||
Route::prefix('')
|
||||
->middleware('shop')
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/shop.php'));
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,9 @@ class ClientContactRepository extends BaseRepository
|
||||
|
||||
});
|
||||
|
||||
//need to reload here to shake off stale contacts
|
||||
$client->load('contacts');
|
||||
|
||||
//always made sure we have one blank contact to maintain state
|
||||
if ($client->contacts->count() == 0) {
|
||||
|
||||
|
@ -78,7 +78,7 @@ class ClientRepository extends BaseRepository
|
||||
$data['name'] = $client->present()->name();
|
||||
}
|
||||
|
||||
info("{$client->present()->name} has a balance of {$client->balance} with a paid to date of {$client->paid_to_date}");
|
||||
//info("{$client->present()->name} has a balance of {$client->balance} with a paid to date of {$client->paid_to_date}");
|
||||
|
||||
if (array_key_exists('documents', $data)) {
|
||||
$this->saveDocuments($data['documents'], $client);
|
||||
|
@ -56,6 +56,7 @@ class MarkPaid extends AbstractService
|
||||
$payment->client_id = $this->invoice->client_id;
|
||||
$payment->transaction_reference = ctrans('texts.manual_entry');
|
||||
$payment->currency_id = $this->invoice->client->getSetting('currency_id');
|
||||
$payment->is_manual = true;
|
||||
/* Create a payment relationship to the invoice entity */
|
||||
$payment->save();
|
||||
|
||||
|
@ -132,6 +132,7 @@ class CompanyTransformer extends EntityTransformer
|
||||
'enabled_item_tax_rates' => (int) $company->enabled_item_tax_rates,
|
||||
'client_can_register' => (bool) $company->client_can_register,
|
||||
'is_large' => (bool) $company->is_large,
|
||||
'enable_shop_api' => (bool) $company->enable_shop_api,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -84,22 +84,10 @@ class HtmlEngine
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
private function buildEntityDataArray() :array
|
||||
public function buildEntityDataArray() :array
|
||||
{
|
||||
if (!$this->client->currency()) {
|
||||
throw new \Exception(debug_backtrace()[1]['function'], 1);
|
||||
@ -132,21 +120,24 @@ class HtmlEngine
|
||||
$data['$number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.invoice_number')];
|
||||
$data['$entity.terms'] = ['value' => $this->entity->terms ?: ' ', 'label' => ctrans('texts.invoice_terms')];
|
||||
$data['$terms'] = &$data['$entity.terms'];
|
||||
}
|
||||
$data['$view_link'] = ['value' => '<a href="' .$this->invitation->getLink() .'">'. ctrans('texts.view_invoice').'</a>', 'label' => ctrans('texts.view_invoice')];
|
||||
}
|
||||
|
||||
if ($this->entity_string == 'quote') {
|
||||
$data['$entity_label'] = ['value' => '', 'label' => ctrans('texts.quote')];
|
||||
$data['$number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.quote_number')];
|
||||
$data['$entity.terms'] = ['value' => $this->entity->terms ?: ' ', 'label' => ctrans('texts.quote_terms')];
|
||||
$data['$terms'] = &$data['$entity.terms'];
|
||||
}
|
||||
$data['$view_link'] = ['value' => '<a href="' .$this->invitation->getLink() .'">'. ctrans('texts.view_quote').'</a>', 'label' => ctrans('texts.view_quote')];
|
||||
}
|
||||
|
||||
if ($this->entity_string == 'credit') {
|
||||
$data['$entity_label'] = ['value' => '', 'label' => ctrans('texts.credit')];
|
||||
$data['$number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.credit_number')];
|
||||
$data['$entity.terms'] = ['value' => $this->entity->terms ?: ' ', 'label' => ctrans('texts.credit_terms')];
|
||||
$data['$terms'] = &$data['$entity.terms'];
|
||||
}
|
||||
$data['$view_link'] = ['value' => '<a href="' .$this->invitation->getLink() .'">'. ctrans('texts.view_credit').'</a>', 'label' => ctrans('texts.view_credit')];
|
||||
}
|
||||
|
||||
$data['$entity_number'] = &$data['$number'];
|
||||
|
||||
|
@ -60,14 +60,6 @@ class SystemHealth
|
||||
$system_health = false;
|
||||
}
|
||||
|
||||
if (!self::checkNode()) {
|
||||
$system_health = false;
|
||||
}
|
||||
|
||||
if (!self::checkNpm()) {
|
||||
$system_health = false;
|
||||
}
|
||||
|
||||
return [
|
||||
'system_health' => $system_health,
|
||||
'extensions' => self::extensions(),
|
||||
@ -90,13 +82,14 @@ class SystemHealth
|
||||
exec('node -v', $foo, $exitCode);
|
||||
|
||||
if ($exitCode === 0) {
|
||||
return true;
|
||||
return $foo[0];
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static function checkNpm()
|
||||
@ -105,14 +98,14 @@ class SystemHealth
|
||||
exec('npm -v', $foo, $exitCode);
|
||||
|
||||
if ($exitCode === 0) {
|
||||
return true;
|
||||
}
|
||||
return $foo[0];
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}catch (\Exception $e) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static function simpleDbCheck() :bool
|
||||
|
@ -187,6 +187,7 @@ trait MakesInvoiceValues
|
||||
}
|
||||
|
||||
$calc = $this->calc();
|
||||
$invitation = $this->invitations->where('client_contact_id', $contact->id)->first();
|
||||
|
||||
$data = [];
|
||||
$data['$tax'] = ['value' => '', 'label' => ctrans('texts.tax')];
|
||||
@ -214,6 +215,7 @@ trait MakesInvoiceValues
|
||||
$data['$number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.invoice_number')];
|
||||
$data['$entity.terms'] = ['value' => $this->terms ?: ' ', 'label' => ctrans('texts.invoice_terms')];
|
||||
$data['$terms'] = &$data['$entity.terms'];
|
||||
$data['$view_link'] = ['value' => '<a href="' .$invitation->getLink() .'">'. ctrans('texts.view_invoice').'</a>', 'label' => ctrans('texts.view_invoice')];
|
||||
}
|
||||
|
||||
if ($this instanceof Quote) {
|
||||
@ -221,13 +223,15 @@ trait MakesInvoiceValues
|
||||
$data['$number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.quote_number')];
|
||||
$data['$entity.terms'] = ['value' => $this->terms ?: ' ', 'label' => ctrans('texts.quote_terms')];
|
||||
$data['$terms'] = &$data['$entity.terms'];
|
||||
}
|
||||
$data['$view_link'] = ['value' => '<a href="' .$invitation->getLink() .'">'. ctrans('texts.view_quote').'</a>', 'label' => ctrans('texts.view_quote')];
|
||||
}
|
||||
|
||||
if ($this instanceof Credit) {
|
||||
$data['$entity_label'] = ['value' => '', 'label' => ctrans('texts.credit')];
|
||||
$data['$number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.credit_number')];
|
||||
$data['$entity.terms'] = ['value' => $this->terms ?: ' ', 'label' => ctrans('texts.credit_terms')];
|
||||
$data['$terms'] = &$data['$entity.terms'];
|
||||
$data['$view_link'] = ['value' => '<a href="' .$invitation->getLink() .'">'. ctrans('texts.view_credit').'</a>', 'label' => ctrans('texts.view_credit')];
|
||||
}
|
||||
|
||||
$data['$entity_number'] = &$data['$number'];
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
],
|
||||
'contacts' => [
|
||||
'driver' => 'eloquent',
|
||||
|
||||
'model' => App\Models\ClientContact::class,
|
||||
],
|
||||
|
||||
|
30
database/migrations/2020_07_28_104218_shop_token.php
Normal file
30
database/migrations/2020_07_28_104218_shop_token.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class ShopToken extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('companies', function (Blueprint $table) {
|
||||
$table->boolean('enable_shop_api')->default(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
@ -136,8 +136,8 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
|
||||
Route::post('emails', 'EmailController@send')->name('email.send');
|
||||
|
||||
/*Subscription and Webhook routes */
|
||||
Route::post('hooks', 'SubscriptionController@subscribe')->name('hooks.subscribe');
|
||||
Route::delete('hooks/{subscription_id}', 'SubscriptionController@unsubscribe')->name('hooks.unsubscribe');
|
||||
// Route::post('hooks', 'SubscriptionController@subscribe')->name('hooks.subscribe');
|
||||
// Route::delete('hooks/{subscription_id}', 'SubscriptionController@unsubscribe')->name('hooks.unsubscribe');
|
||||
|
||||
Route::resource('webhooks', 'WebhookController');
|
||||
Route::post('webhooks/bulk', 'WebhookController@bulk')->name('webhooks.bulk');
|
||||
|
14
routes/shop.php
Normal file
14
routes/shop.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::group(['middleware' => ['company_key_db','locale'], 'prefix' => 'api/v1'], function () {
|
||||
|
||||
Route::get('shop/products', 'Shop\ProductController@index');
|
||||
Route::post('shop/clients', 'Shop\ClientController@store');
|
||||
Route::post('shop/invoices', 'Shop\InvoiceController@store');
|
||||
Route::get('shop/client/{contact_key}', 'Shop\ClientController@show');
|
||||
Route::get('shop/invoice/{invitation_key}', 'Shop\InvoiceController@show');
|
||||
Route::get('shop/product/{product_key}', 'Shop\ProductController@show');
|
||||
|
||||
});
|
204
tests/Feature/Shop/ShopInvoiceTest.php
Normal file
204
tests/Feature/Shop/ShopInvoiceTest.php
Normal file
@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Shop;
|
||||
|
||||
use App\Factory\CompanyUserFactory;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @covers App\Http\Controllers\Shop\InvoiceController
|
||||
*/
|
||||
|
||||
class ShopInvoiceTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
use MockAccountData;
|
||||
|
||||
public function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
Model::reguard();
|
||||
|
||||
$this->makeTestData();
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
}
|
||||
|
||||
public function testTokenSuccess()
|
||||
{
|
||||
$this->company->enable_shop_api = true;
|
||||
$this->company->save();
|
||||
|
||||
$response = null;
|
||||
|
||||
try {
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-COMPANY-KEY' => $this->company->company_key
|
||||
])->get('api/v1/shop/products');
|
||||
}
|
||||
|
||||
catch (ValidationException $e) {
|
||||
$this->assertNotNull($message);
|
||||
}
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testTokenFailure()
|
||||
{
|
||||
|
||||
$this->company->enable_shop_api = true;
|
||||
$this->company->save();
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-COMPANY-KEY' => $this->company->company_key
|
||||
])->get('/api/v1/products');
|
||||
|
||||
|
||||
$response->assertStatus(403);
|
||||
|
||||
$arr = $response->json();
|
||||
}
|
||||
|
||||
public function testCompanyEnableShopApiBooleanWorks()
|
||||
{
|
||||
try {
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-COMPANY-KEY' => $this->company->company_key
|
||||
])->get('api/v1/shop/products');
|
||||
}
|
||||
|
||||
catch (ValidationException $e) {
|
||||
$this->assertNotNull($message);
|
||||
}
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
public function testGetByProductKey()
|
||||
{
|
||||
|
||||
$this->company->enable_shop_api = true;
|
||||
$this->company->save();
|
||||
|
||||
$product = factory(\App\Models\Product::class)->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
]);
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-COMPANY-KEY' => $this->company->company_key
|
||||
])->get('/api/v1/shop/product/'.$product->product_key);
|
||||
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals($product->hashed_id, $arr['data']['id']);
|
||||
}
|
||||
|
||||
public function testGetByClientByContactKey()
|
||||
{
|
||||
|
||||
$this->company->enable_shop_api = true;
|
||||
$this->company->save();
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-COMPANY-KEY' => $this->company->company_key
|
||||
])->get('/api/v1/shop/client/'.$this->client->contacts->first()->contact_key);
|
||||
|
||||
|
||||
$response->assertStatus(200);
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals($this->client->hashed_id, $arr['data']['id']);
|
||||
|
||||
}
|
||||
|
||||
public function testCreateClientOnShopRoute()
|
||||
{
|
||||
|
||||
$this->company->enable_shop_api = true;
|
||||
$this->company->save();
|
||||
|
||||
|
||||
$data = [
|
||||
'name' => 'ShopClient',
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-COMPANY-KEY' => $this->company->company_key
|
||||
])->post('/api/v1/shop/clients/', $data);
|
||||
|
||||
|
||||
$response->assertStatus(200);
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals('ShopClient', $arr['data']['name']);
|
||||
|
||||
}
|
||||
|
||||
public function testCreateInvoiceOnShopRoute()
|
||||
{
|
||||
|
||||
$this->company->enable_shop_api = true;
|
||||
$this->company->save();
|
||||
|
||||
$data = [
|
||||
'name' => 'ShopClient',
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-COMPANY-KEY' => $this->company->company_key
|
||||
])->post('/api/v1/shop/clients/', $data);
|
||||
|
||||
|
||||
$response->assertStatus(200);
|
||||
$arr = $response->json();
|
||||
|
||||
$client_hashed_id = $arr['data']['id'];
|
||||
|
||||
$invoice_data = [
|
||||
'client_id' => $client_hashed_id,
|
||||
'po_number' => 'shop_order'
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-COMPANY-KEY' => $this->company->company_key
|
||||
])->post('/api/v1/shop/invoices/', $invoice_data);
|
||||
|
||||
|
||||
$response->assertStatus(200);
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals('shop_order', $arr['data']['po_number']);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -92,7 +92,6 @@ class DesignTest extends TestCase
|
||||
|
||||
$this->assertNotNull($html);
|
||||
|
||||
|
||||
$this->quote = factory(\App\Models\Invoice::class)->create([
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
|
@ -225,6 +225,7 @@ trait MockAccountData
|
||||
$this->quote = $this->quote_calc->getQuote();
|
||||
|
||||
$this->quote->number = $this->getNextQuoteNumber($this->client);
|
||||
$this->quote->service()->createInvitations()->markSent();
|
||||
|
||||
$this->quote->setRelation('client', $this->client);
|
||||
$this->quote->setRelation('company', $this->company);
|
||||
@ -242,6 +243,7 @@ trait MockAccountData
|
||||
|
||||
$this->credit->save();
|
||||
|
||||
$this->credit->service()->createInvitations()->markSent();
|
||||
|
||||
$this->credit_calc = new InvoiceSum($this->credit);
|
||||
$this->credit_calc->build();
|
||||
|
@ -126,8 +126,8 @@ class FactoryCreationTest extends TestCase
|
||||
$cliz->save();
|
||||
|
||||
$this->assertNotNull($cliz->contacts);
|
||||
$this->assertEquals(1, $cliz->contacts->count());
|
||||
$this->assertInternalType("int", $cliz->contacts->first()->id);
|
||||
$this->assertEquals(0, $cliz->contacts->count());
|
||||
$this->assertInternalType("int", $cliz->id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user