@feedmepos/mf-order-setting 0.0.85 → 0.0.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DisplaySystemView-hmlT9gsb.js → DisplaySystemView-DjFBEWoq.js} +1 -1
- package/dist/{KioskDevicesView-fW6M9Hao.js → KioskDevicesView-RKMdLuB3.js} +1 -1
- package/dist/{KioskDevicesView.vue_vue_type_script_setup_true_lang-GrsnYo80.js → KioskDevicesView.vue_vue_type_script_setup_true_lang-BrG6Au5z.js} +3 -3
- package/dist/{KioskSettingView-BdEPftHH.js → KioskSettingView-CzelEig6.js} +3 -3
- package/dist/{KioskView-Bwk9S0tc.js → KioskView-Bi5Kc4cS.js} +35 -30
- package/dist/OrderSettingsView-BfxrjGAi.js +68958 -0
- package/dist/{app-BnrruYco.js → app-Bg-n-Eug.js} +8316 -7952
- package/dist/app.js +1 -1
- package/dist/common/index.d.ts +6 -7
- package/dist/frontend/mf-order/src/app.d.ts +24 -8
- package/dist/frontend/mf-order/src/main.d.ts +24 -8
- package/dist/frontend/mf-order/src/modules/order-setting/kiosk/interface.d.ts +2 -0
- package/dist/frontend/mf-order/src/stores/order-setting/index.d.ts +18 -99
- package/dist/frontend/mf-order/src/views/order-settings/delivery/delivery.d.ts +1 -0
- package/dist/frontend/mf-order/src/views/order-settings/delivery/inhouse/InHouseDelivery.vue.d.ts +3 -0
- package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/IntegratedDelivery.vue.d.ts +12 -1
- package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/IntegrationIdentityDetails.vue.d.ts +12 -0
- package/dist/frontend/mf-order/src/views/order-settings/pickup/PickUpSettingDialogContent.vue.d.ts +3 -0
- package/dist/frontend/mf-order/tsconfig.app.tsbuildinfo +1 -1
- package/dist/{index-LyvBqKnv.js → index-0eYg6XEb.js} +1 -1
- package/dist/{index-D5wABuUx.js → index-C7Ug4fCi.js} +1 -1
- package/dist/{index-D7IWjZdy.js → index-g_rocKrp.js} +2 -2
- package/dist/order.dto-MKeJAj6d.js +39215 -0
- package/dist/package/entity/alert/investigation.dto.d.ts +3 -0
- package/dist/package/entity/alert/suggestion.dto.d.ts +3 -0
- package/dist/package/entity/delivery/delivery.dto.d.ts +1 -11
- package/dist/package/entity/incoming-order/incoming-order-to-bill.dto.d.ts +89 -51
- package/dist/package/entity/index.d.ts +0 -7
- package/dist/package/entity/kiosk/kiosk.dto.d.ts +6 -0
- package/dist/package/entity/kiosk/marketing/marketing.dto.d.ts +26 -0
- package/dist/package/entity/member/member.dto.d.ts +12 -12
- package/dist/package/entity/order/dine-in/dine-in.do.d.ts +9 -159
- package/dist/package/entity/order/dine-in/dine-in.dto.d.ts +3 -17
- package/dist/package/entity/order/effects/effect.dto.d.ts +32 -0
- package/dist/package/entity/order/menu/menu.dto.d.ts +6 -144
- package/dist/package/entity/order/order.do.d.ts +109 -269
- package/dist/package/entity/order/order.dto.d.ts +408 -782
- package/dist/package/entity/order/order.enum.d.ts +1 -1
- package/dist/package/entity/order/timeslot/timeslot.dto.d.ts +4 -4
- package/dist/package/entity/order-platform/foodpanda/foodpanda-order.dto.d.ts +1 -11
- package/dist/package/entity/order-platform/grabfood/grabfood-order.do.d.ts +1 -11
- package/dist/package/entity/order-platform/order-platform.dto.d.ts +278 -234
- package/dist/package/entity/order-platform/shopeefood/shopeefood-order.do.d.ts +1 -11
- package/dist/package/entity/order-platform/tng/tng-menu.do.d.ts +6 -6
- package/dist/package/entity/order-setting/delivery/inhouse-delivery.dto.d.ts +3 -0
- package/dist/package/entity/order-setting/dine-in/dine-in.dto.d.ts +65 -0
- package/dist/package/entity/order-setting/kiosk/kiosk.dto.d.ts +1004 -0
- package/dist/package/entity/order-setting/order-setting.do.d.ts +5 -337
- package/dist/package/entity/order-setting/order-setting.dto.d.ts +879 -678
- package/dist/package/entity/order-setting/pickup/pickup.dto.d.ts +3 -0
- package/dist/package/entity/order-setting/sequence/sequence.do.d.ts +0 -41
- package/dist/package/entity/order-setting/sequence/sequence.dto.d.ts +0 -43
- package/dist/package/entity/order-setting/sms/sms.do.d.ts +3 -3
- package/dist/package/entity/order-setting/sms/sms.dto.d.ts +3 -3
- package/dist/package/entity/queue/queue.do.d.ts +2 -2
- package/dist/package/entity/queue/queue.dto.d.ts +49 -65
- package/dist/package/entity/restaurant/restaurant.dto.d.ts +11 -0
- package/dist/package/entity/websocket/websocket.dto.d.ts +33 -161
- package/dist/package/entity/websocket/websocket.enum.d.ts +1 -1
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/locales/en-US.json +6 -2
- package/src/locales/ja-JP.json +6 -2
- package/src/locales/th-TH.json +6 -2
- package/src/locales/zh-CN.json +6 -2
- package/src/modules/order-setting/kiosk/interface.ts +12 -0
- package/src/stores/order-setting/mapper.spec.ts +36 -0
- package/src/stores/order-setting/mapper.ts +5 -0
- package/src/views/order-settings/delivery/DeliverySetting.vue +5 -5
- package/src/views/order-settings/delivery/delivery.spec.ts +34 -0
- package/src/views/order-settings/delivery/delivery.ts +14 -1
- package/src/views/order-settings/delivery/integrated-delivery/IntegratedDelivery.vue +10 -1
- package/src/views/order-settings/delivery/integrated-delivery/IntegrationIdentityDetails.vue +121 -22
- package/src/views/order-settings/delivery/integrated-delivery/LinemanSetting.vue +161 -10
- package/dist/OrderSettingsView-DVXfVdXj.js +0 -94831
- package/dist/common/booking/index.d.ts +0 -38
- package/dist/order.dto-D7HGiueX.js +0 -43514
- package/dist/package/entity/booking/booking.do.d.ts +0 -17197
- package/dist/package/entity/booking/booking.dto.d.ts +0 -305
- package/dist/package/entity/booking/booking.enum.d.ts +0 -7
- package/dist/package/entity/order/dine-in/reservation.do.d.ts +0 -75
- package/dist/package/entity/order/dine-in/reservation.dto.d.ts +0 -15
- package/dist/package/entity/order-setting/reservation/reservation.do.d.ts +0 -662
- package/dist/package/entity/order-setting/reservation/reservation.dto.d.ts +0 -527
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, type PropType, reactive } from 'vue'
|
|
2
|
+
import { computed, onUnmounted, type PropType, reactive, watch } from 'vue'
|
|
3
3
|
|
|
4
4
|
import type { FdoLinkedDelivery } from '@feedmepos/core/entity'
|
|
5
5
|
import { type FdoLinemanSettings } from '@entity'
|
|
@@ -10,6 +10,7 @@ import { remoteOrderApi } from '@/api/remoteOrder'
|
|
|
10
10
|
import { useCoreStore, useI18n } from '@feedmepos/mf-common'
|
|
11
11
|
import { useSnackbarFunctions } from '@/components/snackbar'
|
|
12
12
|
import IntegratedDelivery from './IntegratedDelivery.vue'
|
|
13
|
+
import IntegrationIdentityDetails from './IntegrationIdentityDetails.vue'
|
|
13
14
|
import { clone } from '@/helpers/object'
|
|
14
15
|
|
|
15
16
|
export interface LinemanDeliveryData {
|
|
@@ -87,20 +88,151 @@ const { currentRestaurant } = useCoreStore()
|
|
|
87
88
|
const { showSuccess, showError } = useSnackbarFunctions()
|
|
88
89
|
const { isLoading, startAsyncCallWithErr } = useLoading()
|
|
89
90
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
// Lineman has no generated integration id: the FeedMe restaurant id IS the
|
|
92
|
+
// `storeId` we register with them and the one their menu/order webhooks carry.
|
|
93
|
+
const restaurantId = computed(() => currentRestaurant.value?._id ?? '')
|
|
94
|
+
|
|
95
|
+
// One block support can paste into the Lark thread in a single press. Composed
|
|
96
|
+
// here rather than in the card because platform, restaurant and status are the
|
|
97
|
+
// caller's to know. It is also the snapshot that survives the next sync, which
|
|
98
|
+
// nulls `menuSyncError` and replaces `menuSyncRequestId`.
|
|
99
|
+
const supportSummary = computed(() => [
|
|
100
|
+
{ label: t('order.platform'), value: 'LINE MAN' },
|
|
101
|
+
{ label: t('order.restaurantId'), value: restaurantId.value },
|
|
102
|
+
{ label: t('order.status'), value: data.integrated.status },
|
|
103
|
+
{ label: t('order.lastSync'), value: data.integrated.lastSynchronize },
|
|
104
|
+
{ label: t('order.lastAcceptedSyncRequestId'), value: data.integrated.menuSyncRequestId }
|
|
105
|
+
])
|
|
106
|
+
|
|
107
|
+
// A sync writes its outcome onto the setting either way: PROCESSING with a
|
|
108
|
+
// fresh menuSyncRequestId when LINE MAN accepts the request, FAILED with the
|
|
109
|
+
// rejection body when it does not. Neither reaches this component - the
|
|
110
|
+
// rejected call only surfaces as a snackbar - so read the record back instead
|
|
111
|
+
// of mirroring the one branch we happened to take.
|
|
112
|
+
//
|
|
113
|
+
// Only the sync-owned fields are taken. The rest of `integrated` is bound to
|
|
114
|
+
// the form, which may hold edits the merchant has not saved yet.
|
|
115
|
+
//
|
|
116
|
+
// Reads race each other: a poll issued before a re-sync can resolve after that
|
|
117
|
+
// sync's own read and roll the panel back to the previous attempt, so only the
|
|
118
|
+
// newest read is allowed to write.
|
|
119
|
+
let latestRead = 0
|
|
120
|
+
// `stopPolling` only clears a pending timer, so a read already in flight at
|
|
121
|
+
// unmount has to check for itself before touching state or queueing another
|
|
122
|
+
// poll - otherwise navigating away mid-read leaves the loop running.
|
|
123
|
+
let isActive = true
|
|
124
|
+
|
|
125
|
+
async function readSyncState() {
|
|
126
|
+
const read = ++latestRead
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const setting = await remoteOrderApi.integratedDelivery.readLineman(restaurantId.value)
|
|
130
|
+
if (!isActive || read !== latestRead || !setting) return
|
|
131
|
+
|
|
132
|
+
data.integrated = {
|
|
133
|
+
...data.integrated,
|
|
134
|
+
status: setting.status,
|
|
135
|
+
menuSyncError: setting.menuSyncError,
|
|
136
|
+
menuSyncRequestId: setting.menuSyncRequestId,
|
|
137
|
+
lastSynchronize: setting.lastSynchronize,
|
|
138
|
+
updatedAt: setting.updatedAt
|
|
139
|
+
}
|
|
140
|
+
emits('update:model-value', { manual: data.manual, auto: data.integrated })
|
|
141
|
+
} catch (error) {
|
|
142
|
+
// Any sync result has already been reported. A failed read-back only leaves
|
|
143
|
+
// the diagnostics stale, which the next poll or reload fixes, so do not
|
|
144
|
+
// bury that result under a second error - and do not stop the polling loop,
|
|
145
|
+
// which would turn one dropped request into a permanently stale panel.
|
|
146
|
+
console.error('Failed to read Lineman setting', error)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// PROCESSING is not a resting state: LINE MAN confirms the sync over a webhook
|
|
151
|
+
// that lands on the backend, so the record moves to SUCCESS/FAILED without this
|
|
152
|
+
// panel hearing about it. Keep asking until it settles, otherwise an error that
|
|
153
|
+
// arrives a minute after the sync - the case these diagnostics exist for - is
|
|
154
|
+
// invisible until a reload.
|
|
155
|
+
const SYNC_POLL_INTERVAL_MS = 10_000
|
|
156
|
+
// LINE MAN has never confirmed a sync back to us, or it has and the webhook was
|
|
157
|
+
// rejected. Either way further polling will not learn anything, so stop rather
|
|
158
|
+
// than hold an open tab on a permanent timer. A reload re-arms the watcher.
|
|
159
|
+
const SYNC_POLL_TIMEOUT_MS = 5 * 60_000
|
|
160
|
+
|
|
161
|
+
let pollTimer: ReturnType<typeof setTimeout> | null = null
|
|
162
|
+
let pollDeadline = 0
|
|
163
|
+
|
|
164
|
+
function stopPolling() {
|
|
165
|
+
if (!pollTimer) return
|
|
166
|
+
clearTimeout(pollTimer)
|
|
167
|
+
pollTimer = null
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function queueNextPoll() {
|
|
171
|
+
// Chained rather than setInterval: a slow read cannot stack requests on top
|
|
172
|
+
// of each other.
|
|
173
|
+
pollTimer = setTimeout(async () => {
|
|
174
|
+
pollTimer = null
|
|
175
|
+
await readSyncState()
|
|
176
|
+
|
|
177
|
+
if (isActive && data.integrated.status === 'PROCESSING' && Date.now() < pollDeadline) {
|
|
178
|
+
queueNextPoll()
|
|
179
|
+
}
|
|
180
|
+
}, SYNC_POLL_INTERVAL_MS)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function startPolling() {
|
|
184
|
+
stopPolling()
|
|
185
|
+
pollDeadline = Date.now() + SYNC_POLL_TIMEOUT_MS
|
|
186
|
+
queueNextPoll()
|
|
187
|
+
}
|
|
95
188
|
|
|
96
|
-
|
|
97
|
-
|
|
189
|
+
// `immediate` so a panel opened while a sync is still in flight picks it up,
|
|
190
|
+
// not only one that watched the sync start.
|
|
191
|
+
watch(
|
|
192
|
+
() => data.integrated.status,
|
|
193
|
+
(status) => {
|
|
194
|
+
if (status !== 'PROCESSING') {
|
|
195
|
+
stopPolling()
|
|
98
196
|
return
|
|
99
197
|
}
|
|
198
|
+
if (!pollTimer) startPolling()
|
|
199
|
+
},
|
|
200
|
+
{ immediate: true }
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
onUnmounted(() => {
|
|
204
|
+
isActive = false
|
|
205
|
+
stopPolling()
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
async function syncMenu() {
|
|
209
|
+
const partnerId = data.integrated.partnerID
|
|
210
|
+
const catalogId = data.integrated.catalogId
|
|
211
|
+
|
|
212
|
+
if (!partnerId || !restaurantId.value) {
|
|
213
|
+
showError('Missing Lineman partnerID or restaurantId')
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
await startAsyncCallWithErr(async () => {
|
|
218
|
+
try {
|
|
219
|
+
await remoteOrderApi.integratedDelivery.syncLinemanMenu(
|
|
220
|
+
partnerId,
|
|
221
|
+
restaurantId.value,
|
|
222
|
+
catalogId
|
|
223
|
+
)
|
|
100
224
|
|
|
101
|
-
|
|
225
|
+
showSuccess(t('order.syncMenuSuccess'))
|
|
226
|
+
} finally {
|
|
227
|
+
// Inside the callback so the button stays disabled until the panel has
|
|
228
|
+
// caught up, and in `finally` so a rejected sync refreshes too.
|
|
229
|
+
await readSyncState()
|
|
102
230
|
|
|
103
|
-
|
|
231
|
+
// Re-syncing while already PROCESSING leaves the status unchanged, so the
|
|
232
|
+
// watcher does not fire and the window would still be the previous
|
|
233
|
+
// attempt's - possibly already expired. This attempt gets a fresh one.
|
|
234
|
+
if (data.integrated.status === 'PROCESSING') startPolling()
|
|
235
|
+
}
|
|
104
236
|
})
|
|
105
237
|
}
|
|
106
238
|
</script>
|
|
@@ -112,6 +244,7 @@ async function syncMenu() {
|
|
|
112
244
|
:can-use-auto-delivery-integration="canUseAutoDeliveryIntegration"
|
|
113
245
|
:show-test-order-actions="false"
|
|
114
246
|
:sync-menu-loading="isLoading"
|
|
247
|
+
hide-menu-sync-error-tooltip
|
|
115
248
|
@update:model-value="updateDataPass"
|
|
116
249
|
@sync-menu="syncMenu"
|
|
117
250
|
>
|
|
@@ -123,5 +256,23 @@ async function syncMenu() {
|
|
|
123
256
|
value=""
|
|
124
257
|
/>
|
|
125
258
|
</template>
|
|
259
|
+
<!-- `menuSyncError` comes from the slot rather than `data.integrated` so the
|
|
260
|
+
card shows the same item-name-resolved string the tooltip used to, and
|
|
261
|
+
the tooltip itself is suppressed to keep one copy of the error. -->
|
|
262
|
+
<template #integration-details="{ menuSyncError }">
|
|
263
|
+
<IntegrationIdentityDetails
|
|
264
|
+
hide-identity
|
|
265
|
+
:guidance="t('order.linemanSyncDiagnosticsGuidance')"
|
|
266
|
+
:reference-id="data.integrated.menuSyncRequestId"
|
|
267
|
+
:reference-label="t('order.lastAcceptedSyncRequestId')"
|
|
268
|
+
:message="menuSyncError"
|
|
269
|
+
:message-label="t('order.menuSyncError')"
|
|
270
|
+
show-empty-message
|
|
271
|
+
:support-summary="[
|
|
272
|
+
...supportSummary,
|
|
273
|
+
{ label: t('order.menuSyncError'), value: menuSyncError }
|
|
274
|
+
]"
|
|
275
|
+
/>
|
|
276
|
+
</template>
|
|
126
277
|
</IntegratedDelivery>
|
|
127
278
|
</template>
|