Sms & Email

This commit is contained in:
2026-10-20 10:45:03 +05:30
parent a40e463e8b
commit 0e423b806c
29 changed files with 13845 additions and 26 deletions
@@ -0,0 +1,52 @@
using System.ComponentModel.DataAnnotations;
namespace ERPCore.Dtos.Config;
/// <summary>Day-end owner report settings (docs/DAY_END_OWNER_REPORT_PLAN.md §3.5).</summary>
/// <param name="SendAtLocalTime">"HH:mm" in <paramref name="TimeZone"/>.</param>
public sealed record OwnerReportConfigDto(
bool Enabled, bool SmsEnabled, bool EmailEnabled, string SendAtLocalTime, bool IncludeBranchBreakdown,
IReadOnlyList<OwnerReportRecipientDto> Recipients, string TimeZone, DateTime? UpdatedAt, int? UpdatedBy);
public sealed record OwnerReportRecipientDto(int RecipientId, string Name, string? Mobile, string? Email, bool IsActive);
public sealed class UpdateOwnerReportConfigRequest
{
[Required] public bool? Enabled { get; set; }
[Required] public bool? SmsEnabled { get; set; }
[Required] public bool? EmailEnabled { get; set; }
[Required] public bool? IncludeBranchBreakdown { get; set; }
/// <summary>"HH:mm", 24-hour.</summary>
[Required, RegularExpression(@"^([01]\d|2[0-3]):[0-5]\d$", ErrorMessage = "Send time must be HH:mm (24-hour).")]
public string SendAtLocalTime { get; set; } = "21:00";
/// <summary>The full list — recipients not in it are removed. At most 5.</summary>
[Required, MaxLength(5, ErrorMessage = "At most 5 recipients.")]
public List<OwnerReportRecipientInput> Recipients { get; set; } = new();
}
public sealed class OwnerReportRecipientInput
{
/// <summary>Existing recipient to update; null adds a new one.</summary>
public int? RecipientId { get; set; }
[Required, StringLength(100, MinimumLength = 1)] public string Name { get; set; } = string.Empty;
[StringLength(20)] public string? Mobile { get; set; }
[StringLength(200), EmailAddress] public string? Email { get; set; }
public bool IsActive { get; set; } = true;
}
/// <summary>The report as it would be sent for <paramref name="Date"/>.</summary>
public sealed record OwnerReportPreviewDto(DateOnly Date, string SmsText, string EmailSubject, string EmailHtml);
public sealed class OwnerReportTestRequest
{
/// <summary>Day to report; null = today in the report's time zone.</summary>
public DateOnly? Date { get; set; }
}
public sealed record OwnerReportSendResultDto(string Channel, string RecipientName, string Destination, bool Ok, string? Error);
public sealed record OwnerReportDispatchDto(
long DispatchId, DateOnly BusinessDate, string Channel, string RecipientName, string Destination,
string Status, int Attempts, string? Error, bool IsTest, DateTime CreatedAt, DateTime? SentAt);
@@ -11,11 +11,11 @@ public sealed record WarehouseDto(int WarehouseId, string Code, string Name, str
public sealed record BinDto(int BinId, int WarehouseId, string Code, string? BinType);
/// <summary>Sri Lankan phone rule for master data — mirrors the frontend's `lib/validations/phone.ts`:
/// 10 digits starting with 0, or +94 followed by 9 digits; spaces and hyphens allowed between digits.</summary>
/// 10 digits starting with 0, or 94 followed by 9 digits with or without a leading +; spaces and hyphens allowed between digits.</summary>
public static class PhoneRules
{
public const string Pattern = @"^(?:0(?:[\s-]*\d){9}|\+94(?:[\s-]*\d){9})[\s-]*$";
public const string Message = "Enter a valid Sri Lankan phone number: 10 digits starting with 0 (0771234567) or +94 followed by 9 digits (+94771234567).";
public const string Pattern = @"^(?:0(?:[\s-]*\d){9}|\+?94(?:[\s-]*\d){9})[\s-]*$";
public const string Message = "Enter a valid Sri Lankan phone number: 10 digits starting with 0 (0771234567), or 94 followed by 9 digits (94771234567 or +94771234567).";
}
public sealed class CreateWarehouseRequest