Merge pull request #3876 from turbo124/v2

Allow searching on entity routes
This commit is contained in:
David Bomba 2020-07-02 21:03:12 +10:00 committed by GitHub
commit 7f90d8d45b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 461 additions and 293 deletions

View File

@ -81,6 +81,8 @@ class CheckData extends Command
}
$this->checkInvoiceBalances();
$this->checkInvoicePayments();
$this->checkPaidToDates();
$this->checkClientBalances();
$this->checkContacts();
$this->checkCompanyData();
@ -314,7 +316,73 @@ class CheckData extends Command
$this->logMessage("{$wrong_balances} clients with incorrect balances");
}
private function checkPaidToDates()
{
$wrong_paid_to_dates = 0;
Client::withTrashed()->cursor()->each(function ($client) use($wrong_paid_to_dates){
$total_invoice_payments = 0;
$client->invoices->where('is_deleted', false)->each(function ($invoice) use($total_invoice_payments, $wrong_paid_to_dates){
$total_amount = $invoice->payments->sum('pivot.amount');
$total_refund = $invoice->payments->sum('pivot.refunded');
info("Pivot = " . $total_amount . " - " . $total_refund);
$total_invoice_payments += ($total_amount - $total_refund);
info($total_invoice_payments);
});
info($total_invoice_payments . " = ". $client->paid_to_date);
if($total_invoice_payments != $client->paid_to_date) {
$wrong_paid_to_dates++;
$this->logMessage($client->present()->name . " - " . $client->id . " - Paid to date does not match Client Paid To Date = {$client->paid_to_date} - Invoice Payments = {$total_invoice_payments}");
$this->isValid = false;
}
});
$this->logMessage("{$wrong_paid_to_dates} clients with incorrect paid to dates");
}
private function checkInvoicePayments()
{
$wrong_balances = 0;
$wrong_paid_to_dates = 0;
Client::cursor()->each(function ($client) use($wrong_balances){
$client->invoices->where('is_deleted', false)->each(function ($invoice) use($wrong_balances){
$total_amount = $invoice->payments->sum('pivot.amount');
$total_refund = $invoice->payments->sum('pivot.refunded');
$total_paid = $total_amount - $total_refund;
if($total_paid != ($invoice->amount - $invoice->balance)) {
$wrong_balances++;
$this->logMessage($client->present()->name . " - " . $client->id . " - balances do not match Invoice Amount = {$invoice->amount} - Invoice Balance = {$invoice->balance} Total paid = {$total_paid}");
$this->isValid = false;
}
});
});
$this->logMessage("{$wrong_balances} clients with incorrect invoice balances");
}
private function checkClientBalances()

View File

@ -82,7 +82,7 @@ class DemoMode extends Command
private function createSmallAccount()
{
$this->count = 10;
$this->count = 100;
$this->info('Creating Small Account and Company');
@ -90,6 +90,7 @@ class DemoMode extends Command
$company = factory(\App\Models\Company::class)->create([
'account_id' => $account->id,
'slack_webhook_url' => config('ninja.notification.slack'),
'enabled_modules' => 4095,
]);
@ -154,7 +155,6 @@ class DemoMode extends Command
]);
}
factory(\App\Models\Product::class, 50)->create([
'user_id' => $user->id,
'company_id' => $company->id,
@ -166,7 +166,10 @@ class DemoMode extends Command
$z = $x+1;
$this->info("Creating client # ".$z);
$this->createClient($company, $user);
if(rand(0,1))
$this->createClient($company, $user);
else
$this->createClient($company, $u2);
}
for($x=0; $x<$this->count; $x++)
@ -236,7 +239,7 @@ class DemoMode extends Command
$client->id_number = $this->getNextClientNumber($client);
$settings = $client->settings;
$settings->currency_id = (string)rand(1,79);
$settings->currency_id = (string)rand(1,3);
$client->settings = $settings;
$country = Country::all()->random();
@ -326,8 +329,8 @@ class DemoMode extends Command
$invoice->tax_rate3 = 5;
}
$invoice->custom_value1 = $faker->date;
$invoice->custom_value2 = rand(0, 1) ? 'yes' : 'no';
// $invoice->custom_value1 = $faker->date;
// $invoice->custom_value2 = rand(0, 1) ? 'yes' : 'no';
$invoice->save();
@ -361,7 +364,11 @@ class DemoMode extends Command
$credit = factory(\App\Models\Credit::class)->create(['user_id' => $client->user->id, 'company_id' => $client->company->id, 'client_id' => $client->id]);
$dateable = Carbon::now()->subDays(rand(0, 90));
if((bool)rand(0,1))
$dateable = Carbon::now()->subDays(rand(0, 90));
else
$dateable = Carbon::now()->addDays(rand(0, 90));
$credit->date = $dateable;
$credit->line_items = $this->buildLineItems(rand(1, 10));

