Merge branch 'CpeProvisioning/fix' into 'master'

cpeprov fix

See merge request fronk/thetool!1847
This commit is contained in:
Luca Haid
2025-10-15 11:07:33 +00:00
2 changed files with 46 additions and 76 deletions

View File

@@ -488,6 +488,7 @@ class CpeprovisioningController extends mfBaseController
'spin' => $order->owner->spin, 'customer' => $order->owner->getCompanyOrName(),
'owner_email' => $order->owner->email,
'owner_phone' => $order->owner->phone,
'owner_customer_number' => $order->owner->customer_number,
'owner_full_address' => $order->owner->street . ", " . $order->owner->zip . " " . $order->owner->city,
'product_name' => $product->product->name, 'product_code' => $term->code ?? '',
'access_type' => $attrs['bras_type']->value,

View File

@@ -1,4 +1,3 @@
// Cpeprovisioning.js
Vue.component('tt-chip', {
props: {
checked: { type: Boolean, default: false }
@@ -11,10 +10,10 @@ Vue.component('Cpeprovisioning', {
<div class="cpe-provisioning-page">
<tt-card>
<div class="filter-grid">
<tt-select label="Netzgebiet" :options="networkOptions" v-model="filters.network_id" @input="fetchData(true)" sm/>
<tt-select label="Provisioningstatus" :options="statusOptions" v-model="filters.routerconfig_finished" @input="fetchData(true)" sm/>
<tt-select label="Verzögerte Herstellung" :options="delayOptions" v-model="filters.hide_delayed_finish" @input="fetchData(true)" sm/>
<tt-input label="Suche" v-model="filters.owner" sm placeholder="Kunde, SPIN, Adresse..." @input="applyClientSideFilter"/>
<tt-select label="Netzgebiet" :options="networkOptions" v-model="filters.network_id" @input="debouncedFetchData" sm/>
<tt-select label="Provisioningstatus" :options="statusOptions" v-model="filters.routerconfig_finished" @input="debouncedFetchData" sm/>
<tt-select label="Verzögerte Herstellung" :options="delayOptions" v-model="filters.hide_delayed_finish" @input="debouncedFetchData" sm/>
<tt-input label="Suche" v-model="filters.owner" sm placeholder="Kunde, SPIN, Adresse..." @input="debouncedFetchData"/>
<div class="filter-actions">
<tt-button text="Anwenden" @click="fetchData(true)" additional-class="btn-primary" sm/>
<tt-button text="Zurücksetzen" @click="resetFilters" additional-class="btn-secondary" sm/>
@@ -36,7 +35,9 @@ Vue.component('Cpeprovisioning', {
<div v-for="item in filteredItems" :key="item.orderproduct_id" class="cpe-card" :class="{ 'is-dirty': item.isDirty }">
<div class="cpe-card-header">
<div class="customer-info">
<strong>{{ item.customer }}</strong>
<span style="display: ruby;">
<strong>{{ item.customer }}<small v-if="item.owner_customer_number" class="text-muted ml-2">#{{ item.owner_customer_number }}</small></strong>
</span>
<small class="text-muted">SPIN: <span class="text-pink">{{ item.spin }}</span></small>
</div>
<div class="location-contact-header">
@@ -142,6 +143,7 @@ Vue.component('Cpeprovisioning', {
delayOptions: [ { value: '1', text: 'Nicht anzeigen' }, { value: '0', text: 'Anzeigen' } ],
page: 1,
pagination: {},
debouncedFetchData: null
}
},
computed: {
@@ -153,6 +155,9 @@ Vue.component('Cpeprovisioning', {
return window.TT_CONFIG.ROUTER_OPTIONS || [];
}
},
created() {
this.debouncedFetchData = _.debounce(this.fetchData.bind(this, true), 400);
},
methods: {
async fetchData(isNewSearch = false) {
if (isNewSearch) {
@@ -163,18 +168,14 @@ Vue.component('Cpeprovisioning', {
}
if (!isNewSearch && this.pagination.total_pages && this.page > this.pagination.total_pages) {
return; // No more pages to load
return;
}
this.loading = true;
const payload = {
pagination: { page: this.page, per_page: 25 },
filters: {
network_id: this.filters.network_id,
routerconfig_finished: this.filters.routerconfig_finished,
hide_delayed_finish: this.filters.hide_delayed_finish,
},
filters: { ...this.filters },
order: { key: 'order_id', order: 'desc' }
};
@@ -198,7 +199,8 @@ Vue.component('Cpeprovisioning', {
this.pagination = data.pagination;
this.page++;
this.applyClientSideFilter();
this.filteredItems = this.items;
} catch (error) {
console.error("Error fetching CPE data:", error);
window.notify('error', 'Fehler beim Laden der Daten.');
@@ -206,20 +208,6 @@ Vue.component('Cpeprovisioning', {
this.loading = false;
}
},
applyClientSideFilter() {
if (!this.filters.owner) {
this.filteredItems = this.items;
return;
}
const search = this.filters.owner.toLowerCase();
this.filteredItems = this.items.filter(item => {
return (item.customer && item.customer.toLowerCase().includes(search)) ||
(item.spin && item.spin.toLowerCase().includes(search)) ||
(item.owner_full_address && item.owner_full_address.toLowerCase().includes(search)) ||
(item.product_name && item.product_name.toLowerCase().includes(search)) ||
(item.network && item.network.toLowerCase().includes(search));
});
},
resetFilters() {
this.filters = { network_id: '', routerconfig_finished: '0', hide_delayed_finish: '1', owner: '' };
this.fetchData(true);
@@ -227,69 +215,50 @@ Vue.component('Cpeprovisioning', {
markDirty(item) {
this.$set(item, 'isDirty', true);
},
async checkShipping(row) {
async checkShipping(item) {
await this.$nextTick();
let wasPrefilled = false;
if (row.cpe_data.shipping && row.cpe_data.routertype) {
const shippingData = this.window.TT_CONFIG.ROUTER_SHIPPING_DATA[row.cpe_data.routertype];
if (item.cpe_data.shipping && item.cpe_data.routertype) {
const shippingData = this.window.TT_CONFIG.ROUTER_SHIPPING_DATA[item.cpe_data.routertype];
if (shippingData) {
if (!row.cpe_data.ship_weight) {
this.$set(row.cpe_data, 'ship_weight', shippingData.weight);
wasPrefilled = true;
}
if (!row.cpe_data.ship_length) {
this.$set(row.cpe_data, 'ship_length', shippingData.length);
wasPrefilled = true;
}
if (!row.cpe_data.ship_width) {
this.$set(row.cpe_data, 'ship_width', shippingData.width);
wasPrefilled = true;
}
if (!row.cpe_data.ship_height) {
this.$set(row.cpe_data, 'ship_height', shippingData.height);
wasPrefilled = true;
}
this.$set(item.cpe_data, 'ship_weight', shippingData.weight);
this.$set(item.cpe_data, 'ship_length', shippingData.length);
this.$set(item.cpe_data, 'ship_width', shippingData.width);
this.$set(item.cpe_data, 'ship_height', shippingData.height);
this.window.notify('success', 'Versanddaten wurden automatisch ausgefüllt.');
}
} else if (!row.cpe_data.shipping) {
// Clear the fields if shipping is unchecked
row.cpe_data.ship_weight = '';
row.cpe_data.ship_length = '';
row.cpe_data.ship_width = '';
row.cpe_data.ship_height = '';
}
if (wasPrefilled) {
this.markDirty(row);
this.window.notify('success', 'Versanddaten wurden automatisch ausgefüllt.');
} else if (!item.cpe_data.shipping) {
item.cpe_data.ship_weight = '';
item.cpe_data.ship_length = '';
item.cpe_data.ship_width = '';
item.cpe_data.ship_height = '';
}
},
_buildSavePayload(row) {
_buildSavePayload(item) {
return {
id: row.cpe_id,
order_id: row.order_id,
orderproduct_id: row.orderproduct_id,
termination_id: row.termination_id,
ont_sn: row.ont_sn,
vlans: row.vlans,
...row.cpe_data,
shipping: row.cpe_data.shipping ? 1 : 0,
routerconfig_finished: row.cpe_data.routerconfig_finished ? 1 : 0,
id: item.cpe_id,
order_id: item.order_id,
orderproduct_id: item.orderproduct_id,
termination_id: item.termination_id,
ont_sn: item.ont_sn,
vlans: item.vlans,
...item.cpe_data,
shipping: item.cpe_data.shipping ? 1 : 0,
routerconfig_finished: item.cpe_data.routerconfig_finished ? 1 : 0,
};
},
async saveCpe(row) {
this.$set(row, 'isSaving', true);
const payload = this._buildSavePayload(row);
async saveCpe(item) {
this.$set(item, 'isSaving', true);
const payload = this._buildSavePayload(item);
try {
const { data } = await axios.post(this.window.TT_CONFIG.CPE_PROV_API_SAVE_URL, payload);
if (data.success) {
this.window.notify('success', data.message);
if (this.filters.routerconfig_finished === '0' && payload.routerconfig_finished) {
this.items = this.items.filter(item => item.orderproduct_id !== row.orderproduct_id);
this.applyClientSideFilter();
this.items = this.items.filter(i => i.orderproduct_id !== item.orderproduct_id);
this.filteredItems = this.items;
} else {
const index = this.items.findIndex(item => item.orderproduct_id === row.orderproduct_id);
const index = this.items.findIndex(i => i.orderproduct_id === item.orderproduct_id);
if (index !== -1) {
this.$set(this.items[index], 'isDirty', false);
}
@@ -300,7 +269,7 @@ Vue.component('Cpeprovisioning', {
} catch (error) {
this.window.notify('error', 'Ein unerwarteter Fehler ist aufgetreten.');
} finally {
this.$set(row, 'isSaving', false);
this.$set(item, 'isSaving', false);
}
}
},