mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 13:12:50 +01:00
commit
28ac3e6f4d
@ -1 +1 @@
|
||||
5.5.11
|
||||
5.5.12
|
@ -587,21 +587,21 @@ class CreditController extends BaseController
|
||||
$this->credit_repository->archive($credit);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($credit);
|
||||
return $this->itemResponse($credit);
|
||||
}
|
||||
break;
|
||||
case 'restore':
|
||||
$this->credit_repository->restore($credit);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($credit);
|
||||
return $this->itemResponse($credit);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
$this->credit_repository->delete($credit);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($credit);
|
||||
return $this->itemResponse($credit);
|
||||
}
|
||||
break;
|
||||
case 'email':
|
||||
|
@ -722,14 +722,14 @@ class InvoiceController extends BaseController
|
||||
$this->invoice_repo->restore($invoice);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($invoice);
|
||||
return $this->itemResponse($invoice);
|
||||
}
|
||||
break;
|
||||
case 'archive':
|
||||
$this->invoice_repo->archive($invoice);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($invoice);
|
||||
return $this->itemResponse($invoice);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
@ -737,7 +737,7 @@ class InvoiceController extends BaseController
|
||||
$this->invoice_repo->delete($invoice);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($invoice);
|
||||
return $this->itemResponse($invoice);
|
||||
}
|
||||
break;
|
||||
case 'cancel':
|
||||
|
@ -623,14 +623,14 @@ class PurchaseOrderController extends BaseController
|
||||
$this->purchase_order_repository->restore($purchase_order);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($purchase_order);
|
||||
return $this->itemResponse($purchase_order);
|
||||
}
|
||||
break;
|
||||
case 'archive':
|
||||
$this->purchase_order_repository->archive($purchase_order);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($purchase_order);
|
||||
return $this->itemResponse($purchase_order);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
@ -638,7 +638,7 @@ class PurchaseOrderController extends BaseController
|
||||
$this->purchase_order_repository->delete($purchase_order);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($purchase_order);
|
||||
return $this->itemResponse($purchase_order);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -684,7 +684,7 @@ class PurchaseOrderController extends BaseController
|
||||
}
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($purchase_order);
|
||||
return $this->itemResponse($purchase_order);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -728,7 +728,7 @@ class QuoteController extends BaseController
|
||||
$this->quote_repo->restore($quote);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($quote);
|
||||
return $this->itemResponse($quote);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -736,7 +736,7 @@ class QuoteController extends BaseController
|
||||
$this->quote_repo->archive($quote);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($quote);
|
||||
return $this->itemResponse($quote);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -744,7 +744,7 @@ class QuoteController extends BaseController
|
||||
$this->quote_repo->delete($quote);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($quote);
|
||||
return $this->itemResponse($quote);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -511,21 +511,21 @@ class RecurringExpenseController extends BaseController
|
||||
$this->recurring_expense_repo->archive($recurring_expense);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($recurring_expense);
|
||||
return $this->itemResponse($recurring_expense);
|
||||
}
|
||||
break;
|
||||
case 'restore':
|
||||
$this->recurring_expense_repo->restore($recurring_expense);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($recurring_expense);
|
||||
return $this->itemResponse($recurring_expense);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
$this->recurring_expense_repo->delete($recurring_expense);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($recurring_expense);
|
||||
return $this->itemResponse($recurring_expense);
|
||||
}
|
||||
break;
|
||||
case 'email':
|
||||
|
@ -662,21 +662,21 @@ class RecurringInvoiceController extends BaseController
|
||||
$this->recurring_invoice_repo->archive($recurring_invoice);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($recurring_invoice);
|
||||
return $this->itemResponse($recurring_invoice);
|
||||
}
|
||||
break;
|
||||
case 'restore':
|
||||
$this->recurring_invoice_repo->restore($recurring_invoice);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($recurring_invoice);
|
||||
return $this->itemResponse($recurring_invoice);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
$this->recurring_invoice_repo->delete($recurring_invoice);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($recurring_invoice);
|
||||
return $this->itemResponse($recurring_invoice);
|
||||
}
|
||||
break;
|
||||
case 'email':
|
||||
|
@ -47,15 +47,4 @@ class LoginRequest extends Request
|
||||
];
|
||||
}
|
||||
|
||||
// public function prepareForValidation()
|
||||
// {
|
||||
// $input = $this->all();
|
||||
|
||||
// // if(base64_decode(base64_encode($input['password'])) === $input['password'])
|
||||
// // $input['password'] = base64_decode($input['password']);
|
||||
|
||||
// // nlog($input['password']);
|
||||
|
||||
// $this->replace($input);
|
||||
// }
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Http\Requests\Task;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\Project;
|
||||
use App\Models\Task;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Validation\Rule;
|
||||
@ -38,19 +39,49 @@ class StoreTaskRequest extends Request
|
||||
$rules['number'] = Rule::unique('tasks')->where('company_id', auth()->user()->company()->id);
|
||||
}
|
||||
|
||||
if(isset($this->client_id))
|
||||
$rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
||||
|
||||
if(isset($this->project_id))
|
||||
$rules['project_id'] = 'bail|required|exists:projects,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
||||
|
||||
$rules['timelog'] = ['bail','array',function ($attribute, $values, $fail) {
|
||||
|
||||
foreach($values as $k)
|
||||
{
|
||||
if(!is_int($k[0]) || !is_int($k[1]))
|
||||
$fail('The '.$attribute.' - '.print_r($k,1).' is invalid. Unix timestamps only.');
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
|
||||
return $this->globalRules($rules);
|
||||
}
|
||||
|
||||
public function prepareForValidation()
|
||||
{
|
||||
$input = $this->all();
|
||||
|
||||
$input = $this->decodePrimaryKeys($this->all());
|
||||
|
||||
if (array_key_exists('status_id', $input) && is_string($input['status_id'])) {
|
||||
$input['status_id'] = $this->decodePrimaryKey($input['status_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);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Http\Requests\Task;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\Project;
|
||||
use App\Utils\Traits\ChecksEntityStatus;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Validation\Rule;
|
||||
@ -39,6 +40,22 @@ class UpdateTaskRequest extends Request
|
||||
$rules['number'] = Rule::unique('tasks')->where('company_id', auth()->user()->company()->id)->ignore($this->task->id);
|
||||
}
|
||||
|
||||
if(isset($this->client_id))
|
||||
$rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
||||
|
||||
if(isset($this->project_id))
|
||||
$rules['project_id'] = 'bail|required|exists:projects,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
||||
|
||||
$rules['timelog'] = ['bail','array',function ($attribute, $values, $fail) {
|
||||
|
||||
foreach($values as $k)
|
||||
{
|
||||
if(!is_int($k[0]) || !is_int($k[1]))
|
||||
$fail('The '.$attribute.' - '.print_r($k,1).' is invalid. Unix timestamps only.');
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
return $this->globalRules($rules);
|
||||
}
|
||||
|
||||
@ -50,6 +67,20 @@ class UpdateTaskRequest extends Request
|
||||
$input['status_id'] = $this->decodePrimaryKey($input['status_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']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (array_key_exists('color', $input) && is_null($input['color'])) {
|
||||
$input['color'] = '';
|
||||
}
|
||||
|
@ -24,7 +24,8 @@ class BlackListRule implements Rule
|
||||
'vusra.com',
|
||||
'fourthgenet.com',
|
||||
'arxxwalls.com',
|
||||
'superhostforumla.com'
|
||||
'superhostforumla.com',
|
||||
'wnpop.com',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -324,6 +324,10 @@ class NinjaMailerJob implements ShouldQueue
|
||||
if($this->company->is_disabled && !$this->override)
|
||||
return true;
|
||||
|
||||
/* To handle spam users we drop all emails from flagged accounts */
|
||||
if(Ninja::isHosted() && $this->company->account && $this->company->account->is_flagged)
|
||||
return true;
|
||||
|
||||
/* On the hosted platform we set default contacts a @example.com email address - we shouldn't send emails to these types of addresses */
|
||||
if(Ninja::isHosted() && $this->nmo->to_user && strpos($this->nmo->to_user->email, '@example.com') !== false)
|
||||
return true;
|
||||
@ -336,10 +340,6 @@ class NinjaMailerJob implements ShouldQueue
|
||||
if(Ninja::isHosted() && $this->company->account && $this->company->account->emailQuotaExceeded())
|
||||
return true;
|
||||
|
||||
/* To handle spam users we drop all emails from flagged accounts */
|
||||
if(Ninja::isHosted() && $this->company->account && $this->company->account->is_flagged)
|
||||
return true;
|
||||
|
||||
/* If the account is verified, we allow emails to flow */
|
||||
if(Ninja::isHosted() && $this->company->account && $this->company->account->is_verified_account) {
|
||||
|
||||
|
@ -236,6 +236,11 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
return $this->hasMany(Task::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function payments()
|
||||
{
|
||||
return $this->hasMany(Payment::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function recurring_invoices()
|
||||
{
|
||||
return $this->hasMany(RecurringInvoice::class)->withTrashed();
|
||||
@ -627,11 +632,6 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
public function payments()
|
||||
{
|
||||
return $this->hasMany(Payment::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function timezone_offset()
|
||||
{
|
||||
$offset = 0;
|
||||
|
@ -15,6 +15,7 @@ use App\Models\Invoice;
|
||||
use App\Services\AbstractService;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class HandleRestore extends AbstractService
|
||||
{
|
||||
@ -24,6 +25,10 @@ class HandleRestore extends AbstractService
|
||||
|
||||
private $payment_total = 0;
|
||||
|
||||
private $total_payments = 0;
|
||||
|
||||
private $adjustment_amount = 0;
|
||||
|
||||
public function __construct(Invoice $invoice)
|
||||
{
|
||||
$this->invoice = $invoice;
|
||||
@ -47,16 +52,90 @@ class HandleRestore extends AbstractService
|
||||
//adjust ledger balance
|
||||
$this->invoice->ledger()->updateInvoiceBalance($this->invoice->balance, "Restored invoice {$this->invoice->number}")->save();
|
||||
|
||||
$this->invoice->client->service()->updateBalance($this->invoice->balance)->save();
|
||||
$this->invoice->client
|
||||
->service()
|
||||
->updateBalance($this->invoice->balance)
|
||||
->updatePaidToDate($this->invoice->paid_to_date)
|
||||
->save();
|
||||
|
||||
$this->windBackInvoiceNumber();
|
||||
|
||||
$this->invoice->is_deleted = false;
|
||||
$this->invoice->save();
|
||||
|
||||
$this->restorePaymentables()
|
||||
->setAdjustmentAmount()
|
||||
->adjustPayments();
|
||||
|
||||
return $this->invoice;
|
||||
}
|
||||
|
||||
/* Touches all paymentables as deleted */
|
||||
private function restorePaymentables()
|
||||
{
|
||||
$this->invoice->payments->each(function ($payment) {
|
||||
$payment->paymentables()
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->update(['deleted_at' => false]);
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
private function setAdjustmentAmount()
|
||||
{
|
||||
foreach ($this->invoice->payments as $payment) {
|
||||
$this->adjustment_amount += $payment->paymentables
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->sum(DB::raw('amount'));
|
||||
|
||||
$this->adjustment_amount += $payment->paymentables
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->sum(DB::raw('refunded'));
|
||||
}
|
||||
|
||||
$this->total_payments = $this->invoice->payments->sum('amount') - $this->invoice->payments->sum('refunded');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function adjustPayments()
|
||||
{
|
||||
//if total payments = adjustment amount - that means we need to delete the payments as well.
|
||||
|
||||
if ($this->adjustment_amount == $this->total_payments) {
|
||||
$this->invoice->payments()->update(['payments.deleted_at' => null, 'payments.is_deleted' => false]);
|
||||
} else {
|
||||
|
||||
//adjust payments down by the amount applied to the invoice payment.
|
||||
|
||||
$this->invoice->payments->each(function ($payment) {
|
||||
$payment_adjustment = $payment->paymentables
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->sum(DB::raw('amount'));
|
||||
|
||||
$payment_adjustment -= $payment->paymentables
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->sum(DB::raw('refunded'));
|
||||
|
||||
$payment->amount += $payment_adjustment;
|
||||
$payment->applied += $payment_adjustment;
|
||||
$payment->is_deleted = false;
|
||||
$payment->restore();
|
||||
$payment->save();
|
||||
});
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
private function windBackInvoiceNumber()
|
||||
{
|
||||
$findme = '_'.ctrans('texts.deleted');
|
||||
|
@ -394,7 +394,7 @@ class Design extends BaseDesign
|
||||
public function productTable(): array
|
||||
{
|
||||
$product_items = collect($this->entity->line_items)->filter(function ($item) {
|
||||
return $item->type_id == 1 || $item->type_id == 6;
|
||||
return $item->type_id == 1 || $item->type_id == 6 || $item->type_id == 5;
|
||||
});
|
||||
|
||||
if (count($product_items) == 0) {
|
||||
|
@ -282,9 +282,9 @@ trait MakesInvoiceValues
|
||||
}
|
||||
|
||||
if ($table_type == '$task' && $item->type_id != 2) {
|
||||
if ($item->type_id != 4 && $item->type_id != 5) {
|
||||
// if ($item->type_id != 4 && $item->type_id != 5) {
|
||||
continue;
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
$helpers = new Helpers();
|
||||
|
@ -136,7 +136,6 @@
|
||||
"if [ \"${IS_DOCKER:-false}\" != \"true\" ]; then vendor/bin/snappdf download; fi"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"vendor/bin/snappdf download",
|
||||
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
||||
],
|
||||
"post-root-package-install": [
|
||||
|
@ -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.11',
|
||||
'app_tag' => '5.5.11',
|
||||
'app_version' => '5.5.12',
|
||||
'app_tag' => '5.5.12',
|
||||
'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: "/canvaskit/"
|
||||
canvasKitBaseUrl: "{{config('ninja.app_url')}}/canvaskit/"
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
|
@ -15,6 +15,7 @@ use App\Factory\InvoiceItemFactory;
|
||||
use App\Models\Client;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
@ -41,6 +42,150 @@ class DeleteInvoiceTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testDeleteAndRestoreInvoice()
|
||||
{
|
||||
//create an invoice for 36000 with a partial of 6000
|
||||
|
||||
$data = [
|
||||
'name' => 'A Nice Client - About to be deleted',
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/clients', $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$client_hash_id = $arr['data']['id'];
|
||||
$client = Client::find($this->decodePrimaryKey($client_hash_id));
|
||||
|
||||
$this->assertEquals($client->balance, 0);
|
||||
$this->assertEquals($client->paid_to_date, 0);
|
||||
|
||||
$line_items = [];
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 36000;
|
||||
|
||||
$line_items[] = (array) $item;
|
||||
|
||||
$invoice = [
|
||||
'status_id' => 1,
|
||||
'number' => '',
|
||||
'discount' => 0,
|
||||
'is_amount_discount' => 1,
|
||||
'po_number' => '3434343',
|
||||
'public_notes' => 'notes',
|
||||
'is_deleted' => 0,
|
||||
'partial' => 6000,
|
||||
'custom_value1' => 0,
|
||||
'custom_value2' => 0,
|
||||
'custom_value3' => 0,
|
||||
'custom_value4' => 0,
|
||||
'client_id' => $client_hash_id,
|
||||
'line_items' => (array) $line_items,
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/invoices/', $invoice)
|
||||
->assertStatus(200);
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$invoice_one_hashed_id = $arr['data']['id'];
|
||||
|
||||
$invoice = Invoice::find($this->decodePrimaryKey($invoice_one_hashed_id));
|
||||
|
||||
$invoice = $invoice->service()->markSent()->save();
|
||||
|
||||
$this->assertEquals(6000, $invoice->partial);
|
||||
$this->assertEquals(36000, $invoice->amount);
|
||||
|
||||
|
||||
// apply a payment of 6000
|
||||
|
||||
$data = [
|
||||
'amount' => 6000,
|
||||
'client_id' => $client->hashed_id,
|
||||
'invoices' => [
|
||||
[
|
||||
'invoice_id' => $invoice->hashed_id,
|
||||
'amount' => 6000,
|
||||
],
|
||||
],
|
||||
'date' => '2019/12/12',
|
||||
];
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/payments?include=invoices', $data);
|
||||
} catch (ValidationException $e) {
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
$this->assertNotNull($message);
|
||||
}
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$payment_id = $arr['data']['id'];
|
||||
|
||||
$payment = Payment::withTrashed()->whereId($this->decodePrimaryKey($payment_id))->first();
|
||||
|
||||
$this->assertEquals(6000, $payment->amount);
|
||||
$this->assertEquals(6000, $payment->applied);
|
||||
|
||||
$this->assertEquals(6000, $payment->client->paid_to_date);
|
||||
|
||||
$invoice = $invoice->fresh();
|
||||
|
||||
$this->assertEquals(30000, $invoice->balance);
|
||||
$this->assertEquals(6000, $invoice->paid_to_date);
|
||||
|
||||
//delete the invoice an inspect the balances
|
||||
|
||||
$invoice_repo = new InvoiceRepository();
|
||||
|
||||
$invoice = $invoice_repo->delete($invoice);
|
||||
$invoice = $invoice->fresh();
|
||||
|
||||
$this->assertTrue($invoice->is_deleted);
|
||||
|
||||
$payment = $payment->fresh();
|
||||
|
||||
$this->assertTrue($payment->is_deleted);
|
||||
$this->assertEquals(4, $payment->status_id);
|
||||
|
||||
$client->fresh();
|
||||
|
||||
$this->assertEquals(0, $client->balance);
|
||||
$this->assertEquals(0, $client->paid_to_date);
|
||||
|
||||
//restore the invoice. this should also rehydrate the payments and restore the correct paid to dates on the client record
|
||||
|
||||
$invoice_repo->restore($invoice);
|
||||
$invoice = $invoice->fresh();
|
||||
$client = $client->fresh();
|
||||
$payment = $payment->fresh();
|
||||
|
||||
$this->assertEquals(30000, $invoice->balance);
|
||||
$this->assertEquals(6000, $invoice->paid_to_date);
|
||||
$this->assertEquals(6000, $client->paid_to_date);
|
||||
$this->assertEquals(30000, $client->balance);
|
||||
$this->assertEquals(6000, $payment->amount);
|
||||
$this->assertFalse($payment->is_deleted);
|
||||
$this->assertNull($payment->deleted_at);
|
||||
|
||||
}
|
||||
|
||||
public function testInvoiceDeletionAfterCancellation()
|
||||
{
|
||||
$data = [
|
||||
|
@ -46,6 +46,18 @@ class InvoiceTest extends TestCase
|
||||
$this->makeTestData();
|
||||
}
|
||||
|
||||
|
||||
public function testInvoiceArchiveAction()
|
||||
{
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/invoices/'.$this->invoice->hashed_id.'/archive',)
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
|
||||
public function testMarkingDeletedInvoiceAsSent()
|
||||
{
|
||||
Client::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id])->each(function ($c) {
|
||||
@ -290,4 +302,6 @@ class InvoiceTest extends TestCase
|
||||
])->post('/api/v1/invoices/', $data)
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -42,6 +42,97 @@ class TaskApiTest extends TestCase
|
||||
Model::reguard();
|
||||
}
|
||||
|
||||
public function testTimeLogValidation()
|
||||
{
|
||||
$data = [
|
||||
'timelog' => $this->faker->firstName(),
|
||||
];
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/tasks', $data);
|
||||
|
||||
$arr = $response->json();
|
||||
} catch (ValidationException $e) {
|
||||
$response->assertStatus(302);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function testTimeLogValidation1()
|
||||
{
|
||||
$data = [
|
||||
'timelog' => [[1,2],[3,4]],
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/tasks', $data);
|
||||
|
||||
$arr = $response->json();
|
||||
$response->assertStatus(200);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function testTimeLogValidation2()
|
||||
{
|
||||
$data = [
|
||||
'timelog' => [],
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/tasks', $data);
|
||||
|
||||
$arr = $response->json();
|
||||
$response->assertStatus(200);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function testTimeLogValidation3()
|
||||
{
|
||||
$data = [
|
||||
'timelog' => [["a","b"],["c","d"]],
|
||||
];
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/tasks', $data);
|
||||
|
||||
$arr = $response->json();
|
||||
} catch (ValidationException $e) {
|
||||
$response->assertStatus(302);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function testTimeLogValidation4()
|
||||
{
|
||||
$data = [
|
||||
'timelog' => [[1,2],[3,0]],
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/tasks', $data);
|
||||
|
||||
$arr = $response->json();
|
||||
$response->assertStatus(200);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function testStartTask()
|
||||
{
|
||||
$log = [
|
||||
@ -76,6 +167,7 @@ class TaskApiTest extends TestCase
|
||||
$data = [
|
||||
'description' => $this->faker->firstName(),
|
||||
'number' => 'taskynumber',
|
||||
'client_id' => $this->client->id,
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
@ -126,6 +218,24 @@ class TaskApiTest extends TestCase
|
||||
$this->assertNotEmpty($arr['data']['number']);
|
||||
}
|
||||
|
||||
public function testTaskWithBadClientId()
|
||||
{
|
||||
$data = [
|
||||
'client_id' => $this->faker->firstName(),
|
||||
];
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/tasks', $data);
|
||||
$arr = $response->json();
|
||||
} catch (ValidationException $e) {
|
||||
$response->assertStatus(302);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function testTaskPostWithActionStart()
|
||||
{
|
||||
$data = [
|
||||
|
@ -13,6 +13,7 @@ namespace Tests\Unit;
|
||||
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use App\Helpers\Invoice\InvoiceSumInclusive;
|
||||
use App\Models\Invoice;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\MockAccountData;
|
||||
@ -41,11 +42,47 @@ class InvoiceTest extends TestCase
|
||||
|
||||
$this->invoice->line_items = $this->buildLineItems();
|
||||
|
||||
$this->invoice->usesinclusive_taxes = true;
|
||||
$this->invoice->uses_inclusive_taxes = true;
|
||||
|
||||
$this->invoice_calc = new InvoiceSum($this->invoice);
|
||||
}
|
||||
|
||||
public function testInclusiveRounding()
|
||||
{
|
||||
$this->invoice->line_items = [];
|
||||
$this->invoice->discount = 0;
|
||||
$this->invoice->uses_inclusive_taxes = true;
|
||||
$this->invoice->save();
|
||||
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 50;
|
||||
$item->tax_name1 = "taxy";
|
||||
$item->tax_rate1 = 19;
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 50;
|
||||
$item->tax_name1 = "taxy";
|
||||
$item->tax_rate1 = 19;
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
$this->invoice->line_items = $line_items;
|
||||
$this->invoice->save();
|
||||
|
||||
$invoice_calc = new InvoiceSumInclusive($this->invoice);
|
||||
|
||||
$invoice_calc->build();
|
||||
// $this->invoice->save();
|
||||
|
||||
$this->assertEquals($invoice_calc->getTotalTaxes(), 15.96);
|
||||
|
||||
}
|
||||
|
||||
private function buildLineItems()
|
||||
{
|
||||
$line_items = [];
|
||||
|
Loading…
Reference in New Issue
Block a user