diff --git a/app/Models/Expense.php b/app/Models/Expense.php index dccf548c71..88107688fe 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -146,12 +146,9 @@ class Expense extends BaseModel ]; public static array $bulk_update_columns = [ - 'tax_rate1', - 'tax_name1', - 'tax_rate2', - 'tax_name2', - 'tax_rate3', - 'tax_name3', + 'tax1', + 'tax2', + 'tax3', 'custom_value1', 'custom_value2', 'custom_value3', diff --git a/app/Models/Product.php b/app/Models/Product.php index 1a96b690df..3189e5c283 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -216,7 +216,7 @@ class Product extends BaseModel return $converter->convert($this->notes ?? ''); } - public static function markdownHelp(string $notes = '') + public static function markdownHelp(?string $notes = '') { $converter = new CommonMarkConverter([ @@ -226,7 +226,7 @@ class Product extends BaseModel ], ]); - return $converter->convert($notes); + return $converter->convert($notes ?? ''); } diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index 07972881e0..3211161174 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -247,12 +247,9 @@ class RecurringInvoice extends BaseModel protected $touches = []; public static array $bulk_update_columns = [ - 'tax_rate1', - 'tax_name1', - 'tax_rate2', - 'tax_name2', - 'tax_rate3', - 'tax_name3', + 'tax1', + 'tax2', + 'tax3', 'custom_value1', 'custom_value2', 'custom_value3', diff --git a/app/Repositories/BaseRepository.php b/app/Repositories/BaseRepository.php index 285a42005e..6deed887b2 100644 --- a/app/Repositories/BaseRepository.php +++ b/app/Repositories/BaseRepository.php @@ -396,23 +396,24 @@ class BaseRepository public function bulkUpdate(\Illuminate\Database\Eloquent\Builder $model, string $column, mixed $new_value): void { /** Handle taxes being updated */ - if(in_array($column, ['tax_name1','tax_name2','tax_name3'])) { + if(in_array($column, ['tax1','tax2','tax3'])) { $parts = explode("||", $new_value); if (count($parts) !== 2) return; - $tax_name = trim($parts[0]); + $tax_name_column = str_replace("tax", "tax_name", $column); $rate = filter_var($parts[1], FILTER_VALIDATE_FLOAT); - + $tax_name = $parts[0]; + if ($rate === false) return; - $taxrate_column = str_replace("name", "rate", $column); + $taxrate_column = str_replace("tax", "tax_rate", $column); $model->update([ - $column => $tax_name, + $tax_name_column => $tax_name, $taxrate_column => $rate, ]); return; diff --git a/app/Services/Payment/DeletePayment.php b/app/Services/Payment/DeletePayment.php index 74973c0f8a..ae323ed4e5 100644 --- a/app/Services/Payment/DeletePayment.php +++ b/app/Services/Payment/DeletePayment.php @@ -133,11 +133,16 @@ class DeletePayment //sometimes the payment is NOT created properly, this catches the payment and prevents the paid to date reducing inappropriately. if ($this->update_client_paid_to_date) { + + $reduced_paid_to_date = $this->payment->amount < 0 ? $this->payment->amount * -1 : min(0, ($this->payment->amount - $this->payment->refunded - $this->_paid_to_date_deleted) * -1); + + // $reduced_paid_to_date = min(0, ($this->payment->amount - $this->payment->refunded - $this->_paid_to_date_deleted) * -1); + $this->payment - ->client - ->service() - ->updatePaidToDate(min(0, ($this->payment->amount - $this->payment->refunded - $this->_paid_to_date_deleted) * -1)) - ->save(); + ->client + ->service() + ->updatePaidToDate($reduced_paid_to_date) + ->save(); } return $this; diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index e4cf16d5d1..b0ba65e404 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -124,7 +124,7 @@ class TemplateService $this->twig->addFilter($filter); $allowedTags = ['if', 'for', 'set', 'filter']; - $allowedFilters = ['replace', 'escape', 'e', 'upper', 'lower', 'capitalize', 'filter', 'length', 'merge','format_currency', 'format_number','format_percent_number','map', 'join', 'first', 'date', 'sum', 'number_format','nl2br']; + $allowedFilters = ['replace', 'escape', 'e', 'upper', 'lower', 'capitalize', 'filter', 'length', 'merge','format_currency', 'format_number','format_percent_number','map', 'join', 'first', 'date', 'sum', 'number_format','nl2br','striptags']; $allowedFunctions = ['range', 'cycle', 'constant', 'date',]; $allowedProperties = ['type_id']; $allowedMethods = ['img','t']; diff --git a/lang/en/texts.php b/lang/en/texts.php index dc311e2a10..c0c9d26e70 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5364,7 +5364,7 @@ $lang = array( 'merged_vendors' => 'Successfully merged vendors', 'hidden_taxes_warning' => 'Somes taxes are hidden due to current tax settings. :link', 'tax3' => 'Third Tax', - + 'negative_payment_warning' => 'Are you sure you want to create a negative payment? This cannot be used as a credit or payment.' ); return $lang; diff --git a/tests/Feature/ClassificationTest.php b/tests/Feature/ClassificationTest.php index 4ed072e928..ba72be59b8 100644 --- a/tests/Feature/ClassificationTest.php +++ b/tests/Feature/ClassificationTest.php @@ -33,7 +33,6 @@ class ClassificationTest extends TestCase $this->makeTestData(); - } public function testClientClassification() diff --git a/tests/Feature/ExpenseApiTest.php b/tests/Feature/ExpenseApiTest.php index bcad510fbb..5dc9b3b461 100644 --- a/tests/Feature/ExpenseApiTest.php +++ b/tests/Feature/ExpenseApiTest.php @@ -66,7 +66,7 @@ class ExpenseApiTest extends TestCase $data = [ 'action' => 'bulk_update', 'ids' => $expenses->get()->pluck('hashed_id'), - 'column' => 'tax_name1', + 'column' => 'tax1', 'new_value' => 'GST||10', ]; diff --git a/tests/Feature/Export/ExportCsvTest.php b/tests/Feature/Export/ExportCsvTest.php deleted file mode 100644 index 977c2d54ac..0000000000 --- a/tests/Feature/Export/ExportCsvTest.php +++ /dev/null @@ -1,81 +0,0 @@ -withoutMiddleware( - ThrottleRequests::class - ); - - $this->makeTestData(); - - $this->withoutExceptionHandling(); - } - - public function testExportCsv() - { - $csv = Writer::createFromFileObject(new \SplTempFileObject()); - - $header_invoice = Invoice::take(10)->get()->toArray(); - $header_item = $header_invoice[0]['line_items'][0]; - unset($header_invoice[0]['line_items']); - - $header_invoice_keys = array_keys($header_invoice[0]); - $header_item_keys = array_keys((array) $header_item); - - $header_invoice_values = array_values($header_invoice[0]); - $header_item_values = array_values((array) $header_item); - - $merged_values = array_merge($header_invoice_values, (array) $header_item_values); - $merged_keys = array_merge($header_invoice_keys, (array) $header_item_keys); - - // nlog(print_r($merged_keys, 1)); - // nlog(print_r($merged_values, 1)); - - foreach ($merged_keys as &$key) { - $key = ctrans('texts.'.$key); - } - - $csv->insertOne($merged_keys); - - foreach (Invoice::take(10)->get() as $invoice) { - foreach ($invoice->line_items as $item) { - unset($invoice->line_items); - - $csv->insertOne(array_merge($invoice->toArray(), (array) $item)); - } - } - - // Storage::put('invy.csv', $csv->getContent()); - - $this->markTestSkipped(); - } -} diff --git a/tests/Feature/PaymentTest.php b/tests/Feature/PaymentTest.php index 0b44556b6a..53ae567072 100644 --- a/tests/Feature/PaymentTest.php +++ b/tests/Feature/PaymentTest.php @@ -62,6 +62,64 @@ class PaymentTest extends TestCase ); } + public function testNegativePaymentPaidToDate() + { + + $c = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + ]); + + $this->assertEquals(0, $c->balance); + $this->assertEquals(0, $c->paid_to_date); + $this->assertEquals(0, $c->credit_balance); + $this->assertEquals(0, $c->payment_balance); + + $data = [ + 'amount' => -500, + 'client_id' => $c->hashed_id, + 'invoices' => [ + ], + 'credits' => [ + ], + 'date' => '2020/12/11', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson('/api/v1/payments/', $data); + + $response->assertStatus(200); + + $p = $response->json()['data']; + + $payment = Payment::find($this->decodePrimaryKey($p['id'])); + + $this->assertEquals(-500, $payment->amount); + $this->assertEquals(0, $payment->refunded); + $this->assertEquals(0, $payment->applied); + + $c = $c->fresh(); + + $this->assertEquals(0, $c->balance); + $this->assertEquals(-500, $c->paid_to_date); + $this->assertEquals(0, $c->credit_balance); + $this->assertEquals(0, $c->payment_balance); + + $p = $payment->service()->deletePayment()->save(); + + $c = $c->fresh(); + + $this->assertEquals(0, $c->balance); + $this->assertEquals(0, $c->paid_to_date); + $this->assertEquals(0, $c->credit_balance); + $this->assertEquals(0, $c->payment_balance); + + + + } + public function testNullPaymentAmounts() { diff --git a/tests/MockAccountData.php b/tests/MockAccountData.php index 20e55c9339..aad8866a89 100644 --- a/tests/MockAccountData.php +++ b/tests/MockAccountData.php @@ -32,6 +32,7 @@ use App\Models\ClientContact; use App\Models\Company; use App\Models\CompanyGateway; use App\Models\CompanyToken; +use App\Models\Country; use App\Models\Credit; use App\Models\CreditInvitation; use App\Models\Expense; @@ -203,6 +204,10 @@ trait MockAccountData { config(['database.default' => config('ninja.db.default')]); + if(Country::count() == 0){ + Artisan::call('db:seed', ['--force' => true]); + } + $this->faker = \Faker\Factory::create(); $fake_email = $this->faker->email(); @@ -339,6 +344,7 @@ trait MockAccountData 'user_id' => $user_id, 'company_id' => $this->company->id, 'currency_id' => 1, + // 'country_id' => 840, ]); $vendor_contact = VendorContact::factory()->create([ diff --git a/tests/MockUnitData.php b/tests/MockUnitData.php index dab18fc9ed..6b4575af13 100644 --- a/tests/MockUnitData.php +++ b/tests/MockUnitData.php @@ -45,6 +45,11 @@ trait MockUnitData public function makeTestData() { + + if (\App\Models\Country::count() == 0) { + \Illuminate\Support\Facades\Artisan::call('db:seed', ['--force' => true]); + } + $this->faker = \Faker\Factory::create(); $this->account = Account::factory()->create(); diff --git a/tests/Unit/EntityTest.php b/tests/Unit/EntityTest.php index c6b28fdb1c..5cebbf190f 100644 --- a/tests/Unit/EntityTest.php +++ b/tests/Unit/EntityTest.php @@ -34,7 +34,7 @@ use Illuminate\Foundation\Testing\DatabaseTransactions; class EntityTest extends TestCase { use MockAccountData; - use DatabaseTransactions; + // use DatabaseTransactions; public $invoice; @@ -66,6 +66,8 @@ class EntityTest extends TestCase $this->assertEquals('InvoiceInvitation', class_basename($entity_type)); $this->assertEquals('InvoiceInvitation', class_basename($invitation)); + + $this->invoice->forceDelete(); } public function testDocumentRelationExists() @@ -84,4 +86,20 @@ class EntityTest extends TestCase $this->assertTrue(method_exists(Task::class, 'documents')); } + + protected function tearDown(): void + { + + + // $this->company->company_users->each(function ($company_user) { + // $company_user->user->forceDelete(); + // $company_user->forceDelete(); + // }); + + // // Clean up any resources or reset state if necessary + // $this->account->delete(); + + + parent::tearDown(); + } } diff --git a/tests/Unit/GeneratesConvertedQuoteCounterTest.php b/tests/Unit/GeneratesConvertedQuoteCounterTest.php index 7930bb774a..5d172e6d00 100644 --- a/tests/Unit/GeneratesConvertedQuoteCounterTest.php +++ b/tests/Unit/GeneratesConvertedQuoteCounterTest.php @@ -11,19 +11,20 @@ namespace Tests\Unit; -use App\Models\Account; -use App\Models\Client; -use App\Models\ClientContact; -use App\Models\Company; -use App\Models\Invoice; -use App\Models\Quote; +use Tests\TestCase; use App\Models\User; -use App\Utils\Traits\GeneratesConvertedQuoteCounter; +use App\Models\Quote; +use App\Models\Client; +use App\Models\Account; +use App\Models\Company; +use App\Models\Country; +use App\Models\Invoice; +use App\Models\ClientContact; use App\Utils\Traits\MakesHash; use Illuminate\Database\Eloquent\Model; -use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Facades\Session; -use Tests\TestCase; +use App\Utils\Traits\GeneratesConvertedQuoteCounter; +use Illuminate\Foundation\Testing\DatabaseTransactions; /** * @@ -47,6 +48,11 @@ class GeneratesConvertedQuoteCounterTest extends TestCase Session::start(); $this->faker = \Faker\Factory::create(); Model::reguard(); + + if (\App\Models\Country::count() == 0) { + \Illuminate\Support\Facades\Artisan::call('db:seed', ['--force' => true]); + } + } public function testCounterExtraction() diff --git a/tests/Unit/PermissionsTest.php b/tests/Unit/PermissionsTest.php index bf895156b3..a04b82ef95 100644 --- a/tests/Unit/PermissionsTest.php +++ b/tests/Unit/PermissionsTest.php @@ -40,6 +40,10 @@ class PermissionsTest extends TestCase protected function setUp(): void { parent::setUp(); + + if (\App\Models\Country::count() == 0) { + \Illuminate\Support\Facades\Artisan::call('db:seed', ['--force' => true]); + } $this->faker = \Faker\Factory::create(); diff --git a/tests/Unit/RecurringDateTest.php b/tests/Unit/RecurringDateTest.php index 91bc6fd115..e68a144f68 100644 --- a/tests/Unit/RecurringDateTest.php +++ b/tests/Unit/RecurringDateTest.php @@ -50,10 +50,6 @@ class RecurringDateTest extends TestCase $this->assertEquals('2022-02-28', $next_month->format('Y-m-d')); - // $next_month = $today->addMonthNoOverflow(); - - // $this->assertEquals('2022-03-31', $next_month->format('Y-m-d')); - } } diff --git a/tests/Unit/RecurringExpenseCloneTest.php b/tests/Unit/RecurringExpenseCloneTest.php index a16e7957a4..46fa54be8c 100644 --- a/tests/Unit/RecurringExpenseCloneTest.php +++ b/tests/Unit/RecurringExpenseCloneTest.php @@ -33,6 +33,11 @@ class RecurringExpenseCloneTest extends TestCase { parent::setUp(); $this->faker = \Faker\Factory::create(); + + if (\App\Models\Country::count() == 0) { + \Illuminate\Support\Facades\Artisan::call('db:seed', ['--force' => true]); + } + } public function testBadBase64String()