@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
package/src/locales/th-TH.json
CHANGED
|
@@ -130,8 +130,12 @@
|
|
|
130
130
|
"integrationReferenceId": "รหัสอ้างอิงการเชื่อมต่อ",
|
|
131
131
|
"platformStoreId": "รหัสร้านค้าบนแพลตฟอร์ม",
|
|
132
132
|
"copy": "คัดลอก",
|
|
133
|
-
"
|
|
134
|
-
"
|
|
133
|
+
"copiedToClipboard": "คัดลอก{label}แล้ว",
|
|
134
|
+
"copyToClipboardFailed": "ไม่สามารถคัดลอก{label}ได้",
|
|
135
|
+
"restaurantId": "รหัสร้านอาหาร",
|
|
136
|
+
"supportSummary": "ข้อมูลสำหรับฝ่ายสนับสนุน",
|
|
137
|
+
"lastAcceptedSyncRequestId": "รหัสคำขอซิงค์ล่าสุดที่ได้รับการตอบรับ",
|
|
138
|
+
"linemanSyncDiagnosticsGuidance": "Lineman จะยืนยันผลการซิงค์เมนูแบบอะซิงโครนัส รหัสนี้เป็นของคำขอซิงค์ครั้งล่าสุดที่ Lineman ตอบรับ หากการซิงค์ครั้งล่าสุดถูกปฏิเสธทันที ข้อความแสดงข้อผิดพลาดด้านล่างจะเป็นของครั้งนั้น ขณะที่รหัสยังคงอ้างถึงครั้งก่อนที่ได้รับการตอบรับ กรุณาคัดลอกทั้งสองอย่างแนบไปกับเรื่องที่แจ้งฝ่ายสนับสนุน",
|
|
135
139
|
"primaryStore": "ร้านค้าหลัก",
|
|
136
140
|
"removeStore": "ลบ",
|
|
137
141
|
"removeStoreConfirm": "ลบร้าน '{merchantID}' ใช่หรือไม่?",
|
package/src/locales/zh-CN.json
CHANGED
|
@@ -130,8 +130,12 @@
|
|
|
130
130
|
"integrationReferenceId": "集成参考 ID",
|
|
131
131
|
"platformStoreId": "平台门店 ID",
|
|
132
132
|
"copy": "复制",
|
|
133
|
-
"
|
|
134
|
-
"
|
|
133
|
+
"copiedToClipboard": "已复制{label}",
|
|
134
|
+
"copyToClipboardFailed": "无法复制{label}",
|
|
135
|
+
"restaurantId": "餐厅 ID",
|
|
136
|
+
"supportSummary": "支持信息",
|
|
137
|
+
"lastAcceptedSyncRequestId": "最近一次受理的同步请求 ID",
|
|
138
|
+
"linemanSyncDiagnosticsGuidance": "Lineman 会以异步方式确认菜单同步结果。此 ID 属于 Lineman 最近一次受理的同步请求。如果最新一次尝试被直接拒绝,下方的错误信息属于该次尝试,而此 ID 仍指向此前受理的那一次。请将两者一并复制到支持工单中。",
|
|
135
139
|
"primaryStore": "主门店",
|
|
136
140
|
"removeStore": "删除",
|
|
137
141
|
"removeStoreConfirm": "确定删除门店「{merchantID}」吗?",
|
|
@@ -94,6 +94,12 @@ export interface MfKioskOrderSetting {
|
|
|
94
94
|
autoSendKitchen: boolean | null,
|
|
95
95
|
autoCloseBill: boolean | null,
|
|
96
96
|
printReceiptAfterClose: boolean | null,
|
|
97
|
+
// Whether POS may reject a kiosk order (KDI-5089). No form control edits it
|
|
98
|
+
// — ops set it — but it MUST be carried here anyway: the mapper rebuilds
|
|
99
|
+
// kioskSettings field by field and the backend $sets the whole
|
|
100
|
+
// subdocument, so a field the mapper drops is deleted on the next save of
|
|
101
|
+
// an unrelated kiosk field. That is how prod MY lost it on 2026-09-22.
|
|
102
|
+
allowReject: boolean | null,
|
|
97
103
|
// Locales the kiosk may offer the customer. null or [] = no restriction,
|
|
98
104
|
// i.e. the kiosk shows every language it ships. Anything else is the exact
|
|
99
105
|
// allowed set.
|
|
@@ -122,6 +128,12 @@ export interface MfKioskOrderSettingForm {
|
|
|
122
128
|
autoSendKitchen: boolean | null,
|
|
123
129
|
autoCloseBill: boolean | null,
|
|
124
130
|
printReceiptAfterClose: boolean | null,
|
|
131
|
+
// Whether POS may reject a kiosk order (KDI-5089). No form control edits it
|
|
132
|
+
// — ops set it — but it MUST be carried here anyway: the mapper rebuilds
|
|
133
|
+
// kioskSettings field by field and the backend $sets the whole
|
|
134
|
+
// subdocument, so a field the mapper drops is deleted on the next save of
|
|
135
|
+
// an unrelated kiosk field. That is how prod MY lost it on 2026-09-22.
|
|
136
|
+
allowReject: boolean | null,
|
|
125
137
|
// Locales the kiosk may offer the customer. null or [] = no restriction,
|
|
126
138
|
// i.e. the kiosk shows every language it ships. Anything else is the exact
|
|
127
139
|
// allowed set.
|
|
@@ -68,3 +68,39 @@ describe('kiosk cover carousel round-trip', () => {
|
|
|
68
68
|
expect(saved(form).coverCarousel).toBeNull()
|
|
69
69
|
})
|
|
70
70
|
})
|
|
71
|
+
|
|
72
|
+
describe('kiosk allowReject round-trip (KDI-5089)', () => {
|
|
73
|
+
// The regression this guards, found on prod MY 2026-09-22: no form control
|
|
74
|
+
// edits allowReject — ops set it — so the mapper has to carry it purely to
|
|
75
|
+
// hand it back. While it was missing, every portal kiosk save rebuilt
|
|
76
|
+
// kioskSettings without it and the backend's whole-subdocument $set deleted
|
|
77
|
+
// it, which turns the POS reject button back on for kiosk orders.
|
|
78
|
+
it('reads a stored allowReject: false back onto the form', () => {
|
|
79
|
+
expect(toKioskForm({ allowReject: false }).allowReject).toBe(false)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('reads a stored allowReject: true back onto the form', () => {
|
|
83
|
+
expect(toKioskForm({ allowReject: true }).allowReject).toBe(true)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// null, not false: unset means "inherit dineInSettings", and collapsing it to
|
|
87
|
+
// a boolean here is what would pin the value and kill that inheritance.
|
|
88
|
+
it('reads an unset allowReject as null, not false', () => {
|
|
89
|
+
expect(toKioskForm({}).allowReject).toBeNull()
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('saves the merchant choice back', () => {
|
|
93
|
+
expect(saved({ ...defaultKioskOrderSetting, allowReject: false }).allowReject).toBe(false)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('omits the field when unset, so the backend keeps inheriting', () => {
|
|
97
|
+
expect(saved({ ...defaultKioskOrderSetting, allowReject: null }).allowReject).toBeUndefined()
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('survives a full read-then-save round trip of an unrelated edit', () => {
|
|
101
|
+
const form = toKioskForm({ allowReject: false, canTakeaway: true })
|
|
102
|
+
// The merchant toggles something else entirely.
|
|
103
|
+
form.takeaway.enabled = false
|
|
104
|
+
expect(saved(form).allowReject).toBe(false)
|
|
105
|
+
})
|
|
106
|
+
})
|
|
@@ -84,6 +84,7 @@ export const defaultKioskOrderSetting: MfKioskOrderSettingForm = {
|
|
|
84
84
|
autoSendKitchen: null,
|
|
85
85
|
autoCloseBill: null,
|
|
86
86
|
printReceiptAfterClose: null,
|
|
87
|
+
allowReject: null,
|
|
87
88
|
languages: null
|
|
88
89
|
}
|
|
89
90
|
|
|
@@ -154,6 +155,9 @@ const toKiosk = (
|
|
|
154
155
|
autoSendKitchen: kioskOrderSettings?.autoSendKitchen ?? null,
|
|
155
156
|
autoCloseBill: kioskOrderSettings?.autoCloseBill ?? null,
|
|
156
157
|
printReceiptAfterClose: kioskOrderSettings?.printReceiptAfterClose ?? null,
|
|
158
|
+
// Read back purely so the write side can hand it straight back. Nothing in
|
|
159
|
+
// the form touches it; dropping it here deletes it on the next save.
|
|
160
|
+
allowReject: kioskOrderSettings?.allowReject ?? null,
|
|
157
161
|
// Stored [] means the same thing as unset ("all languages"), so collapse it
|
|
158
162
|
// to null here — the form only ever has to reason about null vs a real set.
|
|
159
163
|
languages: kioskOrderSettings?.languages?.length ? [...kioskOrderSettings.languages] : null
|
|
@@ -255,6 +259,7 @@ const toOrderKioskSettingsDto = (
|
|
|
255
259
|
autoSendKitchen: kioskSetting.autoSendKitchen ?? undefined,
|
|
256
260
|
autoCloseBill: kioskSetting.autoCloseBill ?? undefined,
|
|
257
261
|
printReceiptAfterClose: kioskSetting.printReceiptAfterClose ?? undefined,
|
|
262
|
+
allowReject: kioskSetting.allowReject ?? undefined,
|
|
258
263
|
// Omit rather than send [] when the merchant restricts nothing, so the
|
|
259
264
|
// saved document stays free of a field that means "all languages" anyway.
|
|
260
265
|
languages: kioskSetting.languages?.length ? kioskSetting.languages : undefined,
|
|
@@ -216,12 +216,13 @@ import deliveryData from './delivery.data'
|
|
|
216
216
|
import {
|
|
217
217
|
getInvalidExternalMenuCatalogOrderTypes,
|
|
218
218
|
useDelivery,
|
|
219
|
+
isHiddenDeliveryKey,
|
|
220
|
+
AUTO_INTEGRATION_CLIENT,
|
|
219
221
|
type DeliveryCompany,
|
|
220
222
|
type LinkedDeliveryDoc
|
|
221
223
|
} from './delivery'
|
|
222
224
|
import { useLoading } from '@/composables/loading'
|
|
223
225
|
import { remoteOrderApi } from '@/api/remoteOrder'
|
|
224
|
-
import { AUTO_INTEGRATION_CLIENT } from '../delivery/delivery'
|
|
225
226
|
import { useMenuStore } from '@/stores/menu/menu'
|
|
226
227
|
import ManualIntegratedDeliverySetting from './components/ManualIntegratedDeliverySetting.vue'
|
|
227
228
|
import { insertOrUpdate, remove, sort } from '@/helpers/iteration'
|
|
@@ -850,14 +851,13 @@ const integratedCompanies = computed<IntegratedDeliveryRow[]>(() => {
|
|
|
850
851
|
]
|
|
851
852
|
|
|
852
853
|
return [
|
|
853
|
-
// FeedMe
|
|
854
|
-
//
|
|
855
|
-
// off (e.g. Go plan). Third-party delivery integrations remain available.
|
|
854
|
+
// In-house delivery is part of "FeedMe online ordering", so it stays hidden when
|
|
855
|
+
// QR ordering is off (e.g. Go plan). Third-party delivery integrations remain available.
|
|
856
856
|
...(qrEnabled.value ? feedmeDelivery : []),
|
|
857
857
|
...integratedDelivery.filter((delivery) => {
|
|
858
858
|
return isIntegratedPlatformSupported(delivery.key, currentCountry.value)
|
|
859
859
|
})
|
|
860
|
-
]
|
|
860
|
+
].filter((row) => !isHiddenDeliveryKey(row.key))
|
|
861
861
|
})
|
|
862
862
|
|
|
863
863
|
const loadingKey = computed(() => {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { F_DELIVERY_TYPE } from '@feedmepos/core/entity'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
import { AUTO_INTEGRATION_CLIENT, isHiddenDeliveryKey } from './delivery'
|
|
4
|
+
|
|
5
|
+
// delivery.ts pulls in @feedmepos/mf-common for useCoreStore, whose dist bundle
|
|
6
|
+
// crashes under vitest; isHiddenDeliveryKey never touches it, so stub it out.
|
|
7
|
+
vi.mock('@feedmepos/mf-common', () => ({ useCoreStore: () => ({}) }))
|
|
8
|
+
|
|
9
|
+
describe('isHiddenDeliveryKey', () => {
|
|
10
|
+
it('hides the TNG integration (pending TNGD delivery/pickup support)', () => {
|
|
11
|
+
expect(isHiddenDeliveryKey(AUTO_INTEGRATION_CLIENT.tng)).toBe(true)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('hides FeedMe Express (service ended 1 Feb 2026)', () => {
|
|
15
|
+
expect(isHiddenDeliveryKey(F_DELIVERY_TYPE.enum.FEEDME)).toBe(true)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('keeps every other delivery row visible', () => {
|
|
19
|
+
const stillShown = [
|
|
20
|
+
AUTO_INTEGRATION_CLIENT.foodpanda,
|
|
21
|
+
AUTO_INTEGRATION_CLIENT.grabfood,
|
|
22
|
+
AUTO_INTEGRATION_CLIENT.lineman,
|
|
23
|
+
AUTO_INTEGRATION_CLIENT.shopeefood,
|
|
24
|
+
AUTO_INTEGRATION_CLIENT.gofood,
|
|
25
|
+
AUTO_INTEGRATION_CLIENT.deliveroo,
|
|
26
|
+
AUTO_INTEGRATION_CLIENT.external,
|
|
27
|
+
F_DELIVERY_TYPE.enum.IN_HOUSE
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
for (const key of stillShown) {
|
|
31
|
+
expect(isHiddenDeliveryKey(key)).toBe(false)
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
})
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
F_PAYMENT_NAME,
|
|
3
|
+
FdoLinkedDelivery,
|
|
4
|
+
F_COUNTRY,
|
|
5
|
+
F_DELIVERY_TYPE
|
|
6
|
+
} from '@feedmepos/core/entity'
|
|
2
7
|
import { useCoreStore } from '@feedmepos/mf-common'
|
|
3
8
|
import { F_ORDER_PLATFORM, type FdoExternalSetting } from '@entity'
|
|
4
9
|
|
|
@@ -29,6 +34,10 @@ export type ExternalMenuOrderTypeWithRequiredCatalog = Extract<
|
|
|
29
34
|
'delivery' | 'pickup'
|
|
30
35
|
>
|
|
31
36
|
|
|
37
|
+
// Pending TNGD delivery/pickup support on the Near Me SPI.
|
|
38
|
+
const TNG_PENDING_DELIVERY_KEYS: string[] = [AUTO_INTEGRATION_CLIENT.tng]
|
|
39
|
+
const DISCONTINUED_DELIVERY_KEYS: string[] = [F_DELIVERY_TYPE.enum.FEEDME]
|
|
40
|
+
|
|
32
41
|
export function externalMenuOrderTypeRequiresCatalog(
|
|
33
42
|
platform: FdoExternalSetting['platform'],
|
|
34
43
|
orderType: ExternalMenuOrderType
|
|
@@ -59,6 +68,10 @@ export function getInvalidExternalMenuCatalogOrderTypes(
|
|
|
59
68
|
})
|
|
60
69
|
}
|
|
61
70
|
|
|
71
|
+
export function isHiddenDeliveryKey(key: string): boolean {
|
|
72
|
+
return TNG_PENDING_DELIVERY_KEYS.includes(key) || DISCONTINUED_DELIVERY_KEYS.includes(key)
|
|
73
|
+
}
|
|
74
|
+
|
|
62
75
|
function formatDeliveryCompanyKey(key: string) {
|
|
63
76
|
return key.toLowerCase().replace('_', '').toLowerCase()
|
|
64
77
|
}
|
|
@@ -54,6 +54,14 @@ const props = defineProps({
|
|
|
54
54
|
type: Boolean,
|
|
55
55
|
default: false
|
|
56
56
|
},
|
|
57
|
+
// Lineman renders the same error inside the diagnostics card below, where it
|
|
58
|
+
// is copyable. Rendering it here as well would show support the same string
|
|
59
|
+
// twice, so that panel suppresses this tooltip and takes the formatted value
|
|
60
|
+
// through the `integration-details` slot instead.
|
|
61
|
+
hideMenuSyncErrorTooltip: {
|
|
62
|
+
type: Boolean,
|
|
63
|
+
default: false
|
|
64
|
+
},
|
|
57
65
|
showTestOrderActions: {
|
|
58
66
|
type: Boolean,
|
|
59
67
|
default: true
|
|
@@ -346,7 +354,7 @@ const formattedMenuSyncError = computed(() => {
|
|
|
346
354
|
<slot name="order-setting" :editable="!canEdit" />
|
|
347
355
|
</div>
|
|
348
356
|
|
|
349
|
-
<slot name="integration-details" />
|
|
357
|
+
<slot name="integration-details" :menu-sync-error="formattedMenuSyncError" />
|
|
350
358
|
|
|
351
359
|
<!-- Commision rate not used yet -->
|
|
352
360
|
<!-- <div class="mb-5">
|
|
@@ -386,6 +394,7 @@ const formattedMenuSyncError = computed(() => {
|
|
|
386
394
|
</div>
|
|
387
395
|
<FmTooltip
|
|
388
396
|
v-if="
|
|
397
|
+
!hideMenuSyncErrorTooltip &&
|
|
389
398
|
(modelValue.auto.status === 'FAILED' || alwaysShowMenuSyncError) &&
|
|
390
399
|
formattedMenuSyncError !== null
|
|
391
400
|
"
|
package/src/views/order-settings/delivery/integrated-delivery/IntegrationIdentityDetails.vue
CHANGED
|
@@ -3,6 +3,11 @@ import { computed } from 'vue'
|
|
|
3
3
|
import { useI18n } from '@feedmepos/mf-common'
|
|
4
4
|
import { useSnackbarFunctions } from '@/components/snackbar'
|
|
5
5
|
|
|
6
|
+
interface SupportSummaryRow {
|
|
7
|
+
label: string
|
|
8
|
+
value?: string | null
|
|
9
|
+
}
|
|
10
|
+
|
|
6
11
|
const props = defineProps<{
|
|
7
12
|
integrationId?: string | null
|
|
8
13
|
partnerId?: string | null
|
|
@@ -10,68 +15,135 @@ const props = defineProps<{
|
|
|
10
15
|
providerId?: string | null
|
|
11
16
|
providerLabel?: string
|
|
12
17
|
storeLabel?: string
|
|
18
|
+
// Drops the id rows and keeps only the support diagnostics below. For
|
|
19
|
+
// Lineman there is no FeedMe-side integration identity worth showing — it
|
|
20
|
+
// reuses the restaurant id — so the rows would only be noise.
|
|
21
|
+
hideIdentity?: boolean
|
|
22
|
+
// Overrides the tooltip next to the title. The default text describes
|
|
23
|
+
// GrabFood/Foodpanda/ShopeeFood multi-store ids; platforms whose FeedMe
|
|
24
|
+
// identity works differently pass their own.
|
|
25
|
+
guidance?: string
|
|
26
|
+
// Support-facing extras: the id the platform gave us for the last async menu
|
|
27
|
+
// sync, and whatever message came back with it. Neither carries its own copy
|
|
28
|
+
// button - both are lines in `supportSummary`, and a per-row button would
|
|
29
|
+
// only offer support a worse paste than the block below.
|
|
30
|
+
referenceId?: string | null
|
|
31
|
+
referenceLabel?: string
|
|
32
|
+
message?: string | null
|
|
33
|
+
messageLabel?: string
|
|
34
|
+
// The backend nulls `message` out when a sync starts and again when it
|
|
35
|
+
// succeeds, so hiding the row leaves support unable to tell "no failure" from
|
|
36
|
+
// "not wired up". Callers that want the state either way render a dash.
|
|
37
|
+
showEmptyMessage?: boolean
|
|
38
|
+
// Rows for the one-press support block. The card cannot build this itself -
|
|
39
|
+
// platform, restaurant and status live on the caller - so it takes the lines
|
|
40
|
+
// already composed and only owns the formatting. Empty values are dropped so
|
|
41
|
+
// a half-populated record still yields a clean paste.
|
|
42
|
+
supportSummary?: SupportSummaryRow[]
|
|
13
43
|
}>()
|
|
14
44
|
|
|
15
45
|
const { t } = useI18n()
|
|
16
46
|
const { showSuccess, showError } = useSnackbarFunctions()
|
|
17
47
|
|
|
18
48
|
const visiblePartnerId = computed(() => props.partnerId || null)
|
|
49
|
+
const guidanceText = computed(() => props.guidance || t('order.integrationIdGuidance'))
|
|
50
|
+
const showIdentity = computed(() => !props.hideIdentity)
|
|
51
|
+
const showCard = computed(
|
|
52
|
+
() =>
|
|
53
|
+
(showIdentity.value &&
|
|
54
|
+
Boolean(props.integrationId || props.partnerId || props.providerId || props.storeLabel)) ||
|
|
55
|
+
Boolean(props.referenceId || props.message || props.showEmptyMessage)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
// The record is destructive - the next sync nulls the error and replaces the
|
|
59
|
+
// request id - so this block is often the only surviving evidence of a failure
|
|
60
|
+
// once support has pasted it into the ticket.
|
|
61
|
+
const supportSummaryText = computed(() =>
|
|
62
|
+
(props.supportSummary ?? [])
|
|
63
|
+
.filter((row) => row.value)
|
|
64
|
+
.map((row) => `${row.label}: ${row.value}`)
|
|
65
|
+
.join('\n')
|
|
66
|
+
)
|
|
19
67
|
|
|
20
|
-
async function
|
|
21
|
-
|
|
68
|
+
async function copySupportSummary() {
|
|
69
|
+
await copyValue(supportSummaryText.value, t('order.supportSummary'))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function copyValue(value: string | null | undefined, label: string) {
|
|
73
|
+
if (!value) return
|
|
22
74
|
try {
|
|
23
|
-
await navigator.clipboard.writeText(
|
|
24
|
-
showSuccess(t('order.
|
|
75
|
+
await navigator.clipboard.writeText(value)
|
|
76
|
+
showSuccess(t('order.copiedToClipboard', { label }))
|
|
25
77
|
} catch {
|
|
26
|
-
showError(t('order.
|
|
78
|
+
showError(t('order.copyToClipboardFailed', { label }))
|
|
27
79
|
}
|
|
28
80
|
}
|
|
29
81
|
</script>
|
|
30
82
|
|
|
31
83
|
<template>
|
|
32
84
|
<div
|
|
33
|
-
v-if="
|
|
85
|
+
v-if="showCard"
|
|
34
86
|
class="integration-details"
|
|
35
87
|
:class="{ 'integration-details--owned': storeLabel }"
|
|
36
88
|
>
|
|
37
89
|
<div class="integration-details__header">
|
|
38
90
|
<div class="integration-details__title">
|
|
39
91
|
<div class="fm-typo-en-title-sm-600">{{ t('order.integrationDetails') }}</div>
|
|
40
|
-
<FmTooltip :content="
|
|
41
|
-
<FmIcon
|
|
42
|
-
name="info"
|
|
43
|
-
size="sm"
|
|
44
|
-
class="cursor-help text-fm-color-neutral-gray-400"
|
|
45
|
-
/>
|
|
92
|
+
<FmTooltip :content="guidanceText" :z-index="1000">
|
|
93
|
+
<FmIcon name="info" size="sm" class="cursor-help text-fm-color-neutral-gray-400" />
|
|
46
94
|
</FmTooltip>
|
|
47
95
|
</div>
|
|
48
96
|
<span v-if="storeLabel" class="integration-details__store-label fm-typo-en-body-sm-600">
|
|
49
97
|
{{ storeLabel }}
|
|
50
98
|
</span>
|
|
51
99
|
</div>
|
|
52
|
-
<div class="integration-details__row fm-typo-cn-body-md-400">
|
|
100
|
+
<div v-if="showIdentity" class="integration-details__row fm-typo-cn-body-md-400">
|
|
53
101
|
<span class="text-fm-color-neutral-gray-400">{{ t('order.feedmeIntegrationId') }}</span>
|
|
54
102
|
<div class="integration-details__value">
|
|
55
103
|
<code>{{ integrationId || t('order.integrationIdNotAssigned') }}</code>
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
104
|
+
<span v-if="integrationId" class="integration-details__action">
|
|
105
|
+
<FmButton
|
|
106
|
+
variant="tertiary"
|
|
107
|
+
size="md"
|
|
108
|
+
:label="t('order.copy')"
|
|
109
|
+
@click="copyValue(integrationId, t('order.feedmeIntegrationId'))"
|
|
110
|
+
/>
|
|
111
|
+
</span>
|
|
63
112
|
</div>
|
|
64
113
|
</div>
|
|
65
|
-
<div
|
|
114
|
+
<div
|
|
115
|
+
v-if="showIdentity && visiblePartnerId"
|
|
116
|
+
class="integration-details__row fm-typo-cn-body-md-400"
|
|
117
|
+
>
|
|
66
118
|
<span class="text-fm-color-neutral-gray-400">{{ partnerLabel || t('order.partnerId') }}</span>
|
|
67
119
|
<code>{{ visiblePartnerId }}</code>
|
|
68
120
|
</div>
|
|
69
|
-
<div v-if="providerId" class="integration-details__row fm-typo-cn-body-md-400">
|
|
121
|
+
<div v-if="showIdentity && providerId" class="integration-details__row fm-typo-cn-body-md-400">
|
|
70
122
|
<span class="text-fm-color-neutral-gray-400">{{
|
|
71
123
|
providerLabel || t('order.platformStoreId')
|
|
72
124
|
}}</span>
|
|
73
125
|
<code>{{ providerId }}</code>
|
|
74
126
|
</div>
|
|
127
|
+
<div v-if="referenceId" class="integration-details__row fm-typo-cn-body-md-400">
|
|
128
|
+
<span class="text-fm-color-neutral-gray-400">{{
|
|
129
|
+
referenceLabel || t('order.integrationReferenceId')
|
|
130
|
+
}}</span>
|
|
131
|
+
<code>{{ referenceId }}</code>
|
|
132
|
+
</div>
|
|
133
|
+
<div v-if="message || showEmptyMessage" class="integration-details__row fm-typo-cn-body-md-400">
|
|
134
|
+
<span class="text-fm-color-neutral-gray-400">{{
|
|
135
|
+
messageLabel || t('order.menuSyncError')
|
|
136
|
+
}}</span>
|
|
137
|
+
<code class="integration-details__message">{{ message || '-' }}</code>
|
|
138
|
+
</div>
|
|
139
|
+
<div v-if="supportSummaryText" class="integration-details__summary">
|
|
140
|
+
<FmButton
|
|
141
|
+
variant="secondary"
|
|
142
|
+
size="md"
|
|
143
|
+
:label="t('order.copy')"
|
|
144
|
+
@click="copySupportSummary"
|
|
145
|
+
/>
|
|
146
|
+
</div>
|
|
75
147
|
</div>
|
|
76
148
|
</template>
|
|
77
149
|
|
|
@@ -126,6 +198,33 @@ async function copyIntegrationId() {
|
|
|
126
198
|
gap: 0.5rem;
|
|
127
199
|
}
|
|
128
200
|
|
|
201
|
+
/* FmButton's root is a flex box with `overflow: hidden` and no
|
|
202
|
+
`flex-shrink: 0`, so an opaque single-token value would squeeze it until its
|
|
203
|
+
own label was clipped. Pin the button at its natural width and make the
|
|
204
|
+
value the only thing that gives. */
|
|
205
|
+
.integration-details__action {
|
|
206
|
+
display: inline-flex;
|
|
207
|
+
flex: 0 0 auto;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.integration-details__value > code {
|
|
211
|
+
flex: 1 1 auto;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.integration-details__summary {
|
|
215
|
+
display: flex;
|
|
216
|
+
justify-content: flex-end;
|
|
217
|
+
margin-top: 0.25rem;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* A sync message can be a long JSON blob: keep it in its own column like every
|
|
221
|
+
other value and let it scroll rather than stretch the card. */
|
|
222
|
+
.integration-details__message {
|
|
223
|
+
max-height: 9rem;
|
|
224
|
+
overflow-y: auto;
|
|
225
|
+
white-space: pre-wrap;
|
|
226
|
+
}
|
|
227
|
+
|
|
129
228
|
code {
|
|
130
229
|
min-width: 0;
|
|
131
230
|
overflow-wrap: anywhere;
|