View File

@ -49,6 +49,16 @@ class ClientFilters extends QueryFilters
return $this->builder->whereBetween('balance', [$parts[0], $parts[1]]);
}
public function email(string $email):Builder
{
return $this->builder->where('email', $email);
}
public function id_number(string $id_number):Builder
{
return $this->builder->where('id_number', $id_number);
}
/**
* Filter based on search text
*

View File

@ -70,6 +70,11 @@ class InvoiceFilters extends QueryFilters
return $this->builder;
}
public function invoice_number(string $invoice_number):Builder
{
return $this->builder->where('number', $invoice_number);
}
/**
* Filter based on search text
*

View File

@ -23,6 +23,6 @@ class PingController extends BaseController
*/
public function index()
{
return response()->json('success', 200);
return response()->json(['company_name' => auth()->user()->getCompany()->present()->name()], 200);
}
}

View File

@ -89,8 +89,8 @@ class PreviewController extends BaseController
{
if (request()->has('entity') &&
request()->has('entity_id') &&
strlen(request()->input('entity')) > 1 &&
strlen(request()->input('entity_id')) > 1 &&
!empty(request()->input('entity')) &&
!empty(request()->input('entity_id')) &&
request()->has('body')) {
$design_object = json_decode(json_encode(request()->input('design')));

View File

@ -0,0 +1,16 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class SchedulerController extends Controller
{
public function index()
{
if(auth()->user()->company()->account->latest_version == '0.0.0')
return response()->json(['message' => 'Scheduler has never run'], 400);
else
return response()->json(['message' => 'Scheduler has run'], 200);
}
}

View File

@ -19,6 +19,7 @@ use App\Models\Client;
use App\Models\GroupSetting;
use App\Utils\Traits\MakesHash;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Cache;
class StoreClientRequest extends Request
{
@ -101,8 +102,11 @@ class StoreClientRequest extends Request
}
} elseif (!property_exists($settings, 'currency_id')) {
$settings->currency_id = (string)auth()->user()->company()->settings->currency_id;
}
}
if (isset($input['currency_code'])) {
$settings->currency_id = $this->getCurrencyCode($input['currency_code']);
}
$input['settings'] = $settings;
@ -130,6 +134,14 @@ class StoreClientRequest extends Request
}
}
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);
}
@ -141,4 +153,27 @@ class StoreClientRequest extends Request
'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;
}
}

View File

@ -80,7 +80,9 @@ class StorePaymentRequest extends Request
$input['is_manual'] = true;
info(print_r($input,1));
if(!isset($input['date'])) {
$input['date'] = now()->format('Y-m-d');
}
$this->replace($input);
}
@ -90,7 +92,7 @@ class StorePaymentRequest extends Request
$rules = [
'amount' => 'numeric|required',
'amount' => [new PaymentAmountsBalanceRule(),new ValidCreditsPresentRule()],
'date' => 'required',
//'date' => 'required',
'client_id' => 'bail|required|exists:clients,id',
'invoices.*.invoice_id' => 'required|distinct|exists:invoices,id',
'invoices.*.invoice_id' => new ValidInvoicesRules($this->all()),

View File

@ -483,8 +483,8 @@ class Import implements ShouldQueue
throw new ResourceDependencyMissing('Processing invoices failed, because of missing dependency - clients.');
}
$modified['client_id'] = $this->transformId('clients', $resource['client_id']);
$modified['user_id'] = $this->processUserId($resource);
$modified['client_id'] = $this->transformId('clients', $resource['client_id']);
$modified['user_id'] = $this->processUserId($resource);
$modified['company_id'] = $this->company->id;
$modified['line_items'] = $this->cleanItems($modified['line_items']);

View File

@ -286,12 +286,15 @@ class RecurringInvoice extends BaseModel
case RecurringInvoice::FREQUENCY_TWO_YEARS:
return ctrans('texts.freq_two_years');
break;
case RecurringInvoice::RECURS_INDEFINITELY:
return ctrans('texts.freq_indefinitely');
break;
default:
# code...
break;
}
}
public function recurringDates()
{
//todo send back a list of the next send dates and due dates
}
}

