1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-09-24 10:21:35 +02:00

Merge pull request #7777 from turbo124/v5-stable

5.5.15
This commit is contained in:
David Bomba 2022-08-22 19:49:39 +10:00 committed by GitHub
commit a61f41dad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 417 additions and 45 deletions

View File

@ -1 +1 @@
5.5.14 5.5.15

View File

@ -14,6 +14,7 @@ namespace App\Http\Requests\Expense;
use App\Http\Requests\Request; use App\Http\Requests\Request;
use App\Http\ValidationRules\Expense\UniqueExpenseNumberRule; use App\Http\ValidationRules\Expense\UniqueExpenseNumberRule;
use App\Models\Expense; use App\Models\Expense;
use App\Models\Project;
use App\Models\PurchaseOrder; use App\Models\PurchaseOrder;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
@ -65,13 +66,29 @@ class StoreExpenseRequest extends Request
$input['color'] = ''; $input['color'] = '';
} }
/* Ensure the project is related */
if (array_key_exists('project_id', $input) && isset($input['project_id'])) {
$project = Project::withTrashed()->find($input['project_id'])->company()->first();
if($project){
$input['client_id'] = $project->client_id;
}
else
{
unset($input['project_id']);
}
}
$this->replace($input); $this->replace($input);
} }
public function messages() public function messages()
{ {
return [ return [
'unique' => ctrans('validation.unique', ['attribute' => 'email']), // 'unique' => ctrans('validation.unique', ['attribute' => 'number']),
]; ];
} }
} }

View File

@ -12,6 +12,7 @@
namespace App\Http\Requests\Expense; namespace App\Http\Requests\Expense;
use App\Http\Requests\Request; use App\Http\Requests\Request;
use App\Models\Project;
use App\Utils\Traits\ChecksEntityStatus; use App\Utils\Traits\ChecksEntityStatus;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
@ -35,10 +36,7 @@ class UpdateExpenseRequest extends Request
{ {
/* Ensure we have a client name, and that all emails are unique*/ /* Ensure we have a client name, and that all emails are unique*/
$rules = []; $rules = [];
// $rules['country_id'] = 'integer|nullable';
// $rules['contacts.*.email'] = 'nullable|distinct';
if (isset($this->number)) { if (isset($this->number)) {
$rules['number'] = Rule::unique('expenses')->where('company_id', auth()->user()->company()->id)->ignore($this->expense->id); $rules['number'] = Rule::unique('expenses')->where('company_id', auth()->user()->company()->id)->ignore($this->expense->id);
} }
@ -46,16 +44,6 @@ class UpdateExpenseRequest extends Request
return $this->globalRules($rules); return $this->globalRules($rules);
} }
public function messages()
{
return [
'unique' => ctrans('validation.unique', ['attribute' => 'email']),
'email' => ctrans('validation.email', ['attribute' => 'email']),
'name.required' => ctrans('validation.required', ['attribute' => 'name']),
'required' => ctrans('validation.required', ['attribute' => 'email']),
];
}
public function prepareForValidation() public function prepareForValidation()
{ {
$input = $this->all(); $input = $this->all();
@ -74,6 +62,20 @@ class UpdateExpenseRequest extends Request
$input['currency_id'] = (string) auth()->user()->company()->settings->currency_id; $input['currency_id'] = (string) auth()->user()->company()->settings->currency_id;
} }
/* Ensure the project is related */
if (array_key_exists('project_id', $input) && isset($input['project_id'])) {
$project = Project::withTrashed()->find($input['project_id'])->company()->first();
if($project){
$input['client_id'] = $project->client_id;
}
else
{
unset($input['project_id']);
}
}
$this->replace($input); $this->replace($input);
} }
} }

View File

@ -68,15 +68,14 @@ class StorePaymentRequest extends Request
if (isset($input['credits']) && is_array($input['credits']) !== false) { if (isset($input['credits']) && is_array($input['credits']) !== false) {
foreach ($input['credits'] as $key => $value) { foreach ($input['credits'] as $key => $value) {
if (array_key_exists('credit_id', $input['credits'][$key])) { if (array_key_exists('credit_id', $input['credits'][$key])) {
$input['credits'][$key]['credit_id'] = $value['credit_id']; // $input['credits'][$key]['credit_id'] = $value['credit_id'];
$input['credits'][$key]['credit_id'] = $this->decodePrimaryKey($value['credit_id']);
$credits_total += $value['amount']; $credits_total += $value['amount'];
} }
} }
} }
// if (array_key_exists('amount', $input))
// $input['amount'] = 0;
if (isset($input['credits']) && is_array($input['credits']) === false) { if (isset($input['credits']) && is_array($input['credits']) === false) {
$input['credits'] = null; $input['credits'] = null;
} }
@ -97,14 +96,14 @@ class StorePaymentRequest extends Request
public function rules() public function rules()
{ {
$rules = [ $rules = [
'amount' => ['numeric', 'bail', new PaymentAmountsBalanceRule(), new ValidCreditsPresentRule()], 'amount' => ['numeric', 'bail', new PaymentAmountsBalanceRule(), new ValidCreditsPresentRule($this->all())],
'client_id' => 'bail|required|exists:clients,id', 'client_id' => 'bail|required|exists:clients,id',
'invoices.*.invoice_id' => 'bail|required|distinct|exists:invoices,id', 'invoices.*.invoice_id' => 'bail|required|distinct|exists:invoices,id',
'invoices.*.amount' => 'bail|required', 'invoices.*.amount' => 'bail|required',
'invoices.*.invoice_id' => new ValidInvoicesRules($this->all()), 'invoices.*.invoice_id' => new ValidInvoicesRules($this->all()),
'credits.*.credit_id' => 'bail|required|exists:credits,id', 'credits.*.credit_id' => 'bail|required|exists:credits,id',
'credits.*.credit_id' => new ValidCreditsRules($this->all()), 'credits.*.credit_id' => new ValidCreditsRules($this->all()),
'credits.*.amount' => ['required', new CreditsSumRule($this->all())], 'credits.*.amount' => ['bail','required', new CreditsSumRule($this->all())],
'invoices' => new ValidPayableInvoicesRule(), 'invoices' => new ValidPayableInvoicesRule(),
'number' => ['nullable', 'bail', Rule::unique('payments')->where('company_id', auth()->user()->company()->id)], 'number' => ['nullable', 'bail', Rule::unique('payments')->where('company_id', auth()->user()->company()->id)],

View File

@ -36,7 +36,7 @@ class UpdatePaymentRequest extends Request
public function rules() public function rules()
{ {
$rules = [ $rules = [
'invoices' => ['array', new PaymentAppliedValidAmount, new ValidCreditsPresentRule], 'invoices' => ['array', new PaymentAppliedValidAmount, new ValidCreditsPresentRule($this->all())],
'invoices.*.invoice_id' => 'distinct', 'invoices.*.invoice_id' => 'distinct',
'documents' => 'mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx', 'documents' => 'mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx',
]; ];
@ -79,6 +79,14 @@ class UpdatePaymentRequest extends Request
} }
} }
} }
if (isset($input['credits']) && is_array($input['credits']) !== false) {
foreach ($input['credits'] as $key => $value) {
if (array_key_exists('credits', $input['credits'][$key])) {
$input['credits'][$key]['credit_id'] = $this->decodePrimaryKey($value['credit_id']);
}
}
}
$this->replace($input); $this->replace($input);
} }

View File

@ -70,8 +70,8 @@ class StoreTaskRequest extends Request
/* Ensure the project is related */ /* Ensure the project is related */
if (array_key_exists('project_id', $input) && isset($input['project_id'])) { if (array_key_exists('project_id', $input) && isset($input['project_id'])) {
$project = Project::withTrashed()->find($input['project_id'])->company()->first(); $project = Project::withTrashed()->where('id', $input['project_id'])->company()->first();
;
if($project){ if($project){
$input['client_id'] = $project->client_id; $input['client_id'] = $project->client_id;
} }

View File

@ -69,7 +69,7 @@ class UpdateTaskRequest extends Request
/* Ensure the project is related */ /* Ensure the project is related */
if (array_key_exists('project_id', $input) && isset($input['project_id'])) { if (array_key_exists('project_id', $input) && isset($input['project_id'])) {
$project = Project::withTrashed()->find($input['project_id'])->company()->first(); $project = Project::withTrashed()->where('id', $input['project_id'])->company()->first();
if($project){ if($project){
$input['client_id'] = $project->client_id; $input['client_id'] = $project->client_id;

View File

@ -50,11 +50,14 @@ class ValidCreditsRules implements Rule
} }
$unique_array = []; $unique_array = [];
$cred_collection = Credit::withTrashed()->whereIn('id', array_column($this->input['credits'], 'credit_id'))->get();
foreach ($this->input['credits'] as $credit) { foreach ($this->input['credits'] as $credit) {
$unique_array[] = $credit['credit_id']; $unique_array[] = $credit['credit_id'];
$cred = Credit::find($this->decodePrimaryKey($credit['credit_id'])); // $cred = Credit::find($this->decodePrimaryKey($credit['credit_id']));
$cred = $cred_collection->firstWhere('id', $credit['credit_id']);
if (! $cred) { if (! $cred) {
$this->error_msg = ctrans('texts.credit_not_found'); $this->error_msg = ctrans('texts.credit_not_found');

View File

@ -51,6 +51,9 @@ class ValidInvoicesRules implements Rule
$unique_array = []; $unique_array = [];
/////
$inv_collection = Invoice::withTrashed()->whereIn('id', array_column($this->input['invoices'], 'invoice_id'))->get();
//todo optimize this into a single query //todo optimize this into a single query
foreach ($this->input['invoices'] as $invoice) { foreach ($this->input['invoices'] as $invoice) {
$unique_array[] = $invoice['invoice_id']; $unique_array[] = $invoice['invoice_id'];
@ -61,7 +64,10 @@ class ValidInvoicesRules implements Rule
return false; return false;
} }
$inv = Invoice::withTrashed()->whereId($invoice['invoice_id'])->first(); /////
$inv = $inv_collection->firstWhere('id', $invoice['invoice_id']);
// $inv = Invoice::withTrashed()->whereId($invoice['invoice_id'])->first();
if (! $inv) { if (! $inv) {
$this->error_msg = ctrans('texts.invoice_not_found'); $this->error_msg = ctrans('texts.invoice_not_found');

View File

@ -22,6 +22,13 @@ class ValidCreditsPresentRule implements Rule
{ {
use MakesHash; use MakesHash;
private $input;
public function __construct($input)
{
$this->input = $input;
}
/** /**
* @param string $attribute * @param string $attribute
* @param mixed $value * @param mixed $value
@ -44,11 +51,10 @@ class ValidCreditsPresentRule implements Rule
{ {
//todo need to ensure the clients credits are here not random ones! //todo need to ensure the clients credits are here not random ones!
if (request()->input('credits') && is_array(request()->input('credits')) && count(request()->input('credits')) > 0) { if (array_key_exists('credits', $this->input) && is_array($this->input['credits']) && count($this->input['credits']) > 0) {
$credit_collection = Credit::whereIn('id', $this->transformKeys(array_column(request()->input('credits'), 'credit_id'))) $credit_collection = Credit::whereIn('id', array_column($this->input['credits'], 'credit_id'))->count();
->count();
return $credit_collection == count(request()->input('credits')); return $credit_collection == count($this->input['credits']);
} }
return true; return true;

View File

@ -85,6 +85,13 @@ class ApplyCreditPayment implements ShouldQueue
->save(); ->save();
} }
//22-08-2022
$this->credit
->client
->service()
->adjustCreditBalance($this->amount * -1)
->save();
/* Update Payment Applied Amount*/ /* Update Payment Applied Amount*/
$this->payment->save(); $this->payment->save();
} }

View File

@ -12,6 +12,7 @@
namespace App\Jobs\Ninja; namespace App\Jobs\Ninja;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Models\Client;
use App\Models\Company; use App\Models\Company;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
@ -54,6 +55,8 @@ class CompanySizeCheck implements ShouldQueue
private function check() private function check()
{ {
nlog("Checking all company sizes");
Company::where('is_large', false)->withCount(['invoices', 'clients', 'products'])->cursor()->each(function ($company) { Company::where('is_large', false)->withCount(['invoices', 'clients', 'products'])->cursor()->each(function ($company) {
if ($company->invoices_count > 500 || $company->products_count > 500 || $company->clients_count > 500) { if ($company->invoices_count > 500 || $company->products_count > 500 || $company->clients_count > 500) {
nlog("Marking company {$company->id} as large"); nlog("Marking company {$company->id} as large");
@ -61,5 +64,17 @@ class CompanySizeCheck implements ShouldQueue
$company->account->companies()->update(['is_large' => true]); $company->account->companies()->update(['is_large' => true]);
} }
}); });
nlog("updating all client credit balances");
Client::where('updated_at', '>', now()->subDay())
->cursor()
->each(function ($client){
$client->credit_balance = $client->service()->getCreditBalance();
$client->save();
});
} }
} }

View File

@ -42,13 +42,16 @@ class MailSentListener implements ShouldQueue
*/ */
public function handle(MessageSent $event) public function handle(MessageSent $event)
{ {
if(!Ninja::isHosted()); if(!Ninja::isHosted())
return; return;
$message_id = $event->sent->getMessageId(); $message_id = $event->sent->getMessageId();
$message = MessageConverter::toEmail($event->sent->getOriginalMessage()); $message = MessageConverter::toEmail($event->sent->getOriginalMessage());
if(!$message->getHeaders()->get('x-invitation'))
return;
$invitation_key = $message->getHeaders()->get('x-invitation')->getValue(); $invitation_key = $message->getHeaders()->get('x-invitation')->getValue();
if($message_id && $invitation_key) if($message_id && $invitation_key)

View File

@ -0,0 +1,89 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Notifications\Ninja;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class UserQualityNotification extends Notification
{
/**
* Create a new notification instance.
*
* @return void
*/
protected User $user;
protected string $account_key;
public function __construct(User $user, string $account_key)
{
$this->user = $user;
$this->account_key = $account_key;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['slack'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return MailMessage
*/
public function toMail($notifiable)
{
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
public function toSlack($notifiable)
{
$content = "User Quality notification {$this->user->present()->name()} \n";
$content .= "Account: {$this->account_key }\n";
return (new SlackMessage)
->success()
->from(ctrans('texts.notification_bot'))
->image('https://app.invoiceninja.com/favicon.png')
->content($content);
}
}

View File

@ -23,7 +23,10 @@ class UserObserver
*/ */
public function created(User $user) public function created(User $user)
{ {
//
if(class_exists(\Modules\Admin\Jobs\Account\UserQuality::class))
\Modules\Admin\Jobs\Account\UserQuality::dispatch($user, $user->account->key);
} }
/** /**
@ -34,6 +37,10 @@ class UserObserver
*/ */
public function updated(User $user) public function updated(User $user)
{ {
if(class_exists(\Modules\Admin\Jobs\Account\UserQuality::class))
\Modules\Admin\Jobs\Account\UserQuality::dispatch($user, $user->account->key);
} }
/** /**

View File

@ -339,6 +339,11 @@ class BaseRepository
else else
event('eloquent.updated: App\Models\Credit', $model); event('eloquent.updated: App\Models\Credit', $model);
if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Credit::STATUS_DRAFT)) {
$model->client->service()->adjustCreditBalance(($state['finished_amount'] - $state['starting_amount']))->save();
}
} }
if ($model instanceof Quote) { if ($model instanceof Quote) {

View File

@ -43,4 +43,31 @@ class CreditRepository extends BaseRepository
{ {
return CreditInvitation::where('key', $key)->first(); return CreditInvitation::where('key', $key)->first();
} }
public function delete($credit)
{
if ($credit->is_deleted) {
return;
}
$credit = $credit->service()->deleteCredit()->save();
return parent::delete($credit);
}
public function restore($credit)
{
//we cannot restore a deleted payment.
if (! $credit->trashed()) {
return;
}
parent::restore($credit);
$credit = $credit->service()->restoreCredit()->save();
return $credit;
}
} }

View File

@ -139,7 +139,8 @@ class PaymentRepository extends BaseRepository {
//todo optimize this into a single query //todo optimize this into a single query
foreach ($data['invoices'] as $paid_invoice) { foreach ($data['invoices'] as $paid_invoice) {
$invoice = Invoice::withTrashed()->whereId($paid_invoice['invoice_id'])->first(); // $invoice = Invoice::withTrashed()->whereId($paid_invoice['invoice_id'])->first();
$invoice = $invoices->firstWhere('id', $paid_invoice['invoice_id']);
if ($invoice) { if ($invoice) {
$invoice = $invoice->service() $invoice = $invoice->service()
@ -157,16 +158,20 @@ class PaymentRepository extends BaseRepository {
if (array_key_exists('credits', $data) && is_array($data['credits'])) { if (array_key_exists('credits', $data) && is_array($data['credits'])) {
$credit_totals = array_sum(array_column($data['credits'], 'amount')); $credit_totals = array_sum(array_column($data['credits'], 'amount'));
$credits = Credit::whereIn('id', $this->transformKeys(array_column($data['credits'], 'credit_id')))->get(); // $credits = Credit::whereIn('id', $this->transformKeys(array_column($data['credits'], 'credit_id')))->get();
$credits = Credit::whereIn('id', array_column($data['credits'], 'credit_id'))->get();
$payment->credits()->saveMany($credits); $payment->credits()->saveMany($credits);
//todo optimize into a single query //todo optimize into a single query
foreach ($data['credits'] as $paid_credit) { foreach ($data['credits'] as $paid_credit) {
$credit = Credit::withTrashed()->find($this->decodePrimaryKey($paid_credit['credit_id'])); // $credit = Credit::withTrashed()->find($paid_credit['credit_id']);
$credit = $credits->firstWhere('id', $paid_credit['credit_id']);
if ($credit) { if ($credit) {
$credit = $credit->service()->markSent()->save(); $credit = $credit->service()->markSent()->save();
ApplyCreditPayment::dispatchNow($credit, $payment, $paid_credit['amount'], $credit->company); (new ApplyCreditPayment($credit, $payment, $paid_credit['amount'], $credit->company))->handle();
} }
} }
} }
@ -245,7 +250,7 @@ class PaymentRepository extends BaseRepository {
event(new PaymentWasDeleted($payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); event(new PaymentWasDeleted($payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
return $payment; return $payment;
//return parent::delete($payment);
} }
public function restore($payment) public function restore($payment)

View File

@ -142,6 +142,7 @@ class CreditService
$client = $this->credit->client->fresh(); $client = $this->credit->client->fresh();
$client->service() $client->service()
->updatePaidToDate($adjustment) ->updatePaidToDate($adjustment)
->adjustCreditBalance($adjustment * -1)
->save(); ->save();
event('eloquent.created: App\Models\Payment', $payment); event('eloquent.created: App\Models\Payment', $payment);
@ -256,6 +257,29 @@ class CreditService
return $this; return $this;
} }
public function deleteCredit()
{
$this->credit
->client
->service()
->adjustCreditBalance($this->credit->balance * -1)
->save();
return $this;
}
public function restoreCredit()
{
$this->credit
->client
->service()
->adjustCreditBalance($this->credit->balance)
->save();
return $this;
}
/** /**
* Saves the credit. * Saves the credit.
* @return Credit object * @return Credit object

View File

@ -45,6 +45,11 @@ class MarkSent
->touchPdf() ->touchPdf()
->save(); ->save();
$this->client
->service()
->adjustCreditBalance($this->credit->amount)
->save();
event(new CreditWasMarkedSent($this->credit, $this->credit->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); event(new CreditWasMarkedSent($this->credit, $this->credit->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
return $this->credit; return $this->credit;

View File

@ -162,6 +162,7 @@ class DeletePayment
$client $client
->service() ->service()
->updatePaidToDate(($paymentable_credit->pivot->amount) * -1) ->updatePaidToDate(($paymentable_credit->pivot->amount) * -1)
->adjustCreditBalance($paymentable_credit->pivot->amount)
->save(); ->save();
}); });
} }

View File

@ -90,7 +90,7 @@ class Number
return (float) $s; return (float) $s;
} }
// remove all seperators from first part and keep the end // remove all separators from first part and keep the end
$s = str_replace('.', '', substr($s, 0, -3)).substr($s, -3); $s = str_replace('.', '', substr($s, 0, -3)).substr($s, -3);
// return float // return float

View File

@ -14,8 +14,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true), 'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => '5.5.14', 'app_version' => '5.5.15',
'app_tag' => '5.5.14', 'app_tag' => '5.5.15',
'minimum_client_version' => '5.0.16', 'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1', 'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''), 'api_secret' => env('API_SECRET', ''),

View File

@ -21,7 +21,7 @@
</script> </script>
<script> <script>
window.flutterConfiguration = { window.flutterConfiguration = {
canvasKitBaseUrl: "{{config('ninja.app_url')}}/canvaskit/" canvasKitBaseUrl: "/canvaskit/"
}; };
</script> </script>
</head> </head>

View File

@ -13,11 +13,13 @@ namespace Tests\Feature;
use App\DataMapper\CompanySettings; use App\DataMapper\CompanySettings;
use App\DataMapper\DefaultSettings; use App\DataMapper\DefaultSettings;
use App\Factory\InvoiceItemFactory;
use App\Models\Account; use App\Models\Account;
use App\Models\Client; use App\Models\Client;
use App\Models\ClientContact; use App\Models\ClientContact;
use App\Models\Company; use App\Models\Company;
use App\Models\CompanyToken; use App\Models\CompanyToken;
use App\Models\Credit;
use App\Models\User; use App\Models\User;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
@ -61,6 +63,97 @@ class ClientTest extends TestCase
$this->makeTestData(); $this->makeTestData();
} }
private function buildLineItems($number = 2)
{
$line_items = [];
for($x=0; $x<$number; $x++)
{
$item = InvoiceItemFactory::create();
$item->quantity = 1;
$item->cost = 10;
$line_items[] = $item;
}
return $line_items;
}
public function testCreditBalance()
{
$this->client->credit_balance = 0;
$this->client->save();
$this->assertEquals(0, $this->client->credit_balance);
$credit = [
'status_id' => 1,
'number' => 'dfdfd',
'discount' => 0,
'is_amount_discount' => 1,
'number' => '34343xx43',
'public_notes' => 'notes',
'is_deleted' => 0,
'custom_value1' => 0,
'custom_value2' => 0,
'custom_value3' => 0,
'custom_value4' => 0,
'status' => 1,
'client_id' => $this->encodePrimaryKey($this->client->id),
'line_items' => $this->buildLineItems()
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/credits/', $credit)
->assertStatus(200);
$arr = $response->json();
$credit_id = $arr['data']['id'];
$credit = Credit::find($this->decodePrimaryKey($credit_id));
$this->assertNotNull($credit);
$this->assertEquals(0, $credit->balance);
$credit->service()->markSent()->save();
$this->assertEquals(20, $credit->balance);
$this->assertEquals(20, $credit->client->fresh()->credit_balance);
//lets now update the credit and increase its balance, this should also increase the credit balance
$data = [
'number' => 'dfdfd',
'discount' => 0,
'is_amount_discount' => 1,
'number' => '34343xx43',
'public_notes' => 'notes',
'is_deleted' => 0,
'custom_value1' => 0,
'custom_value2' => 0,
'custom_value3' => 0,
'custom_value4' => 0,
'status' => 1,
'client_id' => $this->encodePrimaryKey($this->client->id),
'line_items' => $this->buildLineItems(3)
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->put('/api/v1/credits/'.$credit->hashed_id, $data)
->assertStatus(200);
$credit = $credit->fresh();
$this->assertEquals(30, $credit->balance);
$this->assertEquals(30, $credit->client->fresh()->credit_balance);
}
public function testStoreClientUsingCountryCode() public function testStoreClientUsingCountryCode()
{ {
$data = [ $data = [

View File

@ -78,7 +78,7 @@ class ImportCompanyTest extends TestCase
{ {
parent::setUp(); parent::setUp();
$this->artisan('db:seed'); // $this->artisan('db:seed');
$this->withoutMiddleware( $this->withoutMiddleware(
ThrottleRequests::class ThrottleRequests::class

View File

@ -70,4 +70,54 @@ class CreditBalanceTest extends TestCase
$this->assertEquals($this->client->service()->getCreditBalance(), 0); $this->assertEquals($this->client->service()->getCreditBalance(), 0);
} }
public function testCreditDeleteCheckClientBalance()
{
$credit = Credit::factory()->create([
'user_id' => $this->user->id,
'company_id' => $this->company->id,
'client_id' => $this->client->id,
'balance' => 10,
'number' => 'testing-number-01',
'status_id' => Credit::STATUS_SENT,
]);
$credit->client->credit_balance = 10;
$credit->push();
//delete invoice
$data = [
'ids' => [$credit->hashed_id],
];
//restore invoice
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/credits/bulk?action=delete', $data)->assertStatus(200);
$client = $credit->client->fresh();
$this->assertEquals(0, $client->credit_balance);
//restore invoice
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/credits/bulk?action=restore', $data)->assertStatus(200);
$client = $credit->client->fresh();
$this->assertEquals(10, $client->credit_balance);
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/credits/bulk?action=archive', $data)->assertStatus(200);
$client = $credit->client->fresh();
$this->assertEquals(10, $client->credit_balance);
}
} }