mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2026-03-03 03:07:01 +00:00
Merge pull request #11595 from turbo124/v5-develop
Minor fixes for type casting freshbooks imports
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
871
public/vendor/livewire/livewire.esm.js
vendored
871
public/vendor/livewire/livewire.esm.js
vendored
File diff suppressed because it is too large
Load Diff
6
public/vendor/livewire/livewire.esm.js.map
vendored
6
public/vendor/livewire/livewire.esm.js.map
vendored
File diff suppressed because one or more lines are too long
622
public/vendor/livewire/livewire.js
vendored
622
public/vendor/livewire/livewire.js
vendored
File diff suppressed because it is too large
Load Diff
15
public/vendor/livewire/livewire.min.js
vendored
15
public/vendor/livewire/livewire.min.js
vendored
File diff suppressed because one or more lines are too long
6
public/vendor/livewire/livewire.min.js.map
vendored
6
public/vendor/livewire/livewire.min.js.map
vendored
File diff suppressed because one or more lines are too long
2
public/vendor/livewire/manifest.json
vendored
2
public/vendor/livewire/manifest.json
vendored
@@ -1,2 +1,2 @@
|
||||
|
||||
{"/livewire.js":"df3a17f2"}
|
||||
{"/livewire.js":"61e33937"}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user