diff --git a/app/Console/Commands/DemoMode.php b/app/Console/Commands/DemoMode.php
index 8cde523d3eed..4418b807067d 100644
--- a/app/Console/Commands/DemoMode.php
+++ b/app/Console/Commands/DemoMode.php
@@ -188,6 +188,7 @@ class DemoMode extends Command
$company_token->account_id = $account->id;
$company_token->name = 'test token';
$company_token->token = 'TOKEN';
+ $company_token->is_system = true;
$company_token->save();
$u2->companies()->attach($company->id, [
diff --git a/app/DataMapper/Tax/ClientTaxData.php b/app/DataMapper/Tax/ClientTaxData.php
new file mode 100644
index 000000000000..6ec89b628c84
--- /dev/null
+++ b/app/DataMapper/Tax/ClientTaxData.php
@@ -0,0 +1,21 @@
+checkAppSetup() !== false && $account = Account::first()) {
//always redirect invoicing.co to invoicing.co
- if (Ninja::isHosted() && !in_array(request()->getSchemeAndHttpHost(), ['https://staging.invoicing.co', 'https://invoicing.co', 'https://demo.invoicing.co'])) {
+ if (Ninja::isHosted() && !in_array(request()->getSchemeAndHttpHost(), ['https://staging.invoicing.co', 'https://invoicing.co', 'https://demo.invoicing.co', 'https://invoiceninja.net'])) {
return redirect()->secure('https://invoicing.co');
}
diff --git a/app/Models/Company.php b/app/Models/Company.php
index bdc442937101..c94361099a93 100644
--- a/app/Models/Company.php
+++ b/app/Models/Company.php
@@ -429,6 +429,8 @@ class Company extends BaseModel
'convert_payment_currency',
'convert_expense_currency',
'notify_vendor_when_paid',
+ 'calculate_taxes',
+ 'tax_all_products',
];
protected $hidden = [
diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php
index ef381eb035d6..0fb21f6454cc 100644
--- a/app/Models/Invoice.php
+++ b/app/Models/Invoice.php
@@ -582,7 +582,7 @@ class Invoice extends BaseModel
/**
* Access the invoice calculator object.
*
- * @return stdClass The invoice calculator object getters
+ * @return \stdClass The invoice calculator object getters
*/
public function calc()
{
diff --git a/app/Models/Product.php b/app/Models/Product.php
index 29174daaf466..f52c4427e99b 100644
--- a/app/Models/Product.php
+++ b/app/Models/Product.php
@@ -105,6 +105,13 @@ class Product extends BaseModel
use SoftDeletes;
use Filterable;
+
+ public const PRODUCT_TYPE_PHYSICAL = 1;
+ public const PRODUCT_TYPE_SERVICE = 2;
+ public const PRODUCT_TYPE_DIGITAL = 3;
+ public const PRODUCT_TYPE_FREIGHT = 4;
+ public const PRODUCT_TAX_EXEMPT = 5;
+
protected $fillable = [
'custom_value1',
'custom_value2',
@@ -126,6 +133,7 @@ class Product extends BaseModel
'stock_notification',
'max_quantity',
'product_image',
+ 'tax_id',
];
protected $touches = [];
diff --git a/app/Transformers/CompanyTransformer.php b/app/Transformers/CompanyTransformer.php
index a167c6812fd7..8571375f7d5a 100644
--- a/app/Transformers/CompanyTransformer.php
+++ b/app/Transformers/CompanyTransformer.php
@@ -193,6 +193,8 @@ class CompanyTransformer extends EntityTransformer
'convert_expense_currency' => (bool) $company->convert_expense_currency,
'notify_vendor_when_paid' => (bool) $company->notify_vendor_when_paid,
'invoice_task_hours' => (bool) $company->invoice_task_hours,
+ 'calculate_taxes' => (bool) $company->calculate_taxes,
+ 'tax_all_products' => (bool) $company->tax_all_products,
];
}
diff --git a/app/Transformers/InvoiceTransformer.php b/app/Transformers/InvoiceTransformer.php
index a35e1d4c2082..5e3b0a93955d 100644
--- a/app/Transformers/InvoiceTransformer.php
+++ b/app/Transformers/InvoiceTransformer.php
@@ -149,6 +149,7 @@ class InvoiceTransformer extends EntityTransformer
'paid_to_date' => (float) $invoice->paid_to_date,
'subscription_id' => $this->encodePrimaryKey($invoice->subscription_id),
'auto_bill_enabled' => (bool) $invoice->auto_bill_enabled,
+ 'tax_data' => $invoice->tax_data ?: '',
];
}
}
diff --git a/app/Transformers/ProductTransformer.php b/app/Transformers/ProductTransformer.php
index 3d0247da0002..4f3f6706d950 100644
--- a/app/Transformers/ProductTransformer.php
+++ b/app/Transformers/ProductTransformer.php
@@ -95,6 +95,7 @@ class ProductTransformer extends EntityTransformer
'stock_notification_threshold' => (int) $product->stock_notification_threshold,
'max_quantity' => (int) $product->max_quantity,
'product_image' => (string) $product->product_image ?: '',
+ 'tax_id' => (int) $product->tax_id ?: 1,
];
}
}
diff --git a/database/migrations/2023_03_21_053933_tax_calculations_for_invoices.php b/database/migrations/2023_03_21_053933_tax_calculations_for_invoices.php
new file mode 100644
index 000000000000..1c6d885e9f37
--- /dev/null
+++ b/database/migrations/2023_03_21_053933_tax_calculations_for_invoices.php
@@ -0,0 +1,45 @@
+mediumText('tax_data')->nullable(); //json object
+ });
+
+ Schema::table('companies', function (Blueprint $table) {
+ $table->boolean('calculate_taxes')->default(false); //setting to turn on/off tax calculations
+ $table->boolean('tax_all_products')->default(false); //globally tax all products if none defined
+ $table->boolean('tax_data');
+ });
+
+ Schema::table('products', function (Blueprint $table){
+ $table->unsignedInteger('tax_id')->nullable(); // the product tax constant
+ });
+
+ Schema::table('clients', function (Blueprint $table){
+ $table->boolean('tax_data');
+ });
+
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ //
+ }
+};
diff --git a/lang/en/texts.php b/lang/en/texts.php
index 054f2c91fea4..4d43dc320f55 100644
--- a/lang/en/texts.php
+++ b/lang/en/texts.php
@@ -174,7 +174,6 @@ $LANG = array(
'payment_gateway' => 'Payment Gateway',
'gateway_id' => 'Gateway',
'email_notifications' => 'Email Notifications',
- 'email_sent' => 'Email me when an invoice is sent',
'email_viewed' => 'Email me when an invoice is viewed',
'email_paid' => 'Email me when an invoice is paid',
'site_updates' => 'Site Updates',
@@ -907,8 +906,6 @@ $LANG = array(
'expense' => 'Expense',
'expenses' => 'Expenses',
'new_expense' => 'Enter Expense',
- 'enter_expense' => 'Enter Expense',
- 'vendors' => 'Vendors',
'new_vendor' => 'New Vendor',
'payment_terms_net' => 'Net',
'vendor' => 'Vendor',
@@ -1203,7 +1200,6 @@ $LANG = array(
'plan_pending_monthly' => 'Will switch to monthly on :date',
'plan_refunded' => 'A refund has been issued.',
- 'live_preview' => 'Live Preview',
'page_size' => 'Page Size',
'live_preview_disabled' => 'Live preview has been disabled to support selected font',
'invoice_number_padding' => 'Padding',
@@ -1460,40 +1456,6 @@ $LANG = array(
'payment_type_GoCardless' => 'GoCardless',
'payment_type_Zelle' => 'Zelle',
- // Industries
- 'industry_Accounting & Legal' => 'Accounting & Legal',
- 'industry_Advertising' => 'Advertising',
- 'industry_Aerospace' => 'Aerospace',
- 'industry_Agriculture' => 'Agriculture',
- 'industry_Automotive' => 'Automotive',
- 'industry_Banking & Finance' => 'Banking & Finance',
- 'industry_Biotechnology' => 'Biotechnology',
- 'industry_Broadcasting' => 'Broadcasting',
- 'industry_Business Services' => 'Business Services',
- 'industry_Commodities & Chemicals' => 'Commodities & Chemicals',
- 'industry_Communications' => 'Communications',
- 'industry_Computers & Hightech' => 'Computers & Hightech',
- 'industry_Defense' => 'Defense',
- 'industry_Energy' => 'Energy',
- 'industry_Entertainment' => 'Entertainment',
- 'industry_Government' => 'Government',
- 'industry_Healthcare & Life Sciences' => 'Healthcare & Life Sciences',
- 'industry_Insurance' => 'Insurance',
- 'industry_Manufacturing' => 'Manufacturing',
- 'industry_Marketing' => 'Marketing',
- 'industry_Media' => 'Media',
- 'industry_Nonprofit & Higher Ed' => 'Nonprofit & Higher Ed',
- 'industry_Pharmaceuticals' => 'Pharmaceuticals',
- 'industry_Professional Services & Consulting' => 'Professional Services & Consulting',
- 'industry_Real Estate' => 'Real Estate',
- 'industry_Restaurant & Catering' => 'Restaurant & Catering',
- 'industry_Retail & Wholesale' => 'Retail & Wholesale',
- 'industry_Sports' => 'Sports',
- 'industry_Transportation' => 'Transportation',
- 'industry_Travel & Luxury' => 'Travel & Luxury',
- 'industry_Other' => 'Other',
- 'industry_Photography' => 'Photography',
-
// Countries
'country_Afghanistan' => 'Afghanistan',
'country_Albania' => 'Albania',
@@ -4230,7 +4192,6 @@ $LANG = array(
'activity_104' => ':user restored recurring invoice :recurring_invoice',
'new_login_detected' => 'New login detected for your account.',
'new_login_description' => 'You recently logged in to your Invoice Ninja account from a new location or device:
IP: :ip
Time: :time
Email: :email',
- 'download_backup_subject' => 'Your company backup is ready for download',
'contact_details' => 'Contact Details',
'download_backup_subject' => 'Your company backup is ready for download',
'account_passwordless_login' => 'Account passwordless login',
@@ -4355,7 +4316,6 @@ $LANG = array(
'has_tasks' => 'Has Tasks',
'registration' => 'Registration',
'unauthorized_stripe_warning' => 'Please authorize Stripe to accept online payments.',
- 'fpx' => 'FPX',
'update_all_records' => 'Update all records',
'set_default_company' => 'Set Default Company',
'updated_company' => 'Successfully updated company',
@@ -4546,7 +4506,6 @@ $LANG = array(
'reminder_message' => 'Reminder for invoice :number for :balance',
'gmail_credentials_invalid_subject' => 'Send with GMail invalid credentials',
'gmail_credentials_invalid_body' => 'Your GMail credentials are not correct, please log into the administrator portal and navigate to Settings > User Details and disconnect and reconnect your GMail account. We will send you this notification daily until this issue is resolved',
- 'notification_invoice_sent' => 'The following client :client was emailed Invoice :invoice for :amount.',
'total_columns' => 'Total Fields',
'view_task' => 'View Task',
'cancel_invoice' => 'Cancel',
@@ -5027,6 +4986,35 @@ $LANG = array(
'notification_payment_emailed' => 'Payment :payment was emailed to :client',
'notification_payment_emailed_subject' => 'Payment :payment was emailed',
'record_not_found' => 'Record not found',
+ 'product_tax_exempt' => 'Product Tax Exempt',
+ 'product_type_physical' => 'Physical Goods',
+ 'product_type_digital' => 'Digital Goods',
+ 'product_type_service' => 'Services',
+ 'product_type_freight' => 'Shipping',
+ 'minimum_payment_amount' => 'Minimum Payment Amount',
+ 'client_initiated_payments' => 'Client Initiated Payments',
+ 'client_initiated_payments_help' => 'Support making a payment in the client portal without an invoice',
+ 'share_invoice_quote_columns' => 'Share Invoice/Quote Columns',
+ 'cc_email' => 'CC Email',
+ 'payment_balance' => 'Payment Balance',
+ 'view_report_permission' => 'Allow user to access the reports, data is limited to available permissions',
+ 'activity_138' => 'Payment :payment was emailed to :client',
+ 'one_time_products' => 'One-Time Products',
+ 'optional_one_time_products' => 'Optional One-Time Products',
+ 'required' => 'Required',
+ 'hidden' => 'Hidden',
+ 'payment_links' => 'Payment Links',
+ 'payment_link' => 'Payment Link',
+ 'new_payment_link' => 'New Payment Link',
+ 'edit_payment_link' => 'Edit Payment Link',
+ 'created_payment_link' => 'Successfully created payment link',
+ 'updated_payment_link' => 'Successfully updated payment link',
+ 'archived_payment_link' => 'Successfully archived payment link',
+ 'deleted_payment_link' => 'Successfully deleted payment link',
+ 'removed_payment_link' => 'Successfully removed payment link',
+ 'restored_payment_link' => 'Successfully restored payment link',
+ 'search_payment_link' => 'Search 1 Payment Link',
+ 'search_payment_links' => 'Search :count Payment Links',
);
diff --git a/resources/views/portal/ninja2020/pre_payments/index.blade.php b/resources/views/portal/ninja2020/pre_payments/index.blade.php
index 2a0455c25f63..0e3498850c35 100644
--- a/resources/views/portal/ninja2020/pre_payments/index.blade.php
+++ b/resources/views/portal/ninja2020/pre_payments/index.blade.php
@@ -40,9 +40,13 @@
type="text"
class="input mt-0 mr-4 relative"
name="amount"
- placeholder="{{ $minimum_amount }}"
+ placeholder=""
min="{{ $minimum_amount }}"/>
-
+
+ @if($minimum_amount > 0)
+
{{ ctrans('texts.minimum_required_payment', ['amount' => $minimum_amount])}}
+ @endif + @if($errors->has('amount')){{ $errors->first('amount') }}
@endif