diff --git a/modules/admin/src/KonSoft.Admin.Application.Contracts/Dtos/AddressDto.cs b/modules/admin/src/KonSoft.Admin.Application.Contracts/Dtos/AddressDto.cs new file mode 100644 index 0000000..45c2de5 --- /dev/null +++ b/modules/admin/src/KonSoft.Admin.Application.Contracts/Dtos/AddressDto.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KonSoft.Admin.Dtos +{ + public class AddressDto + { + public string ContactName { get; set; } + public string ContactPhone { get; set; } + public string DetailAddress { get; set; } + public string City { get; set; } + public string District { get; set; } + } +} diff --git a/modules/admin/src/KonSoft.Admin.Application.Contracts/Dtos/CreateOrderDto.cs b/modules/admin/src/KonSoft.Admin.Application.Contracts/Dtos/CreateOrderDto.cs new file mode 100644 index 0000000..82a4b50 --- /dev/null +++ b/modules/admin/src/KonSoft.Admin.Application.Contracts/Dtos/CreateOrderDto.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KonSoft.Admin.Dtos +{ + public class CreateOrderDto + { + [Required] + public Guid CustomerId { get; set; } + [Required] + public Guid ServiceId { get; set; } + [Required] + public DateTime ServiceTime { get; set; } + [Required] + public decimal Amount { get; set; } + [Required] + public AddressDto Address { get; set; } + + public string Remark { get; set; } + } +} diff --git a/modules/admin/src/KonSoft.Admin.Application.Contracts/Dtos/OrderDto.cs b/modules/admin/src/KonSoft.Admin.Application.Contracts/Dtos/OrderDto.cs new file mode 100644 index 0000000..9a542bd --- /dev/null +++ b/modules/admin/src/KonSoft.Admin.Application.Contracts/Dtos/OrderDto.cs @@ -0,0 +1,25 @@ +using KonSoft.Admin.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KonSoft.Admin.Dtos +{ + public class OrderDto + { + public Guid Id { get; set; } + public string OrderSN { get; set; } + public Guid CustomerId { get; set; } + public Guid? WorkerId { get; set; } + public Guid ServiceId { get; set; } + public DateTime ServiceTime { get; set; } + public OrderStatus Status { get; set; } + public decimal Amount { get; set; } + public decimal PaidAmount { get; set; } + public string PaymentMethod { get; set; } + public AddressDto Address { get; set; } + public string Remark { get; set; } + } +} diff --git a/modules/admin/src/KonSoft.Admin.Application.Contracts/Dtos/PayOrderDto.cs b/modules/admin/src/KonSoft.Admin.Application.Contracts/Dtos/PayOrderDto.cs new file mode 100644 index 0000000..d9128bf --- /dev/null +++ b/modules/admin/src/KonSoft.Admin.Application.Contracts/Dtos/PayOrderDto.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KonSoft.Admin.Dtos +{ + public class PayOrderDto + { + } +} diff --git a/modules/admin/src/KonSoft.Admin.Application.Contracts/IApplicationServices/IOrderAppService.cs b/modules/admin/src/KonSoft.Admin.Application.Contracts/IApplicationServices/IOrderAppService.cs new file mode 100644 index 0000000..6d82e97 --- /dev/null +++ b/modules/admin/src/KonSoft.Admin.Application.Contracts/IApplicationServices/IOrderAppService.cs @@ -0,0 +1,26 @@ +using KonSoft.Admin.Dtos; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; + +namespace KonSoft.Admin.IApplicationServices +{ + public interface IOrderAppService : IApplicationService + { + /// + /// 创建订单 + /// + /// + /// + Task CreateAsync(CreateOrderDto input); + Task PayAsync(Guid orderId, PayOrderDto input); + Task AssignAsync(Guid orderId, Guid workerId); + Task StartServiceAsync(Guid orderId); + Task CompleteServiceAsync(Guid orderId); + Task ConfirmAsync(Guid orderId); + Task CancelAsync(Guid orderId, string reason); + } +} diff --git a/modules/admin/src/KonSoft.Admin.Application/AdminApplicationAutoMapperProfile.cs b/modules/admin/src/KonSoft.Admin.Application/AdminApplicationAutoMapperProfile.cs index 4c9d249..de3045e 100644 --- a/modules/admin/src/KonSoft.Admin.Application/AdminApplicationAutoMapperProfile.cs +++ b/modules/admin/src/KonSoft.Admin.Application/AdminApplicationAutoMapperProfile.cs @@ -1,4 +1,6 @@ using AutoMapper; +using KonSoft.Admin.Dtos; +using KonSoft.Admin.Entities; namespace KonSoft.Admin; @@ -9,5 +11,9 @@ public class AdminApplicationAutoMapperProfile : Profile /* You can configure your AutoMapper mapping configuration here. * Alternatively, you can split your mapping configurations * into multiple profile classes for a better organization. */ + + CreateMap(); + //CreateMap(); + CreateMap(); } } diff --git a/modules/admin/src/KonSoft.Admin.Application/ApplicationServices/OrderAppService.cs b/modules/admin/src/KonSoft.Admin.Application/ApplicationServices/OrderAppService.cs new file mode 100644 index 0000000..238de99 --- /dev/null +++ b/modules/admin/src/KonSoft.Admin.Application/ApplicationServices/OrderAppService.cs @@ -0,0 +1,115 @@ +using KonSoft.Admin.Dtos; +using KonSoft.Admin.Entities; +using KonSoft.Admin.IApplicationServices; +using KonSoft.Admin.Repositories; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; +using Volo.Abp.ObjectMapping; + +namespace KonSoft.Admin.ApplicationServices +{ + public class OrderAppService : ApplicationService, IOrderAppService + { + private readonly IOrderRepository _orderRepository; + + public OrderAppService(IOrderRepository orderRepository) + { + _orderRepository = orderRepository; + } + /// + /// 分配师傅 + /// + /// + /// + /// + /// + public async Task AssignAsync(Guid orderId, Guid workerId) + { + var order = await _orderRepository.GetAsync(o => o.Id == orderId); + order.AssignWorker(workerId); + } + + /// + /// 取消订单 + /// + /// + /// + /// + /// + public async Task CancelAsync(Guid orderId, string reason) + { + var order = await _orderRepository.GetAsync(o => o.Id == orderId); + order.Cancel(reason); + } + /// + /// 完成订单 + /// + /// + /// + /// + public async Task CompleteServiceAsync(Guid orderId) + { + var order = await _orderRepository.GetAsync(o => o.Id == orderId); + order.CompleteService(); + } + /// + /// 确认订单 + /// + /// + /// + /// + public async Task ConfirmAsync(Guid orderId) + { + var order = await _orderRepository.GetAsync(o => o.Id == orderId); + order.ConfirmCompletion(); + } + /// + /// 创建订单 + /// + /// + /// + /// + public async Task CreateAsync(CreateOrderDto input) + { + // 生成订单号 TODO + var orderSN = "SN001"; + var address = ObjectMapper.Map(input.Address); + var order = new Order(Guid.NewGuid(), orderSN, input.CustomerId, input.ServiceId, input.ServiceTime, input.Amount, address, input.Remark); + + await _orderRepository.InsertAsync(order); + return ObjectMapper.Map(order); + } + /// + /// 支付 + /// + /// + /// + /// + /// + public Task PayAsync(Guid orderId, PayOrderDto input) + { + throw new NotImplementedException(); + } + /// + /// 开始订单 + /// + /// + /// + /// + public async Task StartServiceAsync(Guid orderId) + { + var order = await _orderRepository.GetAsync(o => o.Id == orderId); + order.StartService(); + } + + public async Task GetAsync(Guid id) + { + var order = await _orderRepository.GetAsync(o => o.Id == id); + return ObjectMapper.Map(order); + } + } +} diff --git a/modules/admin/src/KonSoft.Admin.Application/KonSoft.Admin.Application.csproj b/modules/admin/src/KonSoft.Admin.Application/KonSoft.Admin.Application.csproj index e7f94a2..f7879a4 100644 --- a/modules/admin/src/KonSoft.Admin.Application/KonSoft.Admin.Application.csproj +++ b/modules/admin/src/KonSoft.Admin.Application/KonSoft.Admin.Application.csproj @@ -6,8 +6,8 @@ KonSoft.Admin - - + + diff --git a/modules/admin/src/KonSoft.Admin.Domain.Shared/Enums/OrderStatus.cs b/modules/admin/src/KonSoft.Admin.Domain.Shared/Enums/OrderStatus.cs new file mode 100644 index 0000000..9689b7b --- /dev/null +++ b/modules/admin/src/KonSoft.Admin.Domain.Shared/Enums/OrderStatus.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KonSoft.Admin.Enums +{ + public enum OrderStatus + { + PendingPayment, // 待支付 + PaidWaitingAssign, // 已支付待派单 + AssignedWaitingService, // 已派单待服务 + InService, // 服务中 + WaitingConfirm, // 待用户确认 + Completed, // 已完成 + Canceled, // 已取消 + Refunding, // 退款中 + Refunded // 已退款 + + } +} diff --git a/modules/admin/src/KonSoft.Admin.Domain/Entities/AddressInfo.cs b/modules/admin/src/KonSoft.Admin.Domain/Entities/AddressInfo.cs new file mode 100644 index 0000000..7c418d4 --- /dev/null +++ b/modules/admin/src/KonSoft.Admin.Domain/Entities/AddressInfo.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Values; + +namespace KonSoft.Admin.Entities +{ + /// + /// 地址 + /// + public class AddressInfo : ValueObject + { + /// + /// 联系人 + /// + public string ContactName { get; private set; } + /// + /// 手机号 + /// + public string ContactPhone { get; private set; } + /// + /// 详细地址 + /// + public string DetailAddress { get; private set; } + /// + /// 城市 + /// + public string City { get; private set; } + /// + /// 区域 + /// + public string District { get; private set; } + + + public AddressInfo() { } + + public AddressInfo(string contactName, string contactPhone, string detailAddress, string city, string district) + { + ContactName = contactName; + ContactPhone = contactPhone; + DetailAddress = detailAddress; + City = city; + District = district; + } + + + protected override IEnumerable GetAtomicValues() + { + yield return ContactName; + yield return ContactPhone; + yield return DetailAddress; + yield return City; + yield return District; + } + + } +} diff --git a/modules/admin/src/KonSoft.Admin.Domain/Entities/Order.cs b/modules/admin/src/KonSoft.Admin.Domain/Entities/Order.cs new file mode 100644 index 0000000..d3ac54a --- /dev/null +++ b/modules/admin/src/KonSoft.Admin.Domain/Entities/Order.cs @@ -0,0 +1,155 @@ +using KonSoft.Admin.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.Identity; + +namespace KonSoft.Admin.Entities +{ + public class Order : FullAuditedAggregateRoot + { + /// + /// 订单编号 + /// + public string OrderSN { get; private set; } + + /// + /// 用户ID + /// + public Guid CustomerId { get; private set; } + /// + /// 家政人员ID + /// + public Guid? WorkerId { get; private set; } + + ///// + ///// 用户ID + ///// + //public virtual IdentityUser Customer { get; private set; } + ///// + ///// 家政人员ID + ///// + //public virtual IdentityUser? Worker { get; private set; } + /// + /// 服务项目ID + /// + public Guid ServiceId { get; private set; } + + /// + /// 服务预约时间 + /// + public DateTime ServiceTime { get; private set; } + + public OrderStatus Status { get; private set; } + + /// + /// 应付金额 + /// + public decimal Amount { get; private set; } + /// + /// 实付金额 + /// + public decimal PaidAmount { get; private set; } + /// + /// 支付方式 + /// + public string PaymentMethod { get; private set; } + /// + /// 地址 + /// + public AddressInfo Address { get; private set; } + + /// + /// 备注 + /// + public string? Remark { get; private set; } + /// + /// 取消原因 + /// + public string? CancelReason { get; private set; } + + protected Order() { } + + + public Order(Guid id, string orderSN, Guid customerId, Guid serviceId, DateTime serviceTime, decimal amount, AddressInfo address, string remark = null) + : base(id) + { + OrderSN = orderSN; + CustomerId = customerId; + ServiceId = serviceId; + ServiceTime = serviceTime; + Amount = amount; + Address = address; + Remark = remark; + Status = OrderStatus.PendingPayment; + } + + + public void MarkPaid(decimal paidAmount, string method) + { + if (Status != OrderStatus.PendingPayment) + throw new InvalidOperationException("订单不在待付款状态"); + + + PaidAmount = paidAmount; + PaymentMethod = method; + Status = OrderStatus.PaidWaitingAssign; + } + + + public void AssignWorker(Guid workerId) + { + if (Status != OrderStatus.PaidWaitingAssign) + throw new InvalidOperationException("订单无法分配师傅"); + + + WorkerId = workerId; + Status = OrderStatus.AssignedWaitingService; + } + + + public void StartService() + { + if (Status != OrderStatus.AssignedWaitingService) + throw new InvalidOperationException("订单无法开始"); + + + Status = OrderStatus.InService; + } + + + public void CompleteService() + { + if (Status != OrderStatus.InService) + throw new InvalidOperationException("订单未开始服务,无法完成"); + + + Status = OrderStatus.WaitingConfirm; + } + + + public void ConfirmCompletion() + { + if (Status != OrderStatus.WaitingConfirm) + throw new InvalidOperationException("订单无法确认"); + + + Status = OrderStatus.Completed; + } + + + public void Cancel(string reason) + { + // 若已完成或退款中则不可取消 + if (Status == OrderStatus.Completed || Status == OrderStatus.Refunding || Status == OrderStatus.Refunded) + throw new InvalidOperationException("订单无法被取消"); + + + CancelReason = reason; + Status = OrderStatus.Canceled; + } + } +} diff --git a/modules/admin/src/KonSoft.Admin.Domain/Repositories/IOrderRepository.cs b/modules/admin/src/KonSoft.Admin.Domain/Repositories/IOrderRepository.cs new file mode 100644 index 0000000..26449f5 --- /dev/null +++ b/modules/admin/src/KonSoft.Admin.Domain/Repositories/IOrderRepository.cs @@ -0,0 +1,14 @@ +using KonSoft.Admin.Entities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace KonSoft.Admin.Repositories +{ + public interface IOrderRepository : IRepository + { + } +} diff --git a/modules/admin/src/KonSoft.Admin.EntityFrameworkCore/EntityFrameworkCore/AdminDbContext.cs b/modules/admin/src/KonSoft.Admin.EntityFrameworkCore/EntityFrameworkCore/AdminDbContext.cs index f78d79f..f916b52 100644 --- a/modules/admin/src/KonSoft.Admin.EntityFrameworkCore/EntityFrameworkCore/AdminDbContext.cs +++ b/modules/admin/src/KonSoft.Admin.EntityFrameworkCore/EntityFrameworkCore/AdminDbContext.cs @@ -1,4 +1,5 @@ -using Microsoft.EntityFrameworkCore; +using KonSoft.Admin.Entities; +using Microsoft.EntityFrameworkCore; using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.BackgroundJobs.EntityFrameworkCore; using Volo.Abp.Data; @@ -53,6 +54,10 @@ public class AdminDbContext : #endregion + #region 订单 + public DbSet Order { get; set; } + #endregion + public AdminDbContext(DbContextOptions options) : base(options) { diff --git a/modules/admin/src/KonSoft.Admin.EntityFrameworkCore/EntityFrameworkCore/Configures/ApplicationDbContextModelBuilderExtensions.cs b/modules/admin/src/KonSoft.Admin.EntityFrameworkCore/EntityFrameworkCore/Configures/ApplicationDbContextModelBuilderExtensions.cs new file mode 100644 index 0000000..030a2fa --- /dev/null +++ b/modules/admin/src/KonSoft.Admin.EntityFrameworkCore/EntityFrameworkCore/Configures/ApplicationDbContextModelBuilderExtensions.cs @@ -0,0 +1,37 @@ +using KonSoft.Admin.Entities; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp; + +namespace KonSoft.Admin.EntityFrameworkCore.Configures +{ + public static class ApplicationDbContextModelBuilderExtensions + { + public static void ConfigureApplication([NotNull] this ModelBuilder builder) + { + Check.NotNull(builder, nameof(builder)); + + builder.Entity(b => + { + b.ToTable(AdminConsts.DbTablePrefix + "Order" + AdminConsts.DbSchema); + + b.OwnsOne(o => o.Address, a => + { + a.Property(p => p.ContactName).HasColumnName("ContactName").HasMaxLength(50); + a.Property(p => p.ContactPhone).HasColumnName("ContactPhone").HasMaxLength(20); + a.Property(p => p.DetailAddress).HasColumnName("DetailAddress").HasMaxLength(200); + a.Property(p => p.City).HasColumnName("City").HasMaxLength(50); + a.Property(p => p.District).HasColumnName("District").HasMaxLength(50); + }); + }); + + } + + + } +} diff --git a/modules/admin/src/KonSoft.Admin.EntityFrameworkCore/EntityFrameworkCore/Repositories/OrderRepository.cs b/modules/admin/src/KonSoft.Admin.EntityFrameworkCore/EntityFrameworkCore/Repositories/OrderRepository.cs new file mode 100644 index 0000000..956a252 --- /dev/null +++ b/modules/admin/src/KonSoft.Admin.EntityFrameworkCore/EntityFrameworkCore/Repositories/OrderRepository.cs @@ -0,0 +1,21 @@ +using KonSoft.Admin.Entities; +using KonSoft.Admin.Repositories; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace KonSoft.Admin.EntityFrameworkCore.Repositories +{ + public class OrderRepository : EfCoreRepository, IOrderRepository + { + public OrderRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } + } +}