diff --git a/app/Models/Location.php b/app/Models/Location.php index 88eca085fd..c839e80085 100644 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -24,22 +24,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property int $user_id * @property int|null $vendor_id * @property int|null $client_id - * @property int|null $assigned_user_id * @property string|null $name - * @property string|null $website - * @property string|null $private_notes - * @property string|null $public_notes - * @property string|null $client_hash - * @property string|null $logo - * @property string|null $phone - * @property string|null $routing_id - * @property float $balance - * @property float $paid_to_date - * @property float $credit_balance - * @property int|null $last_login - * @property int|null $industry_id - * @property int|null $size_id - * @property object|array|null $e_invoice * @property string|null $address1 * @property string|null $address2 * @property string|null $city @@ -52,10 +37,10 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property string|null $custom_value4 * @property bool $is_deleted * @property bool $is_shipping_location - * @property object|array|null $tax_data * @property int|null $created_at * @property int|null $updated_at * @property int|null $deleted_at + * @property object|array|null $tax_data * @property-read mixed $hashed_id * @property-read \App\Models\User $user * @property-read \App\Models\Client|null $client diff --git a/app/Models/Task.php b/app/Models/Task.php index eda0b81716..c58740f661 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -16,6 +16,8 @@ use Carbon\CarbonInterval; use App\Models\CompanyUser; use Illuminate\Support\Carbon; use App\Utils\Traits\MakesHash; +use Illuminate\Support\Facades\App; +use Elastic\ScoutDriverPlus\Searchable; use Illuminate\Database\Eloquent\SoftDeletes; use App\Libraries\Currency\Conversion\CurrencyApi; @@ -105,6 +107,7 @@ class Task extends BaseModel use MakesHash; use SoftDeletes; use Filterable; + use Searchable; protected $fillable = [ 'client_id', @@ -147,6 +150,78 @@ class Task extends BaseModel return self::class; } + public function toSearchableArray() + { + $locale = $this->company->locale(); + + App::setLocale($locale); + + $project = $this->project ? " | [ {$this->project->name} ]" : ' '; + $client = $this->client ? " | {$this->client->present()->name()} ]" : ' '; + + // Get basic data + $data = [ + 'id' => $this->company->db.":".$this->id, + 'name' => ctrans('texts.task') . " " . ($this->number ?? '') . $project . $client, + 'hashed_id' => $this->hashed_id, + 'number' => (string)$this->number, + 'description' => (string)$this->description, + 'task_rate' => (float) $this->rate, + 'is_deleted' => (bool) $this->is_deleted, + 'custom_value1' => (string) $this->custom_value1, + 'custom_value2' => (string) $this->custom_value2, + 'custom_value3' => (string) $this->custom_value3, + 'custom_value4' => (string) $this->custom_value4, + 'company_key' => $this->company->company_key, + 'time_log' => $this->normalizeTimeLog($this->time_log), + ]; + + return $data; + } + + /** + * Normalize time_log for Elasticsearch indexing + * Handles polymorphic structure: [start, end?, description?, billable?] + */ + private function normalizeTimeLog($time_log): array + { + // Handle null/empty cases + if (empty($time_log)) { + return []; + } + + $logs = json_decode($time_log, true); + + // Validate decoded data + if (!is_array($logs) || empty($logs)) { + return []; + } + + $normalized = []; + + foreach ($logs as $log) { + // Skip invalid entries + if (!is_array($log) || !isset($log[0])) { + continue; + } + + $normalized[] = [ + 'start_time' => (int) $log[0], + 'end_time' => isset($log[1]) && $log[1] !== 0 ? (int) $log[1] : null, + 'description' => isset($log[2]) ? trim((string) $log[2]) : '', + 'billable' => isset($log[3]) ? (bool) $log[3] : false, + 'is_running' => isset($log[1]) && $log[1] === 0, + ]; + } + + return $normalized; + } + + public function getScoutKey() + { + return $this->company->db.":".$this->id; + } + /** * Get all of the users that belong to the team. * diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 209f65cdd7..0b8a218edd 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -198,6 +198,15 @@ class HtmlEngine $data['$payment_schedule_interval'] = ['value' => $this->entity->paymentScheduleInterval(), 'label' => ctrans('texts.payment_schedule')]; } + $data['$location1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'location1', $this->entity->location?->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'location1')]; + $data['$location2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'location2', $this->entity->location?->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'location2')]; + $data['$location3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'location3', $this->entity->location?->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'location3')]; + $data['$location4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'location4', $this->entity->location?->custom_value4, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'location4')]; + $data['$location.custom1'] = &$data['$location1']; + $data['$location.custom2'] = &$data['$location2']; + $data['$location.custom3'] = &$data['$location3']; + $data['$location.custom4'] = &$data['$location4']; + if ($this->entity_string == 'invoice' || $this->entity_string == 'recurring_invoice') { $data['$entity'] = ['value' => ctrans('texts.invoice'), 'label' => ctrans('texts.invoice')]; $data['$number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.invoice_number')]; @@ -217,7 +226,7 @@ class HtmlEngine $data['$invoice.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice2', $this->entity->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice2')]; $data['$invoice.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice3', $this->entity->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice3')]; $data['$invoice.custom4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice4', $this->entity->custom_value4, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice4')]; - + $data['$custom1'] = &$data['$invoice.custom1']; $data['$custom2'] = &$data['$invoice.custom2']; $data['$custom3'] = &$data['$invoice.custom3']; diff --git a/app/Utils/VendorHtmlEngine.php b/app/Utils/VendorHtmlEngine.php index 9fe999888c..db4f2a03be 100644 --- a/app/Utils/VendorHtmlEngine.php +++ b/app/Utils/VendorHtmlEngine.php @@ -179,6 +179,15 @@ class VendorHtmlEngine $data['$subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal(), $this->vendor) ?: ' ', 'label' => ctrans('texts.subtotal')]; $data['$gross_subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getGrossSubTotal(), $this->vendor) ?: ' ', 'label' => ctrans('texts.subtotal')]; + $data['$location1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'location1', $this->entity->location?->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'location1')]; + $data['$location2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'location2', $this->entity->location?->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'location2')]; + $data['$location3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'location3', $this->entity->location?->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'location3')]; + $data['$location4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'location4', $this->entity->location?->custom_value4, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'location4')]; + $data['$location.custom1'] = &$data['$location1']; + $data['$location.custom2'] = &$data['$location2']; + $data['$location.custom3'] = &$data['$location3']; + $data['$location.custom4'] = &$data['$location4']; + if ($this->entity->uses_inclusive_taxes) { $data['$net_subtotal'] = ['value' => Number::formatMoney(($this->entity_calc->getSubTotal() - $this->entity->total_taxes - $this->entity_calc->getTotalDiscount()), $this->vendor) ?: ' ', 'label' => ctrans('texts.net_subtotal')]; } else { diff --git a/composer.json b/composer.json index 84ecf5629d..1eb1244a93 100644 --- a/composer.json +++ b/composer.json @@ -67,7 +67,6 @@ "intervention/image": "^2.5", "invoiceninja/einvoice": "dev-main", "invoiceninja/ubl_invoice": "^3", - "invoiceninja/admin-api": "dev-main", "josemmo/facturae-php": "^1.7", "laracasts/presenter": "^0.2.1", "laravel/framework": "^v11", @@ -222,8 +221,8 @@ "url": "https://github.com/turbo124/snappdf" }, { - "type": "vcs", - "url": "https://github.com/invoiceninja/admin-api" + "type": "path", + "url": "../admin-api" } ], "minimum-stability": "dev", diff --git a/composer.lock b/composer.lock index 3f14e3db0d..72ab198289 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "34fdac2d80247045c92d8ddf41ca0d50", + "content-hash": "76aa3099a372c88f8afbbca1d30fc30c", "packages": [ { "name": "afosto/yaac", @@ -4482,74 +4482,6 @@ ], "time": "2022-05-21T17:30:32+00:00" }, - { - "name": "invoiceninja/admin-api", - "version": "dev-main", - "source": { - "type": "git", - "url": "git@github.com:invoiceninja/admin-api.git", - "reference": "d81d466bee660731986a8cd8a73262d63d758a1d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/invoiceninja/admin-api/zipball/d81d466bee660731986a8cd8a73262d63d758a1d", - "reference": "d81d466bee660731986a8cd8a73262d63d758a1d", - "shasum": "" - }, - "require": { - "afosto/yaac": "^1.5", - "asm/php-ansible": "dev-main", - "ext-curl": "*", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-simplexml": "*", - "illuminate/database": "^11", - "illuminate/support": "^11", - "imdhemy/laravel-purchases": "^1.7", - "php": "^8.2|^8.3|^8.4" - }, - "require-dev": { - "larastan/larastan": "^3.0", - "orchestra/testbench": "^9.0", - "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^11.0" - }, - "default-branch": true, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "InvoiceNinja\\AdminApi\\Providers\\AdminApiServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "InvoiceNinja\\AdminApi\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "Tests\\": "tests/" - } - }, - "license": [ - "Elastic" - ], - "authors": [ - { - "name": "David Bomba", - "email": "turbo124@gmail.com" - } - ], - "description": "API endpoints for the admin interface", - "support": { - "source": "https://github.com/invoiceninja/admin-api/tree/main", - "issues": "https://github.com/invoiceninja/admin-api/issues" - }, - "time": "2025-08-30T22:31:51+00:00" - }, { "name": "invoiceninja/einvoice", "version": "dev-main", @@ -21561,7 +21493,6 @@ "asm/php-ansible": 20, "beganovich/snappdf": 20, "invoiceninja/einvoice": 20, - "invoiceninja/admin-api": 20, "socialiteproviders/apple": 20 }, "prefer-stable": true,