PageSourceSearch

https://www.cyberotecnica.com/assets/js/orca-uom-workspace.js?v=2

js cyberotecnica.com collected 2026-09-28 11:11:15 UTC 13,884 bytes, 259 lines download raw bytes

1(function () {
2    'use strict';
3
4    function create(options) {
5        var ctx = options.context;
6        var state = { key: '', catalog: null, pending: null, sequence: 0, connection: null,
7            reconnectTimer: null, liveAttempts: 0, liveError: '', invalidated: false, stopped: false };
8        var L = options.label;
9
10        function activeInventory() {
11            return !state.stopped && !ctx.disposed && ctx.entitytype === 'forinventory_item'
12                && ctx.mode !== 'list' && ctx.schema && ctx.schema.uom_conversions === true;
13        }
14        function key() {
15            var scope = ownerScope();
16            return [ctx.viewId, ctx.companyid, scope.owner_type, scope.product_id, scope.inventory_item_id, ctx.values.uom || ''].join('|');
17        }
18        function ownerScope() {
19            var internal = ctx.values._uom_owner_type === 'inventory' || !ctx.values.qbo_item_id;
20            var id = ctx.recordid || ctx.values.Id || ctx.values.id || '';
21            return internal
22                ? { owner_type: id ? 'inventory' : 'global', product_id: '', inventory_item_id: id }
23                : { owner_type: 'finance', product_id: ctx.values.qbo_item_id, inventory_item_id: '' };
24        }
25        function field(name) {
26            return options.body().querySelector('[data-orca-field="' + name + '"]');
27        }
28        function unitLabel(name, value) {
29            var fields = ((ctx.schema || {}).sections || []).flatMap(function (section) { return section.fields || []; });
30            var config = fields.find(function (entry) { return entry.key === name; });
31            var item = config && (config.options || []).find(function (entry) { return entry.value === value; });
32            return item ? item.label : value;
33        }
34        function newButton(icon, title, action) {
35            var button = document.createElement('button');
36            button.type = 'button';
37            button.className = 'flex h-7 w-7 shrink-0 items-center justify-center rounded-md border-0 p-0 disabled:cursor-not-allowed disabled:opacity-50 ' + options.buttonClass('setup');
38            button.title = title;
39            button.setAttribute('aria-label', title);
40            var glyph = document.createElement('span');
41            glyph.className = 'material-symbols-outlined text-base leading-none';
42            glyph.textContent = icon;
43            button.appendChild(glyph);
44            button.addEventListener('click', action);
45            return button;
46        }
47        function bindPurchase() {
48            var select = field('purchase_uom');
49            if (!select || select.dataset.orcaUomBound) return;
50            select.dataset.orcaUomBound = '1';
51            var host = document.createElement('div');
52            host.className = 'flex h-9 w-full min-w-0 items-center gap-1';
53            select.before(host);
54            host.appendChild(select);
55            select.classList.add('h-9', 'min-w-0', 'flex-1');
56            var add = newButton('add', L('Create UoM conversion'), function () {
57                var scope = ownerScope();
58                if (scope.owner_type === 'global' || !ctx.values.uom || ctx.schema.can_manage_uom !== true) {
59                    options.status(L('Save the inventory product before creating a conversion.'), '#f59e0b');
60                    return;
61                }
62                options.openConversion(Object.assign({}, scope, {
63                    product_id_display: ctx.values.qbo_item_id_display || '',
64                    inventory_item_id_display: ctx.values.name || ctx.values.sku || '',
65                    to_uom: ctx.values.uom
66                }), ['owner_type', 'product_id', 'inventory_item_id', 'to_uom']);
67            });
68            add.dataset.orcaUomCreate = '1';
69            host.appendChild(add);
70            var retry = newButton('refresh', L('Retry'), function () {
71                state.liveAttempts = 0;
72                clearTimeout(state.reconnectTimer);
73                state.reconnectTimer = null;
74                refresh(true);
75                watch();
76            });
77            retry.dataset.orcaUomRetry = '1';
78            host.appendChild(retry);
79            var stock = field('uom');
80            if (stock && !stock.dataset.orcaUomBound) {
81                stock.dataset.orcaUomBound = '1';
82                stock.addEventListener('change', function () { refresh(); });
83            }
84        }
85        function controls() {
86            var select = field('purchase_uom');
87            if (!select) return;
88            select.disabled = !!ctx.uomCatalogPending || !!ctx.uomCatalogError || !!ctx.saving;
89            var add = options.body().querySelector('[data-orca-uom-create]');
90            if (add) {
91                add.disabled = !!ctx.saving || ctx.schema.can_manage_uom !== true || ownerScope().owner_type === 'global' || !ctx.values.uom;
92                add.title = ownerScope().owner_type === 'global' ? L('Save the inventory product before creating a conversion.') : L('Create UoM conversion');
93                add.setAttribute('aria-label', add.title);
94            }
95            var retry = options.body().querySelector('[data-orca-uom-retry]');
96            if (retry) retry.classList.toggle('!hidden', !ctx.uomCatalogError && !state.liveError);
97        }
98        function applyCatalog(catalog) {
99            var select = field('purchase_uom');
100            if (!select) return false;
101            var current = String(ctx.values.purchase_uom || '').trim().toLowerCase();
102            var units = catalog.purchase_units;
103            if (!Array.isArray(units)) throw new Error(L('Unit conversions are unavailable.'));
104            select.replaceChildren();
105            var blank = document.createElement('option');
106            blank.value = '';
107            blank.textContent = L('Select a compatible purchase unit.');
108            select.appendChild(blank);
109            units.forEach(function (unit) {
110                var option = document.createElement('option');
111                option.value = unit.value;
112                option.textContent = unitLabel('purchase_uom', unit.value) || unit.label || unit.value;
113                select.appendChild(option);
114            });
115            var cleared = current && !units.some(function (unit) { return unit.value === current; });
116            if (cleared) {
117                ctx.values.purchase_uom = '';
118                ctx.dirty = true;
119                options.status(L('Purchase unit cleared. Select a compatible unit.'), '#f59e0b');
120            }
121            select.value = cleared ? '' : current;
122            return !!cleared;
123        }
124        function refresh(force, announce) {
125            if (!activeInventory()) return Promise.resolve(null);
126            bindPurchase();
127            if (ctx.saving) { state.invalidated = state.invalidated || !!force; return Promise.resolve(null); }
128            var wanted = key();
129            if (!force && !state.invalidated && state.key === wanted) {
130                if (state.catalog) applyCatalog(state.catalog);
131                controls();
132                return state.pending ? state.pending.promise : Promise.resolve(state.catalog);
133            }
134            if (state.pending) state.pending.controller.abort();
135            var sequence = ++state.sequence;
136            var controller = new AbortController();
137            state.key = wanted;
138            state.catalog = null;
139            state.invalidated = false;
140            ctx.uomCatalogPending = true;
141            ctx.uomCatalogError = '';
142            controls();
143            var promise = options.command('uom_catalog', Object.assign(ownerScope(), {
144                stock_uom: ctx.values.uom || ''
145            }), controller.signal).then(function (response) {
146                if (state.stopped || ctx.disposed || sequence !== state.sequence || key() !== wanted) return null;
147                if (!response || response.success === false || !response.values)
148                    throw new Error(response && response.message || L('Unit conversions are unavailable.'));
149                state.catalog = response.values;
150                var cleared = applyCatalog(state.catalog);
151                if (announce && !cleared) options.status(L('UoM conversions updated.'), '#22c55e');
152                return state.catalog;
153            }).catch(function (error) {
154                if (error.name === 'AbortError' || state.stopped || ctx.disposed || sequence !== state.sequence || key() !== wanted) return null;
155                state.catalog = null;
156                ctx.uomCatalogError = error.message || L('Unit conversions are unavailable.');
157                options.status(ctx.uomCatalogError, '#f87171');
158                return null;
159            }).finally(function () {
160                if (sequence !== state.sequence) return;
161                state.pending = null;
162                ctx.uomCatalogPending = false;
163                controls();
164            });
165            state.pending = { controller: controller, promise: promise };
166            return promise;
167        }
168        function watch() {
169            if (!activeInventory() || state.connection || state.reconnectTimer || state.liveAttempts >= 3 || !window.signalR) return;
170            var connection = new window.signalR.HubConnectionBuilder().withUrl('/orcaHub')
171                .withAutomaticReconnect([0, 1000, 3000, 10000]).configureLogging(window.signalR.LogLevel.Warning).build();
172            state.connection = connection;
173            function join() {
174                return connection.invoke('JoinEntityForm', ctx.companyid, 'uom_conversion', '_list', ctx.uiSurface).then(function () {
175                    if (state.stopped || state.connection !== connection) return;
176                    state.liveAttempts = 0;
177                    state.liveError = '';
178                    state.invalidated = true;
179                    controls();
180                    return refresh(true);
181                });
182            }
183            function disconnected(error) {
184                if (state.stopped || state.connection !== connection) return;
185                state.connection = null;
186                state.invalidated = true;
187                state.liveError = L('Unit conversion updates are unavailable.');
188                options.status(state.liveError + (error && error.message ? ' ' + error.message : ''), '#f59e0b');
189                controls();
190                connection.stop().catch(function (stopError) { console.warn('Unit conversion subscription cleanup failed', stopError); });
191                if (++state.liveAttempts < 3) {
192                    state.reconnectTimer = setTimeout(function () {
193                        state.reconnectTimer = null;
194                        watch();
195                    }, state.liveAttempts === 1 ? 1000 : 3000);
196                }
197            }
198            connection.on('entityFormChanged', function (payload) {
199                try {
200                    var message = typeof payload === 'string' ? JSON.parse(payload) : payload;
201                    if (state.connection !== connection || !message || message.companyid !== ctx.companyid
202                        || message.entitytype !== 'uom_conversion' || message.recordid !== '_list') return;
203                    state.invalidated = true;
204                    refresh(true, true);
205                } catch (error) { console.error('Invalid unit conversion notification', error); }
206            });
207            connection.onclose(disconnected);
208            connection.onreconnected(function () {
209                join().catch(disconnected);
210            });
211            connection.start().then(join).catch(disconnected);
212        }
213        function inverse() {
214            var display = options.body().querySelector('[data-orca-field-wrap="inverse_rate"] > div');
215            if (!display) return;
216            var rate = Number(ctx.values.rate);
217            var from = String(ctx.values.from_uom || '');
218            var to = String(ctx.values.to_uom || '');
219            var text = from && to && Number.isFinite(rate) && rate > 0 && Number.isFinite(1 / rate)
220                ? '1 ' + to + ' = ' + String(1 / rate) + ' ' + from : 'N/A';
221            display.replaceChildren();
222            var icon = document.createElement('span');
223            icon.className = 'material-symbols-outlined mr-1 text-sm text-slate-500';
224            icon.textContent = 'lock';
225            var value = document.createElement('span');
226            value.className = 'min-w-0 break-words text-xs';
227            value.textContent = text;
228            display.append(icon, value);
229        }
230        function sync() {
231            if (state.stopped || ctx.disposed) return;
232            if (activeInventory()) {
233                refresh();
234                watch();
235            } else if (ctx.entitytype === 'uom_conversion' && ctx.mode !== 'list') {
236                ['from_uom', 'to_uom', 'rate'].forEach(function (name) {
237                    var input = field(name);
238                    if (!input || input.dataset.orcaUomBound) return;
239                    input.dataset.orcaUomBound = '1';
240                    if (name === 'rate') input.setAttribute('step', 'any');
241                    input.addEventListener('input', inverse);
242                    input.addEventListener('change', inverse);
243                });
244                inverse();
245            }
246        }
247        function stop() {
248            state.stopped = true;
249            ++state.sequence;
250            clearTimeout(state.reconnectTimer);
251            state.reconnectTimer = null;
252            if (state.pending) state.pending.controller.abort();
253            if (state.connection) state.connection.stop().catch(function (error) { console.warn('Unit conversion subscription cleanup failed', error); });
254            state.connection = null;
255        }
256        return { sync: sync, refresh: refresh, stop: stop };
257    }
258    window.OrcaUomWorkspace = { create: create };
259})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.