Merge pull request #11595 from turbo124/v5-develop

Minor fixes for type casting freshbooks imports
This commit is contained in:
David Bomba
2026-01-25 17:17:31 +11:00
committed by GitHub
13 changed files with 1238 additions and 571 deletions

View File

@@ -85,11 +85,11 @@ class InvoiceTransformer extends BaseTransformer
return ($record[$field] / $record['Line Subtotal']) * 100;
}
$tax_amount1 = isset($record['Tax 1 Amount']) ? $record['Tax 1 Amount'] : 0;
$tax_amount1 = isset($record['Tax 1 Amount']) ? floatval($record['Tax 1 Amount']) : 0;
$tax_amount2 = isset($record['Tax 2 Amount']) ? $record['Tax 2 Amount'] : 0;
$tax_amount2 = isset($record['Tax 2 Amount']) ? floatval($record['Tax 2 Amount']) : 0;
$line_total = isset($record['Line Total']) ? $record['Line Total'] : 0;
$line_total = isset($record['Line Total']) ? floatval($record['Line Total']) : 0;
$subtotal = $line_total - $tax_amount2 - $tax_amount1;

View File

@@ -186,8 +186,6 @@ class InvoiceCheckOverdue implements ShouldQueue
continue;
}
nlog($company_user->permissions);
$overdue_invoices_collection = $overdue_invoices;
$invoice = Invoice::withTrashed()->find($overdue_invoices[0]['id']);
@@ -205,7 +203,7 @@ class InvoiceCheckOverdue implements ShouldQueue
$overdue_invoices_collection = collect($overdue_invoices)
->filter(function ($overdue_invoice) use ($user) {
$invoice = Invoice::withTrashed()->find($overdue_invoice['id']);
nlog([$invoice->user_id, $user->id, $invoice->assigned_user_id, $user->id]);
// nlog([$invoice->user_id, $user->id, $invoice->assigned_user_id, $user->id]);
return $invoice->user_id == $user->id || $invoice->assigned_user_id == $user->id;
})
->toArray();
@@ -243,6 +241,7 @@ class InvoiceCheckOverdue implements ShouldQueue
/**
* Send notifications for an overdue invoice to all relevant company users.
* @deprecated in favour of sendOverdueNotifications to send a summary email to all users
*/
/** @phpstan-ignore-next-line */
private function notifyOverdueInvoice(Invoice $invoice): void

View File

@@ -15,7 +15,6 @@ namespace App\Livewire\Flow2;
use Livewire\Component;
use App\Libraries\MultiDB;
use App\Models\CompanyGateway;
use Livewire\Attributes\Computed;
use App\Services\Client\RFFService;
use App\Utils\Traits\WithSecureContext;

File diff suppressed because one or more lines are too long

View File