View File

@ -73,13 +73,12 @@ class ClientContactRepository extends BaseRepository
//always made sure we have one blank contact to maintain state
if ($client->contacts->count() == 0) {
info("no contacts found");
$new_contact = ClientContactFactory::create($client->company_id, $client->user_id);
$new_contact->client_id = $client->id;
$new_contact->contact_key = Str::random(40);
$new_contact->is_primary = true;
$new_contact->save();
}
}

View File

@ -12,9 +12,11 @@
namespace App\Transformers;
use App\Models\Backup;
use App\Models\Client;
use App\Models\Document;
use App\Models\Invoice;
use App\Models\InvoiceInvitation;
use App\Transformers\ClientTransformer;
use App\Transformers\DocumentTransformer;
use App\Transformers\InvoiceHistoryTransformer;
use App\Transformers\InvoiceInvitationTransformer;
@ -30,10 +32,10 @@ class InvoiceTransformer extends EntityTransformer
];
protected $availableIncludes = [
'invitations',
'history'
// 'invitations',
'history',
// 'payments',
// 'client',
'client',
// 'documents',
];
@ -51,6 +53,13 @@ class InvoiceTransformer extends EntityTransformer
return $this->includeCollection($invoice->history, $transformer, Backup::class);
}
public function includeClient(Invoice $invoice)
{
$transformer = new ClientTransformer($this->serializer);
return $this->includeItem($invoice->client, $transformer, Client::class);
}
/*
public function includePayments(Invoice $invoice)
{
@ -59,12 +68,6 @@ class InvoiceTransformer extends EntityTransformer
return $this->includeCollection($invoice->payments, $transformer, ENTITY_PAYMENT);
}
public function includeClient(Invoice $invoice)
{
$transformer = new ClientTransformer($this->account, $this->serializer);
return $this->includeItem($invoice->client, $transformer, ENTITY_CLIENT);
}
public function includeExpenses(Invoice $invoice)
{

View File

@ -55,8 +55,7 @@
"staudenmeir/eloquent-has-many-deep": "^1.11",
"stripe/stripe-php": "^7.0",
"turbo124/beacon": "^1",
"webpatser/laravel-countries": "dev-master#75992ad",
"yajra/laravel-datatables-oracle": "~9.0"
"webpatser/laravel-countries": "dev-master#75992ad"
},
"require-dev": {
"laravelcollective/html": "^6",

432
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,6 @@
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::get('/api/v1/ping', 'PingController@index')->name('ping');
Route::group(['middleware' => ['api_secret_check']], function () {
Route::post('api/v1/signup', 'AccountController@store')->name('signup.submit');
@ -23,6 +22,9 @@ Route::group(['api_secret_check', 'email_db'], function () {
});
Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'api/v1', 'as' => 'api.'], function () {
Route::get('ping', 'PingController@index')->name('ping');
Route::resource('activities', 'ActivityController');// name = (clients. index / create / show / update / destroy / edit
Route::resource('clients', 'ClientController');// name = (clients. index / create / show / update / destroy / edit
@ -103,7 +105,7 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
Route::resource('companies', 'CompanyController');// name = (companies. index / create / show / update / destroy / edit
Route::resource('tokens', 'TokenController');// name = (tokens. index / create / show / update / destroy / edit
Route::resource('tokens', 'TokenController')->middleware('password_protected');// name = (tokens. index / create / show / update / destroy / edit
Route::resource('company_gateways', 'CompanyGatewayController');
@ -154,6 +156,7 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
Route::get('settings', 'SettingsController@index')->name('user.settings');
*/
Route::get('scheduler', 'SchedulerController@index');
Route::post('support/messages/send', 'Support\Messages\SendingController');
});

View File

