diff --git a/app/Http/Requests/Login/LoginRequest.php b/app/Http/Requests/Login/LoginRequest.php index 7d0ab21d8cb0..42aed76b9374 100644 --- a/app/Http/Requests/Login/LoginRequest.php +++ b/app/Http/Requests/Login/LoginRequest.php @@ -36,7 +36,7 @@ class LoginRequest extends Request public function rules() { if (Ninja::isHosted()) { - $email_rules = ['required', new BlackListRule, new EmailBlackListRule]; + $email_rules = ['required', new EmailBlackListRule]; } else { $email_rules = 'required'; } diff --git a/app/Models/Client.php b/app/Models/Client.php index a72dd3344c29..8272e2fc10a5 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -812,6 +812,15 @@ class Client extends BaseModel implements HasLocalePreference return $defaults; } + public function setExchangeRate() + { + + $converter = new CurrencyApi(); + + return 1/$converter->convert(1, $this->currency()->id, $this->company->settings->currency_id); + + } + public function timezone_offset() :int { $offset = 0; diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index e435263879b1..045282f41aaf 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -567,7 +567,7 @@ class InvoiceService /* If client currency differs from the company default currency, then insert the client exchange rate on the model.*/ if (! isset($this->invoice->exchange_rate) && $this->invoice->client->currency()->id != (int) $this->invoice->company->settings->currency_id) { - $this->invoice->exchange_rate = $this->invoice->client->currency()->exchange_rate; + $this->invoice->exchange_rate = $this->invoice->client->setExchangeRate(); } if ($this->invoice->client->getSetting('auto_bill_standard_invoices')) { diff --git a/database/migrations/2024_01_09_084515_product_cost_field_population.php b/database/migrations/2024_01_09_084515_product_cost_field_population.php new file mode 100644 index 000000000000..830470d94ca9 --- /dev/null +++ b/database/migrations/2024_01_09_084515_product_cost_field_population.php @@ -0,0 +1,52 @@ +where('is_deleted', false) + ->cursor() + ->each(function (Invoice $invoice) { + + + $line_items = $invoice->line_items; + + foreach ($line_items as $key => $item) + { + + if($item?->product_cost == 0 && $product = Product::where('company_id', $invoice->company_id)->where('product_key', $item->product_key)->where('cost', '>', 0)->first()) + { + $line_items[$key]->product_cost = $product->cost; + } + } + + $invoice->line_items = $line_items; + $invoice->saveQuietly(); + + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/tests/Feature/ClientTest.php b/tests/Feature/ClientTest.php index b09978d6af67..92632dad2380 100644 --- a/tests/Feature/ClientTest.php +++ b/tests/Feature/ClientTest.php @@ -11,25 +11,27 @@ namespace Tests\Feature; +use Tests\TestCase; +use App\Models\User; +use App\Models\Client; +use App\Models\Credit; +use App\Models\Account; +use App\Models\Company; +use App\Models\Currency; +use Tests\MockAccountData; +use Illuminate\Support\Str; +use App\Models\CompanyToken; +use App\Models\ClientContact; +use App\Utils\Traits\MakesHash; +use App\DataMapper\ClientSettings; 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; -use Illuminate\Foundation\Testing\DatabaseTransactions; -use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Support\Facades\Session; -use Illuminate\Support\Str; use Illuminate\Validation\ValidationException; -use Tests\MockAccountData; -use Tests\TestCase; +use Illuminate\Routing\Middleware\ThrottleRequests; +use Illuminate\Foundation\Testing\DatabaseTransactions; /** * @test @@ -65,6 +67,34 @@ class ClientTest extends TestCase $this->makeTestData(); } + public function testClientExchangeRateCalculation() + { + $settings = ClientSettings::defaults(); + $settings->currency_id = 12; + + $c = Client::factory() + ->create([ + 'company_id' => $this->company->id, + 'user_id' => $this->user->id, + 'settings' => $settings + ]); + + $settings = $this->company->settings; + $settings->currency_id = '3'; + + $this->company->saveSettings($settings, $this->company); + + $client_exchange_rate = round($c->setExchangeRate(),2); + + $aud_currency = Currency::find(12); + $eur_currency = Currency::find(3); + + $synthetic_exchange = $aud_currency->exchange_rate / $eur_currency->exchange_rate; + + $this->assertEquals($client_exchange_rate, round($synthetic_exchange,2)); + + } + public function testStoreClientFixes2() { $data = [ diff --git a/tests/Feature/ProductTest.php b/tests/Feature/ProductTest.php index 7a709e398d33..40af31f9a9cc 100644 --- a/tests/Feature/ProductTest.php +++ b/tests/Feature/ProductTest.php @@ -11,14 +11,16 @@ namespace Tests\Feature; +use App\DataMapper\InvoiceItem; +use Tests\TestCase; +use App\Models\Invoice; use App\Models\Product; +use Tests\MockAccountData; use App\Utils\Traits\MakesHash; use Illuminate\Database\Eloquent\Model; -use Illuminate\Foundation\Testing\DatabaseTransactions; -use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Support\Facades\Session; -use Tests\MockAccountData; -use Tests\TestCase; +use Illuminate\Routing\Middleware\ThrottleRequests; +use Illuminate\Foundation\Testing\DatabaseTransactions; /** * @test @@ -30,6 +32,8 @@ class ProductTest extends TestCase use DatabaseTransactions; use MockAccountData; + protected $faker; + protected function setUp() :void { parent::setUp(); @@ -49,6 +53,72 @@ class ProductTest extends TestCase } + public function testProductCostMigration() + { + $items = []; + + $item = new InvoiceItem(); + $item->product_cost = 0; + $item->product_key = 'test'; + $item->quantity = 1; + $item->cost = 10; + $item->notes = 'product'; + + $items[] = $item; + + $p = Product::factory() + ->create([ + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'product_key' => 'test', + 'cost' => 10, + 'price' => 20, + 'quantity' => 1, + 'notes' => 'product', + ]); + + $i = Invoice::factory() + ->create([ + 'client_id' => $this->client->id, + 'company_id' => $this->company->id, + 'user_id' => $this->user->id, + 'line_items' => $items, + ]); + + + $line_items = $i->line_items; + + $this->assertEquals(0, $line_items[0]->product_cost); + + Invoice::withTrashed() + ->where('is_deleted', false) + ->cursor() + ->each(function (Invoice $invoice) { + + + $line_items = $invoice->line_items; + + foreach ($line_items as $key => $item) { + + if(property_exists($item, 'product_cost') && $item->product_cost == 0 && $product = Product::where('company_id', $invoice->company_id)->where('product_key', $item->product_key)->where('cost', '>', 0)->first()) { + $line_items[$key]->product_cost = $product->cost; + } + } + + $invoice->line_items = $line_items; + $invoice->saveQuietly(); + + }); + + + $i = $i->fresh(); + $line_items = $i->line_items; + + $this->assertEquals(10, $line_items[0]->product_cost); + + + } + public function testSetTaxId() { $p = Product::factory()->create([ diff --git a/tests/Unit/CurrencyApiTest.php b/tests/Unit/CurrencyApiTest.php index 153e566b25df..5db10d26ef9f 100644 --- a/tests/Unit/CurrencyApiTest.php +++ b/tests/Unit/CurrencyApiTest.php @@ -12,6 +12,7 @@ namespace Tests\Unit; use App\Libraries\Currency\Conversion\CurrencyApi; +use App\Models\Currency; use Illuminate\Support\Carbon; use Tests\TestCase; @@ -26,6 +27,21 @@ class CurrencyApiTest extends TestCase parent::setUp(); } + public function testConversionAudToEur() + { + $converter = new CurrencyApi(); + + $converted_amount = $converter->convert(100, 12, 3); + + $aud_currency = Currency::find(12); + $eur_currency = Currency::find(3); + + $converted_synthetic = 100 / ($aud_currency->exchange_rate / $eur_currency->exchange_rate); + + $this->assertEquals(round($converted_synthetic, 2), round($converted_amount, 2)); + + } + public function testCurrencyConversionWorking() { $converter = new CurrencyApi();