diff --git a/app/DataMapper/Tax/US/Rule.php b/app/DataMapper/Tax/US/Rule.php index fbfb5b78b323..59cd75943ca5 100644 --- a/app/DataMapper/Tax/US/Rule.php +++ b/app/DataMapper/Tax/US/Rule.php @@ -165,9 +165,6 @@ class Rule extends BaseRule implements RuleInterface $this->tax_rate1 = 0; $this->tax_name1 = ''; - // $this->tax_rate1 = $this->invoice->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_rate; - // $this->tax_name1 = "Sales Tax"; - return $this; } diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index c551b6d38306..506213d57797 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -105,7 +105,7 @@ class Handler extends ExceptionHandler if($exception instanceof ThrottleRequestsException && class_exists(\Modules\Admin\Events\ThrottledExceptionRaised::class)) { $uri = urldecode(request()->getRequestUri()); - event(new \Modules\Admin\Events\ThrottledExceptionRaised(auth()->user()?->account?->key, $uri, request()->ip())); + // event(new \Modules\Admin\Events\ThrottledExceptionRaised(auth()->user()?->account?->key, $uri, request()->ip())); } Integration::configureScope(function (Scope $scope): void { diff --git a/app/Exceptions/QuoteConversion.php b/app/Exceptions/QuoteConversion.php new file mode 100644 index 000000000000..a4812f4c1bdb --- /dev/null +++ b/app/Exceptions/QuoteConversion.php @@ -0,0 +1,41 @@ +json(['message' => 'This quote has already been converted. Cannot convert again.'], 400); + } +} diff --git a/app/Filters/ExpenseFilters.php b/app/Filters/ExpenseFilters.php index d589362a63b7..325606b30664 100644 --- a/app/Filters/ExpenseFilters.php +++ b/app/Filters/ExpenseFilters.php @@ -106,6 +106,15 @@ class ExpenseFilters extends QueryFilters return $this->builder; } + public function has_invoices(string $value = ''): Builder + { + if ($value == 'true') { + return $this->builder->whereNotNull('invoice_id'); + } + + return $this->builder; + } + /** * Returns a list of expenses that can be matched to bank transactions */ diff --git a/app/Http/Controllers/ActivityController.php b/app/Http/Controllers/ActivityController.php index 9bb69c13f15c..ac850442125e 100644 --- a/app/Http/Controllers/ActivityController.php +++ b/app/Http/Controllers/ActivityController.php @@ -92,46 +92,47 @@ class ActivityController extends BaseController ->company() ->take($default_activities); - if ($request->has('react')) { + // if ($request->has('react')) { - /** @var \App\Models\User auth()->user() */ - $user = auth()->user(); + // /** @var \App\Models\User auth()->user() */ + // $user = auth()->user(); - if (!$user->isAdmin()) { - $activities->where('user_id', auth()->user()->id); - } + // if (!$user->isAdmin()) { + // $activities->where('user_id', auth()->user()->id); + // } - $system = ctrans('texts.system'); + // $system = ctrans('texts.system'); - $data = $activities->cursor()->map(function ($activity) { + // $data = $activities->cursor()->map(function ($activity) { - $arr = - [ - 'client' => $activity->client ? $activity->client : '', - 'contact' => $activity->client ? $activity->contact : '', - 'quote' => $activity->quote ? $activity->quote : '', - 'user' => $activity->user ? $activity->user : '', - 'expense' => $activity->expense ? $activity->expense : '', - 'invoice' => $activity->invoice ? $activity->invoice : '', - 'recurring_invoice' => $activity->recurring_invoice ? $activity->recurring_invoice : '', - 'payment' => $activity->payment ? $activity->payment : '', - 'credit' => $activity->credit ? $activity->credit : '', - 'task' => $activity->task ? $activity->task : '', - 'vendor' => $activity->vendor ? $activity->vendor : '', - 'purchase_order' => $activity->purchase_order ? $activity->purchase_order : '', - 'subscription' => $activity->subscription ? $activity->subscription : '', - 'vendor_contact' => $activity->vendor_contact ? $activity->vendor_contact : '', - 'recurring_expense' => $activity->recurring_expense ? $activity->recurring_expense : '', - ]; + // $arr = + // [ + // 'client' => $activity->client ? $activity->client : '', + // 'contact' => $activity->client ? $activity->contact : '', + // 'quote' => $activity->quote ? $activity->quote : '', + // 'user' => $activity->user ? $activity->user : '', + // 'expense' => $activity->expense ? $activity->expense : '', + // 'invoice' => $activity->invoice ? $activity->invoice : '', + // 'recurring_invoice' => $activity->recurring_invoice ? $activity->recurring_invoice : '', + // 'payment' => $activity->payment ? $activity->payment : '', + // 'credit' => $activity->credit ? $activity->credit : '', + // 'task' => $activity->task ? $activity->task : '', + // 'vendor' => $activity->vendor ? $activity->vendor : '', + // 'purchase_order' => $activity->purchase_order ? $activity->purchase_order : '', + // 'subscription' => $activity->subscription ? $activity->subscription : '', + // 'vendor_contact' => $activity->vendor_contact ? $activity->vendor_contact : '', + // 'recurring_expense' => $activity->recurring_expense ? $activity->recurring_expense : '', + // ]; - $activity_array = $activity->toArray(); + // $activity_array = $activity->toArray(); - return array_merge($arr, $activity_array); - }); + // return array_merge($arr, $activity_array); + // }); - return response()->json(['data' => $data->toArray()], 200); - } - elseif($request->has('reactv2')) { + // return response()->json(['data' => $data->toArray()], 200); + // } + // else + if($request->has('reactv2')) { /** @var \App\Models\User auth()->user() */ $user = auth()->user(); diff --git a/app/Http/Controllers/ChartController.php b/app/Http/Controllers/ChartController.php index 85b387d30202..69669159c68f 100644 --- a/app/Http/Controllers/ChartController.php +++ b/app/Http/Controllers/ChartController.php @@ -61,7 +61,7 @@ class ChartController extends BaseController /** @var \App\Models\User auth()->user() */ $user = auth()->user(); $cs = new ChartService($user->company(), $user, $user->isAdmin()); - + return response()->json($cs->chart_summary($request->input('start_date'), $request->input('end_date')), 200); } diff --git a/app/Http/Requests/Chart/ShowChartRequest.php b/app/Http/Requests/Chart/ShowChartRequest.php index 83754f2a86e0..f7b4f63ba7e0 100644 --- a/app/Http/Requests/Chart/ShowChartRequest.php +++ b/app/Http/Requests/Chart/ShowChartRequest.php @@ -12,9 +12,12 @@ namespace App\Http\Requests\Chart; use App\Http\Requests\Request; +use App\Utils\Traits\MakesDates; class ShowChartRequest extends Request { + use MakesDates; + /** * Determine if the user is authorized to make this request. * @@ -22,14 +25,18 @@ class ShowChartRequest extends Request */ public function authorize() : bool { - return auth()->user()->isAdmin(); + /**@var \App\Models\User auth()->user */ + $user = auth()->user(); + + return $user->isAdmin(); } public function rules() { return [ - 'start_date' => 'date', - 'end_date' => 'date', + 'date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,all_time,custom', + 'start_date' => 'bail|sometimes|date', + 'end_date' => 'bail|sometimes|date', ]; } @@ -37,12 +44,18 @@ class ShowChartRequest extends Request { $input = $this->all(); - if (! array_key_exists('start_date', $input)) { - $input['start_date'] = now()->subDays(20); + if(isset($input['date_range'])) { + $dates = $this->calculateStartAndEndDates($input); + $input['start_date'] = $dates[0]; + $input['end_date'] = $dates[1]; } - if (! array_key_exists('end_date', $input)) { - $input['end_date'] = now(); + if (! isset($input['start_date'])) { + $input['start_date'] = now()->subDays(20)->format('Y-m-d'); + } + + if (! isset($input['end_date'])) { + $input['end_date'] = now()->format('Y-m-d'); } $this->replace($input); diff --git a/app/Jobs/Bank/ProcessBankTransactions.php b/app/Jobs/Bank/ProcessBankTransactions.php index 019f93dc333b..469ba5c98e49 100644 --- a/app/Jobs/Bank/ProcessBankTransactions.php +++ b/app/Jobs/Bank/ProcessBankTransactions.php @@ -79,7 +79,7 @@ class ProcessBankTransactions implements ShouldQueue $e->getMessage(), ]; - $this->bank_integration->account->company->notification(new GenericNinjaAdminNotification($content))->ninja(); + $this->bank_integration->company->notification(new GenericNinjaAdminNotification($content))->ninja(); return; } } while ($this->stop_loop); diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index bae27f44c5c0..674b4e7c0579 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -135,6 +135,7 @@ class Import implements ShouldQueue 'recurring_expenses', 'tasks', 'documents', + 'activities', ]; /** @@ -181,7 +182,7 @@ class Import implements ShouldQueue public function middleware() { - return [(new WithoutOverlapping($this->user->account_id))]; + return [(new WithoutOverlapping($this->company->company_key))]; } /** @@ -303,7 +304,7 @@ class Import implements ShouldQueue if (round($total_invoice_payments, 2) != round($client->paid_to_date, 2)) { $client->paid_to_date = $total_invoice_payments; - $client->save(); + $client->saveQuietly(); } }); } @@ -319,12 +320,12 @@ class Import implements ShouldQueue $company_ledger->notes = 'Migrated Client Balance'; $company_ledger->balance = $invoice_balances; $company_ledger->activity_id = Activity::CREATE_CLIENT; - $company_ledger->save(); + $company_ledger->saveQuietly(); $client->company_ledger()->save($company_ledger); $client->balance = $invoice_balances; - $client->save(); + $client->saveQuietly(); }); } @@ -1776,6 +1777,78 @@ class Import implements ShouldQueue $data = null; } + private function processActivities(array $data): void + { + Activity::where('company_id', $this->company->id)->cursor()->each(function ($a){ + $a->forceDelete(); + nlog("deleting {$a->id}"); + }); + + Activity::unguard(); + + foreach ($data as $resource) { + $modified = $resource; + + $modified['company_id'] = $this->company->id; + $modified['user_id'] = $this->processUserId($resource); + +try { + if (isset($modified['client_id'])) { + $modified['client_id'] = $this->transformId('clients', $resource['client_id']); + } + + if (isset($modified['invoice_id'])) { + $modified['invoice_id'] = $this->transformId('invoices', $resource['invoice_id']); + } + + if (isset($modified['quote_id'])) { + $modified['quote_id'] = $this->transformId('quotes', $resource['quote_id']); + } + + if (isset($modified['recurring_invoice_id'])) { + $modified['recurring_invoice_id'] = $this->transformId('recurring_invoices', $resource['recurring_invoice_id']); + } + + if (isset($modified['payment_id'])) { + $modified['payment_id'] = $this->transformId('payments', $resource['payment_id']); + } + + if (isset($modified['credit_id'])) { + $modified['credit_id'] = $this->transformId('credits', $resource['credit_id']); + } + + if (isset($modified['expense_id'])) { + $modified['expense_id'] = $this->transformId('expenses', $resource['expense_id']); + } + + if (isset($modified['task_id'])) { + $modified['task_id'] = $this->transformId('tasks', $resource['task_id']); + } + + if (isset($modified['client_contact_id'])) { + $modified['client_contact_id'] = $this->transformId('client_contacts', $resource['client_contact_id']); + } + + $modified['updated_at'] = $modified['created_at']; + + $act = Activity::make($modified); + + $act->save(['timestamps' => false]); +} +catch (\Exception $e) { + +nlog("could not import activity: {$e->getMessage()}"); + +} + + } + + + Activity::reguard(); + + } + + private function processExpenses(array $data) :void { Expense::unguard(); diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php index c7955d3f40e7..e11234f6785c 100644 --- a/app/Jobs/Util/ReminderJob.php +++ b/app/Jobs/Util/ReminderJob.php @@ -126,7 +126,7 @@ class ReminderJob implements ShouldQueue } $reminder_template = $invoice->calculateTemplate('invoice'); - nlog("reminder template = {$reminder_template}"); + // nlog("reminder template = {$reminder_template}"); $invoice->service()->touchReminder($reminder_template)->save(); $fees = $this->calcLateFee($invoice, $reminder_template); diff --git a/app/Jobs/Util/WebhookSingle.php b/app/Jobs/Util/WebhookSingle.php index ca6185a5c3dd..26f79e992250 100644 --- a/app/Jobs/Util/WebhookSingle.php +++ b/app/Jobs/Util/WebhookSingle.php @@ -122,7 +122,9 @@ class WebhookSingle implements ShouldQueue $client = new Client(['headers' => array_merge($base_headers, $headers)]); try { - $response = $client->{$subscription->rest_method}($subscription->target_url, [ + $verb = $subscription->rest_method ?? 'post'; + + $response = $client->{$verb}($subscription->target_url, [ RequestOptions::JSON => $data, // or 'json' => [...] ]); diff --git a/app/Listeners/Activity/PaymentCreatedActivity.php b/app/Listeners/Activity/PaymentCreatedActivity.php index adbacbdd88e0..ff0c0abd0889 100644 --- a/app/Listeners/Activity/PaymentCreatedActivity.php +++ b/app/Listeners/Activity/PaymentCreatedActivity.php @@ -38,25 +38,28 @@ class PaymentCreatedActivity implements ShouldQueue * @return void */ public function handle($event) - { + { + MultiDB::setDb($event->company->db); $payment = $event->payment; + $invoice_id = null; + + if($payment->invoices()->exists()) + $invoice_id = $payment->invoices()->first()->id; $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->payment->user_id; - $invoices = $payment->invoices; - $fields = new stdClass; $fields->payment_id = $payment->id; + $fields->invoice_id = $invoice_id; $fields->client_id = $payment->client_id; $fields->user_id = $user_id; $fields->company_id = $payment->company_id; $fields->activity_type_id = Activity::CREATE_PAYMENT; - if (count($invoices) == 0) { - $this->activity_repo->save($fields, $payment, $event->event_vars); - } + $this->activity_repo->save($fields, $payment, $event->event_vars); + } } diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 679373fa0363..d0edf254e2c9 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -515,9 +515,8 @@ class Activity extends StaticModel { $system = ctrans('texts.system'); - return match($variable) { - ':invoice' => $translation = [substr($variable, 1) => [ 'label' => $this?->invoice?->number ?? '', 'hashed_id' => $this->invoice?->hashed_id ?? '']], - ':contact' => $translation = $this->resolveContact(), + match($variable) { + ':invoice' => $translation = [substr($variable, 1) => [ 'label' => $this?->invoice?->number ?? '', 'hashed_id' => $this->invoice?->hashed_id ?? '']], ':user' => $translation = [substr($variable, 1) => [ 'label' => $this?->user?->present()->name() ?? $system, 'hashed_id' => $this->user->hashed_id ?? '']], ':quote' => $translation = [substr($variable, 1) => [ 'label' => $this?->quote?->number ?? '', 'hashed_id' => $this->quote->hashed_id ?? '']], ':credit' => $translation = [substr($variable, 1) => [ 'label' => $this?->credit?->number ?? '', 'hashed_id' => $this->credit->hashed_id ?? '']], @@ -531,6 +530,7 @@ class Activity extends StaticModel ':payment_amount' => $translation = [substr($variable, 1) =>[ 'label' => Number::formatMoney($this?->payment?->amount, $this?->payment?->client) ?? '', 'hashed_id' => '']], ':adjustment' => $translation = [substr($variable, 1) =>[ 'label' => Number::formatMoney($this?->payment?->refunded, $this?->payment?->client) ?? '', 'hashed_id' => '']], ':ip' => $translation = [ 'ip' => $this->ip ?? ''], + ':contact' => $translation = $this->resolveContact(), default => $translation = [], }; diff --git a/app/Models/Expense.php b/app/Models/Expense.php index 648e1d5635e9..00a16129fc9f 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -225,6 +225,11 @@ class Expense extends BaseModel return $this->belongsTo(Company::class); } + public function invoice() + { + return $this->belongsTo(Invoice::class); + } + public function vendor() { return $this->belongsTo(Vendor::class); diff --git a/app/Repositories/PaymentRepository.php b/app/Repositories/PaymentRepository.php index 0b4be3c46880..073f04fd7cec 100644 --- a/app/Repositories/PaymentRepository.php +++ b/app/Repositories/PaymentRepository.php @@ -185,7 +185,7 @@ class PaymentRepository extends BaseRepository $paymentable->payment_id = $payment->id; $paymentable->paymentable_id = $credit->id; $paymentable->paymentable_type = Credit::class; - $paymentable->amount = $paid_invoice['amount']; + $paymentable->amount = $paid_credit['amount']; $paymentable->save(); $credit = $credit->service()->markSent()->save(); diff --git a/app/Services/Chart/ChartService.php b/app/Services/Chart/ChartService.php index c9a8be50eda7..3378c998aeec 100644 --- a/app/Services/Chart/ChartService.php +++ b/app/Services/Chart/ChartService.php @@ -76,6 +76,8 @@ class ChartService $currencies = $this->getCurrencyCodes(); $data = []; + $data['start_date'] = $start_date; + $data['end_date'] = $end_date; foreach ($currencies as $key => $value) { $data[$key]['invoices'] = $this->getInvoiceChartQuery($start_date, $end_date, $key); @@ -97,6 +99,9 @@ class ChartService $data['currencies'] = $this->getCurrencyCodes(); + $data['start_date'] = $start_date; + $data['end_date'] = $end_date; + $revenue = $this->getRevenue($start_date, $end_date); $outstanding = $this->getOutstanding($start_date, $end_date); $expenses = $this->getExpenses($start_date, $end_date); diff --git a/app/Services/Pdf/PdfBuilder.php b/app/Services/Pdf/PdfBuilder.php index 39775948626a..78d8d38fb2a9 100644 --- a/app/Services/Pdf/PdfBuilder.php +++ b/app/Services/Pdf/PdfBuilder.php @@ -653,7 +653,7 @@ class PdfBuilder $data[$key][$table_type.".{$_table_type}4"] = strlen($item->custom_value4) >= 1 ? $helpers->formatCustomFieldValue($this->service->company->custom_fields, "{$_table_type}4", $item->custom_value4, $this->service->config->currency_entity) : ''; if ($item->quantity > 0 || $item->cost > 0) { - $data[$key][$table_type.'.quantity'] = $this->service->config->formatMoney($item->quantity); + $data[$key][$table_type.'.quantity'] = $item->quantity; $data[$key][$table_type.'.unit_cost'] = $this->service->config->formatMoney($item->cost); diff --git a/app/Services/Pdf/PdfMock.php b/app/Services/Pdf/PdfMock.php index 8c569ed0323f..06a572c0680d 100644 --- a/app/Services/Pdf/PdfMock.php +++ b/app/Services/Pdf/PdfMock.php @@ -232,6 +232,9 @@ class PdfMock '$secondary_font_url' => 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', '$contact.signature' => '', '$company_logo_size' => $this->settings->company_logo_size ?: '65%', + '$product.tax_rate1' => ctrans('texts.tax'), + '$product.tax_rate2' => ctrans('texts.tax'), + '$product.tax_rate3' => ctrans('texts.tax'), '$product.tax_name1' => '', '$product.tax_name2' => '', '$product.tax_name3' => '', @@ -688,8 +691,11 @@ class PdfMock '$net_subtotal_label' => ctrans('texts.net_subtotal'), '$credit.total_label' => ctrans('texts.total'), '$quote.amount_label' => ctrans('texts.amount'), - '$description_label' => ctrans('texts.description'), + '$product.tax_rate1_label' => ctrans('texts.tax'), + '$product.tax_rate2_label' => ctrans('texts.tax'), + '$product.tax_rate3_label' => ctrans('texts.tax'), '$product.tax_label' => ctrans('texts.tax'), + '$description_label' => ctrans('texts.description'), '$your_entity_label' => ctrans("texts.your_{$this->entity_string}"), '$view_button_label' => ctrans('texts.view'), '$status_logo_label' => ctrans('texts.logo'), @@ -782,9 +788,9 @@ class PdfMock '$amount_label' => ctrans('texts.amount'), '$notes_label' => ctrans('texts.notes'), '$terms_label' => ctrans('texts.terms'), - 'tax_rate1_label' => ctrans('texts.tax_rate1'), - 'tax_rate2_label' => ctrans('texts.tax_rate2'), - 'tax_rate3_label' => ctrans('texts.tax_rate3'), + '$tax_rate1_label' => ctrans('texts.tax_rate1'), + '$tax_rate2_label' => ctrans('texts.tax_rate2'), + '$tax_rate3_label' => ctrans('texts.tax_rate3'), '$phone_label' => ctrans('texts.phone'), '$email_label' => ctrans('texts.email'), '$taxes_label' => ctrans('texts.taxes'), diff --git a/app/Services/Quote/QuoteService.php b/app/Services/Quote/QuoteService.php index 56ab95d8eb38..fe6189106c47 100644 --- a/app/Services/Quote/QuoteService.php +++ b/app/Services/Quote/QuoteService.php @@ -11,14 +11,14 @@ namespace App\Services\Quote; -use App\Events\Quote\QuoteWasApproved; -use App\Jobs\Entity\CreateEntityPdf; -use App\Jobs\Util\UnlinkFile; -use App\Models\Invoice; -use App\Models\Quote; -use App\Repositories\QuoteRepository; use App\Utils\Ninja; +use App\Models\Quote; +use App\Jobs\Util\UnlinkFile; use App\Utils\Traits\MakesHash; +use App\Exceptions\QuoteConversion; +use App\Jobs\Entity\CreateEntityPdf; +use App\Repositories\QuoteRepository; +use App\Events\Quote\QuoteWasApproved; class QuoteService { @@ -43,7 +43,7 @@ class QuoteService public function convert() :self { if ($this->quote->invoice_id) { - return $this; + throw new QuoteConversion(); } $convert_quote = (new ConvertQuote($this->quote->client))->run($this->quote); diff --git a/app/Services/Scheduler/EmailReport.php b/app/Services/Scheduler/EmailReport.php index ce76e54fad04..f1def5d9b61c 100644 --- a/app/Services/Scheduler/EmailReport.php +++ b/app/Services/Scheduler/EmailReport.php @@ -58,7 +58,8 @@ class EmailReport public function run() { - $start_end_dates = $this->calculateStartAndEndDates(); + $start_end_dates = $this->calculateStartAndEndDates($this->scheduler->parameters); + $data = []; $data = [ diff --git a/app/Services/Tax/Providers/ZipTax.php b/app/Services/Tax/Providers/ZipTax.php index 0cc0dd1a5524..dad7ef0768fc 100644 --- a/app/Services/Tax/Providers/ZipTax.php +++ b/app/Services/Tax/Providers/ZipTax.php @@ -69,7 +69,7 @@ class ZipTax implements TaxProviderInterface private function parseResponse($response) { - if(isset($response['rCode']) && $response['rCode'] == 100) + if(isset($response['rCode']) && $response['rCode'] == 100 && isset($response['results']['0'])) return $response['results']['0']; if(isset($response['rCode']) && class_exists(\Modules\Admin\Events\TaxProviderException::class)) diff --git a/app/Transformers/ExpenseTransformer.php b/app/Transformers/ExpenseTransformer.php index f703da58058a..7fb5c8826638 100644 --- a/app/Transformers/ExpenseTransformer.php +++ b/app/Transformers/ExpenseTransformer.php @@ -11,12 +11,15 @@ namespace App\Transformers; -use App\Models\Document; -use App\Models\Expense; use App\Models\Vendor; +use App\Models\Expense; +use App\Models\Invoice; +use App\Models\Document; +use App\Models\ExpenseCategory; use App\Utils\Traits\MakesHash; -use Illuminate\Database\Eloquent\SoftDeletes; use League\Fractal\Resource\Item; +use Illuminate\Database\Eloquent\SoftDeletes; +use App\Transformers\ExpenseCategoryTransformer; /** * class ExpenseTransformer. @@ -36,6 +39,8 @@ class ExpenseTransformer extends EntityTransformer protected $availableIncludes = [ 'client', 'vendor', + 'category', + 'invoice', ]; public function includeDocuments(Expense $expense) @@ -56,6 +61,28 @@ class ExpenseTransformer extends EntityTransformer return $this->includeItem($expense->client, $transformer, Client::class); } + public function includeInvoice(Expense $expense): ?Item + { + $transformer = new InvoiceTransformer($this->serializer); + + if (!$expense->invoice) { + return null; + } + + return $this->includeItem($expense->invoice, $transformer, Invoice::class); + } + + public function includeCategory(Expense $expense): ?Item + { + $transformer = new ExpenseCategoryTransformer($this->serializer); + + if (!$expense->category) { + return null; + } + + return $this->includeItem($expense->category, $transformer, ExpenseCategory::class); + } + public function includeVendor(Expense $expense): ?Item { $transformer = new VendorTransformer($this->serializer); diff --git a/app/Utils/Traits/MakesDates.php b/app/Utils/Traits/MakesDates.php index f63977932db2..caea8e926d64 100644 --- a/app/Utils/Traits/MakesDates.php +++ b/app/Utils/Traits/MakesDates.php @@ -119,9 +119,9 @@ trait MakesDates * * @return array [$start_date, $end_date]; */ - public function calculateStartAndEndDates(): array + public function calculateStartAndEndDates(array $data): array { - return match ($this->scheduler->parameters['date_range']) { + return match ($data['date_range']) { EmailStatement::LAST7 => [now()->startOfDay()->subDays(7)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')], EmailStatement::LAST30 => [now()->startOfDay()->subDays(30)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')], EmailStatement::LAST365 => [now()->startOfDay()->subDays(365)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')], @@ -131,9 +131,9 @@ trait MakesDates EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->lastOfQuarter()->format('Y-m-d')], EmailStatement::THIS_YEAR => [now()->startOfDay()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->lastOfYear()->format('Y-m-d')], EmailStatement::LAST_YEAR => [now()->startOfDay()->subYearNoOverflow()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->subYearNoOverflow()->lastOfYear()->format('Y-m-d')], - EmailStatement::CUSTOM_RANGE => [$this->scheduler->parameters['start_date'], $this->scheduler->parameters['end_date']], + EmailStatement::CUSTOM_RANGE => [$data['start_date'], $data['end_date']], default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')], }; } -} +} \ No newline at end of file diff --git a/lang/en/texts.php b/lang/en/texts.php index aa92fb260bf5..8d7f8c01f0be 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -3863,7 +3863,7 @@ $LANG = array( 'notification_credit_viewed' => 'The following client :client viewed Credit :credit for :amount.', 'reset_password_text' => 'Enter your email to reset your password.', 'password_reset' => 'Password reset', - 'account_login_text' => 'Welcome back! Glad to see you.', + 'account_login_text' => 'Welcome! Glad to see you.', 'request_cancellation' => 'Request cancellation', 'delete_payment_method' => 'Delete Payment Method', 'about_to_delete_payment_method' => 'You are about to delete the payment method.', diff --git a/tests/Feature/QuoteTest.php b/tests/Feature/QuoteTest.php index c324f05f8c30..320a4f1149d0 100644 --- a/tests/Feature/QuoteTest.php +++ b/tests/Feature/QuoteTest.php @@ -11,16 +11,17 @@ namespace Tests\Feature; -use App\Models\ClientContact; -use App\Models\Project; -use App\Models\Quote; -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 App\Models\Quote; +use App\Models\Project; +use Tests\MockAccountData; +use App\Models\ClientContact; +use App\Utils\Traits\MakesHash; +use App\Exceptions\QuoteConversion; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Session; +use Illuminate\Routing\Middleware\ThrottleRequests; +use Illuminate\Foundation\Testing\DatabaseTransactions; /** * @test @@ -32,6 +33,8 @@ class QuoteTest extends TestCase use DatabaseTransactions; use MockAccountData; + public $faker; + protected function setUp() :void { parent::setUp(); @@ -49,6 +52,19 @@ class QuoteTest extends TestCase ); } + public function testQuoteConversion() + { + $invoice = $this->quote->service()->convertToInvoice(); + + $this->assertInstanceOf('\App\Models\Invoice', $invoice); + + $this->expectException(QuoteConversion::class); + + $invoice = $this->quote->service()->convertToInvoice(); + + + } + public function testQuoteDownloadPDF() { $i = $this->quote->invitations->first();