feat(api): .NET 10 multi-tenant REST API
Full backend implementation: - Multi-tenant cafe/restaurant management (menus, orders, tables, staff) - POS order flow with ZarinPal and Snappfood payment integration - OTP authentication via Kavenegar SMS - QR digital menu with public discover/finder endpoints - Customer loyalty, coupons, CRM - PostgreSQL via EF Core, Redis for caching/sessions - Background jobs, webhook handlers - Full migration history Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
namespace Meezi.API.Models.Auth;
|
||||
|
||||
public record SendOtpRequest(string Phone);
|
||||
|
||||
public record VerifyOtpRequest(string Phone, string Code, string? CafeId = null);
|
||||
|
||||
public record RefreshTokenRequest(string RefreshToken);
|
||||
|
||||
public record AuthTokenResponse(
|
||||
string AccessToken,
|
||||
string RefreshToken,
|
||||
DateTime ExpiresAt,
|
||||
string UserId,
|
||||
string CafeId,
|
||||
string Role,
|
||||
string PlanTier,
|
||||
string Language,
|
||||
string Actor = Meezi.Core.Constants.MeeziActorKinds.Merchant,
|
||||
string? BranchId = null);
|
||||
|
||||
public record SendOtpResponse(bool Sent, int ExpiresInSeconds);
|
||||
@@ -0,0 +1,27 @@
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
namespace Meezi.API.Models.Billing;
|
||||
|
||||
public record SubscribeRequest(PlanTier PlanTier, int Months, string? PaymentMethod = null);
|
||||
|
||||
public record PaymentMethodDto(string Id, string DisplayNameFa, bool IsDefault);
|
||||
|
||||
public record SubscribeResponse(string PaymentId, string PaymentUrl);
|
||||
|
||||
public record BillingStatusDto(
|
||||
PlanTier PlanTier,
|
||||
DateTime? PlanExpiresAt,
|
||||
int OrdersToday,
|
||||
int? OrdersDailyLimit,
|
||||
int CustomersCount,
|
||||
int? CustomersLimit,
|
||||
int SmsUsedThisMonth,
|
||||
int SmsMonthlyLimit,
|
||||
bool Menu3dEnabled,
|
||||
bool MenuAi3dEnabled,
|
||||
int MenuAi3dUsedThisMonth,
|
||||
int MenuAi3dMonthlyLimit,
|
||||
bool DiscoverProfileEnabled,
|
||||
bool IsPlanExpired);
|
||||
|
||||
public record BillingVerifyResult(bool Success, string RedirectUrl);
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace Meezi.API.Models.Branches;
|
||||
|
||||
public record BranchDto(
|
||||
string Id,
|
||||
string Name,
|
||||
string? Address,
|
||||
string? City,
|
||||
string? Phone,
|
||||
bool IsActive,
|
||||
string? LoginPhone = null,
|
||||
string? ManagerName = null,
|
||||
bool IsPendingDeletion = false,
|
||||
DateTime? DeletedAt = null,
|
||||
DateTime? ScheduledPermanentDeleteAt = null,
|
||||
int? DaysUntilPermanentDelete = null);
|
||||
|
||||
public record CreateBranchRequest(
|
||||
string Name,
|
||||
string LoginPhone,
|
||||
string? ManagerName,
|
||||
string? Address,
|
||||
string? City,
|
||||
string? Phone);
|
||||
|
||||
public record PatchBranchRequest(
|
||||
string? Name,
|
||||
string? Address,
|
||||
string? City,
|
||||
string? Phone,
|
||||
bool? IsActive,
|
||||
string? LogoUrl,
|
||||
string? WelcomeText,
|
||||
string? AccentColor,
|
||||
string? WifiPassword,
|
||||
decimal? TaxRate);
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace Meezi.API.Models.Cafes;
|
||||
|
||||
public record CafeSettingsDto(
|
||||
string Id,
|
||||
string Name,
|
||||
string Slug,
|
||||
string? Phone,
|
||||
string? Address,
|
||||
string? City,
|
||||
string? Description,
|
||||
string? LogoUrl,
|
||||
string? CoverImageUrl,
|
||||
string? SnappfoodVendorId,
|
||||
string PlanTier,
|
||||
DateTime? PlanExpiresAt,
|
||||
CafeThemeDto Theme,
|
||||
decimal DefaultTaxRate,
|
||||
bool AllowBranchTaxOverride);
|
||||
|
||||
public record PatchCafeSettingsRequest(
|
||||
string? Name,
|
||||
string? Phone,
|
||||
string? Address,
|
||||
string? City,
|
||||
string? Description,
|
||||
string? LogoUrl,
|
||||
string? CoverImageUrl,
|
||||
string? SnappfoodVendorId,
|
||||
CafeThemeDto? Theme,
|
||||
decimal? DefaultTaxRate,
|
||||
bool? AllowBranchTaxOverride);
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace Meezi.API.Models.Cafes;
|
||||
|
||||
public record CafeThemeCustomColorsDto(
|
||||
string? Primary,
|
||||
string? Secondary,
|
||||
string? Accent,
|
||||
string? Background,
|
||||
string? Surface,
|
||||
string? Text,
|
||||
string? TextMuted,
|
||||
string? Destructive,
|
||||
string? Success,
|
||||
int? PrimaryOpacity = null,
|
||||
int? SecondaryOpacity = null,
|
||||
int? AccentOpacity = null,
|
||||
int? BackgroundOpacity = null,
|
||||
int? SurfaceOpacity = null,
|
||||
int? TextOpacity = null,
|
||||
int? TextMutedOpacity = null,
|
||||
int? DestructiveOpacity = null,
|
||||
int? SuccessOpacity = null);
|
||||
|
||||
public record CafeThemeDto(
|
||||
string PaletteId,
|
||||
string PanelStyle,
|
||||
string MenuStyle,
|
||||
string MenuTexture,
|
||||
string Density,
|
||||
string Radius,
|
||||
CafeThemeCustomColorsDto? Custom);
|
||||
@@ -0,0 +1,23 @@
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
namespace Meezi.API.Models.Consumer;
|
||||
|
||||
public record ConsumerAuthTokenResponse(
|
||||
string AccessToken,
|
||||
string RefreshToken,
|
||||
DateTime ExpiresAt,
|
||||
string UserId,
|
||||
string Phone,
|
||||
string Language);
|
||||
|
||||
public record ConsumerOrderHistoryDto(
|
||||
string Id,
|
||||
string CafeId,
|
||||
string CafeName,
|
||||
string CafeSlug,
|
||||
OrderStatus Status,
|
||||
decimal Total,
|
||||
int DisplayNumber,
|
||||
DateTime CreatedAt,
|
||||
string? TableNumber,
|
||||
int ItemCount);
|
||||
@@ -0,0 +1,50 @@
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
namespace Meezi.API.Models.Crm;
|
||||
|
||||
public record CouponDto(
|
||||
string Id,
|
||||
string Code,
|
||||
CouponType Type,
|
||||
decimal Value,
|
||||
decimal? MinOrderAmount,
|
||||
decimal? MaxDiscount,
|
||||
int? UsageLimit,
|
||||
int UsedCount,
|
||||
CustomerGroup? TargetGroup,
|
||||
DateTime? StartsAt,
|
||||
DateTime? ExpiresAt,
|
||||
bool IsActive);
|
||||
|
||||
public record CreateCouponRequest(
|
||||
string Code,
|
||||
CouponType Type,
|
||||
decimal Value,
|
||||
decimal? MinOrderAmount,
|
||||
decimal? MaxDiscount,
|
||||
int? UsageLimit,
|
||||
CustomerGroup? TargetGroup,
|
||||
DateTime? StartsAt,
|
||||
DateTime? ExpiresAt,
|
||||
bool IsActive = true);
|
||||
|
||||
public record ValidateCouponRequest(string Code, decimal Subtotal);
|
||||
|
||||
public record ValidateCouponResult(
|
||||
string CouponId,
|
||||
string Code,
|
||||
CouponType Type,
|
||||
decimal Value,
|
||||
decimal DiscountAmount);
|
||||
|
||||
public record UpdateCouponRequest(
|
||||
string? Code,
|
||||
CouponType? Type,
|
||||
decimal? Value,
|
||||
decimal? MinOrderAmount,
|
||||
decimal? MaxDiscount,
|
||||
int? UsageLimit,
|
||||
CustomerGroup? TargetGroup,
|
||||
DateTime? StartsAt,
|
||||
DateTime? ExpiresAt,
|
||||
bool? IsActive);
|
||||
@@ -0,0 +1,31 @@
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
namespace Meezi.API.Models.Crm;
|
||||
|
||||
public record CustomerDto(
|
||||
string Id,
|
||||
string Name,
|
||||
string Phone,
|
||||
string? NationalId,
|
||||
string? BirthDateJalali,
|
||||
CustomerGroup Group,
|
||||
int LoyaltyPoints,
|
||||
string? ReferredBy,
|
||||
DateTime CreatedAt);
|
||||
|
||||
public record CreateCustomerRequest(
|
||||
string Name,
|
||||
string Phone,
|
||||
string? NationalId,
|
||||
string? BirthDateJalali,
|
||||
CustomerGroup Group = CustomerGroup.Regular,
|
||||
string? ReferredBy = null);
|
||||
|
||||
public record UpdateCustomerRequest(
|
||||
string? Name,
|
||||
string? Phone,
|
||||
string? NationalId,
|
||||
string? BirthDateJalali,
|
||||
CustomerGroup? Group,
|
||||
int? LoyaltyPoints,
|
||||
string? ReferredBy);
|
||||
@@ -0,0 +1,12 @@
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
namespace Meezi.API.Models.Crm;
|
||||
|
||||
public record SendSmsCampaignRequest(
|
||||
string Message,
|
||||
CustomerGroup? TargetGroup,
|
||||
IReadOnlyList<string>? Phones);
|
||||
|
||||
public record SmsCampaignResult(int SentCount, int FailedCount);
|
||||
|
||||
public record SmsUsageDto(int UsedThisMonth, int MonthlyLimit, string Month);
|
||||
@@ -0,0 +1,20 @@
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
namespace Meezi.API.Models.Delivery;
|
||||
|
||||
public record PlatformRevenueDto(
|
||||
DeliveryPlatform Platform,
|
||||
string PlatformName,
|
||||
int OrderCount,
|
||||
decimal GrossRevenue,
|
||||
decimal Commission,
|
||||
decimal NetRevenue);
|
||||
|
||||
public record DeliveryRevenueReportDto(
|
||||
string PeriodLabel,
|
||||
DateTime UtcFrom,
|
||||
DateTime UtcTo,
|
||||
IReadOnlyList<PlatformRevenueDto> Platforms,
|
||||
decimal TotalGross,
|
||||
decimal TotalCommission,
|
||||
decimal TotalNet);
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace Meezi.API.Models.Discover;
|
||||
|
||||
public record CafeDiscoverProfileDto(
|
||||
IReadOnlyList<string> Themes,
|
||||
string? Size,
|
||||
string? Floors,
|
||||
IReadOnlyList<string> Vibes,
|
||||
IReadOnlyList<string> Occasions,
|
||||
IReadOnlyList<string> SpaceFeatures,
|
||||
string? NoiseLevel,
|
||||
string? PriceTier);
|
||||
|
||||
public record UpsertCafeDiscoverProfileRequest(
|
||||
IReadOnlyList<string>? Themes,
|
||||
string? Size,
|
||||
string? Floors,
|
||||
IReadOnlyList<string>? Vibes,
|
||||
IReadOnlyList<string>? Occasions,
|
||||
IReadOnlyList<string>? SpaceFeatures,
|
||||
string? NoiseLevel,
|
||||
string? PriceTier);
|
||||
|
||||
public record DiscoverProfileTaxonomyDto(
|
||||
IReadOnlyList<string> Themes,
|
||||
IReadOnlyList<string> Sizes,
|
||||
IReadOnlyList<string> Floors,
|
||||
IReadOnlyList<string> Vibes,
|
||||
IReadOnlyList<string> Occasions,
|
||||
IReadOnlyList<string> SpaceFeatures,
|
||||
IReadOnlyList<string> NoiseLevels,
|
||||
IReadOnlyList<string> PriceTiers);
|
||||
@@ -0,0 +1,25 @@
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
namespace Meezi.API.Models.Expenses;
|
||||
|
||||
public record CreateExpenseRequest(
|
||||
string BranchId,
|
||||
string? ShiftId,
|
||||
ExpenseCategory Category,
|
||||
decimal Amount,
|
||||
string? Note,
|
||||
string? ReceiptImageUrl);
|
||||
|
||||
public record ExpenseDto(
|
||||
string Id,
|
||||
string CafeId,
|
||||
string BranchId,
|
||||
string? ShiftId,
|
||||
ExpenseCategory Category,
|
||||
decimal Amount,
|
||||
string? Note,
|
||||
string? ReceiptImageUrl,
|
||||
string CreatedByUserId,
|
||||
DateTime CreatedAt);
|
||||
|
||||
public record ExpenseListResult(IReadOnlyList<ExpenseDto> Items, int Total);
|
||||
@@ -0,0 +1,61 @@
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
namespace Meezi.API.Models.Hr;
|
||||
|
||||
public record EmployeeSummaryDto(
|
||||
string Id,
|
||||
string Name,
|
||||
string Phone,
|
||||
EmployeeRole Role,
|
||||
decimal BaseSalary);
|
||||
|
||||
public record AttendanceDto(
|
||||
string Id,
|
||||
string EmployeeId,
|
||||
string EmployeeName,
|
||||
DateOnly Date,
|
||||
DateTime? ClockIn,
|
||||
DateTime? ClockOut,
|
||||
string? Notes);
|
||||
|
||||
public record ShiftDto(int DayOfWeek, ShiftType ShiftType);
|
||||
|
||||
public record UpsertShiftsRequest(IReadOnlyList<ShiftDto> Shifts);
|
||||
|
||||
public record LeaveRequestDto(
|
||||
string Id,
|
||||
string EmployeeId,
|
||||
string EmployeeName,
|
||||
DateOnly StartDate,
|
||||
DateOnly EndDate,
|
||||
string? Reason,
|
||||
LeaveStatus Status,
|
||||
string? ReviewedBy,
|
||||
DateTime CreatedAt);
|
||||
|
||||
public record CreateLeaveRequest(
|
||||
DateOnly StartDate,
|
||||
DateOnly EndDate,
|
||||
string? Reason);
|
||||
|
||||
public record ReviewLeaveRequest(LeaveStatus Status);
|
||||
|
||||
public record EmployeeSalaryDto(
|
||||
string Id,
|
||||
string EmployeeId,
|
||||
string EmployeeName,
|
||||
string MonthYear,
|
||||
decimal BaseSalary,
|
||||
decimal OvertimePay,
|
||||
decimal Deductions,
|
||||
decimal NetSalary,
|
||||
bool IsPaid);
|
||||
|
||||
public record CreateSalaryRequest(
|
||||
string EmployeeId,
|
||||
string MonthYear,
|
||||
decimal BaseSalary,
|
||||
decimal OvertimePay,
|
||||
decimal Deductions);
|
||||
|
||||
public record TodayShiftDto(ShiftType ShiftType, string Label);
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Meezi.API.Models.Kitchen;
|
||||
|
||||
public record KitchenStationDto(
|
||||
string Id,
|
||||
string? BranchId,
|
||||
string Name,
|
||||
string? PrinterIp,
|
||||
int PrinterPort,
|
||||
int SortOrder,
|
||||
int CategoryCount);
|
||||
|
||||
public record CreateKitchenStationRequest(
|
||||
string Name,
|
||||
string? BranchId,
|
||||
string? PrinterIp,
|
||||
int PrinterPort = 9100,
|
||||
int SortOrder = 0);
|
||||
|
||||
public record UpdateKitchenStationRequest(
|
||||
string? Name,
|
||||
string? BranchId,
|
||||
string? PrinterIp,
|
||||
int? PrinterPort,
|
||||
int? SortOrder);
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace Meezi.API.Models.Menu;
|
||||
|
||||
public record BranchMenuItemDto(
|
||||
string Id,
|
||||
string CategoryId,
|
||||
string Name,
|
||||
string? NameAr,
|
||||
string? NameEn,
|
||||
string? Description,
|
||||
decimal MasterPrice,
|
||||
decimal EffectivePrice,
|
||||
decimal DiscountPercent,
|
||||
string? ImageUrl,
|
||||
string? VideoUrl,
|
||||
string? Model3dUrl,
|
||||
bool IsAvailable,
|
||||
bool IsOverridden,
|
||||
bool HasPriceOverride);
|
||||
|
||||
public record UpsertBranchMenuOverrideRequest(
|
||||
bool IsAvailable,
|
||||
decimal? PriceOverride);
|
||||
|
||||
public record BranchMenuOverrideDto(
|
||||
string MenuItemId,
|
||||
string BranchId,
|
||||
bool IsAvailable,
|
||||
decimal? PriceOverride,
|
||||
DateTime UpdatedAt);
|
||||
@@ -0,0 +1,86 @@
|
||||
namespace Meezi.API.Models.Menu;
|
||||
|
||||
public record MenuCategoryDto(
|
||||
string Id,
|
||||
string Name,
|
||||
string? NameAr,
|
||||
string? NameEn,
|
||||
int SortOrder,
|
||||
string? TaxId,
|
||||
decimal DiscountPercent,
|
||||
string? Icon,
|
||||
string? IconPresetId,
|
||||
string? IconStyle,
|
||||
string? ImageUrl,
|
||||
bool IsActive,
|
||||
string? KitchenStationId);
|
||||
|
||||
public record CreateMenuCategoryRequest(
|
||||
string Name,
|
||||
string? NameAr,
|
||||
string? NameEn,
|
||||
int SortOrder,
|
||||
string? TaxId,
|
||||
decimal DiscountPercent,
|
||||
string? Icon = null,
|
||||
string? IconPresetId = null,
|
||||
string? IconStyle = null,
|
||||
string? ImageUrl = null,
|
||||
bool IsActive = true,
|
||||
string? KitchenStationId = null);
|
||||
|
||||
public record UpdateMenuCategoryRequest(
|
||||
string? Name,
|
||||
string? NameAr,
|
||||
string? NameEn,
|
||||
int? SortOrder,
|
||||
string? TaxId,
|
||||
decimal? DiscountPercent,
|
||||
string? Icon,
|
||||
string? IconPresetId,
|
||||
string? IconStyle,
|
||||
string? ImageUrl,
|
||||
bool? IsActive,
|
||||
string? KitchenStationId);
|
||||
|
||||
public record MenuItemDto(
|
||||
string Id,
|
||||
string CategoryId,
|
||||
string Name,
|
||||
string? NameAr,
|
||||
string? NameEn,
|
||||
string? Description,
|
||||
decimal Price,
|
||||
decimal DiscountPercent,
|
||||
string? ImageUrl,
|
||||
string? VideoUrl,
|
||||
string? Model3dUrl,
|
||||
bool IsAvailable);
|
||||
|
||||
public record CreateMenuItemRequest(
|
||||
string CategoryId,
|
||||
string Name,
|
||||
string? NameAr,
|
||||
string? NameEn,
|
||||
string? Description,
|
||||
decimal Price,
|
||||
decimal DiscountPercent = 0,
|
||||
string? ImageUrl = null,
|
||||
string? VideoUrl = null,
|
||||
string? Model3dUrl = null,
|
||||
bool IsAvailable = true);
|
||||
|
||||
public record UpdateMenuItemRequest(
|
||||
string? CategoryId,
|
||||
string? Name,
|
||||
string? NameAr,
|
||||
string? NameEn,
|
||||
string? Description,
|
||||
decimal? Price,
|
||||
decimal? DiscountPercent,
|
||||
string? ImageUrl,
|
||||
string? VideoUrl,
|
||||
string? Model3dUrl,
|
||||
bool? IsAvailable);
|
||||
|
||||
public record UpdateMenuItemAvailabilityRequest(bool IsAvailable);
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace Meezi.API.Models.Notifications;
|
||||
|
||||
public record CafeNotificationDto(
|
||||
string Id,
|
||||
string Type,
|
||||
string Title,
|
||||
string? Body,
|
||||
string? ReferenceId,
|
||||
string? TableNumber,
|
||||
bool IsRead,
|
||||
DateTime CreatedAt);
|
||||
|
||||
public record NotificationListDto(
|
||||
IReadOnlyList<CafeNotificationDto> Items,
|
||||
int UnreadCount);
|
||||
|
||||
public record MarkNotificationsReadRequest(
|
||||
IReadOnlyList<string>? Ids,
|
||||
bool All = false);
|
||||
@@ -0,0 +1,81 @@
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
namespace Meezi.API.Models.Orders;
|
||||
|
||||
public record OrderItemDto(
|
||||
string Id,
|
||||
string MenuItemId,
|
||||
string MenuItemName,
|
||||
int Quantity,
|
||||
decimal UnitPrice,
|
||||
string? Notes,
|
||||
bool IsVoided = false,
|
||||
DateTime? VoidedAt = null);
|
||||
|
||||
public record TransferTableRequest(string TargetTableId);
|
||||
|
||||
public record OrderDto(
|
||||
string Id,
|
||||
string CafeId,
|
||||
string? BranchId,
|
||||
string? TableId,
|
||||
string? TableNumber,
|
||||
string? GuestName,
|
||||
string? GuestPhone,
|
||||
string? CustomerName,
|
||||
string? CustomerPhone,
|
||||
string? CustomerId,
|
||||
string? EmployeeId,
|
||||
OrderType OrderType,
|
||||
OrderSource Source,
|
||||
OrderStatus Status,
|
||||
decimal Subtotal,
|
||||
decimal TaxTotal,
|
||||
decimal DiscountAmount,
|
||||
decimal Total,
|
||||
decimal PaidAmount,
|
||||
DateTime CreatedAt,
|
||||
int DisplayNumber,
|
||||
IReadOnlyList<OrderItemDto> Items,
|
||||
IReadOnlyList<PaymentDto> Payments);
|
||||
|
||||
public record AppendOrderItemsRequest(IReadOnlyList<CreateOrderItemRequest> Items);
|
||||
|
||||
public record UpdateOrderSessionRequest(
|
||||
string? GuestName,
|
||||
string? GuestPhone,
|
||||
string? CustomerId);
|
||||
|
||||
|
||||
public record CreateOrderItemRequest(string MenuItemId, int Quantity, string? Notes);
|
||||
|
||||
public record CreateOrderRequest(
|
||||
OrderType OrderType,
|
||||
string? BranchId,
|
||||
string? TableId,
|
||||
string? ReservationId,
|
||||
string? GuestName,
|
||||
string? GuestPhone,
|
||||
string? CustomerId,
|
||||
string? CouponId,
|
||||
IReadOnlyList<CreateOrderItemRequest> Items);
|
||||
|
||||
public record UpdateOrderStatusRequest(OrderStatus Status);
|
||||
|
||||
public record CreatePaymentRequest(PaymentMethod Method, decimal Amount, string? Reference);
|
||||
|
||||
public record RecordPaymentsRequest(
|
||||
IReadOnlyList<CreatePaymentRequest> Payments,
|
||||
int? LoyaltyPointsToRedeem = null);
|
||||
|
||||
public record PaymentDto(string Id, PaymentMethod Method, decimal Amount, PaymentStatus Status, string? Reference);
|
||||
|
||||
public record LiveOrderDto(
|
||||
string Id,
|
||||
int DisplayNumber,
|
||||
OrderStatus Status,
|
||||
string? TableNumber,
|
||||
OrderType OrderType,
|
||||
decimal Total,
|
||||
DateTime CreatedAt,
|
||||
IReadOnlyList<OrderItemDto> Items);
|
||||
@@ -0,0 +1,36 @@
|
||||
namespace Meezi.API.Models.Printing;
|
||||
|
||||
public record BranchPrintSettingsDto(
|
||||
string BranchId,
|
||||
string? ReceiptPrinterIp,
|
||||
int? ReceiptPrinterPort,
|
||||
string? KitchenPrinterIp,
|
||||
int? KitchenPrinterPort,
|
||||
int PaperWidthMm,
|
||||
bool AutoCutEnabled,
|
||||
string? ReceiptHeader,
|
||||
string? ReceiptFooter,
|
||||
string? WifiPassword,
|
||||
string? PosDeviceIp,
|
||||
int? PosDevicePort);
|
||||
|
||||
public record PatchBranchPrintSettingsRequest(
|
||||
string? ReceiptPrinterIp,
|
||||
int? ReceiptPrinterPort,
|
||||
string? KitchenPrinterIp,
|
||||
int? KitchenPrinterPort,
|
||||
int? PaperWidthMm,
|
||||
bool? AutoCutEnabled,
|
||||
string? ReceiptHeader,
|
||||
string? ReceiptFooter,
|
||||
string? WifiPassword,
|
||||
string? PosDeviceIp,
|
||||
int? PosDevicePort);
|
||||
|
||||
public record PosPaymentRequest(string OrderId, decimal Amount);
|
||||
|
||||
public record PosPaymentResultDto(bool Sent, bool Skipped, string? Message);
|
||||
|
||||
public record TestPrintRequest(string PrinterIp, int Port = 9100);
|
||||
|
||||
public record PrintJobResultDto(bool Printed, string? ErrorCode, string? Message);
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Meezi.API.Models.Public;
|
||||
|
||||
public record CoffeeAdvisorRequest(string Purpose, string? CafeSlug = null);
|
||||
|
||||
public record CoffeeAdvisorPickDto(string Name, string Reason, string? MenuItemId);
|
||||
|
||||
public record CoffeeAdvisorResultDto(
|
||||
string Summary,
|
||||
IReadOnlyList<CoffeeAdvisorPickDto> Picks);
|
||||
@@ -0,0 +1,187 @@
|
||||
using Meezi.API.Models.Cafes;
|
||||
using Meezi.API.Models.Discover;
|
||||
using Meezi.API.Models.Orders;
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
namespace Meezi.API.Models.Public;
|
||||
|
||||
// ── Working hours (read-only, for public display) ────────────────────────────
|
||||
|
||||
public record DaySchedulePublicDto(bool IsOpen, string? Open, string? Close);
|
||||
|
||||
public record WorkingHoursPublicDto(
|
||||
DaySchedulePublicDto? Sat,
|
||||
DaySchedulePublicDto? Sun,
|
||||
DaySchedulePublicDto? Mon,
|
||||
DaySchedulePublicDto? Tue,
|
||||
DaySchedulePublicDto? Wed,
|
||||
DaySchedulePublicDto? Thu,
|
||||
DaySchedulePublicDto? Fri);
|
||||
|
||||
// ── NLP parse result (returned by /api/public/discover/nlp-parse) ────────────
|
||||
|
||||
public record DiscoverNlpHintsDto(
|
||||
IReadOnlyList<string> Themes,
|
||||
IReadOnlyList<string> Vibes,
|
||||
IReadOnlyList<string> Occasions,
|
||||
IReadOnlyList<string> SpaceFeatures,
|
||||
string? NoiseLevel,
|
||||
string? PriceTier,
|
||||
string? Size)
|
||||
{
|
||||
public static readonly DiscoverNlpHintsDto Empty =
|
||||
new([], [], [], [], null, null, null);
|
||||
}
|
||||
|
||||
public record CafeBadgePublicDto(string Key, string Label, string Icon);
|
||||
|
||||
public record CafeDiscoverDto(
|
||||
string Id,
|
||||
string Name,
|
||||
string Slug,
|
||||
string? City,
|
||||
string? Address,
|
||||
string? LogoUrl,
|
||||
string? CoverImageUrl,
|
||||
bool IsVerified,
|
||||
double AverageRating,
|
||||
int ReviewCount,
|
||||
CafeDiscoverProfileDto DiscoverProfile,
|
||||
IReadOnlyList<CafeBadgePublicDto> Badges,
|
||||
IReadOnlyList<string> GalleryUrls,
|
||||
bool IsOpenNow,
|
||||
string? InstagramHandle,
|
||||
string? WebsiteUrl,
|
||||
double RelevanceScore);
|
||||
|
||||
public record CafePublicDto(
|
||||
string Id,
|
||||
string Name,
|
||||
string? NameAr,
|
||||
string? NameEn,
|
||||
string Slug,
|
||||
string? City,
|
||||
string? Address,
|
||||
string? Phone,
|
||||
string? LogoUrl,
|
||||
string? CoverImageUrl,
|
||||
string? Description,
|
||||
bool IsVerified,
|
||||
double AverageRating,
|
||||
int ReviewCount,
|
||||
CafeDiscoverProfileDto DiscoverProfile,
|
||||
IReadOnlyList<CafeBadgePublicDto> Badges,
|
||||
IReadOnlyList<string> GalleryUrls,
|
||||
bool IsOpenNow,
|
||||
string? InstagramHandle,
|
||||
string? WebsiteUrl,
|
||||
WorkingHoursPublicDto? WorkingHours);
|
||||
|
||||
public record PublicMenuItemDto(
|
||||
string Id,
|
||||
string CategoryId,
|
||||
string Name,
|
||||
string? NameAr,
|
||||
string? NameEn,
|
||||
string? Description,
|
||||
decimal Price,
|
||||
decimal DiscountPercent,
|
||||
string? ImageUrl,
|
||||
string? VideoUrl,
|
||||
string? Model3dUrl,
|
||||
bool IsAvailable);
|
||||
|
||||
public record PublicMenuCategoryDto(
|
||||
string Id,
|
||||
string Name,
|
||||
string? NameAr,
|
||||
string? NameEn,
|
||||
string? Icon,
|
||||
string? IconPresetId,
|
||||
string? IconStyle,
|
||||
string? ImageUrl,
|
||||
IReadOnlyList<PublicMenuItemDto> Items);
|
||||
|
||||
public record PublicMenuDto(
|
||||
string CafeId,
|
||||
string CafeName,
|
||||
string Slug,
|
||||
CafeThemeDto Theme,
|
||||
IReadOnlyList<PublicMenuCategoryDto> Categories);
|
||||
|
||||
public record GuestCreateOrderRequest(
|
||||
OrderType OrderType,
|
||||
string? TableId,
|
||||
string? GuestPhone,
|
||||
string? GuestName,
|
||||
string? CouponCode,
|
||||
IReadOnlyList<CreateOrderItemRequest> Items,
|
||||
string? CaptchaToken = null);
|
||||
|
||||
public record GuestOrderPlacedDto(
|
||||
string OrderId,
|
||||
OrderStatus Status,
|
||||
decimal Total,
|
||||
string? TableNumber);
|
||||
|
||||
public record PlaceGuestOrderRequest(
|
||||
string TableId,
|
||||
string? GuestName,
|
||||
string? GuestPhone,
|
||||
IReadOnlyList<CreateOrderItemRequest> Items,
|
||||
string? CaptchaToken = null);
|
||||
|
||||
public record PublicSecurityConfigDto(
|
||||
bool AbuseProtectionEnabled,
|
||||
string? TurnstileSiteKey,
|
||||
bool CaptchaRequired);
|
||||
|
||||
public record GuestQrOrderPlacedDto(
|
||||
string OrderId,
|
||||
string OrderNumber,
|
||||
decimal TotalAmount,
|
||||
int ItemCount,
|
||||
OrderStatus Status,
|
||||
string TrackingToken);
|
||||
|
||||
public record OrderTrackingStepDto(
|
||||
string Key,
|
||||
string LabelKey,
|
||||
bool IsComplete,
|
||||
bool IsCurrent);
|
||||
|
||||
public record OrderTrackDto(
|
||||
string Id,
|
||||
string OrderNumber,
|
||||
OrderStatus Status,
|
||||
string StatusLabelKey,
|
||||
decimal Total,
|
||||
string? TableNumber,
|
||||
DateTime CreatedAt,
|
||||
DateTime StatusUpdatedAt,
|
||||
string TrackingToken,
|
||||
IReadOnlyList<OrderTrackingStepDto> Steps,
|
||||
IReadOnlyList<OrderItemDto> Items);
|
||||
|
||||
public record CreateReservationRequest(
|
||||
string GuestName,
|
||||
string GuestPhone,
|
||||
DateOnly Date,
|
||||
TimeOnly Time,
|
||||
int PartySize,
|
||||
string? Notes,
|
||||
string? TableId,
|
||||
string? CaptchaToken = null);
|
||||
|
||||
public record ReservationDto(
|
||||
string Id,
|
||||
string CafeId,
|
||||
string? TableId,
|
||||
string? TableNumber,
|
||||
string GuestName,
|
||||
string GuestPhone,
|
||||
DateOnly Date,
|
||||
TimeOnly Time,
|
||||
int PartySize,
|
||||
ReservationStatus Status,
|
||||
string? Notes);
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Meezi.API.Models.Public;
|
||||
|
||||
public record CafeReviewDto(
|
||||
string Id,
|
||||
string AuthorName,
|
||||
int Rating,
|
||||
string? Comment,
|
||||
string? OwnerReply,
|
||||
DateTime CreatedAt,
|
||||
IReadOnlyList<string> PhotoUrls,
|
||||
bool IsHidden = false);
|
||||
|
||||
public record CreateCafeReviewRequest(
|
||||
string AuthorName,
|
||||
string? AuthorPhone,
|
||||
int Rating,
|
||||
string? Comment,
|
||||
string? CaptchaToken = null);
|
||||
|
||||
public record ReplyCafeReviewRequest(string Reply);
|
||||
|
||||
public record HideCafeReviewRequest(bool IsHidden);
|
||||
@@ -0,0 +1,27 @@
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
namespace Meezi.API.Models.Queue;
|
||||
|
||||
public record QueueTicketDto(
|
||||
string Id,
|
||||
string? BranchId,
|
||||
DateOnly ServiceDate,
|
||||
int Number,
|
||||
string? CustomerLabel,
|
||||
string? OrderId,
|
||||
QueueTicketStatus Status,
|
||||
DateTime IssuedAt);
|
||||
|
||||
public record QueueBoardDto(
|
||||
DateOnly ServiceDate,
|
||||
int? NowServing,
|
||||
int LastIssued,
|
||||
int WaitingCount,
|
||||
IReadOnlyList<QueueTicketDto> Tickets);
|
||||
|
||||
public record IssueQueueTicketRequest(
|
||||
string? BranchId,
|
||||
string? CustomerLabel,
|
||||
string? OrderId);
|
||||
|
||||
public record UpdateQueueTicketStatusRequest(QueueTicketStatus Status);
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace Meezi.API.Models.Reports;
|
||||
|
||||
public record TopProductSnapshotDto(string ProductId, string Name, int Quantity, decimal Revenue);
|
||||
|
||||
public record DailyReportSnapshotDto(
|
||||
string Id,
|
||||
string CafeId,
|
||||
string BranchId,
|
||||
string Date,
|
||||
decimal TotalRevenue,
|
||||
decimal CashRevenue,
|
||||
decimal CardRevenue,
|
||||
decimal CreditRevenue,
|
||||
int TotalOrders,
|
||||
decimal AvgOrderValue,
|
||||
int TotalVoids,
|
||||
decimal VoidAmount,
|
||||
decimal TotalExpenses,
|
||||
decimal NetIncome,
|
||||
IReadOnlyList<TopProductSnapshotDto> TopProducts,
|
||||
DateTime GeneratedAt);
|
||||
|
||||
public record DailyReportSummaryDto(
|
||||
int Days,
|
||||
decimal TotalRevenue,
|
||||
decimal CashRevenue,
|
||||
decimal CardRevenue,
|
||||
decimal CreditRevenue,
|
||||
int TotalOrders,
|
||||
decimal AvgOrderValue,
|
||||
int TotalVoids,
|
||||
decimal VoidAmount,
|
||||
decimal TotalExpenses,
|
||||
decimal NetIncome,
|
||||
IReadOnlyList<DailyReportSnapshotDto> ByBranch);
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace Meezi.API.Models.Reports;
|
||||
|
||||
public record TopItemDto(string MenuItemId, string Name, int Quantity, decimal Revenue);
|
||||
|
||||
public record DailyReportDto(
|
||||
string DateJalali,
|
||||
int TotalOrders,
|
||||
int NewCustomers,
|
||||
int ReturningCustomers,
|
||||
decimal Revenue,
|
||||
decimal TaxTotal,
|
||||
decimal DiscountTotal,
|
||||
IReadOnlyList<TopItemDto> TopItems);
|
||||
|
||||
public record DailyBreakdownDto(string DateJalali, decimal Revenue, decimal Cost);
|
||||
|
||||
public record MonthlyReportDto(
|
||||
string MonthJalali,
|
||||
IReadOnlyList<DailyBreakdownDto> DailyBreakdown,
|
||||
decimal TotalRevenue,
|
||||
decimal TotalCosts,
|
||||
decimal SalaryCosts,
|
||||
decimal OtherCosts,
|
||||
decimal NetProfit);
|
||||
|
||||
public record TrendDayDto(string DateJalali, decimal Revenue, decimal Cost);
|
||||
@@ -0,0 +1,33 @@
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
namespace Meezi.API.Models.Shifts;
|
||||
|
||||
public record ShiftDto(
|
||||
string Id,
|
||||
string CafeId,
|
||||
string BranchId,
|
||||
string OpenedByUserId,
|
||||
string? ClosedByUserId,
|
||||
DateTime OpenedAt,
|
||||
DateTime? ClosedAt,
|
||||
decimal OpeningCash,
|
||||
decimal? ClosingCash,
|
||||
decimal ExpectedCash,
|
||||
decimal? Discrepancy,
|
||||
ShiftStatus Status);
|
||||
|
||||
public record CashTransactionDto(
|
||||
string Id,
|
||||
string ShiftId,
|
||||
string? BranchId,
|
||||
CashTransactionType Type,
|
||||
PaymentMethod Method,
|
||||
decimal Amount,
|
||||
string? ReferenceId,
|
||||
string? Note,
|
||||
string CreatedByUserId,
|
||||
DateTime CreatedAt);
|
||||
|
||||
public record OpenShiftRequest(decimal OpeningCash);
|
||||
|
||||
public record CloseShiftRequest(decimal ClosingCash);
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Meezi.API.Models.Snappfood;
|
||||
|
||||
public record SnappfoodWebhookOrder(
|
||||
string OrderId,
|
||||
string VendorId,
|
||||
string? CustomerName,
|
||||
string? CustomerPhone,
|
||||
decimal Total,
|
||||
IReadOnlyList<SnappfoodWebhookItem> Items);
|
||||
|
||||
public record SnappfoodWebhookItem(
|
||||
string Name,
|
||||
int Quantity,
|
||||
decimal UnitPrice);
|
||||
@@ -0,0 +1,210 @@
|
||||
using Meezi.Core.Enums;
|
||||
|
||||
|
||||
|
||||
namespace Meezi.API.Models.Tables;
|
||||
|
||||
|
||||
|
||||
public record TableDto(
|
||||
|
||||
string Id,
|
||||
|
||||
string BranchId,
|
||||
|
||||
string? SectionId,
|
||||
|
||||
string? SectionName,
|
||||
|
||||
int SortOrder,
|
||||
|
||||
string Number,
|
||||
|
||||
int Capacity,
|
||||
|
||||
string? Floor,
|
||||
|
||||
string QrCode,
|
||||
|
||||
string QrCodeUrl,
|
||||
|
||||
string? ImageUrl,
|
||||
|
||||
string? VideoUrl,
|
||||
|
||||
bool IsActive);
|
||||
|
||||
|
||||
|
||||
public record CreateTableRequest(
|
||||
|
||||
string? BranchId,
|
||||
|
||||
string Number,
|
||||
|
||||
int Capacity = 4,
|
||||
|
||||
string? Floor = null,
|
||||
|
||||
bool IsActive = true);
|
||||
|
||||
|
||||
|
||||
public record CreateBranchTableRequest(
|
||||
|
||||
string Number,
|
||||
|
||||
int Capacity = 4,
|
||||
|
||||
string? Floor = null,
|
||||
|
||||
string? SectionId = null,
|
||||
|
||||
int SortOrder = 0,
|
||||
|
||||
bool IsActive = true);
|
||||
|
||||
|
||||
|
||||
public record PatchTableRequest(
|
||||
|
||||
string? Number,
|
||||
|
||||
int? Capacity,
|
||||
|
||||
string? Floor,
|
||||
|
||||
string? BranchId,
|
||||
|
||||
string? ImageUrl,
|
||||
|
||||
string? VideoUrl,
|
||||
|
||||
bool? IsActive,
|
||||
|
||||
bool? IsCleaning);
|
||||
|
||||
|
||||
|
||||
public record PatchBranchTableRequest(
|
||||
|
||||
string? Number,
|
||||
|
||||
int? Capacity,
|
||||
|
||||
string? Floor,
|
||||
|
||||
string? SectionId,
|
||||
|
||||
int? SortOrder,
|
||||
|
||||
string? ImageUrl,
|
||||
|
||||
string? VideoUrl,
|
||||
|
||||
bool? IsActive,
|
||||
|
||||
bool? IsCleaning);
|
||||
|
||||
|
||||
|
||||
public record TableSectionDto(
|
||||
|
||||
string Id,
|
||||
|
||||
string BranchId,
|
||||
|
||||
string Name,
|
||||
|
||||
int SortOrder,
|
||||
|
||||
bool IsActive,
|
||||
|
||||
int TableCount);
|
||||
|
||||
|
||||
|
||||
public record CreateTableSectionRequest(string Name, int SortOrder = 0);
|
||||
|
||||
|
||||
|
||||
public record PatchTableSectionRequest(
|
||||
|
||||
string? Name,
|
||||
|
||||
int? SortOrder,
|
||||
|
||||
bool? IsActive);
|
||||
|
||||
|
||||
|
||||
public record SetTableCleaningRequest(bool IsCleaning);
|
||||
|
||||
|
||||
|
||||
public record QrResolveResponse(
|
||||
string CafeId,
|
||||
string CafeSlug,
|
||||
string TableId,
|
||||
string TableNumber,
|
||||
string TableName,
|
||||
string BranchId,
|
||||
string BranchName,
|
||||
string CafeName,
|
||||
string PrimaryColor,
|
||||
string? LogoUrl,
|
||||
string WelcomeText,
|
||||
string? WifiPassword,
|
||||
string? Address,
|
||||
bool IsCleaning);
|
||||
|
||||
|
||||
|
||||
public record TableCurrentOrderSummary(
|
||||
string OrderId,
|
||||
OrderStatus Status,
|
||||
decimal Total,
|
||||
string? GuestLabel,
|
||||
OrderSource? Source = null);
|
||||
|
||||
|
||||
|
||||
public record TableBoardDto(
|
||||
|
||||
string Id,
|
||||
|
||||
string BranchId,
|
||||
|
||||
string? SectionId,
|
||||
|
||||
string? SectionName,
|
||||
|
||||
int SortOrder,
|
||||
|
||||
string Number,
|
||||
|
||||
int Capacity,
|
||||
|
||||
string? Floor,
|
||||
|
||||
string QrCode,
|
||||
|
||||
string QrCodeUrl,
|
||||
|
||||
string? ImageUrl,
|
||||
|
||||
string? VideoUrl,
|
||||
|
||||
bool IsActive,
|
||||
|
||||
TableBoardStatus Status,
|
||||
|
||||
TableCurrentOrderSummary? CurrentOrder,
|
||||
|
||||
bool IsCleaning);
|
||||
|
||||
|
||||
|
||||
public record BranchTableOperationResult<T>(bool Success, T? Data, string? ErrorCode, string? Message);
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace Meezi.API.Models.Tap30;
|
||||
|
||||
public record Tap30WebhookOrder(
|
||||
string OrderId,
|
||||
string VendorId,
|
||||
Tap30Customer? Customer,
|
||||
decimal Total,
|
||||
string? PaymentMethod,
|
||||
bool? IsPaid,
|
||||
decimal? Commission,
|
||||
string? DeliveryType,
|
||||
int? EstimatedMinutes,
|
||||
string? DriverName,
|
||||
string? DriverPhone,
|
||||
string? Status,
|
||||
IReadOnlyList<Tap30WebhookItem>? Items);
|
||||
|
||||
public record Tap30Customer(
|
||||
string? Name,
|
||||
string? Phone,
|
||||
string? Address,
|
||||
double? Lat,
|
||||
double? Lng);
|
||||
|
||||
public record Tap30WebhookItem(
|
||||
string? Sku,
|
||||
string Name,
|
||||
int Quantity,
|
||||
decimal UnitPrice,
|
||||
string? Notes);
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Meezi.API.Models.Taxes;
|
||||
|
||||
public record TaxDto(
|
||||
string Id,
|
||||
string Name,
|
||||
decimal Rate,
|
||||
bool IsDefault,
|
||||
bool IsRequired,
|
||||
bool IsCompound);
|
||||
|
||||
public record CreateTaxRequest(
|
||||
string Name,
|
||||
decimal Rate,
|
||||
bool IsDefault = false,
|
||||
bool IsRequired = true,
|
||||
bool IsCompound = false);
|
||||
|
||||
public record UpdateTaxRequest(
|
||||
string? Name,
|
||||
decimal? Rate,
|
||||
bool? IsDefault,
|
||||
bool? IsRequired,
|
||||
bool? IsCompound);
|
||||
Reference in New Issue
Block a user