1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 05:02:36 +01:00

Merge remote-tracking branch 'upstream/v5-develop' into 1314-subscriptions-v3

This commit is contained in:
Benjamin Beganović 2024-03-15 01:29:22 +01:00
commit e9be90779a
14 changed files with 219 additions and 45 deletions

View File

@ -1 +1 @@
5.8.36
5.8.37

View File

@ -159,7 +159,7 @@ class SwissQrGenerator
// Optionally, add some human-readable information about what the bill is for.
$qrBill->setAdditionalInformation(
QrBill\DataGroup\Element\AdditionalInformation::create(
$this->invoice->public_notes ? substr($this->invoice->public_notes, 0, 139) : ctrans('texts.invoice_number_placeholder', ['invoice' => $this->invoice->number])
$this->invoice->public_notes ? substr(strip_tags($this->invoice->public_notes), 0, 139) : ctrans('texts.invoice_number_placeholder', ['invoice' => $this->invoice->number])
)
);

View File

@ -158,7 +158,6 @@ class LicenseController extends BaseController
/* Catch claim license requests */
if (config('ninja.environment') == 'selfhost') {
// $response = Http::get( "http://ninja.test:8000/claim_license", [
$response = Http::get("https://invoicing.co/claim_license", [
'license_key' => $license_key,
'product_id' => 3,

View File

@ -63,7 +63,7 @@ class UpdateClientRequest extends Request
$rules['country_id'] = 'integer|nullable|exists:countries,id';
$rules['shipping_country_id'] = 'integer|nullable|exists:countries,id';
$rules['classification'] = 'bail|sometimes|nullable|in:individual,business,company,partnership,trust,charity,government,other';
$rules['id_number'] = ['sometimes', 'bail', Rule::unique('clients')->where('company_id', $user->company()->id)->ignore($this->client->id)];
$rules['id_number'] = ['sometimes', 'bail', 'nullable', Rule::unique('clients')->where('company_id', $user->company()->id)->ignore($this->client->id)];
$rules['number'] = ['sometimes', 'bail', Rule::unique('clients')->where('company_id', $user->company()->id)->ignore($this->client->id)];
$rules['settings'] = new ValidClientGroupSettingsRule();

View File

@ -52,7 +52,7 @@ class ClientStatement extends Mailable
public function content()
{
return new Content(
view: $this->data['company']->account->isPremium() ? 'email.template.client_premium' : 'email.template.client',
view: 'email.template.client',
text: 'email.template.text',
with: [
'text_body' => $this->data['body'],

View File

@ -75,7 +75,8 @@ class TemplateEmail extends Mailable
$template_name = 'email.template.'.$this->build_email->getTemplate();
if ($this->build_email->getTemplate() == 'light' || $this->build_email->getTemplate() == 'dark') {
$template_name = $this->company->account->isPremium() ? 'email.template.client_premium' : 'email.template.client';
// $template_name = $this->company->account->isPremium() ? 'email.template.client_premium' : 'email.template.client';
$template_name = 'email.template.client';
}
if ($this->build_email->getTemplate() == 'custom') {

View File

@ -72,7 +72,8 @@ class VendorTemplateEmail extends Mailable
$template_name = 'email.template.'.$this->build_email->getTemplate();
if ($this->build_email->getTemplate() == 'light' || $this->build_email->getTemplate() == 'dark') {
$template_name = $this->company->account->isPremium() ? 'email.template.client_premium' : 'email.template.client';
// $template_name = $this->company->account->isPremium() ? 'email.template.client_premium' : 'email.template.client';
$template_name = 'email.template.client';
}
if ($this->build_email->getTemplate() == 'custom') {

View File

@ -107,10 +107,10 @@ class EmailDefaults
match ($this->email->email_object->settings->email_style) {
'plain' => $this->template = 'email.template.plain',
'light' => $this->template = $this->email->email_object->company->account->isPremium() ? 'email.template.client_premium' : 'email.template.client',
'dark' => $this->template = $this->email->email_object->company->account->isPremium() ? 'email.template.client_premium' :'email.template.client',
'light' => $this->template = 'email.template.client',
'dark' => $this->template = 'email.template.client',
'custom' => $this->template = 'email.template.custom',
default => $this->template = $this->email->email_object->company->account->isPremium() ? 'email.template.client_premium' :'email.template.client',
default => $this->template = 'email.template.client',
};
$this->email->email_object->html_template = $this->template;

View File

@ -86,6 +86,33 @@ class Number
return rtrim(rtrim(number_format($value, $precision, $decimal, $thousand), '0'), $decimal);
}
public static function parseFloat($value)
{
if(!$value)
return 0;
//remove everything except for numbers, decimals, commas and hyphens
$value = preg_replace('/[^0-9.,-]+/', '', $value);
$decimal = strpos($value, '.');
$comma = strpos($value, ',');
if($comma === false) //no comma must be a decimal number already
return (float) $value;
if($decimal < $comma){ //decimal before a comma = euro
$value = str_replace(['.',','], ['','.'], $value);
return (float) $value;
}
//comma first = traditional thousand separator
$value = str_replace(',', '', $value);
return (float)$value;
}
/**
* Formats a given value based on the clients currency
* BACK to a float.
@ -93,32 +120,9 @@ class Number
* @param string $value The formatted number to be converted back to float
* @return float The formatted value
*/
public static function parseFloat($value)
public static function parseFloatXX($value)
{
// if(!$value)
// return 0;
// //remove everything except for numbers, decimals, commas and hyphens
// $value = preg_replace('/[^0-9.,-]+/', '', $value);
// $decimal = strpos($value, '.');
// $comma = strpos($value, ',');
// if($comma === false) //no comma must be a decimal number already
// return (float) $value;
// if($decimal < $comma){ //decimal before a comma = euro
// $value = str_replace(['.',','], ['','.'], $value);
// // $value = str_replace(',', '.', $value);
// return (float) $value;
// }
// //comma first = traditional thousan separator
// $value = str_replace(',', '', $value);
// return (float)$value;
if(!$value)
return 0;

View File

@ -17,8 +17,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => env('APP_VERSION', '5.8.36'),
'app_tag' => env('APP_TAG', '5.8.36'),
'app_version' => env('APP_VERSION', '5.8.37'),
'app_tag' => env('APP_TAG', '5.8.37'),
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', false),

View File

@ -0,0 +1,45 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('invoices', function (Blueprint $table) {
$table->decimal('discount', 20, 6)->default(0)->change();
});
Schema::table('credits', function (Blueprint $table) {
$table->decimal('discount', 20, 6)->default(0)->change();
});
Schema::table('quotes', function (Blueprint $table) {
$table->decimal('discount', 20, 6)->default(0)->change();
});
Schema::table('purchase_orders', function (Blueprint $table) {
$table->decimal('discount', 20, 6)->default(0)->change();
});
Schema::table('recurring_invoices', function (Blueprint $table) {
$table->decimal('discount', 20, 6)->default(0)->change();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};

View File

@ -5269,7 +5269,7 @@ $lang = array(
'payment_provider' => 'Payment Provider',
'select_email_provider' => 'Set your email as the sending user',
'purchase_order_items' => 'Purchase Order Items',
'csv_rows_length' => 'No data found in this CSV file',
);
return $lang;

View File

@ -20,6 +20,7 @@ use App\Models\Subscription;
use App\Models\ClientContact;
use App\Utils\Traits\MakesHash;
use App\Models\RecurringInvoice;
use App\Factory\InvoiceItemFactory;
use App\Helpers\Invoice\InvoiceSum;
use App\Repositories\InvoiceRepository;
use Illuminate\Database\Eloquent\Model;
@ -51,6 +52,116 @@ class InvoiceTest extends TestCase
$this->makeTestData();
}
public function testMaxDiscount()
{
$line_items = [];
$item = InvoiceItemFactory::create();
$item->quantity = 1;
$item->cost = 100000000;
$item->type_id = '1';
$line_items[] = $item;
$data = [
'status_id' => 1,
'number' => '',
'discount' => 0,
'is_amount_discount' => 1,
'po_number' => '3434343',
'public_notes' => 'notes',
'is_deleted' => 0,
'custom_value1' => 0,
'custom_value2' => 0,
'custom_value3' => 0,
'custom_value4' => 0,
'client_id' => $this->client->hashed_id,
'line_items' => $line_items,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/invoices?mark_sent=true',$data)
->assertStatus(200);
$arr = $response->json();
$this->assertEquals(2, $arr['data']['status_id']);
$this->assertEquals(100000000, $arr['data']['amount']);
$this->assertEquals(100000000, $arr['data']['balance']);
$data = [
'status_id' => 1,
'number' => '',
'discount' => 100000000,
'is_amount_discount' => 1,
'po_number' => '3434343',
'public_notes' => 'notes',
'is_deleted' => 0,
'custom_value1' => 0,
'custom_value2' => 0,
'custom_value3' => 0,
'custom_value4' => 0,
'client_id' => $this->client->hashed_id,
'line_items' => $line_items,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/invoices?mark_sent=true', $data)
->assertStatus(200);
$arr = $response->json();
$this->assertEquals(2, $arr['data']['status_id']);
$this->assertEquals(0, $arr['data']['amount']);
$this->assertEquals(0, $arr['data']['balance']);
$this->assertEquals(100000000, $arr['data']['discount']);
$line_items = [];
$item = InvoiceItemFactory::create();
$item->quantity = 1;
$item->cost = 100000000;
$item->discount = 100000000;
$item->type_id = '1';
$line_items[] = $item;
$data = [
'status_id' => 1,
'number' => '',
'discount' => 0,
'is_amount_discount' => 1,
'po_number' => '3434343',
'public_notes' => 'notes',
'is_deleted' => 0,
'custom_value1' => 0,
'custom_value2' => 0,
'custom_value3' => 0,
'custom_value4' => 0,
'client_id' => $this->client->hashed_id,
'line_items' => $line_items,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/invoices?mark_sent=true', $data)
->assertStatus(200);
$arr = $response->json();
$this->assertEquals(2, $arr['data']['status_id']);
$this->assertEquals(0, $arr['data']['amount']);
$this->assertEquals(0, $arr['data']['balance']);
}
public function testInvoicePaymentLinkMutation()
{

View File

@ -24,20 +24,20 @@ class NumberTest extends TestCase
public function testRangeOfNumberFormats()
{
$floatvals = [
"22000.76" =>"22 000,76",
"22000.76" =>"22.000,76",
"22000.76" =>"22,000.76",
"22000" =>"22 000",
"22000" =>"22,000",
"22000" =>"22.000",
"22" =>"22.000",
"22000" =>"22.000,",
"22000.76" =>"22000.76",
"22000.76" =>"22000,76",
"1022000.76" =>"1.022.000,76",
"1022000.76" =>"1,022,000.76",
"1000000" =>"1,000,000",
"1000000" =>"1.000.000",
// "1000000" =>"1,000,000",
// "1000000" =>"1.000.000",
"1022000.76" =>"1022000.76",
"1022000.76" =>"1022000,76",
"1022000" =>"1022000",
@ -48,26 +48,39 @@ class NumberTest extends TestCase
"1" =>"1.00",
"1" =>"1,00",
"423545" =>"423545 €",
"423545" =>"423,545 €",
"423545" =>"423.545 €",
// "423545" =>"423,545 €",
// "423545" =>"423.545 €",
"1" =>"1,00 €",
"1.02" =>"€ 1.02",
"1000.02" =>"1'000,02 EUR",
"1000.02" =>"1 000.02$",
"1000.02" =>"1,000.02$",
"1000.02" =>"1.000,02 EURO",
"9.975" => "9.975"
"9.975" => "9.975",
"9975" => "9.975,",
"9975" => "9.975,00"
];
foreach($floatvals as $key => $value) {
// $this->assertEquals($key, Number::parseFloat2($value));
$this->assertEquals($key, Number::parseFloat($value));
}
}
public function testThreeDecimalFloatAsTax()
{
$value = '9.975';
$res = Number::parseFloat($value);
$this->assertEquals(9.975, $res);
}
public function testNegativeFloatParse()
{