764 lines
25 KiB
C#
764 lines
25 KiB
C#
using System;
|
|
using System.Linq;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using TakeoutSaaS.Domain.Stores.Entities;
|
|
using TakeoutSaaS.Domain.Stores.Enums;
|
|
using TakeoutSaaS.Domain.Stores.Repositories;
|
|
using TakeoutSaaS.Infrastructure.App.Persistence;
|
|
|
|
namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
|
|
|
/// <summary>
|
|
/// 门店聚合的 EF Core 仓储实现。
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 初始化仓储。
|
|
/// </remarks>
|
|
public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepository
|
|
{
|
|
/// <inheritdoc />
|
|
public Task<Store?> FindByIdAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.Stores.AsNoTracking();
|
|
if (tenantId <= 0)
|
|
{
|
|
query = query.IgnoreQueryFilters()
|
|
.Where(x => x.DeletedAt == null);
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId);
|
|
}
|
|
|
|
return query
|
|
.Where(x => x.Id == storeId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<Store>> GetByMerchantIdAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return await context.Stores
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId)
|
|
.OrderBy(x => x.Name)
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<Store>> SearchAsync(
|
|
long tenantId,
|
|
long? merchantId,
|
|
StoreStatus? status,
|
|
StoreAuditStatus? auditStatus,
|
|
StoreBusinessStatus? businessStatus,
|
|
StoreOwnershipType? ownershipType,
|
|
string? keyword,
|
|
bool ignoreTenantFilter = false,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.Stores.AsNoTracking();
|
|
if (ignoreTenantFilter)
|
|
{
|
|
query = query.IgnoreQueryFilters()
|
|
.Where(x => x.DeletedAt == null);
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId);
|
|
}
|
|
|
|
if (merchantId.HasValue)
|
|
{
|
|
query = query.Where(x => x.MerchantId == merchantId.Value);
|
|
}
|
|
|
|
if (status.HasValue)
|
|
{
|
|
query = query.Where(x => x.Status == status.Value);
|
|
}
|
|
|
|
if (auditStatus.HasValue)
|
|
{
|
|
query = query.Where(x => x.AuditStatus == auditStatus.Value);
|
|
}
|
|
|
|
if (businessStatus.HasValue)
|
|
{
|
|
query = query.Where(x => x.BusinessStatus == businessStatus.Value);
|
|
}
|
|
|
|
if (ownershipType.HasValue)
|
|
{
|
|
query = query.Where(x => x.OwnershipType == ownershipType.Value);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(keyword))
|
|
{
|
|
var trimmed = keyword.Trim();
|
|
query = query.Where(x => x.Name.Contains(trimmed) || x.Code.Contains(trimmed));
|
|
}
|
|
|
|
var stores = await query
|
|
.OrderBy(x => x.Name)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return stores;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<bool> ExistsStoreWithinDistanceAsync(
|
|
long merchantId,
|
|
long tenantId,
|
|
double longitude,
|
|
double latitude,
|
|
double distanceMeters,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
// 1. 校验距离阈值
|
|
if (distanceMeters <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 2. (空行后) 拉取候选坐标
|
|
var coordinates = await context.Stores
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId)
|
|
.Where(x => x.Longitude.HasValue && x.Latitude.HasValue)
|
|
.Select(x => new { Longitude = x.Longitude!.Value, Latitude = x.Latitude!.Value })
|
|
.ToListAsync(cancellationToken);
|
|
|
|
// 3. (空行后) 计算距离并判断是否命中
|
|
foreach (var coordinate in coordinates)
|
|
{
|
|
var distance = CalculateDistanceMeters(latitude, longitude, coordinate.Latitude, coordinate.Longitude);
|
|
if (distance <= distanceMeters)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// 4. (空行后) 返回未命中结果
|
|
return false;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<Dictionary<long, int>> GetStoreCountsAsync(long? tenantId, IReadOnlyCollection<long> merchantIds, CancellationToken cancellationToken = default)
|
|
{
|
|
if (merchantIds.Count == 0)
|
|
{
|
|
return new Dictionary<long, int>();
|
|
}
|
|
|
|
var query = context.Stores.AsNoTracking();
|
|
if (!tenantId.HasValue || tenantId.Value <= 0)
|
|
{
|
|
query = query.IgnoreQueryFilters();
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId.Value);
|
|
}
|
|
|
|
return await query
|
|
.Where(x => merchantIds.Contains(x.MerchantId))
|
|
.GroupBy(x => x.MerchantId)
|
|
.Select(group => new { group.Key, Count = group.Count() })
|
|
.ToDictionaryAsync(x => x.Key, x => x.Count, cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<StoreBusinessHour>> GetBusinessHoursAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.StoreBusinessHours.AsNoTracking();
|
|
if (tenantId <= 0)
|
|
{
|
|
query = query.IgnoreQueryFilters()
|
|
.Where(x => x.DeletedAt == null);
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId);
|
|
}
|
|
|
|
var hours = await query
|
|
.Where(x => x.StoreId == storeId)
|
|
.OrderBy(x => x.DayOfWeek)
|
|
.ThenBy(x => x.StartTime)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return hours;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<StoreFee?> GetStoreFeeAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.StoreFees.AsNoTracking();
|
|
if (tenantId <= 0)
|
|
{
|
|
query = query.IgnoreQueryFilters()
|
|
.Where(x => x.DeletedAt == null);
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId);
|
|
}
|
|
|
|
return query
|
|
.Where(x => x.StoreId == storeId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddStoreFeeAsync(StoreFee storeFee, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreFees.AddAsync(storeFee, cancellationToken).AsTask();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateStoreFeeAsync(StoreFee storeFee, CancellationToken cancellationToken = default)
|
|
{
|
|
context.StoreFees.Update(storeFee);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<StoreQualification>> GetQualificationsAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.StoreQualifications.AsNoTracking();
|
|
if (tenantId <= 0)
|
|
{
|
|
query = query.IgnoreQueryFilters()
|
|
.Where(x => x.DeletedAt == null);
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId);
|
|
}
|
|
|
|
var qualifications = await query
|
|
.Where(x => x.StoreId == storeId)
|
|
.OrderBy(x => x.SortOrder)
|
|
.ThenBy(x => x.QualificationType)
|
|
.ToListAsync(cancellationToken);
|
|
return qualifications;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<StoreQualification?> FindQualificationByIdAsync(long qualificationId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreQualifications
|
|
.Where(x => x.TenantId == tenantId && x.Id == qualificationId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddQualificationAsync(StoreQualification qualification, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreQualifications.AddAsync(qualification, cancellationToken).AsTask();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateQualificationAsync(StoreQualification qualification, CancellationToken cancellationToken = default)
|
|
{
|
|
context.StoreQualifications.Update(qualification);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task DeleteQualificationAsync(long qualificationId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var existing = await context.StoreQualifications
|
|
.Where(x => x.TenantId == tenantId && x.Id == qualificationId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (existing != null)
|
|
{
|
|
context.StoreQualifications.Remove(existing);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddAuditRecordAsync(StoreAuditRecord record, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreAuditRecords.AddAsync(record, cancellationToken).AsTask();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<StoreAuditRecord>> GetAuditRecordsAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var records = await context.StoreAuditRecords
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.StoreId == storeId)
|
|
.OrderByDescending(x => x.CreatedAt)
|
|
.ToListAsync(cancellationToken);
|
|
return records;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<StoreBusinessHour?> FindBusinessHourByIdAsync(long businessHourId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreBusinessHours
|
|
.Where(x => x.TenantId == tenantId && x.Id == businessHourId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<StoreDeliveryZone>> GetDeliveryZonesAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.StoreDeliveryZones.AsNoTracking();
|
|
if (tenantId <= 0)
|
|
{
|
|
query = query.IgnoreQueryFilters()
|
|
.Where(x => x.DeletedAt == null);
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId);
|
|
}
|
|
|
|
var zones = await query
|
|
.Where(x => x.StoreId == storeId)
|
|
.OrderBy(x => x.SortOrder)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return zones;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<StoreDeliveryZone?> FindDeliveryZoneByIdAsync(long deliveryZoneId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.StoreDeliveryZones.AsQueryable();
|
|
if (tenantId <= 0)
|
|
{
|
|
query = query.IgnoreQueryFilters()
|
|
.Where(x => x.DeletedAt == null);
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId);
|
|
}
|
|
|
|
return query
|
|
.Where(x => x.Id == deliveryZoneId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<StoreHoliday>> GetHolidaysAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.StoreHolidays.AsNoTracking();
|
|
if (tenantId <= 0)
|
|
{
|
|
query = query.IgnoreQueryFilters()
|
|
.Where(x => x.DeletedAt == null);
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId);
|
|
}
|
|
|
|
var holidays = await query
|
|
.Where(x => x.StoreId == storeId)
|
|
.OrderBy(x => x.Date)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return holidays;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<StoreHoliday?> FindHolidayByIdAsync(long holidayId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.StoreHolidays.AsQueryable();
|
|
if (tenantId <= 0)
|
|
{
|
|
query = query.IgnoreQueryFilters()
|
|
.Where(x => x.DeletedAt == null);
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId);
|
|
}
|
|
|
|
return query
|
|
.Where(x => x.Id == holidayId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<StoreTableArea>> GetTableAreasAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var areas = await context.StoreTableAreas
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.StoreId == storeId)
|
|
.OrderBy(x => x.SortOrder)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return areas;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<StoreTableArea?> FindTableAreaByIdAsync(long areaId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreTableAreas
|
|
.Where(x => x.TenantId == tenantId && x.Id == areaId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<StoreTable>> GetTablesAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var tables = await context.StoreTables
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.StoreId == storeId)
|
|
.OrderBy(x => x.TableCode)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return tables;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<StoreTable?> FindTableByIdAsync(long tableId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreTables
|
|
.Where(x => x.TenantId == tenantId && x.Id == tableId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<StoreTable?> FindTableByCodeAsync(string tableCode, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreTables
|
|
.Where(x => x.TenantId == tenantId && x.TableCode == tableCode)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<StorePickupSetting?> GetPickupSettingAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StorePickupSettings
|
|
.Where(x => x.TenantId == tenantId && x.StoreId == storeId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddPickupSettingAsync(StorePickupSetting setting, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StorePickupSettings.AddAsync(setting, cancellationToken).AsTask();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdatePickupSettingAsync(StorePickupSetting setting, CancellationToken cancellationToken = default)
|
|
{
|
|
context.StorePickupSettings.Update(setting);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<StorePickupSlot>> GetPickupSlotsAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var slots = await context.StorePickupSlots
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.StoreId == storeId)
|
|
.OrderBy(x => x.StartTime)
|
|
.ToListAsync(cancellationToken);
|
|
return slots;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<StorePickupSlot?> FindPickupSlotByIdAsync(long slotId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StorePickupSlots
|
|
.Where(x => x.TenantId == tenantId && x.Id == slotId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddPickupSlotsAsync(IEnumerable<StorePickupSlot> slots, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StorePickupSlots.AddRangeAsync(slots, cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdatePickupSlotAsync(StorePickupSlot slot, CancellationToken cancellationToken = default)
|
|
{
|
|
context.StorePickupSlots.Update(slot);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<StoreEmployeeShift>> GetShiftsAsync(long storeId, long tenantId, DateTime? from = null, DateTime? to = null, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.StoreEmployeeShifts
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.StoreId == storeId);
|
|
|
|
if (from.HasValue)
|
|
{
|
|
query = query.Where(x => x.ShiftDate >= from.Value.Date);
|
|
}
|
|
|
|
if (to.HasValue)
|
|
{
|
|
query = query.Where(x => x.ShiftDate <= to.Value.Date);
|
|
}
|
|
|
|
var shifts = await query
|
|
.OrderBy(x => x.ShiftDate)
|
|
.ThenBy(x => x.StartTime)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return shifts;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<StoreEmployeeShift?> FindShiftByIdAsync(long shiftId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreEmployeeShifts
|
|
.Where(x => x.TenantId == tenantId && x.Id == shiftId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddStoreAsync(Store store, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.Stores.AddAsync(store, cancellationToken).AsTask();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddBusinessHoursAsync(IEnumerable<StoreBusinessHour> hours, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreBusinessHours.AddRangeAsync(hours, cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateBusinessHourAsync(StoreBusinessHour hour, CancellationToken cancellationToken = default)
|
|
{
|
|
context.StoreBusinessHours.Update(hour);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddDeliveryZonesAsync(IEnumerable<StoreDeliveryZone> zones, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreDeliveryZones.AddRangeAsync(zones, cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateDeliveryZoneAsync(StoreDeliveryZone zone, CancellationToken cancellationToken = default)
|
|
{
|
|
context.StoreDeliveryZones.Update(zone);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddHolidaysAsync(IEnumerable<StoreHoliday> holidays, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreHolidays.AddRangeAsync(holidays, cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateHolidayAsync(StoreHoliday holiday, CancellationToken cancellationToken = default)
|
|
{
|
|
context.StoreHolidays.Update(holiday);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddTableAreasAsync(IEnumerable<StoreTableArea> areas, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreTableAreas.AddRangeAsync(areas, cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateTableAreaAsync(StoreTableArea area, CancellationToken cancellationToken = default)
|
|
{
|
|
context.StoreTableAreas.Update(area);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddTablesAsync(IEnumerable<StoreTable> tables, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreTables.AddRangeAsync(tables, cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateTableAsync(StoreTable table, CancellationToken cancellationToken = default)
|
|
{
|
|
context.StoreTables.Update(table);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddShiftsAsync(IEnumerable<StoreEmployeeShift> shifts, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.StoreEmployeeShifts.AddRangeAsync(shifts, cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateShiftAsync(StoreEmployeeShift shift, CancellationToken cancellationToken = default)
|
|
{
|
|
context.StoreEmployeeShifts.Update(shift);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
return context.SaveChangesAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task DeleteBusinessHourAsync(long businessHourId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var existing = await context.StoreBusinessHours
|
|
.Where(x => x.TenantId == tenantId && x.Id == businessHourId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (existing != null)
|
|
{
|
|
context.StoreBusinessHours.Remove(existing);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task DeleteDeliveryZoneAsync(long deliveryZoneId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.StoreDeliveryZones.AsQueryable();
|
|
if (tenantId <= 0)
|
|
{
|
|
query = query.IgnoreQueryFilters()
|
|
.Where(x => x.DeletedAt == null);
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId);
|
|
}
|
|
|
|
var existing = await query
|
|
.Where(x => x.Id == deliveryZoneId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (existing != null)
|
|
{
|
|
context.StoreDeliveryZones.Remove(existing);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task DeleteHolidayAsync(long holidayId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.StoreHolidays.AsQueryable();
|
|
if (tenantId <= 0)
|
|
{
|
|
query = query.IgnoreQueryFilters()
|
|
.Where(x => x.DeletedAt == null);
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId);
|
|
}
|
|
|
|
var existing = await query
|
|
.Where(x => x.Id == holidayId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (existing != null)
|
|
{
|
|
context.StoreHolidays.Remove(existing);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task DeleteTableAreaAsync(long areaId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var existing = await context.StoreTableAreas
|
|
.Where(x => x.TenantId == tenantId && x.Id == areaId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (existing != null)
|
|
{
|
|
context.StoreTableAreas.Remove(existing);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task DeleteTableAsync(long tableId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var existing = await context.StoreTables
|
|
.Where(x => x.TenantId == tenantId && x.Id == tableId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (existing != null)
|
|
{
|
|
context.StoreTables.Remove(existing);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task DeletePickupSlotAsync(long slotId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var existing = await context.StorePickupSlots
|
|
.Where(x => x.TenantId == tenantId && x.Id == slotId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (existing != null)
|
|
{
|
|
context.StorePickupSlots.Remove(existing);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task DeleteShiftAsync(long shiftId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var existing = await context.StoreEmployeeShifts
|
|
.Where(x => x.TenantId == tenantId && x.Id == shiftId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (existing != null)
|
|
{
|
|
context.StoreEmployeeShifts.Remove(existing);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateStoreAsync(Store store, CancellationToken cancellationToken = default)
|
|
{
|
|
context.Stores.Update(store);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task DeleteStoreAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var existing = await context.Stores
|
|
.Where(x => x.TenantId == tenantId && x.Id == storeId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (existing == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
context.Stores.Remove(existing);
|
|
}
|
|
|
|
private static double CalculateDistanceMeters(double latitude1, double longitude1, double latitude2, double longitude2)
|
|
{
|
|
const double earthRadius = 6371000d;
|
|
var latRad1 = DegreesToRadians(latitude1);
|
|
var latRad2 = DegreesToRadians(latitude2);
|
|
var deltaLat = DegreesToRadians(latitude2 - latitude1);
|
|
var deltaLon = DegreesToRadians(longitude2 - longitude1);
|
|
var sinLat = Math.Sin(deltaLat / 2);
|
|
var sinLon = Math.Sin(deltaLon / 2);
|
|
var a = sinLat * sinLat + Math.Cos(latRad1) * Math.Cos(latRad2) * sinLon * sinLon;
|
|
var c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
|
|
return earthRadius * c;
|
|
}
|
|
|
|
private static double DegreesToRadians(double degrees) => degrees * (Math.PI / 180d);
|
|
}
|