TorbatYar/frontend/modules/hospitality/constants/resourceRegistry.ts
2026-07-28 20:39:10 +03:30

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>;