diff --git a/VERSION.txt b/VERSION.txt index b6d99a4aca..7de98dd799 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.3.52 \ No newline at end of file +5.3.53 \ No newline at end of file diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index afe61dd9e7..0e0b70570a 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -192,7 +192,7 @@ class Handler extends ExceptionHandler } elseif ($exception instanceof MethodNotAllowedHttpException && $request->expectsJson()) { return response()->json(['message'=>'Method not supported for this route'], 404); } elseif ($exception instanceof ValidationException && $request->expectsJson()) { - nlog($exception->validator->getMessageBag()); + // nlog($exception->validator->getMessageBag()); return response()->json(['message' => 'The given data was invalid.', 'errors' => $exception->validator->getMessageBag()], 422); } elseif ($exception instanceof RelationNotFoundException && $request->expectsJson()) { return response()->json(['message' => $exception->getMessage()], 400); diff --git a/app/Http/Controllers/CreditController.php b/app/Http/Controllers/CreditController.php index 0675437752..82e6c7e022 100644 --- a/app/Http/Controllers/CreditController.php +++ b/app/Http/Controllers/CreditController.php @@ -203,6 +203,11 @@ class CreditController extends BaseController ->triggeredActions($request) ->save(); + if($credit->invoice_id){ + $credit = $credit->service()->markSent()->save(); + $credit->client->service()->updatePaidToDate(-1 * $credit->balance)->save(); + } + event(new CreditWasCreated($credit, $credit->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); return $this->itemResponse($credit); diff --git a/app/Http/Controllers/HostedMigrationController.php b/app/Http/Controllers/HostedMigrationController.php index e61f026d98..ff5c8d4ce5 100644 --- a/app/Http/Controllers/HostedMigrationController.php +++ b/app/Http/Controllers/HostedMigrationController.php @@ -42,7 +42,10 @@ class HostedMigrationController extends Controller } $account = CreateAccount::dispatchNow($request->all(), $request->getClientIp()); - + $account->hosted_client_count = 100; + $account->hosted_company_count = 10; + $account->save(); + $company = $account->companies->first(); $company_token = CompanyToken::where('user_id', auth()->user()->id) diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index f23b049666..eaf62b4b8f 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -658,7 +658,8 @@ class InvoiceController extends BaseController // code... break; case 'mark_paid': - if ($invoice->balance < 0 || $invoice->status_id == Invoice::STATUS_PAID || $invoice->is_deleted === true) { + if ($invoice->status_id == Invoice::STATUS_PAID || $invoice->is_deleted === true) { + // if ($invoice->balance < 0 || $invoice->status_id == Invoice::STATUS_PAID || $invoice->is_deleted === true) { return $this->errorResponse(['message' => ctrans('texts.invoice_cannot_be_marked_paid')], 400); } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 2c28115120..515d5f0df5 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -96,6 +96,7 @@ class Kernel extends HttpKernel 'api' => [ // 'throttle:300,1', + // 'cors', 'bindings', 'query_logging', ], diff --git a/app/Http/Middleware/Cors.php b/app/Http/Middleware/Cors.php index fbeb6e892e..759a7310e8 100644 --- a/app/Http/Middleware/Cors.php +++ b/app/Http/Middleware/Cors.php @@ -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-COMPANY-KEY,X-CLIENT-VERSION,X-API-SECRET,X-API-TOKEN,X-API-PASSWORD,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-CSRF-TOKEN,X-XSRF-TOKEN,X-LIVEWIRE', + 'Access-Control-Allow-Headers'=> 'X-API-PASSWORD-BASE64,X-API-COMPANY-KEY,X-CLIENT-VERSION,X-API-SECRET,X-API-TOKEN,X-API-PASSWORD,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-CSRF-TOKEN,X-XSRF-TOKEN,X-LIVEWIRE', ]; return Response::make('OK', 200, $headers); @@ -26,7 +26,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-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,X-CSRF-TOKEN,X-XSRF-TOKEN,X-LIVEWIRE'); + $response->headers->set('Access-Control-Allow-Headers', 'X-API-PASSWORD-BASE64,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,X-CSRF-TOKEN,X-XSRF-TOKEN,X-LIVEWIRE'); $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')); diff --git a/app/Http/Middleware/SessionDomains.php b/app/Http/Middleware/SessionDomains.php index 0881aad8ed..86fb61a32c 100644 --- a/app/Http/Middleware/SessionDomains.php +++ b/app/Http/Middleware/SessionDomains.php @@ -39,7 +39,7 @@ class SessionDomains } else{ - Cookie::queue(Cookie::forget('invoice_ninja_session', '/')); + // Cookie::queue(Cookie::forget('invoice_ninja_session', '/')); config(['session.domain' => $domain_name]); diff --git a/app/Http/Requests/Credit/StoreCreditRequest.php b/app/Http/Requests/Credit/StoreCreditRequest.php index 5b0cd808ee..2f05fbac1e 100644 --- a/app/Http/Requests/Credit/StoreCreditRequest.php +++ b/app/Http/Requests/Credit/StoreCreditRequest.php @@ -13,6 +13,7 @@ namespace App\Http\Requests\Credit; use App\Http\Requests\Request; use App\Http\ValidationRules\Credit\UniqueCreditNumberRule; +use App\Http\ValidationRules\Credit\ValidInvoiceCreditRule; use App\Models\Credit; use App\Utils\Traits\CleanLineItems; use App\Utils\Traits\MakesHash; @@ -58,7 +59,8 @@ class StoreCreditRequest extends Request $rules['number'] = ['nullable', Rule::unique('credits')->where('company_id', auth()->user()->company()->id)]; $rules['discount'] = 'sometimes|numeric'; - + if($this->invoice_id) + $rules['invoice_id'] = new ValidInvoiceCreditRule(); $rules['line_items'] = 'array'; diff --git a/app/Http/Requests/Invoice/UpdateInvoiceRequest.php b/app/Http/Requests/Invoice/UpdateInvoiceRequest.php index d008d7a36b..10d8665a96 100644 --- a/app/Http/Requests/Invoice/UpdateInvoiceRequest.php +++ b/app/Http/Requests/Invoice/UpdateInvoiceRequest.php @@ -58,8 +58,8 @@ class UpdateInvoiceRequest extends Request $rules['line_items'] = 'array'; $rules['discount'] = 'sometimes|numeric'; - if($this->input('status_id') != Invoice::STATUS_DRAFT) - $rules['balance'] = new InvoiceBalanceSanity($this->invoice, $this->all()); + // if($this->input('status_id') != Invoice::STATUS_DRAFT) + // $rules['balance'] = new InvoiceBalanceSanity($this->invoice, $this->all()); return $rules; } diff --git a/app/Http/ValidationRules/Credit/ValidInvoiceCreditRule.php b/app/Http/ValidationRules/Credit/ValidInvoiceCreditRule.php new file mode 100644 index 0000000000..ad9ec600bd --- /dev/null +++ b/app/Http/ValidationRules/Credit/ValidInvoiceCreditRule.php @@ -0,0 +1,79 @@ +checkIfCreditInvoiceValid($value); //if it exists, return false! + } + + /** + * @return string + */ + public function message() + { + return $this->error_message; + } + + /** + * @return bool + */ + private function checkIfCreditInvoiceValid($value) : bool + { + $invoice = Invoice::withTrashed()->find($value); + + if($invoice->balance >= $invoice->amount){ + $this->error_message = "Cannot reverse an invoice with no payment applied."; + return false; + } + + $existing_credit_amounts = $invoice->credits()->sum('amount'); + + if($this->sumCredit() > ($invoice->amount - $invoice->balance - $existing_credit_amounts)){ + $this->error_message = "Credit cannot exceed the payment / credits already applied to invoice."; + return false; + } + + return true; + } + + private function sumCredit() + { + $cost = 0; + + foreach(request()->input('line_items') as $item) + { + $cost += $item['cost'] * $item['quantity']; + } + + return $cost; + } +} diff --git a/app/Jobs/Account/CreateAccount.php b/app/Jobs/Account/CreateAccount.php index 3277c08479..a9b76f8dbd 100644 --- a/app/Jobs/Account/CreateAccount.php +++ b/app/Jobs/Account/CreateAccount.php @@ -82,7 +82,8 @@ class CreateAccount if(Ninja::isHosted()) { - + $sp794f3f->hosted_client_count = config('ninja.quotas.free.clients'); + $sp794f3f->hosted_company_count = config('ninja.quotas.free.max_companies'); $sp794f3f->trial_started = now(); $sp794f3f->trial_plan = 'pro'; diff --git a/app/Repositories/BaseRepository.php b/app/Repositories/BaseRepository.php index 8858e01332..6ae4bcae40 100644 --- a/app/Repositories/BaseRepository.php +++ b/app/Repositories/BaseRepository.php @@ -327,6 +327,8 @@ class BaseRepository if (! $model->design_id) $model->design_id = $this->decodePrimaryKey($client->getSetting('credit_design_id')); + if(array_key_exists('invoice_id', $data) && $data['invoice_id']) + $model->invoice_id = $data['invoice_id']; if($this->new_model) event('eloquent.created: App\Models\Credit', $model); diff --git a/app/Services/Invoice/MarkPaid.php b/app/Services/Invoice/MarkPaid.php index 90d51588c4..026892f495 100644 --- a/app/Services/Invoice/MarkPaid.php +++ b/app/Services/Invoice/MarkPaid.php @@ -88,7 +88,6 @@ class MarkPaid extends AbstractService $this->invoice ->service() ->applyNumber() - // ->deletePdf() ->touchPdf() ->save(); diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php index 65408f35c7..11a6331bc4 100644 --- a/app/Transformers/AccountTransformer.php +++ b/app/Transformers/AccountTransformer.php @@ -83,6 +83,8 @@ class AccountTransformer extends EntityTransformer 'emails_sent' => (int) $account->emailsSent(), 'email_quota' => (int) $account->getDailyEmailLimit(), 'is_migrated' => (bool) $account->is_migrated, + 'hosted_client_count' => (int) $account->hosted_client_count, + 'hosted_company_count' => (int) $account->hosted_company_count, ]; } diff --git a/config/ninja.php b/config/ninja.php index 14d1578f1b..2d35bf32a7 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -14,8 +14,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => '5.3.52', - 'app_tag' => '5.3.52', + 'app_version' => '5.3.53', + 'app_tag' => '5.3.53', 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', ''), @@ -134,14 +134,19 @@ return [ ], 'quotas' => [ 'free' => [ - 'clients' => 50, 'daily_emails' => 50, + 'clients' => 20, + 'max_companies' => 1, ], 'pro' => [ 'daily_emails' => 100, + 'clients' => 1000000, + 'max_companies' => 10, ], 'enterprise' => [ 'daily_emails' => 200, + 'clients' => 1000000, + 'max_companies' => 10, ], ], 'auth' => [ diff --git a/database/migrations/2022_01_27_223617_add_client_count_to_accounts_table.php b/database/migrations/2022_01_27_223617_add_client_count_to_accounts_table.php new file mode 100644 index 0000000000..2dc113d5c4 --- /dev/null +++ b/database/migrations/2022_01_27_223617_add_client_count_to_accounts_table.php @@ -0,0 +1,31 @@ +unsignedInteger('hosted_client_count')->nullable(); + $table->unsignedInteger('hosted_company_count')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + } +}