mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-12 06:02:39 +01:00
commit
a61f41dad1
@ -1 +1 @@
|
||||
5.5.14
|
||||
5.5.15
|
@ -14,6 +14,7 @@ namespace App\Http\Requests\Expense;
|
||||
use App\Http\Requests\Request;
|
||||
use App\Http\ValidationRules\Expense\UniqueExpenseNumberRule;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Project;
|
||||
use App\Models\PurchaseOrder;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Validation\Rule;
|
||||
@ -65,13 +66,29 @@ class StoreExpenseRequest extends Request
|
||||
$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);
|
||||
}
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'unique' => ctrans('validation.unique', ['attribute' => 'email']),
|
||||
// 'unique' => ctrans('validation.unique', ['attribute' => 'number']),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Http\Requests\Expense;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\Project;
|
||||
use App\Utils\Traits\ChecksEntityStatus;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Validation\Rule;
|
||||
@ -35,9 +36,6 @@ class UpdateExpenseRequest extends Request
|
||||
{
|
||||
/* Ensure we have a client name, and that all emails are unique*/
|
||||
$rules = [];
|
||||
// $rules['country_id'] = 'integer|nullable';
|
||||
|
||||
// $rules['contacts.*.email'] = 'nullable|distinct';
|
||||
|
||||
if (isset($this->number)) {
|
||||
$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);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
$input = $this->all();
|
||||
@ -74,6 +62,20 @@ class UpdateExpenseRequest extends Request
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
@ -68,15 +68,14 @@ class StorePaymentRequest extends Request
|
||||
if (isset($input['credits']) && is_array($input['credits']) !== false) {
|
||||
foreach ($input['credits'] as $key => $value) {
|
||||
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'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (array_key_exists('amount', $input))
|
||||
// $input['amount'] = 0;
|
||||
|
||||
if (isset($input['credits']) && is_array($input['credits']) === false) {
|
||||
$input['credits'] = null;
|
||||
}
|
||||
@ -97,14 +96,14 @@ class StorePaymentRequest extends Request
|
||||
public function 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',
|
||||
'invoices.*.invoice_id' => 'bail|required|distinct|exists:invoices,id',
|
||||
'invoices.*.amount' => 'bail|required',
|
||||
'invoices.*.invoice_id' => new ValidInvoicesRules($this->all()),
|
||||
'credits.*.credit_id' => 'bail|required|exists:credits,id',
|
||||
'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(),
|
||||
'number' => ['nullable', 'bail', Rule::unique('payments')->where('company_id', auth()->user()->company()->id)],
|
||||
|
||||
|
@ -36,7 +36,7 @@ class UpdatePaymentRequest extends Request
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'invoices' => ['array', new PaymentAppliedValidAmount, new ValidCreditsPresentRule],
|
||||
'invoices' => ['array', new PaymentAppliedValidAmount, new ValidCreditsPresentRule($this->all())],
|
||||
'invoices.*.invoice_id' => 'distinct',
|
||||
'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);
|
||||
}
|
||||
|
||||
|
@ -70,8 +70,8 @@ class StoreTaskRequest extends Request
|
||||
|
||||
/* 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();
|
||||
|
||||
$project = Project::withTrashed()->where('id', $input['project_id'])->company()->first();
|
||||
;
|
||||
if($project){
|
||||
$input['client_id'] = $project->client_id;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ class UpdateTaskRequest extends Request
|
||||
|
||||
/* 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();
|
||||
$project = Project::withTrashed()->where('id', $input['project_id'])->company()->first();
|
||||
|
||||
if($project){
|
||||
$input['client_id'] = $project->client_id;
|
||||
|
@ -51,10 +51,13 @@ class ValidCreditsRules implements Rule
|
||||
|
||||
$unique_array = [];
|
||||
|
||||
$cred_collection = Credit::withTrashed()->whereIn('id', array_column($this->input['credits'], 'credit_id'))->get();
|
||||
|
||||
foreach ($this->input['credits'] as $credit) {
|
||||
$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) {
|
||||
$this->error_msg = ctrans('texts.credit_not_found');
|
||||
|
@ -51,6 +51,9 @@ class ValidInvoicesRules implements Rule
|
||||
|
||||
$unique_array = [];
|
||||
|
||||
/////
|
||||
$inv_collection = Invoice::withTrashed()->whereIn('id', array_column($this->input['invoices'], 'invoice_id'))->get();
|
||||
|
||||
//todo optimize this into a single query
|
||||
foreach ($this->input['invoices'] as $invoice) {
|
||||
$unique_array[] = $invoice['invoice_id'];
|
||||
@ -61,7 +64,10 @@ class ValidInvoicesRules implements Rule
|
||||
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) {
|
||||
$this->error_msg = ctrans('texts.invoice_not_found');
|
||||
|
@ -22,6 +22,13 @@ class ValidCreditsPresentRule implements Rule
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
private $input;
|
||||
|
||||
public function __construct($input)
|
||||
{
|
||||
$this->input = $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
@ -44,11 +51,10 @@ class ValidCreditsPresentRule implements Rule
|
||||
{
|
||||
//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) {
|
||||
$credit_collection = Credit::whereIn('id', $this->transformKeys(array_column(request()->input('credits'), 'credit_id')))
|
||||
->count();
|
||||
if (array_key_exists('credits', $this->input) && is_array($this->input['credits']) && count($this->input['credits']) > 0) {
|
||||
$credit_collection = Credit::whereIn('id', array_column($this->input['credits'], 'credit_id'))->count();
|
||||
|
||||
return $credit_collection == count(request()->input('credits'));
|
||||
return $credit_collection == count($this->input['credits']);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -85,6 +85,13 @@ class ApplyCreditPayment implements ShouldQueue
|
||||
->save();
|
||||
}
|
||||
|
||||
//22-08-2022
|
||||
$this->credit
|
||||
->client
|
||||
->service()
|
||||
->adjustCreditBalance($this->amount * -1)
|
||||
->save();
|
||||
|
||||
/* Update Payment Applied Amount*/
|
||||
$this->payment->save();
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Jobs\Ninja;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
@ -54,6 +55,8 @@ class CompanySizeCheck implements ShouldQueue
|
||||
|
||||
private function check()
|
||||
{
|
||||
nlog("Checking all company sizes");
|
||||
|
||||
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) {
|
||||
nlog("Marking company {$company->id} as large");
|
||||
@ -61,5 +64,17 @@ class CompanySizeCheck implements ShouldQueue
|
||||
$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();
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -42,13 +42,16 @@ class MailSentListener implements ShouldQueue
|
||||
*/
|
||||
public function handle(MessageSent $event)
|
||||
{
|
||||
if(!Ninja::isHosted());
|
||||
if(!Ninja::isHosted())
|
||||
return;
|
||||
|
||||
$message_id = $event->sent->getMessageId();
|
||||
|
||||
$message = MessageConverter::toEmail($event->sent->getOriginalMessage());
|
||||
|
||||
if(!$message->getHeaders()->get('x-invitation'))
|
||||
return;
|
||||
|
||||
$invitation_key = $message->getHeaders()->get('x-invitation')->getValue();
|
||||
|
||||
if($message_id && $invitation_key)
|
||||
|
89
app/Notifications/Ninja/UserQualityNotification.php
Normal file
89
app/Notifications/Ninja/UserQualityNotification.php
Normal 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);
|
||||
}
|
||||
}
|
@ -23,7 +23,10 @@ class UserObserver
|
||||
*/
|
||||
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)
|
||||
{
|
||||
|
||||
if(class_exists(\Modules\Admin\Jobs\Account\UserQuality::class))
|
||||
\Modules\Admin\Jobs\Account\UserQuality::dispatch($user, $user->account->key);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -339,6 +339,11 @@ class BaseRepository
|
||||
else
|
||||
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) {
|
||||
|
@ -43,4 +43,31 @@ class CreditRepository extends BaseRepository
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -139,7 +139,8 @@ class PaymentRepository extends BaseRepository {
|
||||
|
||||
//todo optimize this into a single query
|
||||
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) {
|
||||
$invoice = $invoice->service()
|
||||
@ -157,16 +158,20 @@ class PaymentRepository extends BaseRepository {
|
||||
if (array_key_exists('credits', $data) && is_array($data['credits'])) {
|
||||
$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);
|
||||
|
||||
//todo optimize into a single query
|
||||
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) {
|
||||
$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)));
|
||||
|
||||
return $payment;
|
||||
//return parent::delete($payment);
|
||||
|
||||
}
|
||||
|
||||
public function restore($payment)
|
||||
|
@ -142,6 +142,7 @@ class CreditService
|
||||
$client = $this->credit->client->fresh();
|
||||
$client->service()
|
||||
->updatePaidToDate($adjustment)
|
||||
->adjustCreditBalance($adjustment * -1)
|
||||
->save();
|
||||
|
||||
event('eloquent.created: App\Models\Payment', $payment);
|
||||
@ -256,6 +257,29 @@ class CreditService
|
||||
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.
|
||||
* @return Credit object
|
||||
|
@ -45,6 +45,11 @@ class MarkSent
|
||||
->touchPdf()
|
||||
->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)));
|
||||
|
||||
return $this->credit;
|
||||
|
@ -162,6 +162,7 @@ class DeletePayment
|
||||
$client
|
||||
->service()
|
||||
->updatePaidToDate(($paymentable_credit->pivot->amount) * -1)
|
||||
->adjustCreditBalance($paymentable_credit->pivot->amount)
|
||||
->save();
|
||||
});
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ class Number
|
||||
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);
|
||||
|
||||
// return float
|
||||
|
@ -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.5.14',
|
||||
'app_tag' => '5.5.14',
|
||||
'app_version' => '5.5.15',
|
||||
'app_tag' => '5.5.15',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
@ -21,7 +21,7 @@
|
||||
</script>
|
||||
<script>
|
||||
window.flutterConfiguration = {
|
||||
canvasKitBaseUrl: "{{config('ninja.app_url')}}/canvaskit/"
|
||||
canvasKitBaseUrl: "/canvaskit/"
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
|
@ -13,11 +13,13 @@ namespace Tests\Feature;
|
||||
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\DataMapper\DefaultSettings;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\Credit;
|
||||
use App\Models\User;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@ -61,6 +63,97 @@ class ClientTest extends TestCase
|
||||
$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()
|
||||
{
|
||||
$data = [
|
||||
|
@ -78,7 +78,7 @@ class ImportCompanyTest extends TestCase
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed');
|
||||
// $this->artisan('db:seed');
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
|
@ -70,4 +70,54 @@ class CreditBalanceTest extends TestCase
|
||||
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user