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