mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-12 14:12:44 +01:00
Fixes for refunds with credits present
This commit is contained in:
parent
a80f5c665d
commit
7973d7c882
@ -73,7 +73,10 @@ class TaskStatusController extends BaseController
|
||||
*/
|
||||
public function create(CreateTaskStatusRequest $request)
|
||||
{
|
||||
$task_status = TaskStatusFactory::create(auth()->user()->company()->id, auth()->user()->id);
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
$task_status = TaskStatusFactory::create($user->company()->id, auth()->user()->id);
|
||||
|
||||
return $this->itemResponse($task_status);
|
||||
}
|
||||
@ -87,8 +90,10 @@ class TaskStatusController extends BaseController
|
||||
*/
|
||||
public function store(StoreTaskStatusRequest $request)
|
||||
{
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
$task_status = TaskStatusFactory::create(auth()->user()->company()->id, auth()->user()->id);
|
||||
$task_status = TaskStatusFactory::create($user->company()->id, auth()->user()->id);
|
||||
$task_status->fill($request->all());
|
||||
|
||||
$task_status->save();
|
||||
|
@ -29,7 +29,9 @@ class RefundPayment
|
||||
|
||||
private $credit_note;
|
||||
|
||||
private $total_refund;
|
||||
private float $total_refund = 0;
|
||||
|
||||
private float $credits_used = 0;
|
||||
|
||||
private $gateway_refund_status;
|
||||
|
||||
@ -45,8 +47,6 @@ class RefundPayment
|
||||
|
||||
$this->refund_data = $refund_data;
|
||||
|
||||
$this->total_refund = 0;
|
||||
|
||||
$this->gateway_refund_status = false;
|
||||
|
||||
$this->activity_repository = new ActivityRepository();
|
||||
@ -56,9 +56,9 @@ class RefundPayment
|
||||
{
|
||||
$this->payment = $this
|
||||
->calculateTotalRefund() //sets amount for the refund (needed if we are refunding multiple invoices in one payment)
|
||||
->updateCreditables() //return the credits first
|
||||
->processGatewayRefund() //process the gateway refund if needed
|
||||
->setStatus() //sets status of payment
|
||||
->updateCreditables() //return the credits first
|
||||
->updatePaymentables() //update the paymentable items
|
||||
->adjustInvoices()
|
||||
->finalize()
|
||||
@ -104,12 +104,14 @@ class RefundPayment
|
||||
*/
|
||||
private function processGatewayRefund()
|
||||
{
|
||||
if ($this->refund_data['gateway_refund'] !== false && $this->total_refund > 0) {
|
||||
$net_refund = ($this->total_refund - $this->credits_used);
|
||||
|
||||
if ($this->refund_data['gateway_refund'] !== false && $net_refund > 0) {
|
||||
if ($this->payment->company_gateway) {
|
||||
$response = $this->payment->company_gateway->driver($this->payment->client)->refund($this->payment, $this->total_refund);
|
||||
$response = $this->payment->company_gateway->driver($this->payment->client)->refund($this->payment, $net_refund);
|
||||
|
||||
if($response['amount'] ?? false)
|
||||
$this->total_refund = $response['amount'];
|
||||
$net_refund = $response['amount'];
|
||||
|
||||
if($response['voided'] ?? false)
|
||||
{
|
||||
@ -123,7 +125,7 @@ class RefundPayment
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
$this->payment->refunded += $this->total_refund;
|
||||
$this->payment->refunded += $net_refund;
|
||||
|
||||
if ($response['success'] == false) {
|
||||
$this->payment->save();
|
||||
@ -132,7 +134,7 @@ class RefundPayment
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->payment->refunded += $this->total_refund;
|
||||
$this->payment->refunded += $net_refund;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -227,23 +229,29 @@ class RefundPayment
|
||||
*/
|
||||
private function updateCreditables()
|
||||
{
|
||||
|
||||
if ($this->payment->credits()->exists()) {
|
||||
|
||||
$amount_to_refund = $this->total_refund;
|
||||
|
||||
//Adjust credits first!!!
|
||||
foreach ($this->payment->credits as $paymentable_credit) {
|
||||
$available_credit = $paymentable_credit->pivot->amount - $paymentable_credit->pivot->refunded;
|
||||
|
||||
if ($available_credit > $this->total_refund) {
|
||||
$paymentable_credit->pivot->refunded += $this->total_refund;
|
||||
if ($available_credit > $amount_to_refund) {
|
||||
$paymentable_credit->pivot->refunded += $amount_to_refund;
|
||||
$paymentable_credit->pivot->save();
|
||||
|
||||
$paymentable_credit->service()
|
||||
->setStatus(Credit::STATUS_SENT)
|
||||
->updateBalance($this->total_refund)
|
||||
->updatePaidToDate($this->total_refund * -1)
|
||||
->adjustBalance($amount_to_refund)
|
||||
->updatePaidToDate($amount_to_refund * -1)
|
||||
->save();
|
||||
|
||||
|
||||
$this->total_refund = 0;
|
||||
|
||||
$this->credits_used += $amount_to_refund;
|
||||
$amount_to_refund = 0;
|
||||
|
||||
} else {
|
||||
$paymentable_credit->pivot->refunded += $available_credit;
|
||||
$paymentable_credit->pivot->save();
|
||||
@ -254,10 +262,12 @@ class RefundPayment
|
||||
->updatePaidToDate($available_credit * -1)
|
||||
->save();
|
||||
|
||||
$this->total_refund -= $available_credit;
|
||||
$this->credits_used += $available_credit;
|
||||
$amount_to_refund -= $available_credit;
|
||||
|
||||
}
|
||||
|
||||
if ($this->total_refund == 0) {
|
||||
if ($amount_to_refund == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
73
composer.lock
generated
73
composer.lock
generated
@ -485,16 +485,16 @@
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.281.13",
|
||||
"version": "3.281.14",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "5547757d891495713aa7d5770bf04124d48a6ab5"
|
||||
"reference": "4b5b8aab08ef0add75f086bc03c7651799d187db"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5547757d891495713aa7d5770bf04124d48a6ab5",
|
||||
"reference": "5547757d891495713aa7d5770bf04124d48a6ab5",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/4b5b8aab08ef0add75f086bc03c7651799d187db",
|
||||
"reference": "4b5b8aab08ef0add75f086bc03c7651799d187db",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -574,9 +574,9 @@
|
||||
"support": {
|
||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.281.13"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.281.14"
|
||||
},
|
||||
"time": "2023-09-25T18:07:38+00:00"
|
||||
"time": "2023-09-26T18:15:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@ -1353,16 +1353,16 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "3.6.7",
|
||||
"version": "3.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/dbal.git",
|
||||
"reference": "8e0e268052b4a8974cb00215bb2892787021614f"
|
||||
"reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/8e0e268052b4a8974cb00215bb2892787021614f",
|
||||
"reference": "8e0e268052b4a8974cb00215bb2892787021614f",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/00d03067f07482f025d41ab55e4ba0db5eca2cdf",
|
||||
"reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1378,9 +1378,9 @@
|
||||
"doctrine/coding-standard": "12.0.0",
|
||||
"fig/log-test": "^1",
|
||||
"jetbrains/phpstorm-stubs": "2023.1",
|
||||
"phpstan/phpstan": "1.10.34",
|
||||
"phpstan/phpstan": "1.10.35",
|
||||
"phpstan/phpstan-strict-rules": "^1.5",
|
||||
"phpunit/phpunit": "9.6.12",
|
||||
"phpunit/phpunit": "9.6.13",
|
||||
"psalm/plugin-phpunit": "0.18.4",
|
||||
"slevomat/coding-standard": "8.13.1",
|
||||
"squizlabs/php_codesniffer": "3.7.2",
|
||||
@ -1446,7 +1446,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/dbal/issues",
|
||||
"source": "https://github.com/doctrine/dbal/tree/3.6.7"
|
||||
"source": "https://github.com/doctrine/dbal/tree/3.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1462,7 +1462,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-19T20:15:41+00:00"
|
||||
"time": "2023-09-26T20:56:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/deprecations",
|
||||
@ -4287,16 +4287,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v10.24.0",
|
||||
"version": "v10.25.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "bcebd0a4c015d5c38aeec299d355a42451dd3726"
|
||||
"reference": "5132dafecbea5825af7cb4d093d4d7df57aecb61"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/bcebd0a4c015d5c38aeec299d355a42451dd3726",
|
||||
"reference": "bcebd0a4c015d5c38aeec299d355a42451dd3726",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/5132dafecbea5825af7cb4d093d4d7df57aecb61",
|
||||
"reference": "5132dafecbea5825af7cb4d093d4d7df57aecb61",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4314,7 +4314,7 @@
|
||||
"ext-tokenizer": "*",
|
||||
"fruitcake/php-cors": "^1.2",
|
||||
"guzzlehttp/uri-template": "^1.0",
|
||||
"laravel/prompts": "^0.1",
|
||||
"laravel/prompts": "^0.1.9",
|
||||
"laravel/serializable-closure": "^1.3",
|
||||
"league/commonmark": "^2.2.1",
|
||||
"league/flysystem": "^3.8.0",
|
||||
@ -4483,20 +4483,20 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2023-09-19T15:25:04+00:00"
|
||||
"time": "2023-09-26T15:22:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/prompts",
|
||||
"version": "v0.1.8",
|
||||
"version": "v0.1.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/prompts.git",
|
||||
"reference": "68dcc65babf92e1fb43cba0b3f78fc3d8002709c"
|
||||
"reference": "b603410e7af1040aa2d29e0a2cdca570bb63e827"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/prompts/zipball/68dcc65babf92e1fb43cba0b3f78fc3d8002709c",
|
||||
"reference": "68dcc65babf92e1fb43cba0b3f78fc3d8002709c",
|
||||
"url": "https://api.github.com/repos/laravel/prompts/zipball/b603410e7af1040aa2d29e0a2cdca570bb63e827",
|
||||
"reference": "b603410e7af1040aa2d29e0a2cdca570bb63e827",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4505,6 +4505,10 @@
|
||||
"php": "^8.1",
|
||||
"symfony/console": "^6.2"
|
||||
},
|
||||
"conflict": {
|
||||
"illuminate/console": ">=10.17.0 <10.25.0",
|
||||
"laravel/framework": ">=10.17.0 <10.25.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.5",
|
||||
"pestphp/pest": "^2.3",
|
||||
@ -4515,6 +4519,11 @@
|
||||
"ext-pcntl": "Required for the spinner to be animated."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "0.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
@ -4529,9 +4538,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/prompts/issues",
|
||||
"source": "https://github.com/laravel/prompts/tree/v0.1.8"
|
||||
"source": "https://github.com/laravel/prompts/tree/v0.1.9"
|
||||
},
|
||||
"time": "2023-09-19T15:33:56+00:00"
|
||||
"time": "2023-09-26T13:14:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/serializable-closure",
|
||||
@ -15037,16 +15046,16 @@
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v3.28.0",
|
||||
"version": "v3.30.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||
"reference": "113e09fea3d2306319ffaa2423fe3de768b28cff"
|
||||
"reference": "95c64693b2f149966a2bc05a7a4981b0343ea52f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/113e09fea3d2306319ffaa2423fe3de768b28cff",
|
||||
"reference": "113e09fea3d2306319ffaa2423fe3de768b28cff",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/95c64693b2f149966a2bc05a7a4981b0343ea52f",
|
||||
"reference": "95c64693b2f149966a2bc05a7a4981b0343ea52f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -15120,7 +15129,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.28.0"
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.30.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -15128,7 +15137,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-22T20:43:40+00:00"
|
||||
"time": "2023-09-26T22:10:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hamcrest/hamcrest-php",
|
||||
|
@ -16,6 +16,8 @@ trait CreatesApplication
|
||||
{
|
||||
$app = require __DIR__.'/../bootstrap/app.php';
|
||||
|
||||
define('STDIN', fopen("php://stdin", "r"));
|
||||
|
||||
$app->make(Kernel::class)->bootstrap();
|
||||
|
||||
Hash::setRounds(4);
|
||||
|
@ -1310,15 +1310,14 @@ class PaymentTest extends TestCase
|
||||
|
||||
];
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/payments?include=invoices', $data);
|
||||
} catch (ValidationException $e) {
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
$this->assertNotNull($message);
|
||||
}
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/payments?include=invoices', $data);
|
||||
|
||||
$response->assertStatus(422);
|
||||
|
||||
}
|
||||
|
||||
public function testPaymentWithSameInvoiceMultipleTimes()
|
||||
|
@ -11,21 +11,22 @@
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Tests\TestCase;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use Tests\MockAccountData;
|
||||
use App\Models\ClientContact;
|
||||
use App\Factory\ClientFactory;
|
||||
use App\Factory\CreditFactory;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
|
||||
/**
|
||||
* @test
|
||||
@ -37,6 +38,8 @@ class RefundTest extends TestCase
|
||||
use DatabaseTransactions;
|
||||
use MockAccountData;
|
||||
|
||||
public $faker;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
@ -53,7 +56,7 @@ class RefundTest extends TestCase
|
||||
|
||||
$this->makeTestData();
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
// $this->withoutExceptionHandling();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,10 +85,10 @@ class RefundTest extends TestCase
|
||||
|
||||
$this->invoice->save();
|
||||
|
||||
$this->invoice_calc = new InvoiceSum($this->invoice);
|
||||
$this->invoice_calc->build();
|
||||
$invoice_calc = new InvoiceSum($this->invoice);
|
||||
$invoice_calc->build();
|
||||
|
||||
$this->invoice = $this->invoice_calc->getInvoice();
|
||||
$this->invoice = $invoice_calc->getInvoice();
|
||||
$this->invoice->save();
|
||||
|
||||
$data = [
|
||||
@ -119,14 +122,12 @@ class RefundTest extends TestCase
|
||||
|
||||
$response = false;
|
||||
|
||||
try {
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/payments/refund', $data);
|
||||
} catch (ValidationException $e) {
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
}
|
||||
])->postJson('/api/v1/payments/refund', $data);
|
||||
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
@ -165,10 +166,10 @@ class RefundTest extends TestCase
|
||||
|
||||
$this->invoice->save();
|
||||
|
||||
$this->invoice_calc = new InvoiceSum($this->invoice);
|
||||
$this->invoice_calc->build();
|
||||
$invoice_calc = new InvoiceSum($this->invoice);
|
||||
$invoice_calc->build();
|
||||
|
||||
$this->invoice = $this->invoice_calc->getInvoice();
|
||||
$this->invoice = $invoice_calc->getInvoice();
|
||||
$this->invoice->save();
|
||||
|
||||
$this->invoice->setRelation('client', $this->client);
|
||||
@ -217,23 +218,12 @@ class RefundTest extends TestCase
|
||||
'date' => '2020/12/12',
|
||||
];
|
||||
|
||||
$response = false;
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/payments/refund', $data);
|
||||
} catch (ValidationException $e) {
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
|
||||
$this->assertNotNull($message);
|
||||
\Log::error($message);
|
||||
}
|
||||
|
||||
if ($response) {
|
||||
$response->assertStatus(302);
|
||||
}
|
||||
])->postJson('/api/v1/payments/refund', $data);
|
||||
$response->assertStatus(422);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,10 +252,10 @@ class RefundTest extends TestCase
|
||||
|
||||
$this->invoice->save();
|
||||
|
||||
$this->invoice_calc = new InvoiceSum($this->invoice);
|
||||
$this->invoice_calc->build();
|
||||
$invoice_calc = new InvoiceSum($this->invoice);
|
||||
$invoice_calc->build();
|
||||
|
||||
$this->invoice = $this->invoice_calc->getInvoice();
|
||||
$this->invoice = $invoice_calc->getInvoice();
|
||||
$this->invoice->save();
|
||||
|
||||
$data = [
|
||||
@ -346,10 +336,10 @@ class RefundTest extends TestCase
|
||||
|
||||
$this->invoice->save();
|
||||
|
||||
$this->invoice_calc = new InvoiceSum($this->invoice);
|
||||
$this->invoice_calc->build();
|
||||
$invoice_calc = new InvoiceSum($this->invoice);
|
||||
$invoice_calc->build();
|
||||
|
||||
$this->invoice = $this->invoice_calc->getInvoice();
|
||||
$this->invoice = $invoice_calc->getInvoice();
|
||||
$this->invoice->save();
|
||||
|
||||
$data = [
|
||||
@ -439,10 +429,10 @@ class RefundTest extends TestCase
|
||||
|
||||
$this->invoice->save();
|
||||
|
||||
$this->invoice_calc = new InvoiceSum($this->invoice);
|
||||
$this->invoice_calc->build();
|
||||
$invoice_calc = new InvoiceSum($this->invoice);
|
||||
$invoice_calc->build();
|
||||
|
||||
$this->invoice = $this->invoice_calc->getInvoice();
|
||||
$this->invoice = $invoice_calc->getInvoice();
|
||||
$this->invoice->save();
|
||||
|
||||
$data = [
|
||||
@ -485,10 +475,10 @@ class RefundTest extends TestCase
|
||||
|
||||
$this->invoice->save();
|
||||
|
||||
$this->invoice_calc = new InvoiceSum($this->invoice);
|
||||
$this->invoice_calc->build();
|
||||
$invoice_calc = new InvoiceSum($this->invoice);
|
||||
$invoice_calc->build();
|
||||
|
||||
$this->invoice = $this->invoice_calc->getInvoice();
|
||||
$this->invoice = $invoice_calc->getInvoice();
|
||||
$this->invoice->save();
|
||||
|
||||
$data = [
|
||||
@ -553,13 +543,13 @@ class RefundTest extends TestCase
|
||||
|
||||
$this->invoice->line_items = $this->buildLineItems();
|
||||
$this->invoice->uses_inclusive_taxes = false;
|
||||
$this->invoice_client_id = $client->id;
|
||||
$this->invoice->client_id = $client->id;
|
||||
|
||||
$this->invoice->save();
|
||||
$this->invoice_calc = new InvoiceSum($this->invoice);
|
||||
$this->invoice_calc->build();
|
||||
$invoice_calc = new InvoiceSum($this->invoice);
|
||||
$invoice_calc->build();
|
||||
|
||||
$this->invoice = $this->invoice_calc->getInvoice();
|
||||
$this->invoice = $invoice_calc->getInvoice();
|
||||
$this->invoice->save();
|
||||
|
||||
$this->credit = CreditFactory::create($this->company->id, $this->user->id);
|
||||
@ -650,4 +640,172 @@ class RefundTest extends TestCase
|
||||
}
|
||||
|
||||
/*Additional scenarios*/
|
||||
|
||||
public function testRefundsWhenCreditsArePresent()
|
||||
{
|
||||
$i = Invoice::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'status_id' => Invoice::STATUS_SENT,
|
||||
'amount' => 1000,
|
||||
'balance' => 1000,
|
||||
]);
|
||||
|
||||
$c = Credit::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'status_id' => Invoice::STATUS_SENT,
|
||||
'amount' => 100,
|
||||
'balance' => 100,
|
||||
]);
|
||||
|
||||
$data = [
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'invoices' => [
|
||||
[
|
||||
'invoice_id' => $i->hashed_id,
|
||||
'amount' => 1000,
|
||||
],
|
||||
],
|
||||
'credits' => [
|
||||
[
|
||||
'credit_id' => $c->hashed_id,
|
||||
'amount' => 100,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/payments', $data);
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$this->assertEquals(0, $c->fresh()->balance);
|
||||
$this->assertEquals(0, $i->fresh()->balance);
|
||||
|
||||
$payment_id = $arr['data']['id'];
|
||||
|
||||
$refund = [
|
||||
'id' => $payment_id,
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'amount' => 10,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'invoices' => [
|
||||
[
|
||||
'invoice_id' => $i->hashed_id,
|
||||
'amount' => 10,
|
||||
],
|
||||
]
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/payments/refund', $refund);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals(0, $arr['data']['refunded']);
|
||||
|
||||
$this->assertEquals(10, $c->fresh()->balance);
|
||||
$this->assertEquals(10, $i->fresh()->balance);
|
||||
|
||||
}
|
||||
|
||||
public function testRefundsWithSplitCreditAndPaymentRefund()
|
||||
{
|
||||
$i = Invoice::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'status_id' => Invoice::STATUS_SENT,
|
||||
'amount' => 1000,
|
||||
'balance' => 1000,
|
||||
]);
|
||||
|
||||
$c = Credit::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'status_id' => Invoice::STATUS_SENT,
|
||||
'amount' => 100,
|
||||
'balance' => 100,
|
||||
]);
|
||||
|
||||
$data = [
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'invoices' => [
|
||||
[
|
||||
'invoice_id' => $i->hashed_id,
|
||||
'amount' => 1000,
|
||||
],
|
||||
],
|
||||
'credits' => [
|
||||
[
|
||||
'credit_id' => $c->hashed_id,
|
||||
'amount' => 100,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/payments', $data);
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$this->assertEquals(0, $c->fresh()->balance);
|
||||
$this->assertEquals(0, $i->fresh()->balance);
|
||||
|
||||
$payment_id = $arr['data']['id'];
|
||||
$payment = Payment::find($this->decodePrimaryKey($payment_id));
|
||||
|
||||
$this->assertEquals(900, $payment->amount);
|
||||
$this->assertEquals(900, $payment->applied);
|
||||
$this->assertEquals(0, $payment->refunded);
|
||||
|
||||
$refund = [
|
||||
'id' => $payment_id,
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'amount' => 200,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'invoices' => [
|
||||
[
|
||||
'invoice_id' => $i->hashed_id,
|
||||
'amount' => 200,
|
||||
],
|
||||
]
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/payments/refund', $refund);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals(100, $arr['data']['refunded']);
|
||||
|
||||
$this->assertEquals(100, $c->fresh()->balance);
|
||||
$this->assertEquals(200, $i->fresh()->balance);
|
||||
|
||||
$this->assertEquals(900, $payment->fresh()->amount);
|
||||
$this->assertEquals(900, $payment->fresh()->applied);
|
||||
$this->assertEquals(100, $payment->fresh()->refunded);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -43,6 +43,8 @@ class CompanyLedgerTest extends TestCase
|
||||
|
||||
public $account;
|
||||
|
||||
public $faker;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
@ -11,57 +11,58 @@
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use App\DataMapper\ClientRegistrationFields;
|
||||
use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Factory\CompanyUserFactory;
|
||||
use App\Factory\CreditFactory;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Factory\InvoiceInvitationFactory;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Factory\InvoiceToRecurringInvoiceFactory;
|
||||
use App\Factory\PurchaseOrderFactory;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use App\Jobs\Company\CreateCompanyTaskStatuses;
|
||||
use App\Models\Account;
|
||||
use App\Models\BankIntegration;
|
||||
use App\Models\BankTransaction;
|
||||
use App\Models\BankTransactionRule;
|
||||
use App\Models\Task;
|
||||
use App\Models\User;
|
||||
use App\Models\Quote;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\Credit;
|
||||
use App\Models\CreditInvitation;
|
||||
use App\Models\Vendor;
|
||||
use App\Models\Account;
|
||||
use App\Models\Company;
|
||||
use App\Models\Expense;
|
||||
use App\Models\ExpenseCategory;
|
||||
use App\Models\GroupSetting;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Product;
|
||||
use App\Models\Project;
|
||||
use App\Models\PurchaseOrderInvitation;
|
||||
use App\Models\Quote;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\Scheduler;
|
||||
use App\Models\TaskStatus;
|
||||
use App\Utils\TruthSource;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\GroupSetting;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\VendorContact;
|
||||
use App\Factory\CreditFactory;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\RecurringQuote;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Models\BankIntegration;
|
||||
use App\Models\BankTransaction;
|
||||
use App\Models\ExpenseCategory;
|
||||
use App\Models\QuoteInvitation;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Models\CreditInvitation;
|
||||
use App\Models\RecurringExpense;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Models\RecurringQuote;
|
||||
use App\Models\Scheduler;
|
||||
use App\Models\Task;
|
||||
use App\Models\TaskStatus;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\User;
|
||||
use App\Models\Vendor;
|
||||
use App\Models\VendorContact;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\TruthSource;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Factory\CompanyUserFactory;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use App\Models\BankTransactionRule;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use App\Factory\PurchaseOrderFactory;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use App\Models\PurchaseOrderInvitation;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Factory\InvoiceInvitationFactory;
|
||||
use App\DataMapper\ClientRegistrationFields;
|
||||
use App\Jobs\Company\CreateCompanyTaskStatuses;
|
||||
use App\Factory\InvoiceToRecurringInvoiceFactory;
|
||||
|
||||
/**
|
||||
* Class MockAccountData.
|
||||
@ -200,7 +201,9 @@ trait MockAccountData
|
||||
/* Warm up the cache !*/
|
||||
$cached_tables = config('ninja.cached_tables');
|
||||
|
||||
$this->artisan('db:seed --force');
|
||||
Artisan::call('db:seed', [
|
||||
'--force' => true
|
||||
]);
|
||||
|
||||
foreach ($cached_tables as $name => $class) {
|
||||
// check that the table exists in case the migration is pending
|
||||
|
Loading…
Reference in New Issue
Block a user