@@ -12,7 +12,7 @@
"file": "assets/wait-8f4ae121.js"
},
"resources/js/app.js": {
"file": "assets/app-03a29a9d.js",
"file": "assets/app-73d3ce3f.js",
"imports": [
"_index-08e160a7.js",
"__commonjsHelpers-725317a4.js"

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
{"/livewire.js":"df3a17f2"}
{"/livewire.js":"61e33937"}

View File

@@ -37,15 +37,13 @@
@endif
@endforeach
@if($this->showCopyBillingCheckbox())
@component('portal.ninja2020.components.general.card-element-single')
<div class="flex justify-end">
<button type="button" class="bg-gray-100 px-2 py-1 text-sm rounded" wire:click="handleCopyBilling">
<button type="button" id="copy-billing-button" class="bg-gray-100 px-2 py-1 text-sm rounded">
{{ ctrans('texts.copy_billing') }}
</button>
</div>
@endcomponent
@endif
@if($show_terms)
@@ -133,3 +131,106 @@
@endif
</div>
@script
<script>
(function() {
function copyBillingToShipping() {
const form = document.getElementById('required-client-info-form');
if (!form) return;
// Pure vanilla JavaScript - read directly from DOM and update DOM
// Mapping: billing field => shipping field
const fieldMappings = [
{ from: 'client_address_line_1', to: 'client_shipping_address_line_1' },
{ from: 'client_address_line_2', to: 'client_shipping_address_line_2' },
{ from: 'client_city', to: 'client_shipping_city' },
{ from: 'client_state', to: 'client_shipping_state' },
{ from: 'client_postal_code', to: 'client_shipping_postal_code' },
{ from: 'client_country_id', to: 'client_shipping_country_id' }
];
fieldMappings.forEach(function(mapping) {
var from = mapping.from;
var to = mapping.to;
// Find the billing input field
var billingField = form.querySelector('[name="' + from + '"]');
// Find the shipping input field
var shippingField = form.querySelector('[name="' + to + '"]');
if (!billingField || !shippingField) return;
// Try multiple methods to get the current value
var currentValue = '';
// Method 1: Direct .value property
var directValue = billingField.value || '';
// Method 2: Try getting from Livewire if available (for wire:model fields)
var livewireValue = null;
try {
// Check if Livewire is available and has the property
if (typeof window.Livewire !== 'undefined') {
var component = window.Livewire.find(billingField.closest('[wire\\:id]')?.getAttribute('wire:id'));
if (component) {
livewireValue = component.get(from);
}
}
} catch (e) {
// Livewire not available or error reading
}
// Method 3: Use FormData to get form values
var formData = new FormData(form);
var formDataValue = formData.get(from);
// Choose the best value - prioritize what user sees/types
// If direct value exists and is not empty, use it
// Otherwise try Livewire, then FormData
if (directValue !== '' && directValue !== null && directValue !== undefined) {
currentValue = directValue;
} else if (livewireValue !== null && livewireValue !== undefined && livewireValue !== '') {
currentValue = String(livewireValue);
} else if (formDataValue !== null && formDataValue !== undefined) {
currentValue = String(formDataValue);
} else {
currentValue = '';
}
// Directly set the shipping field's DOM .value property
shippingField.value = currentValue;
// Trigger the appropriate event so Livewire's wire:model can sync
if (shippingField.tagName === 'SELECT') {
// For select elements, trigger 'change' event
var changeEvent = new Event('change', { bubbles: true, cancelable: true });
shippingField.dispatchEvent(changeEvent);
} else {
// For input elements, trigger 'input' event
var inputEvent = new Event('input', { bubbles: true, cancelable: true });
shippingField.dispatchEvent(inputEvent);
}
});
}
// Wait for DOM to be ready, then attach event listener
function attachListener() {
var button = document.getElementById('copy-billing-button');
if (button) {
button.addEventListener('click', copyBillingToShipping);
} else {
// Try again after a short delay in case the button hasn't rendered yet
setTimeout(attachListener, 100);
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', attachListener);
} else {
// DOM is already ready
attachListener();
}
})();
</script>
@endscript

View File

@@ -1,5 +1,4 @@
<div x-data="{ fields: @entangle('fields') }"
class="rounded-lg border bg-card text-card-foreground shadow-sm overflow-hidden px-4 py-5 bg-white sm:gap-4 sm:px-6">
<div class="rounded-lg border bg-card text-card-foreground shadow-sm overflow-hidden px-4 py-5 bg-white sm:gap-4 sm:px-6">
<p class="font-semibold tracking-tight group flex items-center gap-2 text-lg mb-3">
{{ ctrans('texts.required_fields') }}
@@ -19,7 +18,7 @@
@foreach($fields as $field)
@component('portal.ninja2020.components.general.card-element', ['title' => $field['label']])
@if($field['name'] == 'client_country_id' || $field['name'] == 'client_shipping_country_id')
<select id="client_country" class="input w-full form-select bg-white" name="{{ $field['name'] }}"
<select id="{{ $field['name'] }}" class="input w-full form-select bg-white" name="{{ $field['name'] }}"
wire:model="{{ $field['name'] }}">
<option value="none"></option>
@@ -43,6 +42,14 @@
@endforeach
<div class="bg-white px-4 py-5 flex items-center w-full justify-end">
<button type="button"
id="copy-billing-button"
class="bg-gray-100 hover:bg-gray-200 px-4 py-2 text-sm rounded transition-colors">
{{ ctrans('texts.copy_billing') }}
</button>
</div>
<div class="bg-white px-4 py-5 flex items-center w-full justify-end space-x-3">
<svg wire:loading class="animate-spin h-5 w-5 text-primary" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24">
@@ -59,3 +66,106 @@
</form>
@endif
</div>
@script
<script>
(function() {
function copyBillingToShipping() {
const form = document.getElementById('required-client-info-form');
if (!form) return;
// Pure vanilla JavaScript - read directly from DOM and update DOM
// Mapping: billing field => shipping field
const fieldMappings = [
{ from: 'client_address_line_1', to: 'client_shipping_address_line_1' },
{ from: 'client_address_line_2', to: 'client_shipping_address_line_2' },
{ from: 'client_city', to: 'client_shipping_city' },
{ from: 'client_state', to: 'client_shipping_state' },
{ from: 'client_postal_code', to: 'client_shipping_postal_code' },
{ from: 'client_country_id', to: 'client_shipping_country_id' }
];
fieldMappings.forEach(function(mapping) {
var from = mapping.from;
var to = mapping.to;
// Find the billing input field
var billingField = form.querySelector('[name="' + from + '"]');
// Find the shipping input field
var shippingField = form.querySelector('[name="' + to + '"]');
if (!billingField || !shippingField) return;
// Try multiple methods to get the current value
var currentValue = '';
// Method 1: Direct .value property
var directValue = billingField.value || '';
// Method 2: Try getting from Livewire if available (for wire:model fields)
var livewireValue = null;
try {
// Check if Livewire is available and has the property
if (typeof window.Livewire !== 'undefined') {
var component = window.Livewire.find(billingField.closest('[wire\\:id]')?.getAttribute('wire:id'));
if (component) {
livewireValue = component.get(from);
}
}
} catch (e) {
// Livewire not available or error reading
}
// Method 3: Use FormData to get form values
var formData = new FormData(form);
var formDataValue = formData.get(from);
// Choose the best value - prioritize what user sees/types
// If direct value exists and is not empty, use it
// Otherwise try Livewire, then FormData
if (directValue !== '' && directValue !== null && directValue !== undefined) {
currentValue = directValue;
} else if (livewireValue !== null && livewireValue !== undefined && livewireValue !== '') {
currentValue = String(livewireValue);
} else if (formDataValue !== null && formDataValue !== undefined) {
currentValue = String(formDataValue);
} else {
currentValue = '';
}
// Directly set the shipping field's DOM .value property
shippingField.value = currentValue;
// Trigger the appropriate event so Livewire's wire:model can sync
if (shippingField.tagName === 'SELECT') {
// For select elements, trigger 'change' event
var changeEvent = new Event('change', { bubbles: true, cancelable: true });
shippingField.dispatchEvent(changeEvent);
} else {
// For input elements, trigger 'input' event
var inputEvent = new Event('input', { bubbles: true, cancelable: true });
shippingField.dispatchEvent(inputEvent);
}
});
}
// Wait for DOM to be ready, then attach event listener
function attachListener() {
var button = document.getElementById('copy-billing-button');
if (button) {
button.addEventListener('click', copyBillingToShipping);
} else {
// Try again after a short delay in case the button hasn't rendered yet
setTimeout(attachListener, 100);
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', attachListener);
} else {
// DOM is already ready
attachListener();
}
})();
</script>
@endscript