diff --git a/.github/workflows/react_release.yml b/.github/workflows/react_release.yml index 050ba6965879..55f42040ffdf 100644 --- a/.github/workflows/react_release.yml +++ b/.github/workflows/react_release.yml @@ -66,7 +66,7 @@ jobs: - name: Build project run: | shopt -s dotglob - tar --exclude='public/storage' --exclude='./htaccess' --exclude='invoiceninja.zip' -zcvf /home/runner/work/invoiceninja/react-invoiceninja.tar * + tar --exclude='public/storage' --exclude='./htaccess' --exclude='invoiceninja.zip' -zcvf /home/runner/work/invoiceninja/invoiceninja.tar * - name: Release uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/') @@ -74,4 +74,4 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: files: | - /home/runner/work/invoiceninja/react-invoiceninja.tar \ No newline at end of file + /home/runner/work/invoiceninja/invoiceninja.tar \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index e2802e6c2f75..000000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,84 +0,0 @@ -on: - release: - types: [released] - -name: Upload Release Asset - -jobs: - build: - name: Upload Release Asset - runs-on: ubuntu-latest - steps: - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: 8.2 - extensions: mysql, mysqlnd, sqlite3, bcmath, gd, curl, zip, openssl, mbstring, xml - - - name: Checkout code - uses: actions/checkout@v1 - with: - ref: v5-develop - - - name: Copy .env file - run: | - cp .env.example .env - - - name: Install composer dependencies - run: | - composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }} - composer install --no-dev - - - name: Prepare Laravel Application - run: | - cp .env.example .env - php artisan key:generate --force - php artisan optimize - php artisan storage:link --force - sudo php artisan cache:clear - sudo find ./vendor/bin/ -type f -exec chmod +x {} \; - sudo find ./ -type d -exec chmod 755 {} \; - - - name: Prepare React FrontEnd - run: | - git clone https://${{secrets.commit_secret}}@github.com/invoiceninja/ui.git - cd ui - git checkout develop - npm i - npm run build - - mkdir -p ../public/react/${{ github.event.release.tag_name }}/ - cp -r dist/react/* ../public/react/${{ github.event.release.tag_name }}/ - cp -r dist/react/* ../public/react/ - cp dist/index.html ../resources/views/react/index.blade.php - - mkdir -p ../public/tinymce_6.4.2/tinymce/js/ - cp -r node_modules/tinymce ../public/tinymce_6.4.2/tinymce/js/ - cd .. - rm -rf ui - php artisan ninja:react - - - name: Prepare JS/CSS assets - run: | - npm i - npm run production - - - name: Cleanup Builds - run: | - sudo rm -rf bootstrap/cache/* - sudo rm -rf node_modules - sudo rm -rf .git - sudo rm .env - - - name: Build project - run: | - shopt -s dotglob - tar --exclude='public/storage' --exclude='./htaccess' --exclude='invoiceninja.zip' -zcvf /home/runner/work/invoiceninja/invoiceninja.tar * - - name: Release - uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - files: | - /home/runner/work/invoiceninja/invoiceninja.tar \ No newline at end of file diff --git a/VERSION.txt b/VERSION.txt index 76d1514ddedb..c355d6e2184c 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.9.9 \ No newline at end of file +5.10.0 \ No newline at end of file diff --git a/app/Export/CSV/ActivityExport.php b/app/Export/CSV/ActivityExport.php index 96d3b98106f5..fea9ba8722cd 100644 --- a/app/Export/CSV/ActivityExport.php +++ b/app/Export/CSV/ActivityExport.php @@ -109,7 +109,7 @@ class ActivityExport extends BaseExport $query = Activity::query() ->where('company_id', $this->company->id); - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'activities'); return $query; } diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php index 2ecdce7c4170..b3ab47c4a5d4 100644 --- a/app/Export/CSV/BaseExport.php +++ b/app/Export/CSV/BaseExport.php @@ -1245,13 +1245,13 @@ class BaseExport * @param Builder $query * @return Builder */ - protected function addDateRange(Builder $query): Builder + protected function addDateRange(Builder $query, ?string $table_name = null): Builder { $query = $this->applyProductFilters($query); $date_range = $this->input['date_range']; - if (array_key_exists('date_key', $this->input) && strlen($this->input['date_key']) > 1) { + if (array_key_exists('date_key', $this->input) && strlen($this->input['date_key']) > 1 && ($this->table_name && $this->columnExists($table_name, $this->input['date_key']))) { $this->date_key = $this->input['date_key']; } @@ -1608,5 +1608,18 @@ class BaseExport ZipDocuments::dispatch($documents, $this->company, $user); } } - + + /** + * Tests that the column exists + * on the table prior to adding it to + * the query builder + * + * @param string $table + * @param string $column + * @return bool + */ + public function columnExists($table, $column): bool + { + return \Illuminate\Support\Facades\Schema::hasColumn($table, $column); + } } diff --git a/app/Export/CSV/ClientExport.php b/app/Export/CSV/ClientExport.php index 8732f9800eef..f0a5314f76e6 100644 --- a/app/Export/CSV/ClientExport.php +++ b/app/Export/CSV/ClientExport.php @@ -131,7 +131,7 @@ class ClientExport extends BaseExport $query->where('is_deleted', 0); } - $query = $this->addDateRange($query); + $query = $this->addDateRange($query,' clients'); if($this->input['document_email_attachment'] ?? false) { $this->queueDocuments($query); diff --git a/app/Export/CSV/ContactExport.php b/app/Export/CSV/ContactExport.php index f21fb8157018..21c673b49d96 100644 --- a/app/Export/CSV/ContactExport.php +++ b/app/Export/CSV/ContactExport.php @@ -63,7 +63,7 @@ class ContactExport extends BaseExport $q->where('is_deleted', false); }); - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'client_contacts'); return $query; diff --git a/app/Export/CSV/CreditExport.php b/app/Export/CSV/CreditExport.php index 16ea287a0101..1295d8ec2b6d 100644 --- a/app/Export/CSV/CreditExport.php +++ b/app/Export/CSV/CreditExport.php @@ -108,7 +108,7 @@ class CreditExport extends BaseExport ->where('company_id', $this->company->id) ->where('is_deleted', $this->input['include_deleted'] ?? false); - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'credits'); $clients = &$this->input['client_id']; diff --git a/app/Export/CSV/DocumentExport.php b/app/Export/CSV/DocumentExport.php index 52757287cb1a..8adfe57a0525 100644 --- a/app/Export/CSV/DocumentExport.php +++ b/app/Export/CSV/DocumentExport.php @@ -76,7 +76,7 @@ class DocumentExport extends BaseExport $query = Document::query()->where('company_id', $this->company->id); - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'documents'); if($this->input['document_email_attachment'] ?? false) { $this->queueDocuments($query); diff --git a/app/Export/CSV/ExpenseExport.php b/app/Export/CSV/ExpenseExport.php index 8610193e824a..dfcc554b8891 100644 --- a/app/Export/CSV/ExpenseExport.php +++ b/app/Export/CSV/ExpenseExport.php @@ -89,7 +89,7 @@ class ExpenseExport extends BaseExport $query->where('is_deleted', 0); } - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'expenses'); if($this->input['status'] ?? false) { $query = $this->addExpenseStatusFilter($query, $this->input['status']); diff --git a/app/Export/CSV/InvoiceExport.php b/app/Export/CSV/InvoiceExport.php index e8c096778313..b4e00d42b8b7 100644 --- a/app/Export/CSV/InvoiceExport.php +++ b/app/Export/CSV/InvoiceExport.php @@ -67,7 +67,7 @@ class InvoiceExport extends BaseExport $query->where('is_deleted', 0); } - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'invoices'); $clients = &$this->input['client_id']; diff --git a/app/Export/CSV/InvoiceItemExport.php b/app/Export/CSV/InvoiceItemExport.php index 7068a33170e1..f6d5d814a763 100644 --- a/app/Export/CSV/InvoiceItemExport.php +++ b/app/Export/CSV/InvoiceItemExport.php @@ -79,7 +79,7 @@ class InvoiceItemExport extends BaseExport $query->where('is_deleted', 0); } - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'invoices'); $clients = &$this->input['client_id']; diff --git a/app/Export/CSV/PaymentExport.php b/app/Export/CSV/PaymentExport.php index 02b519346964..d427b3ebe1d6 100644 --- a/app/Export/CSV/PaymentExport.php +++ b/app/Export/CSV/PaymentExport.php @@ -62,7 +62,7 @@ class PaymentExport extends BaseExport ->where('company_id', $this->company->id) ->where('is_deleted', 0); - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'payments'); $clients = &$this->input['client_id']; diff --git a/app/Export/CSV/ProductExport.php b/app/Export/CSV/ProductExport.php index 48d76b8577d2..69bdca55cffb 100644 --- a/app/Export/CSV/ProductExport.php +++ b/app/Export/CSV/ProductExport.php @@ -75,12 +75,11 @@ class ProductExport extends BaseExport ->withTrashed() ->where('company_id', $this->company->id); - - if(!$this->input['include_deleted'] ?? false) { + if(!$this->input['include_deleted'] ?? false) { //@phpstan-ignore-line $query->where('is_deleted', 0); } - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'products'); if($this->input['document_email_attachment'] ?? false) { $this->queueDocuments($query); diff --git a/app/Export/CSV/ProductSalesExport.php b/app/Export/CSV/ProductSalesExport.php index 7b5eb83a243d..a8e2082d183b 100644 --- a/app/Export/CSV/ProductSalesExport.php +++ b/app/Export/CSV/ProductSalesExport.php @@ -129,7 +129,7 @@ class ProductSalesExport extends BaseExport ->where('is_deleted', 0) ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID]); - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'invoices'); $query = $this->filterByClients($query); diff --git a/app/Export/CSV/PurchaseOrderExport.php b/app/Export/CSV/PurchaseOrderExport.php index c09353387d15..2f83844a4186 100644 --- a/app/Export/CSV/PurchaseOrderExport.php +++ b/app/Export/CSV/PurchaseOrderExport.php @@ -67,7 +67,7 @@ class PurchaseOrderExport extends BaseExport $query->where('is_deleted', 0); } - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'purchase_orders'); $clients = &$this->input['client_id']; diff --git a/app/Export/CSV/PurchaseOrderItemExport.php b/app/Export/CSV/PurchaseOrderItemExport.php index fcebc7810f5c..bf39cc26efe7 100644 --- a/app/Export/CSV/PurchaseOrderItemExport.php +++ b/app/Export/CSV/PurchaseOrderItemExport.php @@ -71,7 +71,7 @@ class PurchaseOrderItemExport extends BaseExport $query->where('is_deleted', 0); } - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'purchase_orders'); $clients = &$this->input['client_id']; diff --git a/app/Export/CSV/QuoteExport.php b/app/Export/CSV/QuoteExport.php index 4844963f4ea2..7c77fd990595 100644 --- a/app/Export/CSV/QuoteExport.php +++ b/app/Export/CSV/QuoteExport.php @@ -73,7 +73,7 @@ class QuoteExport extends BaseExport $query->where('is_deleted', 0); } - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'quotes'); $clients = &$this->input['client_id']; diff --git a/app/Export/CSV/QuoteItemExport.php b/app/Export/CSV/QuoteItemExport.php index 04caacf613ad..ddc7279605f9 100644 --- a/app/Export/CSV/QuoteItemExport.php +++ b/app/Export/CSV/QuoteItemExport.php @@ -74,7 +74,7 @@ class QuoteItemExport extends BaseExport $query->where('is_deleted', 0); } - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'quotes'); $clients = &$this->input['client_id']; diff --git a/app/Export/CSV/RecurringInvoiceExport.php b/app/Export/CSV/RecurringInvoiceExport.php index 500137b88683..d6d26e283422 100644 --- a/app/Export/CSV/RecurringInvoiceExport.php +++ b/app/Export/CSV/RecurringInvoiceExport.php @@ -65,7 +65,7 @@ class RecurringInvoiceExport extends BaseExport $query->where('is_deleted', 0); } - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'recurring_invoices'); $clients = &$this->input['client_id']; diff --git a/app/Export/CSV/TaskExport.php b/app/Export/CSV/TaskExport.php index b04020317801..f630517a2c81 100644 --- a/app/Export/CSV/TaskExport.php +++ b/app/Export/CSV/TaskExport.php @@ -74,7 +74,7 @@ class TaskExport extends BaseExport $query->where('is_deleted', 0); } - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'tasks'); $clients = &$this->input['client_id']; @@ -184,13 +184,13 @@ class TaskExport extends BaseExport foreach ($logs as $key => $item) { if (in_array('task.start_date', $this->input['report_keys']) || in_array('start_date', $this->input['report_keys'])) { - $carbon_object = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name); + $carbon_object = Carbon::createFromTimeStamp((int)$item[0])->setTimezone($timezone_name); $entity['task.start_date'] = $carbon_object->format($date_format_default); $entity['task.start_time'] = $carbon_object->format('H:i:s'); } if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] > 0) { - $carbon_object = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name); + $carbon_object = Carbon::createFromTimeStamp((int)$item[1])->setTimezone($timezone_name); $entity['task.end_date'] = $carbon_object->format($date_format_default); $entity['task.end_time'] = $carbon_object->format('H:i:s'); } diff --git a/app/Export/CSV/VendorExport.php b/app/Export/CSV/VendorExport.php index 5b67792d2b7a..abb682f655eb 100644 --- a/app/Export/CSV/VendorExport.php +++ b/app/Export/CSV/VendorExport.php @@ -68,7 +68,7 @@ class VendorExport extends BaseExport $query->where('is_deleted', 0); } - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'vendors'); if($this->input['document_email_attachment'] ?? false) { $this->queueDocuments($query); diff --git a/app/Export/Decorators/TaskDecorator.php b/app/Export/Decorators/TaskDecorator.php index 85a80dcef5d4..0b48e1cdc613 100644 --- a/app/Export/Decorators/TaskDecorator.php +++ b/app/Export/Decorators/TaskDecorator.php @@ -60,7 +60,7 @@ class TaskDecorator extends Decorator implements DecoratorInterface if(is_array($logs)) { $item = $logs[0]; - return Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name)->format($date_format_default); + return Carbon::createFromTimeStamp((int)$item[0])->setTimezone($timezone_name)->format($date_format_default); } return ''; @@ -89,7 +89,7 @@ class TaskDecorator extends Decorator implements DecoratorInterface if(is_array($logs)) { $item = $logs[1]; - return Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name)->format($date_format_default); + return Carbon::createFromTimeStamp((int)$item[1])->setTimezone($timezone_name)->format($date_format_default); } return ''; diff --git a/app/Http/Controllers/ClientPortal/PaymentController.php b/app/Http/Controllers/ClientPortal/PaymentController.php index b2b63c0cea9e..7efd13510a56 100644 --- a/app/Http/Controllers/ClientPortal/PaymentController.php +++ b/app/Http/Controllers/ClientPortal/PaymentController.php @@ -121,8 +121,16 @@ class PaymentController extends Controller { /** @var \App\Models\CompanyGateway $gateway **/ $gateway = CompanyGateway::findOrFail($request->input('company_gateway_id')); - $payment_hash = PaymentHash::where('hash', $request->payment_hash)->firstOrFail(); - $invoice = Invoice::with('client')->find($payment_hash->fee_invoice_id); + $payment_hash = PaymentHash::with('fee_invoice')->where('hash', $request->payment_hash)->firstOrFail(); + + // if($payment_hash) + $invoice = $payment_hash->fee_invoice; + // else + // $invoice = Invoice::with('client')->where('id',$payment_hash->fee_invoice_id)->orderBy('id','desc')->first(); + + // $invoice = Invoice::with('client')->find($payment_hash->fee_invoice_id); + + $client = $invoice ? $invoice->client : auth()->guard('contact')->user()->client; // 09-07-2022 catch duplicate responses for invoices that already paid here. diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 807340fa1e57..66eed43075f6 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -192,6 +192,7 @@ class ImportController extends Controller $contents = file_get_contents($file->getPathname()); // Store the csv in cache with an expiry of 10 minutes Cache::put($hash.'-'.$entityType, base64_encode($contents), 600); + nlog($hash.'-'.$entityType); } } diff --git a/app/Http/Requests/Project/StoreProjectRequest.php b/app/Http/Requests/Project/StoreProjectRequest.php index fdaca3b2db6a..04c698feef29 100644 --- a/app/Http/Requests/Project/StoreProjectRequest.php +++ b/app/Http/Requests/Project/StoreProjectRequest.php @@ -45,7 +45,8 @@ class StoreProjectRequest extends Request $rules['name'] = 'required'; $rules['client_id'] = 'required|exists:clients,id,company_id,'.$user->company()->id; $rules['budgeted_hours'] = 'sometimes|numeric'; - + $rules['task_rate'] = 'required|bail|numeric'; + if (isset($this->number)) { $rules['number'] = Rule::unique('projects')->where('company_id', $user->company()->id); } @@ -79,6 +80,8 @@ class StoreProjectRequest extends Request $input['budgeted_hours'] = 0; } + $input['task_rate'] = isset($input['task_rate']) ? $input['task_rate'] : 0; + $this->replace($input); } diff --git a/app/Import/Providers/BaseImport.php b/app/Import/Providers/BaseImport.php index 94670d2e9c08..b2897352cc4a 100644 --- a/app/Import/Providers/BaseImport.php +++ b/app/Import/Providers/BaseImport.php @@ -104,6 +104,8 @@ class BaseImport return null; } + nlog("found {$entity_type}"); + $csv = base64_decode($base64_encoded_csv); $csv = mb_convert_encoding($csv, 'UTF-8', 'UTF-8'); diff --git a/app/Jobs/Entity/CreateRawPdf.php b/app/Jobs/Entity/CreateRawPdf.php index 45483faf156f..4d52e4319758 100644 --- a/app/Jobs/Entity/CreateRawPdf.php +++ b/app/Jobs/Entity/CreateRawPdf.php @@ -112,8 +112,7 @@ class CreateRawPdf try { $pdf = $ps->boot()->getPdf(); } catch (\Exception $e) { - echo "EXCEPTION::".PHP_EOL; - echo $e->getMessage().PHP_EOL; + nlog($e->getMessage()); throw new FilePermissionsFailure('Unable to generate the raw PDF'); } diff --git a/app/Jobs/Ninja/SendReminders.php b/app/Jobs/Ninja/SendReminders.php index f04e6f114538..2ea9eca861f2 100644 --- a/app/Jobs/Ninja/SendReminders.php +++ b/app/Jobs/Ninja/SendReminders.php @@ -188,13 +188,13 @@ class SendReminders implements ShouldQueue switch ($schedule_reminder) { case 'after_invoice_date': - return Carbon::parse($invoice->date)->addDays($num_days_reminder)->startOfDay()->addSeconds($offset); + return Carbon::parse($invoice->date)->addDays((int)$num_days_reminder)->startOfDay()->addSeconds($offset); break; case 'before_due_date': - return Carbon::parse($invoice->due_date)->subDays($num_days_reminder)->startOfDay()->addSeconds($offset); + return Carbon::parse($invoice->due_date)->subDays((int)$num_days_reminder)->startOfDay()->addSeconds($offset); break; case 'after_due_date': - return Carbon::parse($invoice->due_date)->addDays($num_days_reminder)->startOfDay()->addSeconds($offset); + return Carbon::parse($invoice->due_date)->addDays((int)$num_days_reminder)->startOfDay()->addSeconds($offset); break; default: return null; diff --git a/app/Listeners/Invoice/UpdateInvoiceActivity.php b/app/Listeners/Invoice/UpdateInvoiceActivity.php index c783e1299161..cce12ba40fd9 100644 --- a/app/Listeners/Invoice/UpdateInvoiceActivity.php +++ b/app/Listeners/Invoice/UpdateInvoiceActivity.php @@ -21,6 +21,7 @@ class UpdateInvoiceActivity implements ShouldQueue { protected $activity_repo; + public $delay = 10; /** * Create the event listener. * @@ -52,5 +53,6 @@ class UpdateInvoiceActivity implements ShouldQueue $fields->invoice_id = $event->invoice->id; $this->activity_repo->save($fields, $event->invoice, $event->event_vars); + } } diff --git a/app/Models/RecurringQuote.php b/app/Models/RecurringQuote.php index ef4c973d2644..b2d86d92dc1f 100644 --- a/app/Models/RecurringQuote.php +++ b/app/Models/RecurringQuote.php @@ -549,7 +549,7 @@ class RecurringQuote extends BaseModel case 'terms': return $this->calculateDateFromTerms($date); default: - return $this->setDayOfMonth($date, $this->due_date_days); + return $this->setDayOfMonth($date, ($this->due_date_days ?? 1)); } } diff --git a/app/Models/Task.php b/app/Models/Task.php index 4646f203c450..5106f86bdd31 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -208,7 +208,7 @@ class Task extends BaseModel $parts = json_decode($this->time_log) ?: []; if (count($parts)) { - return Carbon::createFromTimeStamp($parts[0][0])->timestamp; + return Carbon::createFromTimeStamp((int)$parts[0][0])->timestamp; } else { return null; } @@ -281,11 +281,11 @@ class Task extends BaseModel $parent_entity = $this->client ?? $this->company; if($log[0]) { - $log[0] = Carbon::createFromTimestamp($log[0])->format($parent_entity->date_format().' H:i:s'); + $log[0] = Carbon::createFromTimestamp((int)$log[0])->format($parent_entity->date_format().' H:i:s'); } if($log[1] && $log[1] != 0) { - $log[1] = Carbon::createFromTimestamp($log[1])->format($parent_entity->date_format().' H:i:s'); + $log[1] = Carbon::createFromTimestamp((int)$log[1])->format($parent_entity->date_format().' H:i:s'); } else { $log[1] = ctrans('texts.running'); } @@ -313,11 +313,11 @@ class Task extends BaseModel if($log[0]) { $logged['start_date_raw'] = $log[0]; } - $logged['start_date'] = Carbon::createFromTimestamp($log[0])->setTimeZone($this->company->timezone()->name)->format($parent_entity->date_format().' H:i:s'); + $logged['start_date'] = Carbon::createFromTimestamp((int)$log[0])->setTimeZone($this->company->timezone()->name)->format($parent_entity->date_format().' H:i:s'); if($log[1] && $log[1] != 0) { $logged['end_date_raw'] = $log[1]; - $logged['end_date'] = Carbon::createFromTimestamp($log[1])->setTimeZone($this->company->timezone()->name)->format($parent_entity->date_format().' H:i:s'); + $logged['end_date'] = Carbon::createFromTimestamp((int)$log[1])->setTimeZone($this->company->timezone()->name)->format($parent_entity->date_format().' H:i:s'); } else { $logged['end_date_raw'] = 0; $logged['end_date'] = ctrans('texts.running'); diff --git a/app/Repositories/ActivityRepository.php b/app/Repositories/ActivityRepository.php index b802cec68888..035faa5efa6a 100644 --- a/app/Repositories/ActivityRepository.php +++ b/app/Repositories/ActivityRepository.php @@ -81,6 +81,8 @@ class ActivityRepository extends BaseRepository return; } + $entity = $entity->fresh(); + if (get_class($entity) == Invoice::class || get_class($entity) == Quote::class || get_class($entity) == Credit::class diff --git a/app/Repositories/TaskRepository.php b/app/Repositories/TaskRepository.php index ff6684287aa4..9f880c92026e 100644 --- a/app/Repositories/TaskRepository.php +++ b/app/Repositories/TaskRepository.php @@ -157,7 +157,7 @@ class TaskRepository extends BaseRepository { if(isset($time_log[0][0])) { - return \Carbon\Carbon::createFromTimestamp($time_log[0][0])->addSeconds($task->company->utc_offset()); + return \Carbon\Carbon::createFromTimestamp((int)$time_log[0][0])->addSeconds($task->company->utc_offset()); } return null; diff --git a/app/Services/ClientPortal/InstantPayment.php b/app/Services/ClientPortal/InstantPayment.php index aea285866945..d46052fafb03 100644 --- a/app/Services/ClientPortal/InstantPayment.php +++ b/app/Services/ClientPortal/InstantPayment.php @@ -245,7 +245,7 @@ class InstantPayment $hash_data['billing_context'] = Cache::get($this->request->query('hash')); } elseif ($this->request->hash) { $hash_data['billing_context'] = Cache::get($this->request->hash); - } elseif ($old_hash = PaymentHash::query()->where('fee_invoice_id', $first_invoice->id)->whereNull('payment_id')->first()) { + } elseif ($old_hash = PaymentHash::query()->where('fee_invoice_id', $first_invoice->id)->whereNull('payment_id')->orderBy('id','desc')->first()) { if (isset($old_hash->data->billing_context)) { $hash_data['billing_context'] = $old_hash->data->billing_context; } diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 13f94fe63656..00c619d6236c 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -292,9 +292,9 @@ class InvoiceService //12-10-2022 if ($this->invoice->partial > 0 && !$this->invoice->partial_due_date) { - $this->invoice->partial_due_date = Carbon::parse($this->invoice->date)->addDays($this->invoice->client->getSetting('payment_terms')); + $this->invoice->partial_due_date = Carbon::parse($this->invoice->date)->addDays((int)$this->invoice->client->getSetting('payment_terms')); } else { - $this->invoice->due_date = Carbon::parse($this->invoice->date)->addDays($this->invoice->client->getSetting('payment_terms')); + $this->invoice->due_date = Carbon::parse($this->invoice->date)->addDays((int)$this->invoice->client->getSetting('payment_terms')); } return $this; diff --git a/app/Services/Payment/RefundPayment.php b/app/Services/Payment/RefundPayment.php index ec2a02d20d47..144abff2068c 100644 --- a/app/Services/Payment/RefundPayment.php +++ b/app/Services/Payment/RefundPayment.php @@ -27,10 +27,6 @@ class RefundPayment private float $credits_used = 0; - private $gateway_refund_status; - - private $activity_repository; - private bool $refund_failed = false; private string $refund_failed_message = ''; diff --git a/app/Services/Report/ARDetailReport.php b/app/Services/Report/ARDetailReport.php index 048cb76cd0dd..be8c83069936 100644 --- a/app/Services/Report/ARDetailReport.php +++ b/app/Services/Report/ARDetailReport.php @@ -100,7 +100,7 @@ class ARDetailReport extends BaseExport ->orderBy('due_date', 'ASC') ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]); - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'invoices'); $query = $this->filterByClients($query); diff --git a/app/Services/Report/ClientBalanceReport.php b/app/Services/Report/ClientBalanceReport.php index c5ca05c5fa97..a4a6b9f7eb1b 100644 --- a/app/Services/Report/ClientBalanceReport.php +++ b/app/Services/Report/ClientBalanceReport.php @@ -110,7 +110,7 @@ class ClientBalanceReport extends BaseExport $query = Invoice::query()->where('client_id', $client->id) ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]); - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'invoices'); return [ $client->present()->name(), diff --git a/app/Services/Report/ClientSalesReport.php b/app/Services/Report/ClientSalesReport.php index c2bd9346bdcc..2e88dcccc109 100644 --- a/app/Services/Report/ClientSalesReport.php +++ b/app/Services/Report/ClientSalesReport.php @@ -103,7 +103,7 @@ class ClientSalesReport extends BaseExport $query = Invoice::query()->where('client_id', $client->id) ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID]); - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'invoices'); $amount = $query->sum('amount'); $balance = $query->sum('balance'); diff --git a/app/Services/Report/TaxSummaryReport.php b/app/Services/Report/TaxSummaryReport.php index b44b795570e2..a7b757aa6eb7 100644 --- a/app/Services/Report/TaxSummaryReport.php +++ b/app/Services/Report/TaxSummaryReport.php @@ -81,7 +81,7 @@ class TaxSummaryReport extends BaseExport ->where('is_deleted', 0) ->orderBy('balance', 'desc'); - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'invoices'); $this->csv->insertOne([ctrans('texts.tax_summary')]); $this->csv->insertOne([ctrans('texts.created_on'),' ',$this->translateDate(now()->format('Y-m-d'), $this->company->date_format(), $this->company->locale())]); diff --git a/app/Services/Report/UserSalesReport.php b/app/Services/Report/UserSalesReport.php index 9b3dec875fa6..a94c4b0e9930 100644 --- a/app/Services/Report/UserSalesReport.php +++ b/app/Services/Report/UserSalesReport.php @@ -69,7 +69,7 @@ class UserSalesReport extends BaseExport ->where('is_deleted', 0) ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID]); - $query = $this->addDateRange($query); + $query = $this->addDateRange($query, 'invoices'); $query = $this->filterByClients($query); diff --git a/app/Services/Subscription/SubscriptionStatus.php b/app/Services/Subscription/SubscriptionStatus.php index 8aa6226bfdbe..e4252a8dd3bd 100644 --- a/app/Services/Subscription/SubscriptionStatus.php +++ b/app/Services/Subscription/SubscriptionStatus.php @@ -174,7 +174,7 @@ class SubscriptionStatus extends AbstractService */ private function checkRefundable(): self { - if(!$this->recurring_invoice->subscription->refund_period || $this->recurring_invoice->subscription->refund_period === 0) { + if(!$this->recurring_invoice->subscription->refund_period || (int)$this->recurring_invoice->subscription->refund_period == 0) { return $this->setRefundable(false); } diff --git a/app/Utils/Traits/MakesDates.php b/app/Utils/Traits/MakesDates.php index ec8871ce48fa..0971dfd663a7 100644 --- a/app/Utils/Traits/MakesDates.php +++ b/app/Utils/Traits/MakesDates.php @@ -78,7 +78,7 @@ trait MakesDates */ public function formatDatetime($date, string $format): string { - return Carbon::createFromTimestamp($date)->format($format.' g:i a'); + return Carbon::createFromTimestamp((int)$date)->format($format.' g:i a'); } /** @@ -89,7 +89,7 @@ trait MakesDates */ public function formatDateTimestamp($timestamp, string $format): string { - return Carbon::createFromTimestamp($timestamp)->format($format); + return Carbon::createFromTimestamp((int)$timestamp)->format($format); } private function convertToDateObject($date) diff --git a/app/Utils/Traits/MakesReminders.php b/app/Utils/Traits/MakesReminders.php index dcfd9a95988e..e6e6460abaed 100644 --- a/app/Utils/Traits/MakesReminders.php +++ b/app/Utils/Traits/MakesReminders.php @@ -82,6 +82,9 @@ trait MakesReminders private function checkEndlessReminder($last_sent_date, $endless_reminder_frequency_id): bool { + if(!$last_sent_date) + return false; + if (Carbon::now()->startOfDay()->eq($this->addTimeInterval($last_sent_date, $endless_reminder_frequency_id))) { return true; } diff --git a/config/ninja.php b/config/ninja.php index 88601cd094f8..0fbc5f9ee1b6 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -17,8 +17,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => env('APP_VERSION', '5.9.9'), - 'app_tag' => env('APP_TAG', '5.9.9'), + 'app_version' => env('APP_VERSION', '5.10.0'), + 'app_tag' => env('APP_TAG', '5.10.0'), 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', false), diff --git a/database/migrations/2024_06_23_040253_2024-06-23_indexesforinvoiceid_payment_hashes.php b/database/migrations/2024_06_23_040253_2024-06-23_indexesforinvoiceid_payment_hashes.php new file mode 100644 index 000000000000..c4fc9c592fdc --- /dev/null +++ b/database/migrations/2024_06_23_040253_2024-06-23_indexesforinvoiceid_payment_hashes.php @@ -0,0 +1,28 @@ +unsignedInteger('fee_invoice_id')->nullable()->index()->change(); + }); + + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/database/schema/mysql-schema.sql b/database/schema/mysql-schema.sql index b2f975da4071..c9a662d1dee8 100644 --- a/database/schema/mysql-schema.sql +++ b/database/schema/mysql-schema.sql @@ -1,4 +1,3 @@ -/*!999999\- enable the sandbox mode */ /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; @@ -2431,7 +2430,6 @@ CREATE TABLE `webhooks` ( /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -/*!999999\- enable the sandbox mode */ INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (1,'2014_10_12_100000_create_password_resets_table',1); INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (2,'2014_10_13_000000_create_users_table',1); INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (3,'2019_11_10_115926_create_failed_jobs_table',1);