@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.
Files changed (84) hide show
  1. package/dist/{DisplaySystemView-hmlT9gsb.js → DisplaySystemView-DjFBEWoq.js} +1 -1
  2. package/dist/{KioskDevicesView-fW6M9Hao.js → KioskDevicesView-RKMdLuB3.js} +1 -1
  3. package/dist/{KioskDevicesView.vue_vue_type_script_setup_true_lang-GrsnYo80.js → KioskDevicesView.vue_vue_type_script_setup_true_lang-BrG6Au5z.js} +3 -3
  4. package/dist/{KioskSettingView-BdEPftHH.js → KioskSettingView-CzelEig6.js} +3 -3
  5. package/dist/{KioskView-Bwk9S0tc.js → KioskView-Bi5Kc4cS.js} +35 -30
  6. package/dist/OrderSettingsView-BfxrjGAi.js +68958 -0
  7. package/dist/{app-BnrruYco.js → app-Bg-n-Eug.js} +8316 -7952
  8. package/dist/app.js +1 -1
  9. package/dist/common/index.d.ts +6 -7
  10. package/dist/frontend/mf-order/src/app.d.ts +24 -8
  11. package/dist/frontend/mf-order/src/main.d.ts +24 -8
  12. package/dist/frontend/mf-order/src/modules/order-setting/kiosk/interface.d.ts +2 -0
  13. package/dist/frontend/mf-order/src/stores/order-setting/index.d.ts +18 -99
  14. package/dist/frontend/mf-order/src/views/order-settings/delivery/delivery.d.ts +1 -0
  15. package/dist/frontend/mf-order/src/views/order-settings/delivery/inhouse/InHouseDelivery.vue.d.ts +3 -0
  16. package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/IntegratedDelivery.vue.d.ts +12 -1
  17. package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/IntegrationIdentityDetails.vue.d.ts +12 -0
  18. package/dist/frontend/mf-order/src/views/order-settings/pickup/PickUpSettingDialogContent.vue.d.ts +3 -0
  19. package/dist/frontend/mf-order/tsconfig.app.tsbuildinfo +1 -1
  20. package/dist/{index-LyvBqKnv.js → index-0eYg6XEb.js} +1 -1
  21. package/dist/{index-D5wABuUx.js → index-C7Ug4fCi.js} +1 -1
  22. package/dist/{index-D7IWjZdy.js → index-g_rocKrp.js} +2 -2
  23. package/dist/order.dto-MKeJAj6d.js +39215 -0
  24. package/dist/package/entity/alert/investigation.dto.d.ts +3 -0
  25. package/dist/package/entity/alert/suggestion.dto.d.ts +3 -0
  26. package/dist/package/entity/delivery/delivery.dto.d.ts +1 -11
  27. package/dist/package/entity/incoming-order/incoming-order-to-bill.dto.d.ts +89 -51
  28. package/dist/package/entity/index.d.ts +0 -7
  29. package/dist/package/entity/kiosk/kiosk.dto.d.ts +6 -0
  30. package/dist/package/entity/kiosk/marketing/marketing.dto.d.ts +26 -0
  31. package/dist/package/entity/member/member.dto.d.ts +12 -12
  32. package/dist/package/entity/order/dine-in/dine-in.do.d.ts +9 -159
  33. package/dist/package/entity/order/dine-in/dine-in.dto.d.ts +3 -17
  34. package/dist/package/entity/order/effects/effect.dto.d.ts +32 -0
  35. package/dist/package/entity/order/menu/menu.dto.d.ts +6 -144
  36. package/dist/package/entity/order/order.do.d.ts +109 -269
  37. package/dist/package/entity/order/order.dto.d.ts +408 -782
  38. package/dist/package/entity/order/order.enum.d.ts +1 -1
  39. package/dist/package/entity/order/timeslot/timeslot.dto.d.ts +4 -4
  40. package/dist/package/entity/order-platform/foodpanda/foodpanda-order.dto.d.ts +1 -11
  41. package/dist/package/entity/order-platform/grabfood/grabfood-order.do.d.ts +1 -11
  42. package/dist/package/entity/order-platform/order-platform.dto.d.ts +278 -234
  43. package/dist/package/entity/order-platform/shopeefood/shopeefood-order.do.d.ts +1 -11
  44. package/dist/package/entity/order-platform/tng/tng-menu.do.d.ts +6 -6
  45. package/dist/package/entity/order-setting/delivery/inhouse-delivery.dto.d.ts +3 -0
  46. package/dist/package/entity/order-setting/dine-in/dine-in.dto.d.ts +65 -0
  47. package/dist/package/entity/order-setting/kiosk/kiosk.dto.d.ts +1004 -0
  48. package/dist/package/entity/order-setting/order-setting.do.d.ts +5 -337
  49. package/dist/package/entity/order-setting/order-setting.dto.d.ts +879 -678
  50. package/dist/package/entity/order-setting/pickup/pickup.dto.d.ts +3 -0
  51. package/dist/package/entity/order-setting/sequence/sequence.do.d.ts +0 -41
  52. package/dist/package/entity/order-setting/sequence/sequence.dto.d.ts +0 -43
  53. package/dist/package/entity/order-setting/sms/sms.do.d.ts +3 -3
  54. package/dist/package/entity/order-setting/sms/sms.dto.d.ts +3 -3
  55. package/dist/package/entity/queue/queue.do.d.ts +2 -2
  56. package/dist/package/entity/queue/queue.dto.d.ts +49 -65
  57. package/dist/package/entity/restaurant/restaurant.dto.d.ts +11 -0
  58. package/dist/package/entity/websocket/websocket.dto.d.ts +33 -161
  59. package/dist/package/entity/websocket/websocket.enum.d.ts +1 -1
  60. package/dist/style.css +1 -1
  61. package/package.json +2 -2
  62. package/src/locales/en-US.json +6 -2
  63. package/src/locales/ja-JP.json +6 -2
  64. package/src/locales/th-TH.json +6 -2
  65. package/src/locales/zh-CN.json +6 -2
  66. package/src/modules/order-setting/kiosk/interface.ts +12 -0
  67. package/src/stores/order-setting/mapper.spec.ts +36 -0
  68. package/src/stores/order-setting/mapper.ts +5 -0
  69. package/src/views/order-settings/delivery/DeliverySetting.vue +5 -5
  70. package/src/views/order-settings/delivery/delivery.spec.ts +34 -0
  71. package/src/views/order-settings/delivery/delivery.ts +14 -1
  72. package/src/views/order-settings/delivery/integrated-delivery/IntegratedDelivery.vue +10 -1
  73. package/src/views/order-settings/delivery/integrated-delivery/IntegrationIdentityDetails.vue +121 -22
  74. package/src/views/order-settings/delivery/integrated-delivery/LinemanSetting.vue +161 -10
  75. package/dist/OrderSettingsView-DVXfVdXj.js +0 -94831
  76. package/dist/common/booking/index.d.ts +0 -38
  77. package/dist/order.dto-D7HGiueX.js +0 -43514
  78. package/dist/package/entity/booking/booking.do.d.ts +0 -17197
  79. package/dist/package/entity/booking/booking.dto.d.ts +0 -305
  80. package/dist/package/entity/booking/booking.enum.d.ts +0 -7
  81. package/dist/package/entity/order/dine-in/reservation.do.d.ts +0 -75
  82. package/dist/package/entity/order/dine-in/reservation.dto.d.ts +0 -15
  83. package/dist/package/entity/order-setting/reservation/reservation.do.d.ts +0 -662
  84. 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
- async function syncMenu() {
91
- await startAsyncCallWithErr(async () => {
92
- const partnerId = data.integrated.partnerID
93
- const catalogId = data.integrated.catalogId
94
- const restaurantId = currentRestaurant.value?._id
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
- if (!partnerId || !restaurantId) {
97
- showError('Missing Lineman partnerID or restaurantId')
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
- await remoteOrderApi.integratedDelivery.syncLinemanMenu(partnerId, restaurantId, catalogId)
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
- showSuccess(t('order.syncMenuSuccess'))
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>