1316 lines
48 KiB
TypeScript
1316 lines
48 KiB
TypeScript
"use client";
|
|
|
|
import type { HospitalityListConfig } from "@/modules/hospitality/components/HospitalityListCrudPage";
|
|
import { hospitalityApi } from "@/modules/hospitality/services/hospitality-api";
|
|
import {
|
|
auditColumns,
|
|
codeNameCreateFields,
|
|
codeNameStatusColumns,
|
|
lifecycleStatusOptions,
|
|
venueIdField,
|
|
} from "@/modules/hospitality/constants/fieldHelpers";
|
|
import { venueFormatLabels } from "@/modules/hospitality/design-system/tokens";
|
|
|
|
const venueFormatOptions = Object.entries(venueFormatLabels).map(([value, label]) => ({
|
|
value,
|
|
label,
|
|
}));
|
|
|
|
const menuStatusOptions = [
|
|
{ value: "draft", label: "پیشنویس" },
|
|
{ value: "published", label: "منتشر شده" },
|
|
{ value: "archived", label: "آرشیو" },
|
|
];
|
|
|
|
const tableStatusOptions = [
|
|
{ value: "available", label: "آزاد" },
|
|
{ value: "occupied", label: "اشغال" },
|
|
{ value: "reserved", label: "رزرو" },
|
|
{ value: "cleaning", label: "نظافت" },
|
|
{ value: "out_of_service", label: "خارج از سرویس" },
|
|
];
|
|
|
|
const posPaymentMethodOptions = [
|
|
{ value: "cash", label: "نقد" },
|
|
{ value: "card", label: "کارت" },
|
|
{ value: "other", label: "سایر" },
|
|
];
|
|
|
|
const posDiscountKindOptions = [
|
|
{ value: "percent", label: "درصدی" },
|
|
{ value: "fixed", label: "مبلغ ثابت" },
|
|
];
|
|
|
|
const connectorKindFilter = (kind: string) => (row: Record<string, unknown>) =>
|
|
String(row.kind) === kind;
|
|
|
|
const connectorColumns = [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام" },
|
|
{ key: "kind", header: "نوع" },
|
|
{ key: "external_ref", header: "ارجاع خارجی" },
|
|
{ key: "status", header: "وضعیت", type: "status" as const },
|
|
...auditColumns(),
|
|
];
|
|
|
|
const connectorCreateFields = (kind: string, kindLabel: string) =>
|
|
codeNameCreateFields([
|
|
{
|
|
name: "kind",
|
|
label: "نوع کانکتور",
|
|
type: "select",
|
|
required: true,
|
|
options: [{ value: kind, label: kindLabel }],
|
|
},
|
|
venueIdField(false),
|
|
]);
|
|
|
|
export const hospitalityResources = {
|
|
venues: {
|
|
title: "مکانها (Venues)",
|
|
description: "مدیریت مکانهای مهماننوازی — کافه، رستوران، فستفود و …",
|
|
breadcrumb: "مکانها",
|
|
resourceKey: "venues",
|
|
bundleFeature: null,
|
|
permission: "hospitality.venues.view",
|
|
api: hospitalityApi.venues,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام" },
|
|
{
|
|
key: "venue_format",
|
|
header: "نوع",
|
|
render: (r) => venueFormatLabels[String(r.venue_format)] ?? String(r.venue_format),
|
|
},
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "currency_code", header: "ارز" },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
{ name: "code", label: "کد", required: true },
|
|
{ name: "name", label: "نام", required: true },
|
|
{
|
|
name: "venue_format",
|
|
label: "نوع کسبوکار",
|
|
type: "select",
|
|
required: true,
|
|
options: venueFormatOptions,
|
|
},
|
|
],
|
|
editFields: [
|
|
{ name: "name", label: "نام", required: true },
|
|
{
|
|
name: "status",
|
|
label: "وضعیت",
|
|
type: "select",
|
|
options: lifecycleStatusOptions,
|
|
},
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
branches: {
|
|
title: "شعب",
|
|
breadcrumb: "شعب",
|
|
resourceKey: "branches",
|
|
bundleFeature: null,
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.branches,
|
|
columns: codeNameStatusColumns([{ key: "venue_id", header: "مکان" }]),
|
|
createFields: codeNameCreateFields([venueIdField(), { name: "timezone", label: "منطقه زمانی" }]),
|
|
editFields: [
|
|
{ name: "name", label: "نام", required: true },
|
|
{ name: "status", label: "وضعیت", type: "select", options: lifecycleStatusOptions },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
diningAreas: {
|
|
title: "سالنها",
|
|
breadcrumb: "سالنها",
|
|
resourceKey: "diningAreas",
|
|
bundleFeature: null,
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.diningAreas,
|
|
columns: codeNameStatusColumns([
|
|
{ key: "venue_id", header: "مکان" },
|
|
{ key: "sort_order", header: "ترتیب", type: "text" },
|
|
]),
|
|
createFields: codeNameCreateFields([venueIdField(), { name: "sort_order", label: "ترتیب", type: "number" }]),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
tables: {
|
|
title: "میزها",
|
|
breadcrumb: "میزها",
|
|
resourceKey: "tables",
|
|
bundleFeature: null,
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.tables,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام" },
|
|
{ key: "capacity", header: "ظرفیت" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "dining_area_id", header: "سالن" },
|
|
{ key: "qr_token", header: "توکن QR", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: codeNameCreateFields([
|
|
venueIdField(),
|
|
{ name: "capacity", label: "ظرفیت", type: "number", required: true },
|
|
{ name: "dining_area_id", label: "شناسه سالن" },
|
|
{
|
|
name: "status",
|
|
label: "وضعیت",
|
|
type: "select",
|
|
options: tableStatusOptions,
|
|
},
|
|
]),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
posFloorPlans: {
|
|
title: "نقشه سالن",
|
|
breadcrumb: "نقشه سالن",
|
|
resourceKey: "posFloorPlans",
|
|
bundleFeature: "pos_pro",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.posFloorPlans,
|
|
columns: codeNameStatusColumns([
|
|
{ key: "venue_id", header: "مکان" },
|
|
{ key: "dining_area_id", header: "سالن" },
|
|
]),
|
|
createFields: codeNameCreateFields([
|
|
venueIdField(),
|
|
{ name: "dining_area_id", label: "شناسه سالن" },
|
|
]),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
reservations: {
|
|
title: "رزروها",
|
|
breadcrumb: "رزروها",
|
|
resourceKey: "reservations",
|
|
bundleFeature: "reservation",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.reservations,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "guest_name", header: "مهمان", searchable: true },
|
|
{ key: "guest_phone", header: "تلفن", defaultVisible: false },
|
|
{ key: "party_size", header: "تعداد نفر" },
|
|
{ key: "reserved_from", header: "از", type: "datetime" },
|
|
{ key: "reserved_to", header: "تا", type: "datetime" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "table_id", header: "میز", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "code", label: "کد", required: true },
|
|
{ name: "guest_name", label: "نام مهمان", required: true },
|
|
{ name: "guest_phone", label: "تلفن", type: "tel" },
|
|
{ name: "party_size", label: "تعداد نفر", type: "number", required: true },
|
|
{ name: "reserved_from", label: "شروع رزرو", type: "datetime-local", required: true },
|
|
{ name: "reserved_to", label: "پایان رزرو", type: "datetime-local", required: true },
|
|
{ name: "notes", label: "یادداشت", type: "textarea" },
|
|
],
|
|
rowActions: [
|
|
{
|
|
label: "تأیید",
|
|
onClick: async (tenantId, row) => {
|
|
await hospitalityApi.reservations.updateStatus(tenantId, String(row.id), { status: "confirmed" });
|
|
},
|
|
},
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
waitlist: {
|
|
title: "صف انتظار",
|
|
breadcrumb: "صف انتظار",
|
|
resourceKey: "waitlist",
|
|
bundleFeature: "table_service",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.waitlist,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "guest_name", header: "مهمان", searchable: true },
|
|
{ key: "party_size", header: "تعداد نفر" },
|
|
{ key: "phone", header: "تلفن" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "code", label: "کد", required: true },
|
|
{ name: "guest_name", label: "نام مهمان", required: true },
|
|
{ name: "party_size", label: "تعداد نفر", type: "number", required: true },
|
|
{ name: "phone", label: "تلفن", type: "tel" },
|
|
{ name: "notes", label: "یادداشت", type: "textarea" },
|
|
],
|
|
rowActions: [
|
|
{
|
|
label: "نشست",
|
|
onClick: async (tenantId, row) => {
|
|
await hospitalityApi.waitlist.updateStatus(tenantId, String(row.id), { status: "seated" });
|
|
},
|
|
},
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
menus: {
|
|
title: "منوی دیجیتال",
|
|
breadcrumb: "منوی دیجیتال",
|
|
resourceKey: "menus",
|
|
bundleFeature: "digital_menu",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.menus,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "currency_code", header: "ارز" },
|
|
{ key: "is_default", header: "پیشفرض", render: (r) => (r.is_default ? "بله" : "خیر") },
|
|
...auditColumns(),
|
|
],
|
|
createFields: codeNameCreateFields([
|
|
venueIdField(),
|
|
{ name: "currency_code", label: "ارز", required: true },
|
|
{ name: "is_default", label: "پیشفرض (true/false)" },
|
|
]),
|
|
editFields: [
|
|
{ name: "name", label: "نام", required: true },
|
|
{ name: "status", label: "وضعیت", type: "select", options: menuStatusOptions },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
menuCategories: {
|
|
title: "دستهبندی منو",
|
|
breadcrumb: "دستهبندی منو",
|
|
resourceKey: "menuCategories",
|
|
bundleFeature: "digital_menu",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.menuCategories,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام" },
|
|
{ key: "menu_id", header: "منو" },
|
|
{ key: "sort_order", header: "ترتیب" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
...auditColumns(),
|
|
],
|
|
createFields: codeNameCreateFields([
|
|
venueIdField(),
|
|
{ name: "menu_id", label: "شناسه منو", required: true },
|
|
{ name: "sort_order", label: "ترتیب", type: "number" },
|
|
]),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
menuItems: {
|
|
title: "آیتمهای منو",
|
|
breadcrumb: "آیتمهای منو",
|
|
resourceKey: "menuItems",
|
|
bundleFeature: "digital_menu",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.menuItems,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام", searchable: true },
|
|
{ key: "base_price", header: "قیمت پایه", type: "money" },
|
|
{ key: "is_available", header: "موجود", render: (r) => (r.is_available ? "بله" : "خیر") },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "menu_id", header: "منو", defaultVisible: false },
|
|
{ key: "category_id", header: "دسته", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: codeNameCreateFields([
|
|
venueIdField(),
|
|
{ name: "menu_id", label: "شناسه منو", required: true },
|
|
{ name: "category_id", label: "شناسه دسته" },
|
|
{ name: "base_price", label: "قیمت پایه", type: "number", required: true },
|
|
{ name: "is_available", label: "موجود (true/false)" },
|
|
]),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
modifierGroups: {
|
|
title: "گروه افزودنی",
|
|
breadcrumb: "گروه افزودنی",
|
|
resourceKey: "modifierGroups",
|
|
bundleFeature: "digital_menu",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.modifierGroups,
|
|
columns: codeNameStatusColumns([
|
|
{ key: "selection_mode", header: "حالت انتخاب" },
|
|
{ key: "min_select", header: "حداقل" },
|
|
{ key: "max_select", header: "حداکثر" },
|
|
{ key: "is_required", header: "اجباری", render: (r) => (r.is_required ? "بله" : "خیر") },
|
|
]),
|
|
createFields: codeNameCreateFields([
|
|
venueIdField(),
|
|
{ name: "selection_mode", label: "حالت انتخاب", required: true },
|
|
{ name: "min_select", label: "حداقل انتخاب", type: "number" },
|
|
{ name: "max_select", label: "حداکثر انتخاب", type: "number" },
|
|
{ name: "is_required", label: "اجباری (true/false)" },
|
|
]),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
modifierOptions: {
|
|
title: "گزینه افزودنی",
|
|
breadcrumb: "گزینه افزودنی",
|
|
resourceKey: "modifierOptions",
|
|
bundleFeature: "digital_menu",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.modifierOptions,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام" },
|
|
{ key: "modifier_group_id", header: "گروه" },
|
|
{ key: "price_delta", header: "تغییر قیمت", type: "money" },
|
|
{ key: "is_default", header: "پیشفرض", render: (r) => (r.is_default ? "بله" : "خیر") },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "modifier_group_id", label: "شناسه گروه", required: true },
|
|
{ name: "code", label: "کد", required: true },
|
|
{ name: "name", label: "نام", required: true },
|
|
{ name: "price_delta", label: "تغییر قیمت", type: "number" },
|
|
{ name: "currency_code", label: "ارز" },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
availabilityWindows: {
|
|
title: "قوانین دسترسی",
|
|
breadcrumb: "قوانین دسترسی",
|
|
resourceKey: "availabilityWindows",
|
|
bundleFeature: "digital_menu",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.availabilityWindows,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام" },
|
|
{ key: "scope", header: "دامنه" },
|
|
{ key: "target_id", header: "هدف" },
|
|
{ key: "weekday", header: "روز هفته" },
|
|
{ key: "start_time", header: "شروع" },
|
|
{ key: "end_time", header: "پایان" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
...auditColumns(),
|
|
],
|
|
createFields: codeNameCreateFields([
|
|
venueIdField(),
|
|
{ name: "scope", label: "دامنه", required: true },
|
|
{ name: "target_id", label: "شناسه هدف", required: true },
|
|
{ name: "weekday", label: "روز هفته (0-6)", type: "number" },
|
|
{ name: "start_time", label: "ساعت شروع", required: true },
|
|
{ name: "end_time", label: "ساعت پایان", required: true },
|
|
]),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
menuMediaRefs: {
|
|
title: "کتابخانه رسانه",
|
|
breadcrumb: "کتابخانه رسانه",
|
|
resourceKey: "menuMediaRefs",
|
|
bundleFeature: "digital_menu",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.menuMediaRefs,
|
|
columns: [
|
|
{ key: "kind", header: "نوع رسانه" },
|
|
{ key: "file_ref", header: "فایل" },
|
|
{ key: "alt_text", header: "متن جایگزین" },
|
|
{ key: "menu_id", header: "منو", defaultVisible: false },
|
|
{ key: "menu_item_id", header: "آیتم", defaultVisible: false },
|
|
{ key: "sort_order", header: "ترتیب" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "kind", label: "نوع رسانه", required: true },
|
|
{ name: "file_ref", label: "مرجع فایل", required: true },
|
|
{ name: "alt_text", label: "متن جایگزین" },
|
|
{ name: "menu_id", label: "شناسه منو" },
|
|
{ name: "menu_item_id", label: "شناسه آیتم" },
|
|
{ name: "sort_order", label: "ترتیب", type: "number" },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
qrCodes: {
|
|
title: "منوی QR",
|
|
breadcrumb: "منوی QR",
|
|
resourceKey: "qrCodes",
|
|
bundleFeature: "qr_menu",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.qrCodes,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام" },
|
|
{ key: "token", header: "توکن" },
|
|
{ key: "target_type", header: "نوع هدف" },
|
|
{ key: "ordering_enabled", header: "سفارش", render: (r) => (r.ordering_enabled ? "فعال" : "غیرفعال") },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
...auditColumns(),
|
|
],
|
|
createFields: codeNameCreateFields([
|
|
venueIdField(),
|
|
{ name: "target_type", label: "نوع هدف", required: true },
|
|
{ name: "menu_id", label: "شناسه منو" },
|
|
{ name: "table_id", label: "شناسه میز" },
|
|
{ name: "ordering_enabled", label: "سفارش فعال (true/false)" },
|
|
]),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
qrMenuSessions: {
|
|
title: "پروفایل مهمان",
|
|
breadcrumb: "پروفایل مهمان",
|
|
resourceKey: "qrMenuSessions",
|
|
bundleFeature: "qr_menu",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.qrMenuSessions,
|
|
columns: [
|
|
{ key: "session_token", header: "توکن نشست" },
|
|
{ key: "guest_label", header: "مهمان" },
|
|
{ key: "locale", header: "زبان" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "qr_code_id", header: "QR", defaultVisible: false },
|
|
{ key: "table_id", header: "میز", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "qr_code_id", label: "شناسه QR", required: true },
|
|
{ name: "guest_label", label: "برچسب مهمان" },
|
|
{ name: "locale", label: "زبان" },
|
|
{ name: "menu_id", label: "شناسه منو" },
|
|
{ name: "table_id", label: "شناسه میز" },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
qrOrderingSessions: {
|
|
title: "سفارش QR",
|
|
breadcrumb: "سفارش QR",
|
|
resourceKey: "qrOrderingSessions",
|
|
bundleFeature: "qr_ordering",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.qrOrderingSessions,
|
|
columns: [
|
|
{ key: "session_token", header: "توکن نشست" },
|
|
{ key: "guest_label", header: "مهمان" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "qr_code_id", header: "QR", defaultVisible: false },
|
|
{ key: "table_id", header: "میز" },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "qr_code_id", label: "شناسه QR", required: true },
|
|
{ name: "guest_label", label: "برچسب مهمان" },
|
|
{ name: "notes", label: "یادداشت", type: "textarea" },
|
|
],
|
|
rowActions: [
|
|
{
|
|
label: "ثبت سفارش",
|
|
onClick: async (tenantId, row) => {
|
|
await hospitalityApi.qrOrderingSessions.submit(tenantId, String(row.id));
|
|
},
|
|
},
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
carts: {
|
|
title: "سبد خرید",
|
|
breadcrumb: "سبد خرید",
|
|
resourceKey: "carts",
|
|
bundleFeature: "qr_ordering",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.carts,
|
|
columns: [
|
|
{ key: "ordering_session_id", header: "نشست سفارش" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "currency_code", header: "ارز" },
|
|
{ key: "notes", header: "یادداشت", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "ordering_session_id", label: "شناسه نشست سفارش", required: true },
|
|
{ name: "currency_code", label: "ارز" },
|
|
{ name: "notes", label: "یادداشت", type: "textarea" },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
cartLines: {
|
|
title: "تسویه",
|
|
breadcrumb: "تسویه",
|
|
resourceKey: "cartLines",
|
|
bundleFeature: "qr_ordering",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.cartLines,
|
|
columns: [
|
|
{ key: "cart_id", header: "سبد" },
|
|
{ key: "menu_item_id", header: "آیتم" },
|
|
{ key: "quantity", header: "تعداد" },
|
|
{ key: "unit_price", header: "قیمت واحد", type: "money" },
|
|
{ key: "line_notes", header: "یادداشت", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "cart_id", label: "شناسه سبد", required: true },
|
|
{ name: "menu_item_id", label: "شناسه آیتم", required: true },
|
|
{ name: "quantity", label: "تعداد", type: "number", required: true },
|
|
{ name: "line_notes", label: "یادداشت خط", type: "textarea" },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
kitchenTickets: {
|
|
title: "نمایشگر آشپزخانه",
|
|
breadcrumb: "نمایشگر آشپزخانه",
|
|
resourceKey: "kitchenTickets",
|
|
bundleFeature: "kitchen",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.kitchenTickets,
|
|
refreshIntervalMs: 5000,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "source_type", header: "منبع" },
|
|
{ key: "source_id", header: "شناسه منبع", defaultVisible: false },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "station_id", header: "ایستگاه", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "code", label: "کد", required: true },
|
|
{ name: "source_type", label: "نوع منبع", required: true },
|
|
{ name: "source_id", label: "شناسه منبع", required: true },
|
|
{ name: "station_id", label: "شناسه ایستگاه" },
|
|
{ name: "notes", label: "یادداشت", type: "textarea" },
|
|
],
|
|
rowActions: [
|
|
{
|
|
label: "آماده",
|
|
onClick: async (tenantId, row) => {
|
|
await hospitalityApi.kitchenTickets.updateStatus(tenantId, String(row.id), { status: "ready" });
|
|
},
|
|
},
|
|
{
|
|
label: "تکمیل",
|
|
onClick: async (tenantId, row) => {
|
|
await hospitalityApi.kitchenTickets.updateStatus(tenantId, String(row.id), { status: "bumped" });
|
|
},
|
|
},
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
kitchenTicketItems: {
|
|
title: "صف آشپزخانه",
|
|
breadcrumb: "صف آشپزخانه",
|
|
resourceKey: "kitchenTicketItems",
|
|
bundleFeature: "kitchen",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.kitchenTicketItems,
|
|
refreshIntervalMs: 5000,
|
|
columns: [
|
|
{ key: "kitchen_ticket_id", header: "تیکت" },
|
|
{ key: "menu_item_id", header: "آیتم" },
|
|
{ key: "quantity", header: "تعداد" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "sort_order", header: "ترتیب", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "kitchen_ticket_id", label: "شناسه تیکت", required: true },
|
|
{ name: "menu_item_id", label: "شناسه آیتم", required: true },
|
|
{ name: "quantity", label: "تعداد", type: "number", required: true },
|
|
],
|
|
rowActions: [
|
|
{
|
|
label: "آماده",
|
|
onClick: async (tenantId, row) => {
|
|
await hospitalityApi.kitchenTicketItems.updateStatus(tenantId, String(row.id), { status: "ready" });
|
|
},
|
|
},
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
kitchenTicketsPrep: {
|
|
title: "وضعیت آمادهسازی",
|
|
breadcrumb: "وضعیت آمادهسازی",
|
|
resourceKey: "kitchenTicketsPrep",
|
|
bundleFeature: "kitchen",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.kitchenTickets,
|
|
refreshIntervalMs: 5000,
|
|
listFilter: (row) => String(row.status) === "preparing",
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "source_type", header: "منبع" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "station_id", header: "ایستگاه" },
|
|
...auditColumns(),
|
|
],
|
|
rowActions: [
|
|
{
|
|
label: "آماده",
|
|
onClick: async (tenantId, row) => {
|
|
await hospitalityApi.kitchenTickets.updateStatus(tenantId, String(row.id), { status: "ready" });
|
|
},
|
|
},
|
|
],
|
|
readOnly: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
posTickets: {
|
|
title: "POS Lite",
|
|
breadcrumb: "POS Lite",
|
|
resourceKey: "posTickets",
|
|
bundleFeature: "pos_lite",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.posTickets,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "register_id", header: "صندوق" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "currency_code", header: "ارز" },
|
|
{ key: "table_id", header: "میز", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "code", label: "کد", required: true },
|
|
{ name: "register_id", label: "شناسه صندوق", required: true },
|
|
{ name: "currency_code", label: "ارز" },
|
|
{ name: "table_id", label: "شناسه میز" },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
posRegisters: {
|
|
title: "صندوق",
|
|
breadcrumb: "صندوق",
|
|
resourceKey: "posRegisters",
|
|
bundleFeature: "pos_lite",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.posRegisters,
|
|
columns: codeNameStatusColumns([{ key: "venue_id", header: "مکان" }]),
|
|
createFields: codeNameCreateFields([venueIdField()]),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
posPayments: {
|
|
title: "POS Pro",
|
|
breadcrumb: "POS Pro",
|
|
resourceKey: "posPayments",
|
|
bundleFeature: "pos_pro",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.posPayments,
|
|
columns: [
|
|
{ key: "ticket_id", header: "تیکت" },
|
|
{ key: "method", header: "روش پرداخت" },
|
|
{ key: "amount", header: "مبلغ", type: "money" },
|
|
{ key: "currency_code", header: "ارز" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "external_payment_ref", header: "ارجاع خارجی", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "ticket_id", label: "شناسه تیکت", required: true },
|
|
{
|
|
name: "method",
|
|
label: "روش پرداخت",
|
|
type: "select",
|
|
required: true,
|
|
options: posPaymentMethodOptions,
|
|
},
|
|
{ name: "amount", label: "مبلغ", type: "number", required: true },
|
|
{ name: "currency_code", label: "ارز" },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
posPaymentsList: {
|
|
title: "پرداختها",
|
|
breadcrumb: "پرداختها",
|
|
resourceKey: "posPaymentsList",
|
|
bundleFeature: "pos_pro",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.posPayments,
|
|
columns: [
|
|
{ key: "ticket_id", header: "تیکت" },
|
|
{ key: "method", header: "روش" },
|
|
{ key: "amount", header: "مبلغ", type: "money" },
|
|
{ key: "currency_code", header: "ارز" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "created_at", header: "زمان", type: "datetime" },
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "ticket_id", label: "شناسه تیکت", required: true },
|
|
{
|
|
name: "method",
|
|
label: "روش پرداخت",
|
|
type: "select",
|
|
required: true,
|
|
options: posPaymentMethodOptions,
|
|
},
|
|
{ name: "amount", label: "مبلغ", type: "number", required: true },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
posDiscounts: {
|
|
title: "تخفیفها",
|
|
breadcrumb: "تخفیفها",
|
|
resourceKey: "posDiscounts",
|
|
bundleFeature: "pos_pro",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.posDiscounts,
|
|
listFilter: (row) => !String(row.code ?? "").toUpperCase().startsWith("CPN"),
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام" },
|
|
{ key: "ticket_id", header: "تیکت" },
|
|
{ key: "kind", header: "نوع" },
|
|
{ key: "value", header: "مقدار" },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "ticket_id", label: "شناسه تیکت", required: true },
|
|
{ name: "code", label: "کد", required: true },
|
|
{
|
|
name: "kind",
|
|
label: "نوع",
|
|
type: "select",
|
|
required: true,
|
|
options: posDiscountKindOptions,
|
|
},
|
|
{ name: "value", label: "مقدار", type: "number", required: true },
|
|
{ name: "name", label: "نام" },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
posDiscountsCoupons: {
|
|
title: "کوپنها",
|
|
breadcrumb: "کوپنها",
|
|
resourceKey: "posDiscountsCoupons",
|
|
bundleFeature: "pos_pro",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.posDiscounts,
|
|
listFilter: (row) => String(row.code ?? "").toUpperCase().startsWith("CPN"),
|
|
columns: [
|
|
{ key: "code", header: "کد کوپن" },
|
|
{ key: "name", header: "نام" },
|
|
{ key: "kind", header: "نوع" },
|
|
{ key: "value", header: "مقدار" },
|
|
{ key: "ticket_id", header: "تیکت", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "ticket_id", label: "شناسه تیکت", required: true },
|
|
{ name: "code", label: "کد کوپن (CPN-…)", required: true },
|
|
{
|
|
name: "kind",
|
|
label: "نوع",
|
|
type: "select",
|
|
required: true,
|
|
options: posDiscountKindOptions,
|
|
},
|
|
{ name: "value", label: "مقدار", type: "number", required: true },
|
|
{ name: "name", label: "نام", required: true },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
featureTogglesPromo: {
|
|
title: "پروموشنها",
|
|
breadcrumb: "پروموشنها",
|
|
resourceKey: "featureTogglesPromo",
|
|
bundleFeature: "pos_pro",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.featureToggles,
|
|
useUpsert: true,
|
|
listFilter: (row) => String(row.feature_key ?? "").toLowerCase().includes("promo"),
|
|
columns: [
|
|
{ key: "feature_key", header: "کلید قابلیت" },
|
|
{ key: "enabled", header: "فعال", render: (r) => (r.enabled ? "بله" : "خیر") },
|
|
{ key: "bundle_key", header: "بسته", defaultVisible: false },
|
|
{ key: "venue_id", header: "مکان", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
{ name: "feature_key", label: "کلید قابلیت", required: true, placeholder: "hospitality.promo.*" },
|
|
{
|
|
name: "enabled",
|
|
label: "فعال",
|
|
type: "select",
|
|
required: true,
|
|
options: [
|
|
{ value: "true", label: "بله" },
|
|
{ value: "false", label: "خیر" },
|
|
],
|
|
},
|
|
venueIdField(false),
|
|
],
|
|
} satisfies HospitalityListConfig,
|
|
|
|
connectorRegistrationsCrm: {
|
|
title: "مشتریان",
|
|
breadcrumb: "مشتریان",
|
|
resourceKey: "connectorRegistrationsCrm",
|
|
bundleFeature: "crm_connector",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.connectorRegistrations,
|
|
listFilter: connectorKindFilter("crm"),
|
|
columns: connectorColumns,
|
|
createFields: connectorCreateFields("crm", "CRM"),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
connectorCrm: {
|
|
title: "CRM",
|
|
breadcrumb: "CRM",
|
|
resourceKey: "connectorCrm",
|
|
bundleFeature: "crm_connector",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.connectorRegistrations,
|
|
listFilter: connectorKindFilter("crm"),
|
|
columns: connectorColumns,
|
|
createFields: connectorCreateFields("crm", "CRM"),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
connectorLoyalty: {
|
|
title: "وفاداری",
|
|
breadcrumb: "وفاداری",
|
|
resourceKey: "connectorLoyalty",
|
|
bundleFeature: "loyalty_connector",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.connectorRegistrations,
|
|
listFilter: connectorKindFilter("loyalty"),
|
|
columns: connectorColumns,
|
|
createFields: connectorCreateFields("loyalty", "وفاداری"),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
connectorCommunication: {
|
|
title: "ارتباطات",
|
|
breadcrumb: "ارتباطات",
|
|
resourceKey: "connectorCommunication",
|
|
bundleFeature: "communication_connector",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.connectorRegistrations,
|
|
listFilter: connectorKindFilter("communication"),
|
|
columns: connectorColumns,
|
|
createFields: connectorCreateFields("communication", "ارتباطات"),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
connectorWebsite: {
|
|
title: "وبسایت",
|
|
breadcrumb: "وبسایت",
|
|
resourceKey: "connectorWebsite",
|
|
bundleFeature: "website_connector",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.connectorRegistrations,
|
|
listFilter: connectorKindFilter("website"),
|
|
columns: connectorColumns,
|
|
createFields: connectorCreateFields("website", "وبسایت"),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
connectorDelivery: {
|
|
title: "پیک",
|
|
breadcrumb: "پیک",
|
|
resourceKey: "connectorDelivery",
|
|
bundleFeature: "delivery_connector",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.connectorRegistrations,
|
|
listFilter: connectorKindFilter("delivery"),
|
|
columns: connectorColumns,
|
|
createFields: connectorCreateFields("delivery", "پیک"),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
connectorAccounting: {
|
|
title: "حسابداری",
|
|
breadcrumb: "حسابداری",
|
|
resourceKey: "connectorAccounting",
|
|
bundleFeature: "accounting_connector",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.connectorRegistrations,
|
|
listFilter: connectorKindFilter("accounting"),
|
|
columns: connectorColumns,
|
|
createFields: connectorCreateFields("accounting", "حسابداری"),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
connectorDispatches: {
|
|
title: "ارسال کانکتور",
|
|
breadcrumb: "ارسال کانکتور",
|
|
resourceKey: "connectorDispatches",
|
|
bundleFeature: null,
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.connectorDispatches,
|
|
columns: [
|
|
{ key: "event_type", header: "نوع رویداد" },
|
|
{ key: "direction", header: "جهت" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "registration_id", header: "ثبتنام" },
|
|
{ key: "payload_ref", header: "Payload", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(false),
|
|
{ name: "registration_id", label: "شناسه ثبتنام", required: true },
|
|
{ name: "event_type", label: "نوع رویداد", required: true },
|
|
{ name: "direction", label: "جهت", required: true },
|
|
{ name: "payload_ref", label: "مرجع Payload" },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
pickupOrders: {
|
|
title: "سفارش بیرونبر",
|
|
breadcrumb: "سفارش بیرونبر",
|
|
resourceKey: "pickupOrders",
|
|
bundleFeature: "qr_ordering",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.qrOrderingSessions,
|
|
listFilter: (row) => row.table_id == null,
|
|
columns: [
|
|
{ key: "session_token", header: "توکن" },
|
|
{ key: "guest_label", header: "مهمان" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "notes", header: "یادداشت", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
readOnly: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
onlineOrders: {
|
|
title: "سفارش آنلاین",
|
|
breadcrumb: "سفارش آنلاین",
|
|
resourceKey: "onlineOrders",
|
|
bundleFeature: "qr_ordering",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.qrOrderingSessions,
|
|
listFilter: (row) => row.table_id != null,
|
|
columns: [
|
|
{ key: "session_token", header: "توکن" },
|
|
{ key: "guest_label", header: "مهمان" },
|
|
{ key: "table_id", header: "میز" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
...auditColumns(),
|
|
],
|
|
readOnly: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
orderTimeline: {
|
|
title: "خط زمانی سفارش",
|
|
breadcrumb: "خط زمانی سفارش",
|
|
resourceKey: "orderTimeline",
|
|
bundleFeature: "kitchen",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.kitchenTickets,
|
|
refreshIntervalMs: 10000,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "source_type", header: "منبع" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "created_at", header: "ایجاد", type: "datetime" },
|
|
{ key: "updated_at", header: "بهروزرسانی", type: "datetime" },
|
|
],
|
|
readOnly: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
invoices: {
|
|
title: "فاکتورها",
|
|
breadcrumb: "فاکتورها",
|
|
resourceKey: "invoices",
|
|
bundleFeature: "pos_lite",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.posTickets,
|
|
listFilter: (row) => !["void", "cancelled"].includes(String(row.status)),
|
|
columns: [
|
|
{ key: "code", header: "کد فاکتور" },
|
|
{ key: "register_id", header: "صندوق" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "currency_code", header: "ارز" },
|
|
{ key: "created_at", header: "تاریخ", type: "datetime" },
|
|
],
|
|
readOnly: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
receipts: {
|
|
title: "رسیدها",
|
|
breadcrumb: "رسیدها",
|
|
resourceKey: "receipts",
|
|
bundleFeature: "pos_lite",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.posTickets,
|
|
listFilter: (row) => String(row.status) === "paid",
|
|
columns: [
|
|
{ key: "code", header: "کد رسید" },
|
|
{ key: "register_id", header: "صندوق" },
|
|
{ key: "currency_code", header: "ارز" },
|
|
{ key: "created_at", header: "تاریخ پرداخت", type: "datetime" },
|
|
],
|
|
readOnly: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
analyticsReports: {
|
|
title: "گزارشها",
|
|
breadcrumb: "گزارشها",
|
|
resourceKey: "analyticsReports",
|
|
bundleFeature: "analytics",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.analyticsReports,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام" },
|
|
{
|
|
key: "metric_keys",
|
|
header: "متریکها",
|
|
render: (r) => (Array.isArray(r.metric_keys) ? (r.metric_keys as string[]).join(", ") : "—"),
|
|
},
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
...auditColumns(),
|
|
],
|
|
createFields: codeNameCreateFields([
|
|
venueIdField(false),
|
|
{ name: "metric_keys", label: "متریکها (جدا با کاما)", required: true },
|
|
]),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
analyticsSnapshots: {
|
|
title: "آنالیتیکس",
|
|
breadcrumb: "آنالیتیکس",
|
|
resourceKey: "analyticsSnapshots",
|
|
bundleFeature: "analytics",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.analyticsSnapshots,
|
|
columns: [
|
|
{ key: "report_id", header: "گزارش" },
|
|
{ key: "period_start", header: "شروع دوره" },
|
|
{ key: "period_end", header: "پایان دوره" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{
|
|
key: "metrics",
|
|
header: "متریکها",
|
|
render: (r) =>
|
|
r.metrics && typeof r.metrics === "object"
|
|
? String(Object.keys(r.metrics as object).length)
|
|
: "0",
|
|
},
|
|
...auditColumns(),
|
|
],
|
|
readOnly: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
inventoryOverview: {
|
|
title: "موجودی",
|
|
breadcrumb: "موجودی",
|
|
resourceKey: "inventoryOverview",
|
|
bundleFeature: "analytics",
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.analyticsSnapshots,
|
|
listFilter: (row) => {
|
|
const metrics = row.metrics as Record<string, unknown> | null | undefined;
|
|
if (!metrics) return false;
|
|
return Object.keys(metrics).some((k) => k.toLowerCase().includes("inventory") || k.toLowerCase().includes("stock"));
|
|
},
|
|
columns: [
|
|
{ key: "period_start", header: "شروع" },
|
|
{ key: "period_end", header: "پایان" },
|
|
{
|
|
key: "metrics",
|
|
header: "موجودی",
|
|
render: (r) => {
|
|
const metrics = r.metrics as Record<string, unknown> | undefined;
|
|
if (!metrics) return "—";
|
|
const inv = Object.entries(metrics).find(([k]) =>
|
|
k.toLowerCase().includes("inventory") || k.toLowerCase().includes("stock")
|
|
);
|
|
return inv ? String(inv[1]) : "—";
|
|
},
|
|
},
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
],
|
|
readOnly: true,
|
|
emptyHint:
|
|
"موجودی از متریکهای analytics snapshot مشتق میشود (COUNT محلی). موتور انبار جداگانه نیست — اگر متریک inventory در snapshot نیست، لیست خالی است.",
|
|
} satisfies HospitalityListConfig,
|
|
|
|
settings: {
|
|
title: "تنظیمات",
|
|
breadcrumb: "تنظیمات",
|
|
resourceKey: "settings",
|
|
bundleFeature: null,
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.settings,
|
|
useUpsert: true,
|
|
columns: [
|
|
{ key: "key", header: "کلید", searchable: true },
|
|
{
|
|
key: "value",
|
|
header: "مقدار",
|
|
render: (r) => (r.value != null ? JSON.stringify(r.value) : "—"),
|
|
},
|
|
{ key: "venue_id", header: "مکان", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
{ name: "key", label: "کلید", required: true },
|
|
{ name: "value", label: "مقدار (JSON)", type: "textarea", placeholder: '{"enabled": true}' },
|
|
venueIdField(false),
|
|
],
|
|
} satisfies HospitalityListConfig,
|
|
|
|
permissions: {
|
|
title: "مجوزها",
|
|
breadcrumb: "مجوزها",
|
|
resourceKey: "permissions",
|
|
bundleFeature: null,
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.permissions,
|
|
columns: [
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام" },
|
|
{ key: "bundle_key", header: "بسته", defaultVisible: false },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
{ name: "code", label: "کد", required: true },
|
|
{ name: "name", label: "نام", required: true },
|
|
{ name: "description", label: "توضیح", type: "textarea" },
|
|
{ name: "bundle_key", label: "کلید بسته" },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
roles: {
|
|
title: "نقشها",
|
|
breadcrumb: "نقشها",
|
|
resourceKey: "roles",
|
|
bundleFeature: null,
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.roles,
|
|
columns: codeNameStatusColumns([
|
|
{ key: "venue_id", header: "مکان", defaultVisible: false },
|
|
{
|
|
key: "permission_keys",
|
|
header: "مجوزها",
|
|
render: (r) => (Array.isArray(r.permission_keys) ? (r.permission_keys as string[]).join(", ") : "—"),
|
|
defaultVisible: false,
|
|
},
|
|
]),
|
|
createFields: codeNameCreateFields([
|
|
venueIdField(false),
|
|
{ name: "description", label: "توضیح", type: "textarea" },
|
|
{ name: "permission_keys", label: "مجوزها (جدا با کاما)" },
|
|
]),
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
events: {
|
|
title: "لاگ ممیزی",
|
|
breadcrumb: "لاگ ممیزی",
|
|
resourceKey: "events",
|
|
bundleFeature: null,
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.events,
|
|
columns: [
|
|
{ key: "event_type", header: "نوع رویداد", searchable: true },
|
|
{ key: "title", header: "عنوان", searchable: true },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "venue_id", header: "مکان", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
createFields: [
|
|
venueIdField(),
|
|
{ name: "event_type", label: "نوع رویداد", required: true },
|
|
{ name: "title", label: "عنوان", required: true },
|
|
{ name: "payload", label: "Payload (JSON)", type: "textarea" },
|
|
],
|
|
filterDeleted: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
notifications: {
|
|
title: "اعلانها",
|
|
breadcrumb: "اعلانها",
|
|
resourceKey: "notifications",
|
|
bundleFeature: null,
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.events,
|
|
listFilter: (row) => {
|
|
const t = String(row.event_type ?? "");
|
|
return (
|
|
t.includes("status_changed") ||
|
|
t.includes("submitted") ||
|
|
t.includes("payment") ||
|
|
t.includes("waitlist")
|
|
);
|
|
},
|
|
columns: [
|
|
{ key: "event_type", header: "نوع" },
|
|
{ key: "title", header: "اعلان" },
|
|
{ key: "created_at", header: "زمان", type: "datetime" },
|
|
{ key: "status", header: "وضعیت", type: "status", defaultVisible: false },
|
|
],
|
|
readOnly: true,
|
|
} satisfies HospitalityListConfig,
|
|
|
|
tenantBundles: {
|
|
title: "بستههای فعال",
|
|
breadcrumb: "بستههای فعال",
|
|
resourceKey: "tenantBundles",
|
|
bundleFeature: null,
|
|
permission: "hospitality.view",
|
|
api: hospitalityApi.tenantBundles,
|
|
readOnly: true,
|
|
columns: [
|
|
{ key: "bundle_key", header: "بسته" },
|
|
{ key: "status", header: "وضعیت", type: "status" },
|
|
{ key: "venue_id", header: "مکان", defaultVisible: false },
|
|
{ key: "activated_by", header: "فعالساز", defaultVisible: false },
|
|
{ key: "bundle_definition_id", header: "تعریف بسته", defaultVisible: false },
|
|
...auditColumns(),
|
|
],
|
|
rowActions: [
|
|
{
|
|
label: "غیرفعال",
|
|
variant: "danger",
|
|
onClick: async (tenantId, row) => {
|
|
await hospitalityApi.tenantBundles.deactivate(tenantId, String(row.id));
|
|
},
|
|
},
|
|
],
|
|
} satisfies HospitalityListConfig,
|
|
} as const satisfies Record<string, HospitalityListConfig>;
|