@ -58,32 +58,66 @@ class ClientTest extends TestCase
}
public function testStoreClientUsingCountryCode()
{
$data = [
'name' => 'Country Code Name',
'country_code' => 'US',
'currency_code' => 'USD',
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/clients/', $data);
$arr = $response->json();
$client = Client::find($this->decodePrimaryKey($arr['data']['id']));
$this->assertEquals(840, $client->country_id);
$this->assertEquals(1, $client->settings->currency_id);
$data = [
'name' => 'Country Code Name',
'country_code' => 'USA',
'currency_code' => 'USD',
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/clients/', $data);
$arr = $response->json();
$client = Client::find($this->decodePrimaryKey($arr['data']['id']));
$this->assertEquals(840, $client->country_id);
$this->assertEquals(1, $client->settings->currency_id);
$data = [
'name' => 'Country Code Name',
'country_code' => 'AU',
'currency_code' => 'AUD',
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/clients/', $data);
$arr = $response->json();
$client = Client::find($this->decodePrimaryKey($arr['data']['id']));
$this->assertEquals(36, $client->country_id);
$this->assertEquals(12, $client->settings->currency_id);
}
public function testClientList()
{
// $data = [
// 'first_name' => $this->faker->firstName,
// 'last_name' => $this->faker->lastName,
// 'name' => $this->faker->company,
// 'email' => $this->faker->unique()->safeEmail,
// 'password' => 'ALongAndBrilliantPassword123',
// '_token' => csrf_token(),
// 'privacy_policy' => 1,
// 'terms_of_service' => 1
// ];
// $response = $this->withHeaders([
// 'X-API-SECRET' => config('ninja.api_secret'),
// ])->post('/api/v1/signup?include=account', $data);
// $response->assertStatus(200);
// $acc = $response->json();
// $account = Account::find($this->decodePrimaryKey($acc['data'][0]['account']['id']));
// $this->token = $account->default_company->tokens->first()->token;
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),

View File

@ -3,9 +3,10 @@
namespace Tests\Feature;
use App\DataMapper\DefaultSettings;
use App\Http\Middleware\PasswordProtection;
use App\Models\Account;
use App\Models\CompanyToken;
use App\Models\Company;
use App\Models\CompanyToken;
use App\Models\User;
use App\Utils\Traits\MakesHash;
use Faker\Factory;
@ -14,11 +15,11 @@ use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Http\Request;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use Tests\MockAccountData;
use Tests\TestCase;
use Illuminate\Routing\Middleware\ThrottleRequests;
/**
* @test
@ -43,15 +44,18 @@ class CompanyTokenApiTest extends TestCase
Model::reguard();
$this->withoutMiddleware(
ThrottleRequests::class
ThrottleRequests::class,
);
}
public function testCompanyTokenList()
{
$this->withoutMiddleware(PasswordProtection::class);
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token
'X-API-TOKEN' => $this->token,
'X-API-PASSWORD' => 'ALongAndBriliantPassword',
])->get('/api/v1/tokens');
@ -60,12 +64,15 @@ class CompanyTokenApiTest extends TestCase
public function testCompanyTokenPost()
{
$this->withoutMiddleware(PasswordProtection::class);
$data = [
'name' => $this->faker->firstName,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-PASSWORD' => 'ALongAndBriliantPassword',
'X-API-TOKEN' => $this->token
])->post('/api/v1/tokens', $data);
@ -75,6 +82,8 @@ class CompanyTokenApiTest extends TestCase
public function testCompanyTokenPut()
{
$this->withoutMiddleware(PasswordProtection::class);
$company_token = CompanyToken::whereCompanyId($this->company->id)->first();
$data = [
@ -84,6 +93,7 @@ class CompanyTokenApiTest extends TestCase
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-PASSWORD' => 'ALongAndBriliantPassword',
'X-API-TOKEN' => $this->token
])->put('/api/v1/tokens/'.$this->encodePrimaryKey($company_token->id), $data);
@ -96,11 +106,14 @@ class CompanyTokenApiTest extends TestCase
public function testCompanyTokenGet()
{
$this->withoutMiddleware(PasswordProtection::class);
$company_token = CompanyToken::whereCompanyId($this->company->id)->first();
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-PASSWORD' => 'ALongAndBriliantPassword',
'X-API-TOKEN' => $this->token
])->get('/api/v1/tokens/'.$this->encodePrimaryKey($company_token->id));
@ -110,10 +123,13 @@ class CompanyTokenApiTest extends TestCase
public function testCompanyTokenNotArchived()
{
$this->withoutMiddleware(PasswordProtection::class);
$company_token = CompanyToken::whereCompanyId($this->company->id)->first();
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-PASSWORD' => 'ALongAndBriliantPassword',
'X-API-TOKEN' => $this->token
])->get('/api/v1/tokens/'.$this->encodePrimaryKey($company_token->id));