diff --git a/app/DataMapper/Tax/TaxModel.php b/app/DataMapper/Tax/TaxModel.php index a4f22947cb9c..09a9eae44b3f 100644 --- a/app/DataMapper/Tax/TaxModel.php +++ b/app/DataMapper/Tax/TaxModel.php @@ -68,7 +68,7 @@ class TaxModel $this->regions->AU = new \stdClass(); $this->regions->AU->has_sales_above_threshold = false; $this->regions->AU->tax_all_subregions = false; - $this->regions->AU->vat_threshold = 75000; + $this->regions->AU->tax_threshold = 75000; $this->auSubRegions(); return $this; @@ -115,7 +115,7 @@ class TaxModel $this->regions->EU->has_sales_above_threshold = false; $this->regions->EU->tax_all_subregions = false; - $this->regions->EU->vat_threshold = 10000; + $this->regions->EU->tax_threshold = 10000; $this->euSubRegions(); return $this; diff --git a/app/DataMapper/Tax/tax_model.yaml b/app/DataMapper/Tax/tax_model.yaml index c74c06d664bc..60736e5f5f37 100644 --- a/app/DataMapper/Tax/tax_model.yaml +++ b/app/DataMapper/Tax/tax_model.yaml @@ -106,7 +106,7 @@ region: apply_tax: false EU: tax_all: false - vat_threshold: 10000 + tax_threshold: 10000 has_sales_above_threshold: false subregions: AT: diff --git a/app/Filters/DesignFilters.php b/app/Filters/DesignFilters.php index 53ce1eca7483..06ad08b074eb 100644 --- a/app/Filters/DesignFilters.php +++ b/app/Filters/DesignFilters.php @@ -24,7 +24,6 @@ class DesignFilters extends QueryFilters * @param string $filter * @return Builder * - * @deprecated */ public function filter(string $filter = ''): Builder { @@ -33,7 +32,7 @@ class DesignFilters extends QueryFilters } return $this->builder->where(function ($query) use ($filter) { - $query->where('designs.name', 'like', '%'.$filter.'%'); + $query->where('name', 'like', '%'.$filter.'%'); }); } @@ -58,17 +57,22 @@ class DesignFilters extends QueryFilters /** * Filters the query by the users company ID. * - * @return Illuminate\Database\Eloquent\Builder + * @return Builder */ public function entityFilter(): Builder { - return $this->builder->where('company_id', auth()->user()->company()->id)->orWhere('company_id', null)->orderBy('id', 'asc'); + //19-03-2023 change the scope for the design filters + return $this->builder->where(function ($query) { + $query->where('company_id', auth()->user()->company()->id)->orWhere('company_id', null)->orderBy('id', 'asc'); + // return $this->builder->where('company_id', auth()->user()->company()->id)->orWhere('company_id', null)->orderBy('id', 'asc'); + + }); } /** * Filter the designs by `is_custom` column. * - * @return Illuminate\Database\Eloquent\Builder + * @return Builder */ public function custom(string $custom): Builder { diff --git a/app/Filters/InvoiceFilters.php b/app/Filters/InvoiceFilters.php index 2c8a62b073a1..2cc72fb4e846 100644 --- a/app/Filters/InvoiceFilters.php +++ b/app/Filters/InvoiceFilters.php @@ -35,7 +35,7 @@ class InvoiceFilters extends QueryFilters * - overdue * - reversed * - * @param string client_status The invoice status as seen by the client + * @param string $value The invoice status as seen by the client * @return Builder */ public function client_status(string $value = ''): Builder @@ -88,7 +88,7 @@ class InvoiceFilters extends QueryFilters /** * Filter based on search text. * - * @param string query filter + * @param string $filter * @return Builder * @deprecated */ @@ -126,6 +126,7 @@ class InvoiceFilters extends QueryFilters } /** + * @return Builder * @return Builder * @throws InvalidArgumentException */ @@ -141,6 +142,7 @@ class InvoiceFilters extends QueryFilters /** * @return void + * @return Builder * @throws InvalidArgumentException */ public function overdue(): Builder @@ -174,7 +176,7 @@ class InvoiceFilters extends QueryFilters /** * Sorts the list based on $sort. * - * @param string sort formatted as column|asc + * @param string $sort formatted as column|asc * @return Builder */ public function sort(string $sort = ''): Builder @@ -194,9 +196,9 @@ class InvoiceFilters extends QueryFilters * We need to ensure we are using the correct company ID * as we could be hitting this from either the client or company auth guard * - * @return Illuminate\Database\Query\Builder + * @return Builder */ - public function entityFilter() + public function entityFilter(): Builder { if (auth()->guard('contact')->user()) { return $this->contactViewFilter(); @@ -210,7 +212,7 @@ class InvoiceFilters extends QueryFilters * @return Builder * @throws InvalidArgumentException */ - public function private_notes($filter = '') :Builder + public function private_notes($filter = ''): Builder { if (strlen($filter) == 0) { return $this->builder; diff --git a/app/Filters/ProductFilters.php b/app/Filters/ProductFilters.php index 5357073f34a4..9c3e39e4324c 100644 --- a/app/Filters/ProductFilters.php +++ b/app/Filters/ProductFilters.php @@ -23,9 +23,8 @@ class ProductFilters extends QueryFilters /** * Filter based on search text. * - * @param string query filter + * @param string $filter * @return Builder - * @deprecated */ public function filter(string $filter = ''): Builder { @@ -55,7 +54,7 @@ class ProductFilters extends QueryFilters /** * Sorts the list based on $sort. * - * @param string sort formatted as column|asc + * @param string $sort formatted as column|asc * @return Builder */ public function sort(string $sort = ''): Builder @@ -72,9 +71,9 @@ class ProductFilters extends QueryFilters /** * Filters the query by the users company ID. * - * @return Illuminate\Database\Query\Builder + * @return Builder */ - public function entityFilter() + public function entityFilter(): Builder { return $this->builder->company(); } diff --git a/app/Filters/QueryFilters.php b/app/Filters/QueryFilters.php index a9924bca1225..818af708a52c 100644 --- a/app/Filters/QueryFilters.php +++ b/app/Filters/QueryFilters.php @@ -115,7 +115,7 @@ abstract class QueryFilters * Explodes the value by delimiter. * * @param string $value - * @return stdClass + * @return \stdClass */ public function split($value) : \stdClass { @@ -133,7 +133,7 @@ abstract class QueryFilters * Filters the list based on the status * archived, active, deleted. * - * @param string filter + * @param string $filter * @return Builder */ public function status(string $filter = ''): Builder @@ -196,13 +196,15 @@ abstract class QueryFilters * * -Can only be used on contact routes * - * @return + * @return Builder */ - public function clientFilter() + public function clientFilter(): Builder { if (auth()->guard('contact')->user()) { return $this->builder->where('client_id', auth()->guard('contact')->user()->client->id); } + + return $this->builder; } public function created_at($value = '') @@ -244,7 +246,7 @@ abstract class QueryFilters } - public function is_deleted($value) + public function is_deleted($value = 'true') { if ($value == 'true') { return $this->builder->where('is_deleted', $value)->withTrashed(); diff --git a/app/Filters/RecurringInvoiceFilters.php b/app/Filters/RecurringInvoiceFilters.php index 82dd6fd1d0f8..d87b9bc7b539 100644 --- a/app/Filters/RecurringInvoiceFilters.php +++ b/app/Filters/RecurringInvoiceFilters.php @@ -23,7 +23,7 @@ class RecurringInvoiceFilters extends QueryFilters /** * Filter based on search text. * - * @param string query filter + * @param string $filter * @return Builder * @deprecated */ @@ -50,7 +50,7 @@ class RecurringInvoiceFilters extends QueryFilters * - paused * - completed * - * @param string client_status The invoice status as seen by the client + * @param string $value The invoice status as seen by the client * @return Builder */ public function client_status(string $value = ''): Builder @@ -99,7 +99,7 @@ class RecurringInvoiceFilters extends QueryFilters /** * Sorts the list based on $sort. * - * @param string sort formatted as column|asc + * @param string $sort formatted as column|asc * @return Builder */ public function sort(string $sort = ''): Builder @@ -116,9 +116,9 @@ class RecurringInvoiceFilters extends QueryFilters /** * Filters the query by the users company ID. * - * @return Illuminate\Eloquent\Builder + * @return Illuminate\Database\Eloquent\Builder */ - public function entityFilter() + public function entityFilter(): Builder { return $this->builder->company(); } diff --git a/app/Helpers/Invoice/InvoiceItemSum.php b/app/Helpers/Invoice/InvoiceItemSum.php index 7772bebb3726..f11255a75ac5 100644 --- a/app/Helpers/Invoice/InvoiceItemSum.php +++ b/app/Helpers/Invoice/InvoiceItemSum.php @@ -136,7 +136,7 @@ class InvoiceItemSum private function shouldCalculateTax(): self { - if (!$this->invoice->company->calculate_taxes) { + if (!$this->invoice->company?->calculate_taxes) { $this->calc_tax = false; return $this; } diff --git a/app/Jobs/Cron/AutoBill.php b/app/Jobs/Cron/AutoBill.php index 60f0c2572d76..8fde5b16374c 100644 --- a/app/Jobs/Cron/AutoBill.php +++ b/app/Jobs/Cron/AutoBill.php @@ -11,13 +11,14 @@ namespace App\Jobs\Cron; -use App\Libraries\MultiDB; use App\Models\Invoice; +use App\Libraries\MultiDB; use Illuminate\Bus\Queueable; +use App\Jobs\Entity\EmailEntity; +use Illuminate\Queue\SerializesModels; +use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; class AutoBill implements ShouldQueue { @@ -25,19 +26,13 @@ class AutoBill implements ShouldQueue public $tries = 1; - public int $invoice_id; - - public string $db; - /** * Create a new job instance. * * @return void */ - public function __construct(int $invoice_id, ?string $db) + public function __construct(public int $invoice_id, public ?string $db, public bool $send_email_on_failure = false) { - $this->invoice_id = $invoice_id; - $this->db = $db; } /** @@ -61,6 +56,24 @@ class AutoBill implements ShouldQueue $invoice->service()->autoBill(); } catch (\Exception $e) { nlog("Failed to capture payment for {$this->invoice_id} ->".$e->getMessage()); + + if($this->send_email_on_failure) + { + + $invoice->invitations->each(function ($invitation) use ($invoice) { + if ($invitation->contact && ! $invitation->contact->trashed() && strlen($invitation->contact->email) >= 1 && $invoice->client->getSetting('auto_email_invoice')) { + try { + EmailEntity::dispatch($invitation, $invoice->company)->delay(rand(1, 2)); + } catch (\Exception $e) { + nlog($e->getMessage()); + } + + nlog("Firing email for invoice {$invoice->number}"); + } + }); + + } + } } } diff --git a/app/Jobs/RecurringInvoice/SendRecurring.php b/app/Jobs/RecurringInvoice/SendRecurring.php index 2b9269fd1a7a..e95ab582baa4 100644 --- a/app/Jobs/RecurringInvoice/SendRecurring.php +++ b/app/Jobs/RecurringInvoice/SendRecurring.php @@ -84,11 +84,13 @@ class SendRecurring implements ShouldQueue } //12-01-2023 i moved this block after fillDefaults to handle if standard invoice auto bill config has been enabled, recurring invoice should override. - if ($this->recurring_invoice->auto_bill === 'always') { + if ($this->recurring_invoice->auto_bill == 'always') { $invoice->auto_bill_enabled = true; - } elseif ($this->recurring_invoice->auto_bill === 'optout' || $this->recurring_invoice->auto_bill === 'optin') { - } elseif ($this->recurring_invoice->auto_bill === 'off') { + $invoice->saveQuietly(); + } elseif ($this->recurring_invoice->auto_bill == 'optout' || $this->recurring_invoice->auto_bill == 'optin') { + } elseif ($this->recurring_invoice->auto_bill == 'off') { $invoice->auto_bill_enabled = false; + $invoice->saveQuietly(); } $invoice = $this->createRecurringInvitations($invoice); @@ -111,7 +113,16 @@ class SendRecurring implements ShouldQueue event('eloquent.created: App\Models\Invoice', $invoice); - if ($invoice->client->getSetting('auto_email_invoice')) { + //auto bill, BUT NOT DRAFTS!! + if ($invoice->auto_bill_enabled && $invoice->client->getSetting('auto_bill_date') == 'on_send_date' && $invoice->client->getSetting('auto_email_invoice')) { + nlog("attempting to autobill {$invoice->number}"); + AutoBill::dispatch($invoice->id, $this->db, true)->delay(rand(1, 2)); + } + elseif ($invoice->auto_bill_enabled && $invoice->client->getSetting('auto_bill_date') == 'on_due_date' && $invoice->client->getSetting('auto_email_invoice') && ($invoice->due_date && Carbon::parse($invoice->due_date)->startOfDay()->lte(now()->startOfDay()))) { + nlog("attempting to autobill {$invoice->number}"); + AutoBill::dispatch($invoice->id, $this->db, true)->delay(rand(1, 2)); + } + elseif ($invoice->client->getSetting('auto_email_invoice')) { //Admin notification for recurring invoice sent. if ($invoice->invitations->count() >= 1) { $invoice->entityEmailEvent($invoice->invitations->first(), 'invoice', 'email_template_invoice'); @@ -130,16 +141,7 @@ class SendRecurring implements ShouldQueue }); } - //auto bill, BUT NOT DRAFTS!! - if ($invoice->auto_bill_enabled && $invoice->client->getSetting('auto_bill_date') == 'on_send_date' && $invoice->client->getSetting('auto_email_invoice')) { - nlog("attempting to autobill {$invoice->number}"); - AutoBill::dispatch($invoice->id, $this->db)->delay(rand(1, 2)); - } elseif ($invoice->auto_bill_enabled && $invoice->client->getSetting('auto_bill_date') == 'on_due_date' && $invoice->client->getSetting('auto_email_invoice')) { - if ($invoice->due_date && Carbon::parse($invoice->due_date)->startOfDay()->lte(now()->startOfDay())) { - nlog("attempting to autobill {$invoice->number}"); - AutoBill::dispatch($invoice->id, $this->db)->delay(rand(1, 2)); - } - } + } /** diff --git a/app/Models/Company.php b/app/Models/Company.php index d50594d26aee..e036fe8b1c40 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -873,6 +873,7 @@ class Company extends BaseModel 'convert_expense_currency', 'notify_vendor_when_paid', 'calculate_taxes', + 'tax_data', ]; protected $hidden = [ diff --git a/app/Repositories/ExpenseRepository.php b/app/Repositories/ExpenseRepository.php index 6b2770590b85..b1b8794b98b7 100644 --- a/app/Repositories/ExpenseRepository.php +++ b/app/Repositories/ExpenseRepository.php @@ -103,7 +103,7 @@ class ExpenseRepository extends BaseRepository public function delete($expense) :Expense { - if ($expense->transaction_id) { + if ($expense->transaction()->exists()) { $exp_ids = collect(explode(',', $expense->transaction->expense_id))->filter(function ($id) use ($expense) { return $id != $expense->hashed_id; diff --git a/app/Services/Pdf/PdfMock.php b/app/Services/Pdf/PdfMock.php index b4afd3ebd8ba..6e5ba641c12d 100644 --- a/app/Services/Pdf/PdfMock.php +++ b/app/Services/Pdf/PdfMock.php @@ -63,7 +63,7 @@ class PdfMock $pdf_config->entity_design_id = $pdf_config->settings->{"{$pdf_config->entity_string}_design_id"}; $pdf_config->setPdfVariables(); $pdf_config->setCurrency(Currency::find($this->settings->currency_id)); - $pdf_config->setCountry(Country::find($this->settings->country_id)); + $pdf_config->setCountry(Country::find($this->settings->country_id ?: 840)); $pdf_config->design = Design::find($this->decodePrimaryKey($pdf_config->entity_design_id)); $pdf_config->currency_entity = $this->mock->client;