feat : add payment , zarinpal gateway
add payment entity , add zarinpal gateway and ready for testrelease
parent
8d8ab5dc8f
commit
879b59f0bd
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||||
|
// Use hover for the description of the existing attributes
|
||||||
|
// For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md.
|
||||||
|
"name": ".NET Core Launch (web)",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
// If you have changed target frameworks, make sure to update the program path.
|
||||||
|
"program": "${workspaceFolder}/NetinaShop.Api/bin/Debug/net8.0/NetinaShop.Api.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}/NetinaShop.Api",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
||||||
|
"serverReadyAction": {
|
||||||
|
"action": "openExternally",
|
||||||
|
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"sourceFileMap": {
|
||||||
|
"/Views": "${workspaceFolder}/Views"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ".NET Core Attach",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "attach"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/NetinaShop.sln",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/NetinaShop.sln",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/NetinaShop.sln"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -51,8 +51,7 @@ public class OrderBagController : ICarterModule
|
||||||
=> TypedResults.Ok(await mediator.Send(new SubmitDiscountCommand(orderId, discountCode), cancellationToken));
|
=> TypedResults.Ok(await mediator.Send(new SubmitDiscountCommand(orderId, discountCode), cancellationToken));
|
||||||
|
|
||||||
public async Task<IResult> AddShippingToOrderBagAsync(Guid orderId, [FromBody] SubmitOrderDeliveryCommand request, IMediator mediator, CancellationToken cancellationToken)
|
public async Task<IResult> AddShippingToOrderBagAsync(Guid orderId, [FromBody] SubmitOrderDeliveryCommand request, IMediator mediator, CancellationToken cancellationToken)
|
||||||
=> TypedResults.Ok(
|
=> TypedResults.Ok( await mediator.Send(new SubmitOrderDeliveryCommand(request.Address, request.PostalCode,
|
||||||
await mediator.Send(new SubmitOrderDeliveryCommand(request.Address, request.PostalCode,
|
|
||||||
request.ReceiverPhoneNumber, request.ReceiverFullName, orderId, request.ShippingId), cancellationToken));
|
request.ReceiverPhoneNumber, request.ReceiverFullName, orderId, request.ShippingId), cancellationToken));
|
||||||
|
|
||||||
public async Task<IResult> SubmitOrderPaymentAsync(Guid orderId, [FromQuery] OrderPaymentMethod paymentMethod, IMediator mediator, CancellationToken cancellationToken)
|
public async Task<IResult> SubmitOrderPaymentAsync(Guid orderId, [FromQuery] OrderPaymentMethod paymentMethod, IMediator mediator, CancellationToken cancellationToken)
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
namespace NetinaShop.Api.Controller;
|
using NetinaShop.Domain.Enums;
|
||||||
|
|
||||||
|
namespace NetinaShop.Api.Controller;
|
||||||
public class OrderController : ICarterModule
|
public class OrderController : ICarterModule
|
||||||
{
|
{
|
||||||
public void AddRoutes(IEndpointRouteBuilder app)
|
public void AddRoutes(IEndpointRouteBuilder app)
|
||||||
|
@ -21,11 +23,14 @@ public class OrderController : ICarterModule
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IResult> GetAllAsync(IMediator mediator, [FromQuery] int page = 0, CancellationToken cancellationToken = default)
|
public async Task<IResult> GetAllAsync(IMediator mediator, [FromQuery]long? selectedDate, [FromQuery] OrderStatus? orderStatus, [FromQuery] OrderQueryDateFilter? dateFilter, [FromQuery] int page = 0, CancellationToken cancellationToken = default)
|
||||||
=> TypedResults.Ok(await mediator.Send(new GetOrdersQuery(page), cancellationToken));
|
=> TypedResults.Ok(await mediator.Send(new GetOrdersQuery(Page:page, SelectedDate: selectedDate, OrderStatus:orderStatus, DateFilter:dateFilter), cancellationToken));
|
||||||
|
|
||||||
public async Task<IResult> GetAsync(IMediator mediator,Guid id, CancellationToken cancellationToken = default)
|
public async Task<IResult> GetAsync(IMediator mediator, Guid id, CancellationToken cancellationToken = default)
|
||||||
=> TypedResults.Ok(await mediator.Send(new GetOrderLDtoQuery(id), cancellationToken));
|
{
|
||||||
|
var order = await mediator.Send(new GetOrderLDtoQuery(id), cancellationToken);
|
||||||
|
return TypedResults.Ok(order);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IResult> DeleteAsync(IMediator mediator, Guid id, CancellationToken cancellationToken = default)
|
public async Task<IResult> DeleteAsync(IMediator mediator, Guid id, CancellationToken cancellationToken = default)
|
||||||
=> TypedResults.Ok(await mediator.Send(new DeleteOrderCommand(id), cancellationToken));
|
=> TypedResults.Ok(await mediator.Send(new DeleteOrderCommand(id), cancellationToken));
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
using TypedResults = Microsoft.AspNetCore.Http.TypedResults;
|
||||||
|
|
||||||
|
namespace NetinaShop.Api.Controller;
|
||||||
|
|
||||||
|
public class PaymentController : ICarterModule
|
||||||
|
{
|
||||||
|
|
||||||
|
public virtual void AddRoutes(IEndpointRouteBuilder app)
|
||||||
|
{
|
||||||
|
var group = app.NewVersionedApi("AccountingPayment")
|
||||||
|
.MapGroup($"api/accounting/pay");
|
||||||
|
|
||||||
|
group.MapGet("", GetAllAsync)
|
||||||
|
.WithDisplayName("GetPayments")
|
||||||
|
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser())
|
||||||
|
.HasApiVersion(1.0);
|
||||||
|
|
||||||
|
//group.MapGet("{id}", GetAsync)
|
||||||
|
// .WithDisplayName("GetShipping")
|
||||||
|
// .RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser())
|
||||||
|
// .HasApiVersion(1.0);
|
||||||
|
|
||||||
|
group.MapGet("verify", VerifyPaymentAsync)
|
||||||
|
.HasApiVersion(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET:Get All Entity
|
||||||
|
public async Task<IResult> GetAllAsync([FromQuery] int page, IMediator mediator, CancellationToken cancellationToken)
|
||||||
|
=> TypedResults.Ok(await mediator.Send(new GetPaymentsQuery(page), cancellationToken));
|
||||||
|
|
||||||
|
// GET:Get An Entity By Id
|
||||||
|
public async Task<IResult> GetAsync(Guid id, IMediator mediator, CancellationToken cancellationToken)
|
||||||
|
=> TypedResults.Ok(await mediator.Send(new GetShippingQuery(id), cancellationToken));
|
||||||
|
|
||||||
|
// POST:Create Entity
|
||||||
|
public async Task<IResult> VerifyPaymentAsync([FromQuery] string Authority, [FromQuery] string Status, IPaymentService paymentService,ILogger<PaymentController> logger, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Status == "OK")
|
||||||
|
{
|
||||||
|
var result = await paymentService.VerifyPaymentAsync(authority: Authority, cancellationToken);
|
||||||
|
return TypedResults.Redirect("");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return TypedResults.Redirect("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e.Message);
|
||||||
|
return TypedResults.Redirect("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ public static class LoggerConfig
|
||||||
o.MinimumEventLevel = LogEventLevel.Error;
|
o.MinimumEventLevel = LogEventLevel.Error;
|
||||||
o.Dsn = "https://592b7fbb29464442a8e996247abe857f@watcher.igarson.app/7";
|
o.Dsn = "https://592b7fbb29464442a8e996247abe857f@watcher.igarson.app/7";
|
||||||
})
|
})
|
||||||
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", Serilog.Events.LogEventLevel.Error)
|
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", Serilog.Events.LogEventLevel.Information)
|
||||||
.CreateLogger();
|
.CreateLogger();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
using System.Security.Cryptography;
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using NetinaShop.Repository.Migrations;
|
using NetinaShop.Repository.Migrations;
|
||||||
|
using Refit;
|
||||||
|
|
||||||
namespace NetinaShop.Api.WebFramework.MiddleWares;
|
namespace NetinaShop.Api.WebFramework.MiddleWares;
|
||||||
|
|
||||||
|
@ -73,7 +75,8 @@ public class ExceptionHandlerMiddleware
|
||||||
{
|
{
|
||||||
message = exception.Message;
|
message = exception.Message;
|
||||||
}
|
}
|
||||||
if(exception.AdditionalData==null)
|
|
||||||
|
if (exception.AdditionalData == null)
|
||||||
await WriteToResponseAsync();
|
await WriteToResponseAsync();
|
||||||
else
|
else
|
||||||
await WriteToResponseWithObjectAsync(exception.AdditionalData);
|
await WriteToResponseWithObjectAsync(exception.AdditionalData);
|
||||||
|
@ -90,7 +93,17 @@ public class ExceptionHandlerMiddleware
|
||||||
SetUnAuthorizeResponse(exception);
|
SetUnAuthorizeResponse(exception);
|
||||||
await WriteToResponseAsync();
|
await WriteToResponseAsync();
|
||||||
}
|
}
|
||||||
|
catch (ApiException apiException)
|
||||||
|
{
|
||||||
|
_logger.LogError(apiException, apiException.Message);
|
||||||
|
|
||||||
|
httpStatusCode = HttpStatusCode.InternalServerError;
|
||||||
|
apiStatusCode = ApiResultStatusCode.RefitError;
|
||||||
|
|
||||||
|
message = apiException.Message;
|
||||||
|
|
||||||
|
await WriteToResponseAsync();
|
||||||
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
_logger.LogError(exception, exception.Message);
|
_logger.LogError(exception, exception.Message);
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace NetinaShop.Core.Abstracts;
|
||||||
|
|
||||||
|
public interface IPaymentService : IScopedDependency
|
||||||
|
{
|
||||||
|
Task<string> GetPaymentLinkAsync(double amount, string factorNumber, Guid orderId, Guid userId, string phoneNumber, string fullName, CancellationToken cancellationToken = default);
|
||||||
|
Task<string> VerifyPaymentAsync(string authority, CancellationToken cancellationToken = default);
|
||||||
|
}
|
|
@ -14,26 +14,45 @@ public class SubmitOrderPaymentCommandHandler : IRequestHandler<SubmitOrderPayme
|
||||||
}
|
}
|
||||||
public async Task<SubmitOrderPaymentResponseDto> Handle(SubmitOrderPaymentCommand request, CancellationToken cancellationToken)
|
public async Task<SubmitOrderPaymentResponseDto> Handle(SubmitOrderPaymentCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var order = await _repositoryWrapper.SetRepository<Order>()
|
await _mediator.Send(new CalculateOrderCommand(request.OrderId, true), cancellationToken);
|
||||||
.TableNoTracking
|
|
||||||
.FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken);
|
|
||||||
|
|
||||||
if (order == null)
|
var orderSDto = await _repositoryWrapper.SetRepository<Order>()
|
||||||
|
.TableNoTracking
|
||||||
|
.Where(o => o.Id == request.OrderId)
|
||||||
|
.Select(OrderMapper.ProjectToSDto)
|
||||||
|
.FirstOrDefaultAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (orderSDto == null)
|
||||||
throw new AppException("Order not found", ApiResultStatusCode.NotFound);
|
throw new AppException("Order not found", ApiResultStatusCode.NotFound);
|
||||||
|
|
||||||
|
var order = orderSDto.AdaptToOrder();
|
||||||
|
|
||||||
var response = new SubmitOrderPaymentResponseDto();
|
var response = new SubmitOrderPaymentResponseDto();
|
||||||
|
|
||||||
if (request.PaymentMethod == OrderPaymentMethod.OnlinePayment)
|
if (request.PaymentMethod == OrderPaymentMethod.OnlinePayment)
|
||||||
{
|
{
|
||||||
response.NeedToPayOnline = true;
|
if (request.HasPaid)
|
||||||
response.PaymentUrl = await _paymentService.GetPaymentLinkAsync(order.Id, order.TotalPrice, $"پرداخت سفارش {order.Id}");
|
{
|
||||||
|
response.NeedToPayOnline = false;
|
||||||
|
order.SetSubmitOrder(request.PaymentMethod);
|
||||||
}
|
}
|
||||||
else if (request.PaymentMethod == OrderPaymentMethod.Cash)
|
else
|
||||||
|
{
|
||||||
|
response.NeedToPayOnline = true;
|
||||||
|
response.PaymentUrl = await _paymentService.GetPaymentLinkAsync(orderSDto.TotalPrice, orderSDto.FactorCode, orderSDto.Id, orderSDto.UserId, orderSDto.UserPhoneNumber, orderSDto.UserFullName, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (request.PaymentMethod == OrderPaymentMethod.PayOnDoor)
|
||||||
{
|
{
|
||||||
response.NeedToPayOnline = false;
|
response.NeedToPayOnline = false;
|
||||||
order.SetSubmitOrder(request.PaymentMethod);
|
order.SetSubmitOrder(request.PaymentMethod);
|
||||||
_repositoryWrapper.SetRepository<Order>().Update(order);
|
_repositoryWrapper.SetRepository<Order>().Update(order);
|
||||||
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
await _mediator.Send(new CreatePaymentCommand(order.FactorCode, order.TotalPrice,
|
||||||
|
$"پرداخت نقدی سفارش {order.FactorCode}", string.Empty, string.Empty, string.Empty,
|
||||||
|
PaymentType.PayOnDoor, PaymentStatus.Paid, order.Id
|
||||||
|
, order.UserId), cancellationToken);
|
||||||
}
|
}
|
||||||
else if (request.PaymentMethod == OrderPaymentMethod.CardTransfer)
|
else if (request.PaymentMethod == OrderPaymentMethod.CardTransfer)
|
||||||
{
|
{
|
||||||
|
@ -41,6 +60,11 @@ public class SubmitOrderPaymentCommandHandler : IRequestHandler<SubmitOrderPayme
|
||||||
order.SetSubmitOrder(request.PaymentMethod);
|
order.SetSubmitOrder(request.PaymentMethod);
|
||||||
_repositoryWrapper.SetRepository<Order>().Update(order);
|
_repositoryWrapper.SetRepository<Order>().Update(order);
|
||||||
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
await _mediator.Send(new CreatePaymentCommand(order.FactorCode, order.TotalPrice,
|
||||||
|
$"پرداخت نقدی سفارش {order.FactorCode}", string.Empty, string.Empty, string.Empty,
|
||||||
|
PaymentType.CardTransfer, PaymentStatus.Paid, order.Id
|
||||||
|
, order.UserId), cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
|
|
@ -10,5 +10,5 @@ public sealed record RemoveFromOrderBagCommand(List<OrderBagRequestDto> RequestD
|
||||||
public sealed record SubmitDiscountCommand(Guid OrderId,string DiscountCode) : IRequest<bool>;
|
public sealed record SubmitDiscountCommand(Guid OrderId,string DiscountCode) : IRequest<bool>;
|
||||||
public sealed record SubmitOrderDeliveryCommand(string Address, string PostalCode, string ReceiverPhoneNumber, string ReceiverFullName, Guid OrderId, Guid ShippingId) : IRequest<bool>;
|
public sealed record SubmitOrderDeliveryCommand(string Address, string PostalCode, string ReceiverPhoneNumber, string ReceiverFullName, Guid OrderId, Guid ShippingId) : IRequest<bool>;
|
||||||
|
|
||||||
public sealed record SubmitOrderPaymentCommand(Guid OrderId, OrderPaymentMethod PaymentMethod) : IRequest<SubmitOrderPaymentResponseDto>;
|
public sealed record SubmitOrderPaymentCommand(Guid OrderId, OrderPaymentMethod PaymentMethod , bool HasPaid = false) : IRequest<SubmitOrderPaymentResponseDto>;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
namespace NetinaShop.Domain.CommandQueries.Commands;
|
||||||
|
|
||||||
|
public sealed record CreatePaymentCommand(string FactorNumber, double Amount, string Description, string TransactionCode, string CardPan, string Authority, PaymentType Type, PaymentStatus Status, Guid OrderId, Guid UserId) : IRequest<bool>;
|
||||||
|
public sealed record UpdatePaymentCommand(Guid Id,string FactorNumber, double Amount, string Description, string TransactionCode, string CardPan, string Authority, PaymentType Type, PaymentStatus Status, Guid OrderId, Guid UserId) : IRequest<bool>;
|
|
@ -3,4 +3,4 @@
|
||||||
public sealed record GetOrderLDtoQuery(Guid Id) : IRequest<OrderLDto>;
|
public sealed record GetOrderLDtoQuery(Guid Id) : IRequest<OrderLDto>;
|
||||||
|
|
||||||
public sealed record GetOrderQuery(Guid Id) : IRequest<Order>;
|
public sealed record GetOrderQuery(Guid Id) : IRequest<Order>;
|
||||||
public sealed record GetOrdersQuery(int Page = 0) : IRequest<List<OrderSDto>>;
|
public sealed record GetOrdersQuery(OrderQueryDateFilter? DateFilter, OrderStatus? OrderStatus,long? SelectedDate, int Page = 0) : IRequest<List<OrderSDto>>;
|
|
@ -0,0 +1,4 @@
|
||||||
|
namespace NetinaShop.Domain.CommandQueries.Queries;
|
||||||
|
|
||||||
|
public sealed record GetPaymentQuery(Guid Id = default , string? Authority = null) : IRequest<PaymentSDto>;
|
||||||
|
public sealed record GetPaymentsQuery(int Page = 0) : IRequest<List<PaymentSDto>>;
|
|
@ -1,6 +1,7 @@
|
||||||
namespace NetinaShop.Domain.Dtos.LargDtos;
|
namespace NetinaShop.Domain.Dtos.LargDtos;
|
||||||
public class OrderLDto : BaseDto<OrderLDto,Order>
|
public class OrderLDto : BaseDto<OrderLDto,Order>
|
||||||
{
|
{
|
||||||
|
public string FactorCode { get; set; } = string.Empty;
|
||||||
public long TotalPrice { get; set; }
|
public long TotalPrice { get; set; }
|
||||||
public long DeliveryPrice { get; set; }
|
public long DeliveryPrice { get; set; }
|
||||||
public long TaxesPrice { get; set; }
|
public long TaxesPrice { get; set; }
|
||||||
|
@ -14,9 +15,25 @@ public class OrderLDto : BaseDto<OrderLDto,Order>
|
||||||
public DateTime OrderAt { get; set; }
|
public DateTime OrderAt { get; set; }
|
||||||
public int PreparingMinute { get; set; }
|
public int PreparingMinute { get; set; }
|
||||||
public string DiscountCode { get; set; } = string.Empty;
|
public string DiscountCode { get; set; } = string.Empty;
|
||||||
|
public long TotalPriceWithoutDiscount => TotalPrice + DiscountPrice;
|
||||||
|
|
||||||
public List<OrderProductSDto> OrderProducts { get; internal set; } = new();
|
public string UserFullName { get; set; } = string.Empty;
|
||||||
|
public string UserPhoneNumber { get; set; } = string.Empty;
|
||||||
|
|
||||||
public List<OrderDeliverySDto> OrderDeliveries { get; internal set; } = new();
|
public List<OrderProductSDto> OrderProducts { get; set; } = new();
|
||||||
|
|
||||||
|
public List<OrderDeliverySDto> OrderDeliveries { get; set; } = new();
|
||||||
|
|
||||||
|
public List<PaymentSDto> Payments { get; set; } = new();
|
||||||
|
|
||||||
|
public OrderDeliverySDto OrderDelivery
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (OrderDeliveries.Count > 0)
|
||||||
|
return OrderDeliveries.FirstOrDefault() ?? new OrderDeliverySDto();
|
||||||
|
return new OrderDeliverySDto();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ public class OrderDeliverySDto : BaseDto<OrderDeliverySDto, OrderDelivery>
|
||||||
public string PostalCode { get; set; } = string.Empty;
|
public string PostalCode { get; set; } = string.Empty;
|
||||||
public string ReceiverPhoneNumber { get; set; } = string.Empty;
|
public string ReceiverPhoneNumber { get; set; } = string.Empty;
|
||||||
public string ReceiverFullName { get; set; } = string.Empty;
|
public string ReceiverFullName { get; set; } = string.Empty;
|
||||||
|
public string ShippingMethod { get; set; } = string.Empty;
|
||||||
public Guid OrderId { get; set; }
|
public Guid OrderId { get; set; }
|
||||||
public Guid ShippingId { get; internal set; }
|
public Guid ShippingId { get; internal set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,17 @@
|
||||||
|
|
||||||
public class OrderProductSDto : BaseDto<OrderProductSDto, OrderProduct>
|
public class OrderProductSDto : BaseDto<OrderProductSDto, OrderProduct>
|
||||||
{
|
{
|
||||||
public int Count { get; internal set; }
|
public int Count { get; set; }
|
||||||
public float ProductFee { get; internal set; }
|
public double ProductFee { get; set; }
|
||||||
public float ProductCost { get; internal set; }
|
public double ProductFeeWithDiscount { get; set; }
|
||||||
public OrderStatus OrderProductStatus { get; internal set; }
|
public bool HasDiscount { get; set; }
|
||||||
|
public double ProductCost { get; set; }
|
||||||
|
public double PackingFee { get; set; }
|
||||||
|
public double PackingCost { get; set; }
|
||||||
|
public OrderStatus OrderProductStatus { get; set; }
|
||||||
|
|
||||||
public Guid ProductId { get; internal set; }
|
public Guid ProductId { get; set; }
|
||||||
|
public string ProductName { get; set; } = string.Empty;
|
||||||
public Guid OrderId { get; internal set; }
|
public Guid OrderId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,22 @@
|
||||||
namespace NetinaShop.Domain.Dtos.SmallDtos;
|
namespace NetinaShop.Domain.Dtos.SmallDtos;
|
||||||
public class OrderSDto : BaseDto<OrderSDto, Order>
|
public class OrderSDto : BaseDto<OrderSDto, Order>
|
||||||
{
|
{
|
||||||
public long TotalPrice { get; set; }
|
public double TotalPrice { get; set; }
|
||||||
public long DeliveryPrice { get; set; }
|
public string FactorCode { get; set; } = string.Empty;
|
||||||
public long TaxesPrice { get; set; }
|
public double DeliveryPrice { get; set; }
|
||||||
public long ServicePrice { get; set; }
|
public double TaxesPrice { get; set; }
|
||||||
public long PackingPrice { get; set; }
|
public double ServicePrice { get; set; }
|
||||||
public long TotalProductsPrice { get; set; }
|
public double PackingPrice { get; set; }
|
||||||
public long DiscountPrice { get; set; }
|
public double TotalProductsPrice { get; set; }
|
||||||
|
public double DiscountPrice { get; set; }
|
||||||
public bool IsPayed { get; set; }
|
public bool IsPayed { get; set; }
|
||||||
public OrderStatus OrderStatus { get; set; }
|
public OrderStatus OrderStatus { get; set; }
|
||||||
|
public DateTime PayedAt { get; set; }
|
||||||
public DateTime DoneAt { get; set; }
|
public DateTime DoneAt { get; set; }
|
||||||
public DateTime OrderAt { get; set; }
|
public DateTime OrderAt { get; set; }
|
||||||
public int PreparingMinute { get; set; }
|
public int PreparingMinute { get; set; }
|
||||||
public string DiscountCode { get; set; } = string.Empty;
|
public string DiscountCode { get; set; } = string.Empty;
|
||||||
|
public string UserFullName { get; set; } = string.Empty;
|
||||||
|
public string UserPhoneNumber { get; set; } = string.Empty;
|
||||||
|
public Guid UserId { get; internal set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
using NetinaShop.Domain.Entities.Accounting;
|
||||||
|
|
||||||
|
namespace NetinaShop.Domain.Dtos.SmallDtos;
|
||||||
|
|
||||||
|
public class PaymentSDto : BaseDto<PaymentSDto,Payment>
|
||||||
|
{
|
||||||
|
public string FactorNumber { get; set; } = string.Empty;
|
||||||
|
public double Amount { get; set; }
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
public string TransactionCode { get; set; } = string.Empty;
|
||||||
|
public string CardPan { get; set; } = string.Empty;
|
||||||
|
public string Authority { get; set; } = string.Empty;
|
||||||
|
public PaymentType Type { get; set; }
|
||||||
|
public PaymentStatus Status { get; set; }
|
||||||
|
|
||||||
|
public Guid OrderId { get; set; }
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
public string UserFullName { get; set; } = string.Empty;
|
||||||
|
public string UserPhoneNumber { get; set; } = string.Empty;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace NetinaShop.Domain.Entities.Accounting;
|
||||||
|
|
||||||
|
public partial class Payment
|
||||||
|
{
|
||||||
|
public static Payment Create(string factorNumber, double amount, string description, string transactionCode, string cardPan, string authority, PaymentType type, PaymentStatus status, Guid orderId, Guid userId)
|
||||||
|
{
|
||||||
|
return new Payment(factorNumber, amount, description, transactionCode, cardPan, authority, type, status, orderId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ChangeStatus(PaymentStatus status, string? cardPan = null)
|
||||||
|
{
|
||||||
|
this.Status = status;
|
||||||
|
if (status != PaymentStatus.Paid && cardPan != null)
|
||||||
|
CardPan = cardPan;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
namespace NetinaShop.Domain.Entities.Accounting;
|
||||||
|
|
||||||
|
[AdaptTwoWays("[name]LDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Map | MapType.MapToTarget | MapType.Projection)]
|
||||||
|
[AdaptTwoWays("[name]SDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Map | MapType.MapToTarget)]
|
||||||
|
[AdaptTo("[name]SDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Projection)]
|
||||||
|
[GenerateMapper]
|
||||||
|
|
||||||
|
public partial class Payment : ApiEntity
|
||||||
|
{
|
||||||
|
public Payment()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public Payment(string factorNumber, double amount, string description, string transactionCode, string cardPan, string authority, PaymentType type, PaymentStatus status, Guid orderId, Guid userId)
|
||||||
|
{
|
||||||
|
FactorNumber = factorNumber;
|
||||||
|
Amount = amount;
|
||||||
|
Description = description;
|
||||||
|
TransactionCode = transactionCode;
|
||||||
|
CardPan = cardPan;
|
||||||
|
Authority = authority;
|
||||||
|
Type = type;
|
||||||
|
Status = status;
|
||||||
|
OrderId = orderId;
|
||||||
|
UserId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FactorNumber { get; internal set; } = string.Empty;
|
||||||
|
public double Amount { get; internal set; }
|
||||||
|
public string Description { get; internal set; } = string.Empty;
|
||||||
|
public string TransactionCode { get; internal set; } = string.Empty;
|
||||||
|
public string CardPan { get; internal set; } = string.Empty;
|
||||||
|
public string Authority { get; internal set; } = string.Empty;
|
||||||
|
public PaymentType Type { get; internal set; }
|
||||||
|
public PaymentStatus Status { get; internal set; }
|
||||||
|
|
||||||
|
public Guid OrderId { get; internal set; }
|
||||||
|
public Order? Order { get; internal set; }
|
||||||
|
public Guid UserId { get; internal set; }
|
||||||
|
public ApplicationUser? User { get; internal set; }
|
||||||
|
}
|
|
@ -4,7 +4,8 @@ public partial class Order
|
||||||
{
|
{
|
||||||
public static Order Create(Guid userId)
|
public static Order Create(Guid userId)
|
||||||
{
|
{
|
||||||
return new Order(0, 0, 0, 0, 0, 0, 0, false, OrderStatus.OrderBag, DateTime.MinValue, DateTime.MinValue, 0, string.Empty, userId, OrderPaymentMethod.OnlinePayment);
|
var factorNumber = StringExtensions.GetId(10).ToUpper();
|
||||||
|
return new Order(factorNumber, 0, 0, 0, 0, 0, 0, 0, false, OrderStatus.OrderBag, DateTime.MinValue, DateTime.Now, 0, string.Empty, userId, OrderPaymentMethod.OnlinePayment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ public partial class Order
|
||||||
OrderAt = DateTime.Now;
|
OrderAt = DateTime.Now;
|
||||||
PaymentMethod = paymentMethod;
|
PaymentMethod = paymentMethod;
|
||||||
break;
|
break;
|
||||||
case OrderPaymentMethod.Cash:
|
case OrderPaymentMethod.PayOnDoor:
|
||||||
OrderStatus = OrderStatus.Submitted;
|
OrderStatus = OrderStatus.Submitted;
|
||||||
IsPayed = false;
|
IsPayed = false;
|
||||||
OrderAt = DateTime.Now;
|
OrderAt = DateTime.Now;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
namespace NetinaShop.Domain.Entities.Orders;
|
using NetinaShop.Domain.Entities.Accounting;
|
||||||
|
|
||||||
|
namespace NetinaShop.Domain.Entities.Orders;
|
||||||
|
|
||||||
[AdaptTwoWays("[name]LDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Map | MapType.MapToTarget | MapType.Projection)]
|
[AdaptTwoWays("[name]LDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Map | MapType.MapToTarget | MapType.Projection)]
|
||||||
[AdaptTwoWays("[name]SDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Map | MapType.MapToTarget)]
|
[AdaptTwoWays("[name]SDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Map | MapType.MapToTarget)]
|
||||||
|
@ -12,6 +14,7 @@ public partial class Order : ApiEntity
|
||||||
|
|
||||||
}
|
}
|
||||||
public Order(
|
public Order(
|
||||||
|
string factorCode,
|
||||||
double totalPrice,
|
double totalPrice,
|
||||||
double deliveryPrice,
|
double deliveryPrice,
|
||||||
double taxesPrice,
|
double taxesPrice,
|
||||||
|
@ -19,8 +22,16 @@ public partial class Order : ApiEntity
|
||||||
double packingPrice,
|
double packingPrice,
|
||||||
double totalProductsPrice,
|
double totalProductsPrice,
|
||||||
double discountPrice,
|
double discountPrice,
|
||||||
bool isPayed, OrderStatus orderStatus, DateTime doneAt, DateTime orderAt, int preparingMinute, string discountCode, Guid userId, OrderPaymentMethod paymentMethod)
|
bool isPayed,
|
||||||
|
OrderStatus orderStatus,
|
||||||
|
DateTime doneAt,
|
||||||
|
DateTime orderAt,
|
||||||
|
int preparingMinute,
|
||||||
|
string discountCode,
|
||||||
|
Guid userId,
|
||||||
|
OrderPaymentMethod paymentMethod)
|
||||||
{
|
{
|
||||||
|
FactorCode = factorCode;
|
||||||
TotalPrice = totalPrice;
|
TotalPrice = totalPrice;
|
||||||
DeliveryPrice = deliveryPrice;
|
DeliveryPrice = deliveryPrice;
|
||||||
TaxesPrice = taxesPrice;
|
TaxesPrice = taxesPrice;
|
||||||
|
@ -38,6 +49,7 @@ public partial class Order : ApiEntity
|
||||||
PaymentMethod = paymentMethod;
|
PaymentMethod = paymentMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string FactorCode { get; internal set; } = string.Empty;
|
||||||
public double TotalProductsPrice { get; internal set; }
|
public double TotalProductsPrice { get; internal set; }
|
||||||
public double PackingPrice { get; internal set; }
|
public double PackingPrice { get; internal set; }
|
||||||
public double ServicePrice { get; internal set; }
|
public double ServicePrice { get; internal set; }
|
||||||
|
@ -60,4 +72,6 @@ public partial class Order : ApiEntity
|
||||||
public List<OrderProduct> OrderProducts { get; internal set; } = new();
|
public List<OrderProduct> OrderProducts { get; internal set; } = new();
|
||||||
|
|
||||||
public List<OrderDelivery> OrderDeliveries { get; internal set; } = new();
|
public List<OrderDelivery> OrderDeliveries { get; internal set; } = new();
|
||||||
|
|
||||||
|
public List<Payment> Payments { get; internal set; } = new();
|
||||||
}
|
}
|
|
@ -1,5 +1,8 @@
|
||||||
namespace NetinaShop.Domain.Entities.Orders;
|
namespace NetinaShop.Domain.Entities.Orders;
|
||||||
|
|
||||||
|
[AdaptTwoWays("[name]SDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Map | MapType.MapToTarget)]
|
||||||
|
[AdaptTo("[name]SDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Projection)]
|
||||||
|
[GenerateMapper]
|
||||||
public partial class OrderProduct : ApiEntity
|
public partial class OrderProduct : ApiEntity
|
||||||
{
|
{
|
||||||
public OrderProduct()
|
public OrderProduct()
|
||||||
|
@ -32,8 +35,8 @@ public partial class OrderProduct : ApiEntity
|
||||||
}
|
}
|
||||||
public int Count { get; internal set; }
|
public int Count { get; internal set; }
|
||||||
public double ProductFee { get; internal set; }
|
public double ProductFee { get; internal set; }
|
||||||
public double ProductFeeWithDiscount { get; set; }
|
public double ProductFeeWithDiscount { get; internal set; }
|
||||||
public bool HasDiscount { get; set; }
|
public bool HasDiscount { get; internal set; }
|
||||||
public double ProductCost { get; internal set; }
|
public double ProductCost { get; internal set; }
|
||||||
public double PackingFee { get; internal set; }
|
public double PackingFee { get; internal set; }
|
||||||
public double PackingCost { get; internal set; }
|
public double PackingCost { get; internal set; }
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
public enum OrderPaymentMethod
|
public enum OrderPaymentMethod
|
||||||
{
|
{
|
||||||
[Display(Name = "پرداخت درب محل")]
|
[Display(Name = "پرداخت درب محل")]
|
||||||
Cash,
|
PayOnDoor,
|
||||||
[Display(Name = "پرداخت انلاین")]
|
[Display(Name = "پرداخت انلاین")]
|
||||||
OnlinePayment,
|
OnlinePayment,
|
||||||
[Display(Name = "پرداخت کارت به کارت")]
|
[Display(Name = "پرداخت کارت به کارت")]
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace NetinaShop.Domain.Enums;
|
||||||
|
|
||||||
|
public enum OrderQueryDateFilter
|
||||||
|
{
|
||||||
|
[Display(Name = "امروز")]
|
||||||
|
Today = 0,
|
||||||
|
[Display(Name = "هفته اخیر")]
|
||||||
|
ThisWeek = 1,
|
||||||
|
[Display(Name = "یک ماه اخیر")]
|
||||||
|
ThisMonth = 2,
|
||||||
|
[Display(Name = "تاریخ خاص")]
|
||||||
|
CustomDate = 3,
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace NetinaShop.Domain.Enums;
|
||||||
|
|
||||||
|
public enum PaymentStatus
|
||||||
|
{
|
||||||
|
[Display(Name = "در انتظار پرداخت درگاه")]
|
||||||
|
InPaymentGateway = 0,
|
||||||
|
[Display(Name = "در انتظار پرداخت")]
|
||||||
|
NotPaidYet = 1,
|
||||||
|
[Display(Name = "پرداخت شده")]
|
||||||
|
Paid = 200,
|
||||||
|
[Display(Name = "کنسل شده")]
|
||||||
|
Cancel = 500
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace NetinaShop.Domain.Enums;
|
||||||
|
|
||||||
|
public enum PaymentType
|
||||||
|
{
|
||||||
|
[Display(Name = "نقدی")]
|
||||||
|
Cash,
|
||||||
|
[Display(Name = "کارت به کارت")]
|
||||||
|
CardTransfer,
|
||||||
|
[Display(Name = "آنلاین")]
|
||||||
|
Online,
|
||||||
|
[Display(Name = "در محل")]
|
||||||
|
PayOnDoor
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,140 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using Mapster.Models;
|
||||||
|
using NetinaShop.Domain.Dtos.SmallDtos;
|
||||||
|
using NetinaShop.Domain.Entities.Orders;
|
||||||
|
using NetinaShop.Domain.Entities.Products;
|
||||||
|
|
||||||
|
namespace NetinaShop.Domain.Mappers
|
||||||
|
{
|
||||||
|
public static partial class OrderProductMapper
|
||||||
|
{
|
||||||
|
public static OrderProduct AdaptToOrderProduct(this OrderProductSDto p1)
|
||||||
|
{
|
||||||
|
return p1 == null ? null : new OrderProduct()
|
||||||
|
{
|
||||||
|
Count = p1.Count,
|
||||||
|
ProductFee = p1.ProductFee,
|
||||||
|
ProductFeeWithDiscount = p1.ProductFeeWithDiscount,
|
||||||
|
HasDiscount = p1.HasDiscount,
|
||||||
|
ProductCost = p1.ProductCost,
|
||||||
|
PackingFee = p1.PackingFee,
|
||||||
|
PackingCost = p1.PackingCost,
|
||||||
|
OrderProductStatus = p1.OrderProductStatus,
|
||||||
|
ProductId = p1.ProductId,
|
||||||
|
Product = new Product()
|
||||||
|
{
|
||||||
|
Cost = p1.ProductCost,
|
||||||
|
Id = p1.ProductId
|
||||||
|
},
|
||||||
|
OrderId = p1.OrderId,
|
||||||
|
Order = new Order() {Id = p1.OrderId},
|
||||||
|
Id = p1.Id,
|
||||||
|
CreatedAt = p1.CreatedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static OrderProduct AdaptTo(this OrderProductSDto p2, OrderProduct p3)
|
||||||
|
{
|
||||||
|
if (p2 == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
OrderProduct result = p3 ?? new OrderProduct();
|
||||||
|
|
||||||
|
result.Count = p2.Count;
|
||||||
|
result.ProductFee = p2.ProductFee;
|
||||||
|
result.ProductFeeWithDiscount = p2.ProductFeeWithDiscount;
|
||||||
|
result.HasDiscount = p2.HasDiscount;
|
||||||
|
result.ProductCost = p2.ProductCost;
|
||||||
|
result.PackingFee = p2.PackingFee;
|
||||||
|
result.PackingCost = p2.PackingCost;
|
||||||
|
result.OrderProductStatus = p2.OrderProductStatus;
|
||||||
|
result.ProductId = p2.ProductId;
|
||||||
|
result.Product = funcMain1(new Never(), result.Product, p2);
|
||||||
|
result.OrderId = p2.OrderId;
|
||||||
|
result.Order = funcMain2(new Never(), result.Order, p2);
|
||||||
|
result.Id = p2.Id;
|
||||||
|
result.CreatedAt = p2.CreatedAt;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
public static OrderProductSDto AdaptToSDto(this OrderProduct p8)
|
||||||
|
{
|
||||||
|
return p8 == null ? null : new OrderProductSDto()
|
||||||
|
{
|
||||||
|
Count = p8.Count,
|
||||||
|
ProductFee = p8.ProductFee,
|
||||||
|
ProductFeeWithDiscount = p8.ProductFeeWithDiscount,
|
||||||
|
HasDiscount = p8.HasDiscount,
|
||||||
|
ProductCost = p8.ProductCost,
|
||||||
|
PackingFee = p8.PackingFee,
|
||||||
|
PackingCost = p8.PackingCost,
|
||||||
|
OrderProductStatus = p8.OrderProductStatus,
|
||||||
|
ProductId = p8.ProductId,
|
||||||
|
ProductName = p8.Product != null ? p8.Product.PersianName : string.Empty,
|
||||||
|
OrderId = p8.OrderId,
|
||||||
|
Id = p8.Id,
|
||||||
|
CreatedAt = p8.CreatedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static OrderProductSDto AdaptTo(this OrderProduct p9, OrderProductSDto p10)
|
||||||
|
{
|
||||||
|
if (p9 == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
OrderProductSDto result = p10 ?? new OrderProductSDto();
|
||||||
|
|
||||||
|
result.Count = p9.Count;
|
||||||
|
result.ProductFee = p9.ProductFee;
|
||||||
|
result.ProductFeeWithDiscount = p9.ProductFeeWithDiscount;
|
||||||
|
result.HasDiscount = p9.HasDiscount;
|
||||||
|
result.ProductCost = p9.ProductCost;
|
||||||
|
result.PackingFee = p9.PackingFee;
|
||||||
|
result.PackingCost = p9.PackingCost;
|
||||||
|
result.OrderProductStatus = p9.OrderProductStatus;
|
||||||
|
result.ProductId = p9.ProductId;
|
||||||
|
result.ProductName = p9.Product != null ? p9.Product.PersianName : string.Empty;
|
||||||
|
result.OrderId = p9.OrderId;
|
||||||
|
result.Id = p9.Id;
|
||||||
|
result.CreatedAt = p9.CreatedAt;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
public static Expression<Func<OrderProduct, OrderProductSDto>> ProjectToSDto => p11 => new OrderProductSDto()
|
||||||
|
{
|
||||||
|
Count = p11.Count,
|
||||||
|
ProductFee = p11.ProductFee,
|
||||||
|
ProductFeeWithDiscount = p11.ProductFeeWithDiscount,
|
||||||
|
HasDiscount = p11.HasDiscount,
|
||||||
|
ProductCost = p11.ProductCost,
|
||||||
|
PackingFee = p11.PackingFee,
|
||||||
|
PackingCost = p11.PackingCost,
|
||||||
|
OrderProductStatus = p11.OrderProductStatus,
|
||||||
|
ProductId = p11.ProductId,
|
||||||
|
ProductName = p11.Product != null ? p11.Product.PersianName : string.Empty,
|
||||||
|
OrderId = p11.OrderId,
|
||||||
|
Id = p11.Id,
|
||||||
|
CreatedAt = p11.CreatedAt
|
||||||
|
};
|
||||||
|
|
||||||
|
private static Product funcMain1(Never p4, Product p5, OrderProductSDto p2)
|
||||||
|
{
|
||||||
|
Product result = p5 ?? new Product();
|
||||||
|
|
||||||
|
result.Cost = p2.ProductCost;
|
||||||
|
result.Id = p2.ProductId;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Order funcMain2(Never p6, Order p7, OrderProductSDto p2)
|
||||||
|
{
|
||||||
|
Order result = p7 ?? new Order();
|
||||||
|
|
||||||
|
result.Id = p2.OrderId;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,144 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using Mapster.Models;
|
||||||
|
using NetinaShop.Domain.Dtos.SmallDtos;
|
||||||
|
using NetinaShop.Domain.Entities.Accounting;
|
||||||
|
using NetinaShop.Domain.Entities.Orders;
|
||||||
|
using NetinaShop.Domain.Entities.Users;
|
||||||
|
|
||||||
|
namespace NetinaShop.Domain.Mappers
|
||||||
|
{
|
||||||
|
public static partial class PaymentMapper
|
||||||
|
{
|
||||||
|
public static Payment AdaptToPayment(this PaymentSDto p1)
|
||||||
|
{
|
||||||
|
return p1 == null ? null : new Payment()
|
||||||
|
{
|
||||||
|
FactorNumber = p1.FactorNumber,
|
||||||
|
Amount = p1.Amount,
|
||||||
|
Description = p1.Description,
|
||||||
|
TransactionCode = p1.TransactionCode,
|
||||||
|
CardPan = p1.CardPan,
|
||||||
|
Authority = p1.Authority,
|
||||||
|
Type = p1.Type,
|
||||||
|
Status = p1.Status,
|
||||||
|
OrderId = p1.OrderId,
|
||||||
|
Order = new Order() {Id = p1.OrderId},
|
||||||
|
UserId = p1.UserId,
|
||||||
|
User = new ApplicationUser()
|
||||||
|
{
|
||||||
|
Id = p1.UserId,
|
||||||
|
PhoneNumber = p1.UserPhoneNumber
|
||||||
|
},
|
||||||
|
Id = p1.Id,
|
||||||
|
CreatedAt = p1.CreatedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static Payment AdaptTo(this PaymentSDto p2, Payment p3)
|
||||||
|
{
|
||||||
|
if (p2 == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Payment result = p3 ?? new Payment();
|
||||||
|
|
||||||
|
result.FactorNumber = p2.FactorNumber;
|
||||||
|
result.Amount = p2.Amount;
|
||||||
|
result.Description = p2.Description;
|
||||||
|
result.TransactionCode = p2.TransactionCode;
|
||||||
|
result.CardPan = p2.CardPan;
|
||||||
|
result.Authority = p2.Authority;
|
||||||
|
result.Type = p2.Type;
|
||||||
|
result.Status = p2.Status;
|
||||||
|
result.OrderId = p2.OrderId;
|
||||||
|
result.Order = funcMain1(new Never(), result.Order, p2);
|
||||||
|
result.UserId = p2.UserId;
|
||||||
|
result.User = funcMain2(new Never(), result.User, p2);
|
||||||
|
result.Id = p2.Id;
|
||||||
|
result.CreatedAt = p2.CreatedAt;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
public static PaymentSDto AdaptToSDto(this Payment p8)
|
||||||
|
{
|
||||||
|
return p8 == null ? null : new PaymentSDto()
|
||||||
|
{
|
||||||
|
FactorNumber = p8.FactorNumber,
|
||||||
|
Amount = p8.Amount,
|
||||||
|
Description = p8.Description,
|
||||||
|
TransactionCode = p8.TransactionCode,
|
||||||
|
CardPan = p8.CardPan,
|
||||||
|
Authority = p8.Authority,
|
||||||
|
Type = p8.Type,
|
||||||
|
Status = p8.Status,
|
||||||
|
OrderId = p8.OrderId,
|
||||||
|
UserId = p8.UserId,
|
||||||
|
UserFullName = p8.User != null ? p8.User.FirstName + " " + p8.User.LastName : string.Empty,
|
||||||
|
UserPhoneNumber = p8.User != null ? p8.User.PhoneNumber : string.Empty,
|
||||||
|
Id = p8.Id,
|
||||||
|
CreatedAt = p8.CreatedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static PaymentSDto AdaptTo(this Payment p9, PaymentSDto p10)
|
||||||
|
{
|
||||||
|
if (p9 == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PaymentSDto result = p10 ?? new PaymentSDto();
|
||||||
|
|
||||||
|
result.FactorNumber = p9.FactorNumber;
|
||||||
|
result.Amount = p9.Amount;
|
||||||
|
result.Description = p9.Description;
|
||||||
|
result.TransactionCode = p9.TransactionCode;
|
||||||
|
result.CardPan = p9.CardPan;
|
||||||
|
result.Authority = p9.Authority;
|
||||||
|
result.Type = p9.Type;
|
||||||
|
result.Status = p9.Status;
|
||||||
|
result.OrderId = p9.OrderId;
|
||||||
|
result.UserId = p9.UserId;
|
||||||
|
result.UserFullName = p9.User != null ? p9.User.FirstName + " " + p9.User.LastName : string.Empty;
|
||||||
|
result.UserPhoneNumber = p9.User != null ? p9.User.PhoneNumber : string.Empty;
|
||||||
|
result.Id = p9.Id;
|
||||||
|
result.CreatedAt = p9.CreatedAt;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
public static Expression<Func<Payment, PaymentSDto>> ProjectToSDto => p11 => new PaymentSDto()
|
||||||
|
{
|
||||||
|
FactorNumber = p11.FactorNumber,
|
||||||
|
Amount = p11.Amount,
|
||||||
|
Description = p11.Description,
|
||||||
|
TransactionCode = p11.TransactionCode,
|
||||||
|
CardPan = p11.CardPan,
|
||||||
|
Authority = p11.Authority,
|
||||||
|
Type = p11.Type,
|
||||||
|
Status = p11.Status,
|
||||||
|
OrderId = p11.OrderId,
|
||||||
|
UserId = p11.UserId,
|
||||||
|
UserFullName = p11.User != null ? p11.User.FirstName + " " + p11.User.LastName : string.Empty,
|
||||||
|
UserPhoneNumber = p11.User != null ? p11.User.PhoneNumber : string.Empty,
|
||||||
|
Id = p11.Id,
|
||||||
|
CreatedAt = p11.CreatedAt
|
||||||
|
};
|
||||||
|
|
||||||
|
private static Order funcMain1(Never p4, Order p5, PaymentSDto p2)
|
||||||
|
{
|
||||||
|
Order result = p5 ?? new Order();
|
||||||
|
|
||||||
|
result.Id = p2.OrderId;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ApplicationUser funcMain2(Never p6, ApplicationUser p7, PaymentSDto p2)
|
||||||
|
{
|
||||||
|
ApplicationUser result = p7 ?? new ApplicationUser();
|
||||||
|
|
||||||
|
result.Id = p2.UserId;
|
||||||
|
result.PhoneNumber = p2.UserPhoneNumber;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
namespace NetinaShop.Domain;
|
using NetinaShop.Domain.Entities.Accounting;
|
||||||
|
|
||||||
|
namespace NetinaShop.Domain;
|
||||||
|
|
||||||
public class MapsterRegister : IRegister
|
public class MapsterRegister : IRegister
|
||||||
{
|
{
|
||||||
|
@ -12,6 +14,10 @@ public class MapsterRegister : IRegister
|
||||||
.Map("HeaderFileName", o => o.Files.Count > 0 && o.Files.Any(f => f.IsHeader) ? o.Files.FirstOrDefault(f => f.IsHeader)!.FileName : string.Empty)
|
.Map("HeaderFileName", o => o.Files.Count > 0 && o.Files.Any(f => f.IsHeader) ? o.Files.FirstOrDefault(f => f.IsHeader)!.FileName : string.Empty)
|
||||||
.TwoWays();
|
.TwoWays();
|
||||||
|
|
||||||
|
config.NewConfig<OrderDelivery, OrderDeliverySDto>()
|
||||||
|
.Map("ShippingMethod", o => o.Shipping != null ? o.Shipping.Name : string.Empty)
|
||||||
|
.TwoWays();
|
||||||
|
|
||||||
config.NewConfig<ProductCategory, ProductCategorySDto>()
|
config.NewConfig<ProductCategory, ProductCategorySDto>()
|
||||||
.Map("ParentName", o => o.Parent != null ? o.Parent.Name : string.Empty)
|
.Map("ParentName", o => o.Parent != null ? o.Parent.Name : string.Empty)
|
||||||
.TwoWays();
|
.TwoWays();
|
||||||
|
@ -23,6 +29,31 @@ public class MapsterRegister : IRegister
|
||||||
.IgnoreNullValues(false)
|
.IgnoreNullValues(false)
|
||||||
.TwoWays();
|
.TwoWays();
|
||||||
|
|
||||||
|
config.NewConfig<Order, OrderSDto>()
|
||||||
|
.Map("UserFullName", o => o.User != null ? o.User.FirstName + " " + o.User.LastName : string.Empty)
|
||||||
|
.Map("UserPhoneNumber", o => o.User != null ? o.User.PhoneNumber : string.Empty)
|
||||||
|
.IgnoreNullValues(false)
|
||||||
|
.TwoWays();
|
||||||
|
|
||||||
|
config.NewConfig<Order, OrderLDto>()
|
||||||
|
.Map("UserFullName", o => o.User != null ? o.User.FirstName + " " + o.User.LastName : string.Empty)
|
||||||
|
.Map("UserPhoneNumber", o => o.User != null ? o.User.PhoneNumber : string.Empty)
|
||||||
|
.IgnoreNullValues(false)
|
||||||
|
.TwoWays();
|
||||||
|
|
||||||
|
config.NewConfig<OrderProduct, OrderProductSDto>()
|
||||||
|
.Map("ProductName", o => o.Product != null ? o.Product.PersianName : string.Empty)
|
||||||
|
.IgnoreNullValues(false)
|
||||||
|
.TwoWays();
|
||||||
|
|
||||||
|
config.NewConfig<Payment, PaymentSDto>()
|
||||||
|
.Map("UserFullName", o => o.User != null ? o.User.FirstName + " " + o.User.LastName : string.Empty)
|
||||||
|
.Map("UserPhoneNumber", o => o.User != null ? o.User.PhoneNumber : string.Empty)
|
||||||
|
.IgnoreNullValues(false)
|
||||||
|
.TwoWays();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
config.NewConfig<Product, ProductLDto>()
|
config.NewConfig<Product, ProductLDto>()
|
||||||
.Map("CategoryName", o => o.Category == null ? null : o.Category.Name)
|
.Map("CategoryName", o => o.Category == null ? null : o.Category.Name)
|
||||||
.Map("BrandName", o => o.Brand == null ? null : o.Brand.Name)
|
.Map("BrandName", o => o.Brand == null ? null : o.Brand.Name)
|
||||||
|
|
|
@ -2,5 +2,6 @@
|
||||||
|
|
||||||
public static class RestAddress
|
public static class RestAddress
|
||||||
{
|
{
|
||||||
public static string BaseKaveNegar { get => "https://api.kavenegar.com/v1/"; }
|
public static string BaseKaveNegar => "https://api.kavenegar.com/v1/";
|
||||||
|
public static string BaseZarinpal => "https://api.zarinpal.com/pg";
|
||||||
}
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
namespace NetinaShop.Infrastructure.Models.RestApi.Zarinpal;
|
||||||
|
|
||||||
|
public class ZarinaplPaymentLinkRequest
|
||||||
|
{
|
||||||
|
public string merchant_id { get; set; } = string.Empty;
|
||||||
|
public int amount { get; set; }
|
||||||
|
public string callback_url { get; set; } = string.Empty;
|
||||||
|
public string description { get; set; } = string.Empty;
|
||||||
|
public ZarinaplPaymentLinkRequestMetadata metadata { get; set; } = new();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ZarinaplPaymentLinkRequestMetadata
|
||||||
|
{
|
||||||
|
public string mobile { get; set; } = string.Empty;
|
||||||
|
public string email { get; set; } = string.Empty;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace NetinaShop.Infrastructure.Models.RestApi.Zarinpal;
|
||||||
|
|
||||||
|
public class ZarinaplPaymentLinkResponse
|
||||||
|
{
|
||||||
|
public ZarinaplPaymentLinkResponseData data { get; set; }
|
||||||
|
public List<object> errors { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ZarinaplPaymentLinkResponseData
|
||||||
|
{
|
||||||
|
public int code { get; set; }
|
||||||
|
public string message { get; set; } = string.Empty;
|
||||||
|
public string authority { get; set; } = string.Empty;
|
||||||
|
public string fee_type { get; set; } = string.Empty;
|
||||||
|
public int fee { get; set; }
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
namespace NetinaShop.Infrastructure.Models.RestApi.Zarinpal;
|
||||||
|
|
||||||
|
public class ZarinaplPaymentVerifyResponse
|
||||||
|
{
|
||||||
|
|
||||||
|
public ZarinaplPaymentVerifyResponseData data { get; set; }
|
||||||
|
public List<object> errors { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ZarinaplPaymentVerifyResponseData
|
||||||
|
{
|
||||||
|
public int code { get; set; }
|
||||||
|
public string message { get; set; } = string.Empty;
|
||||||
|
public string card_hash { get; set; } = string.Empty;
|
||||||
|
public string card_pan { get; set; } = string.Empty;
|
||||||
|
public int ref_id { get; set; }
|
||||||
|
public string fee_type { get; set; } = string.Empty;
|
||||||
|
public int fee { get; set; }
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace NetinaShop.Infrastructure.Models.RestApi.Zarinpal;
|
||||||
|
|
||||||
|
public class ZarinaplVerifyPaymentRequest
|
||||||
|
{
|
||||||
|
public string merchant_id { get; set; } = string.Empty;
|
||||||
|
public int amount { get; set; }
|
||||||
|
public string authority { get; set; } = string.Empty;
|
||||||
|
}
|
|
@ -18,11 +18,6 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Models\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Using Include="Amazon.S3" />
|
<Using Include="Amazon.S3" />
|
||||||
<Using Include="Amazon.S3.Model" />
|
<Using Include="Amazon.S3.Model" />
|
||||||
|
|
|
@ -5,9 +5,11 @@ namespace NetinaShop.Infrastructure.RestServices;
|
||||||
public interface IRestApiWrapper : IScopedDependency
|
public interface IRestApiWrapper : IScopedDependency
|
||||||
{
|
{
|
||||||
IKaveNegarRestApi KaveNegarRestApi { get; }
|
IKaveNegarRestApi KaveNegarRestApi { get; }
|
||||||
|
IZarinpalRestApi ZarinpalRestApi { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RestApiWrapper : IRestApiWrapper
|
public class RestApiWrapper : IRestApiWrapper
|
||||||
{
|
{
|
||||||
public IKaveNegarRestApi KaveNegarRestApi => RestService.For<IKaveNegarRestApi>(RestAddress.BaseKaveNegar);
|
public IKaveNegarRestApi KaveNegarRestApi => RestService.For<IKaveNegarRestApi>(RestAddress.BaseKaveNegar);
|
||||||
|
public IZarinpalRestApi ZarinpalRestApi => RestService.For<IZarinpalRestApi>(RestAddress.BaseZarinpal);
|
||||||
}
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using NetinaShop.Infrastructure.Models.RestApi.Zarinpal;
|
||||||
|
|
||||||
|
namespace NetinaShop.Infrastructure.RestServices;
|
||||||
|
|
||||||
|
public interface IZarinpalRestApi
|
||||||
|
{
|
||||||
|
|
||||||
|
[Post("/v4/payment/request.json")]
|
||||||
|
Task<ZarinaplPaymentLinkResponse> GetPaymentLinkAsync([Body] ZarinaplPaymentLinkRequest request);
|
||||||
|
[Post("/v4/payment/verify.json")]
|
||||||
|
Task<ZarinaplPaymentVerifyResponse> VerifyPaymentAsync([Body] ZarinaplVerifyPaymentRequest request);
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
using Amazon.Runtime.Internal;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NetinaShop.Domain.CommandQueries.Commands;
|
||||||
|
using NetinaShop.Domain.CommandQueries.Queries;
|
||||||
|
using NetinaShop.Domain.Entities.Accounting;
|
||||||
|
using NetinaShop.Domain.Entities.Orders;
|
||||||
|
using NetinaShop.Domain.Enums;
|
||||||
|
using NetinaShop.Infrastructure.Models.RestApi.Zarinpal;
|
||||||
|
using NetinaShop.Repository.Repositories.Base.Contracts;
|
||||||
|
|
||||||
|
namespace NetinaShop.Infrastructure.Services;
|
||||||
|
|
||||||
|
public class ZarinpalService : IPaymentService
|
||||||
|
{
|
||||||
|
private readonly IRestApiWrapper _restApiWrapper;
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
private readonly SiteSettings _siteSettings;
|
||||||
|
public ZarinpalService(IRestApiWrapper restApiWrapper,IOptionsSnapshot<SiteSettings> snapshot,IMediator mediator)
|
||||||
|
{
|
||||||
|
_restApiWrapper = restApiWrapper;
|
||||||
|
_mediator = mediator;
|
||||||
|
_siteSettings = snapshot.Value;
|
||||||
|
}
|
||||||
|
public async Task<string> GetPaymentLinkAsync(double amount,string factorNumber, Guid orderId, Guid userId, string phoneNumber , string fullName , CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var request = new ZarinaplPaymentLinkRequest
|
||||||
|
{
|
||||||
|
description = $"پرداخت {amount.ToString("N0")} ریال توسط {fullName} با شماره تماس {phoneNumber} برای سفارش با شماره {factorNumber}",
|
||||||
|
amount = (int)amount,
|
||||||
|
callback_url = Path.Combine("https://api.vesmook.com", "api", "accounting", "pay", "verify"),
|
||||||
|
merchant_id = "4292b845-b510-4d1d-8ee2-097499b198e5",
|
||||||
|
metadata = new ZarinaplPaymentLinkRequestMetadata { mobile = phoneNumber }
|
||||||
|
};
|
||||||
|
var response = await _restApiWrapper.ZarinpalRestApi.GetPaymentLinkAsync(request);
|
||||||
|
if (response.data.code != 100)
|
||||||
|
throw new AppException($"Exception in get link from zarinpal | {response.data.message}");
|
||||||
|
|
||||||
|
|
||||||
|
var createPaymentResult = await _mediator.Send(new CreatePaymentCommand(factorNumber, amount,
|
||||||
|
request.description, string.Empty, string.Empty,
|
||||||
|
response.data.authority, PaymentType.Online,PaymentStatus.InPaymentGateway, orderId, userId), cancellationToken);
|
||||||
|
|
||||||
|
string link = $"https://www.zarinpal.com/pg/StartPay/{response.data.authority}";
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> VerifyPaymentAsync(string authority, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var payment = await _mediator.Send(new GetPaymentQuery(Authority: authority), cancellationToken);
|
||||||
|
var request = new ZarinaplVerifyPaymentRequest
|
||||||
|
{
|
||||||
|
amount = (int)payment.Amount,
|
||||||
|
authority = payment.Authority,
|
||||||
|
merchant_id = "4292b845-b510-4d1d-8ee2-097499b198e5"
|
||||||
|
};
|
||||||
|
var response = await _restApiWrapper.ZarinpalRestApi.VerifyPaymentAsync(request);
|
||||||
|
if (response.data.code != 100)
|
||||||
|
throw new AppException($"Exception in get link from zarinpal | {response.data.message}");
|
||||||
|
|
||||||
|
payment.Status = PaymentStatus.Paid;
|
||||||
|
payment.CardPan = response.data.card_pan;
|
||||||
|
payment.TransactionCode = response.data.ref_id.ToString();
|
||||||
|
|
||||||
|
await _mediator.Send(
|
||||||
|
new UpdatePaymentCommand(payment.Id, payment.FactorNumber, payment.Amount, payment.Description,
|
||||||
|
payment.TransactionCode, payment.CardPan, payment.Authority, payment.Type, payment.Status,
|
||||||
|
payment.OrderId, payment.UserId), cancellationToken);
|
||||||
|
|
||||||
|
await _mediator.Send(new SubmitOrderPaymentCommand(payment.OrderId, OrderPaymentMethod.OnlinePayment, true),cancellationToken);
|
||||||
|
|
||||||
|
return payment.TransactionCode;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +0,0 @@
|
||||||
namespace NetinaShop.Repository.Abstracts;
|
|
||||||
|
|
||||||
public interface IPaymentService : IScopedDependency
|
|
||||||
{
|
|
||||||
Task<string> GetPaymentLinkAsync(Guid orderId, double amount, string description);
|
|
||||||
Task<bool> VerifiedPaymentAsync(string fishNumber, Guid orderId);
|
|
||||||
}
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
using NetinaShop.Domain.Entities.Accounting;
|
||||||
|
|
||||||
|
namespace NetinaShop.Repository.Handlers.Accounting;
|
||||||
|
|
||||||
|
public class CreatePaymentCommandHandler : IRequestHandler<CreatePaymentCommand,bool>
|
||||||
|
{
|
||||||
|
private readonly IRepositoryWrapper _repositoryWrapper;
|
||||||
|
|
||||||
|
public CreatePaymentCommandHandler(IRepositoryWrapper repositoryWrapper)
|
||||||
|
{
|
||||||
|
_repositoryWrapper = repositoryWrapper;
|
||||||
|
}
|
||||||
|
public async Task<bool> Handle(CreatePaymentCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
|
||||||
|
var payment = Payment.Create(request.FactorNumber, request.Amount, request.Description, request.TransactionCode,
|
||||||
|
request.CardPan, request.Authority, request.Type,request.Status, request.OrderId, request.UserId);
|
||||||
|
|
||||||
|
_repositoryWrapper.SetRepository<Payment>()
|
||||||
|
.Add(payment);
|
||||||
|
|
||||||
|
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
using NetinaShop.Domain.Entities.Accounting;
|
||||||
|
|
||||||
|
namespace NetinaShop.Repository.Handlers.Accounting;
|
||||||
|
|
||||||
|
public class GetPaymentQueryHandler : IRequestHandler<GetPaymentQuery,PaymentSDto>
|
||||||
|
{
|
||||||
|
private readonly IRepositoryWrapper _repositoryWrapper;
|
||||||
|
|
||||||
|
public GetPaymentQueryHandler(IRepositoryWrapper repositoryWrapper)
|
||||||
|
{
|
||||||
|
_repositoryWrapper = repositoryWrapper;
|
||||||
|
}
|
||||||
|
public async Task<PaymentSDto> Handle(GetPaymentQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
PaymentSDto? payment = null;
|
||||||
|
if (request.Authority != null)
|
||||||
|
{
|
||||||
|
payment = await _repositoryWrapper.SetRepository<Payment>()
|
||||||
|
.TableNoTracking
|
||||||
|
.Where(p => p.Authority == request.Authority)
|
||||||
|
.Select(PaymentMapper.ProjectToSDto)
|
||||||
|
.FirstOrDefaultAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (request.Id == default)
|
||||||
|
throw new Exception("Id is null");
|
||||||
|
|
||||||
|
payment = await _repositoryWrapper.SetRepository<Payment>()
|
||||||
|
.TableNoTracking
|
||||||
|
.Where(p => p.Id == request.Id)
|
||||||
|
.Select(PaymentMapper.ProjectToSDto)
|
||||||
|
.FirstOrDefaultAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payment == null)
|
||||||
|
throw new AppException("Payment not found !", ApiResultStatusCode.NotFound);
|
||||||
|
|
||||||
|
return payment;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using NetinaShop.Domain.Entities.Accounting;
|
||||||
|
|
||||||
|
namespace NetinaShop.Repository.Handlers.Accounting;
|
||||||
|
|
||||||
|
public class GetPaymentsQueryHandler : IRequestHandler<GetPaymentsQuery,List<PaymentSDto>>
|
||||||
|
{
|
||||||
|
private readonly IRepositoryWrapper _repositoryWrapper;
|
||||||
|
|
||||||
|
public GetPaymentsQueryHandler(IRepositoryWrapper repositoryWrapper)
|
||||||
|
{
|
||||||
|
_repositoryWrapper = repositoryWrapper;
|
||||||
|
}
|
||||||
|
public async Task<List<PaymentSDto>> Handle(GetPaymentsQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await _repositoryWrapper.SetRepository<Payment>()
|
||||||
|
.TableNoTracking
|
||||||
|
.Skip(20 * request.Page)
|
||||||
|
.Take(20)
|
||||||
|
.Select(PaymentMapper.ProjectToSDto)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
using NetinaShop.Domain.Entities.Accounting;
|
||||||
|
|
||||||
|
namespace NetinaShop.Repository.Handlers.Accounting;
|
||||||
|
|
||||||
|
public class UpdatePaymentCommandHandler : IRequestHandler<UpdatePaymentCommand,bool>
|
||||||
|
{
|
||||||
|
private readonly IRepositoryWrapper _repositoryWrapper;
|
||||||
|
|
||||||
|
public UpdatePaymentCommandHandler(IRepositoryWrapper repositoryWrapper)
|
||||||
|
{
|
||||||
|
_repositoryWrapper = repositoryWrapper;
|
||||||
|
}
|
||||||
|
public async Task<bool> Handle(UpdatePaymentCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var ent = await _repositoryWrapper.SetRepository<Payment>()
|
||||||
|
.TableNoTracking
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == request.Id, cancellationToken);
|
||||||
|
if (ent == null)
|
||||||
|
throw new AppException("Payment not found", ApiResultStatusCode.NotFound);
|
||||||
|
|
||||||
|
var newEnt = Payment.Create(request.FactorNumber, request.Amount, request.Description, request.TransactionCode,
|
||||||
|
request.CardPan, request.Authority, request.Type, request.Status, request.OrderId, request.UserId);
|
||||||
|
newEnt.Id = ent.Id;
|
||||||
|
|
||||||
|
_repositoryWrapper.SetRepository<Payment>()
|
||||||
|
.Update(newEnt);
|
||||||
|
|
||||||
|
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
using NetinaShop.Domain.Entities.Orders;
|
||||||
|
|
||||||
|
namespace NetinaShop.Repository.Handlers.Orders;
|
||||||
|
|
||||||
|
public class GetOrderLDtoQueryHandler: IRequestHandler<GetOrderLDtoQuery,OrderLDto>
|
||||||
|
{
|
||||||
|
private readonly IRepositoryWrapper _repositoryWrapper;
|
||||||
|
|
||||||
|
public GetOrderLDtoQueryHandler(IRepositoryWrapper repositoryWrapper)
|
||||||
|
{
|
||||||
|
_repositoryWrapper = repositoryWrapper;
|
||||||
|
}
|
||||||
|
public async Task<OrderLDto> Handle(GetOrderLDtoQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (request.Id == default)
|
||||||
|
throw new AppException("Order id is null");
|
||||||
|
var order = await _repositoryWrapper.SetRepository<Order>()
|
||||||
|
.TableNoTracking
|
||||||
|
.Where(o => o.Id == request.Id)
|
||||||
|
.Select(OrderMapper.ProjectToLDto)
|
||||||
|
.FirstOrDefaultAsync(cancellationToken);
|
||||||
|
if (order == null)
|
||||||
|
throw new AppException("Order not found", ApiResultStatusCode.NotFound);
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,10 +10,42 @@ public class GetOrdersQueryHandler : IRequestHandler<GetOrdersQuery,List<OrderSD
|
||||||
{
|
{
|
||||||
_repositoryWrapper = repositoryWrapper;
|
_repositoryWrapper = repositoryWrapper;
|
||||||
}
|
}
|
||||||
public Task<List<OrderSDto>> Handle(GetOrdersQuery request, CancellationToken cancellationToken)
|
public async Task<List<OrderSDto>> Handle(GetOrdersQuery request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return _repositoryWrapper.SetRepository<Order>()
|
|
||||||
.TableNoTracking
|
IQueryable<Order> orders = _repositoryWrapper.SetRepository<Order>()
|
||||||
|
.TableNoTracking;
|
||||||
|
|
||||||
|
if (request.DateFilter != null)
|
||||||
|
{
|
||||||
|
switch (request.DateFilter)
|
||||||
|
{
|
||||||
|
case OrderQueryDateFilter.CustomDate:
|
||||||
|
if (request.SelectedDate != null)
|
||||||
|
orders = orders.Where(o => o.CreatedAt.Date == DateTimeExtensions.UnixTimeStampToDateTime(request.SelectedDate.Value));
|
||||||
|
else
|
||||||
|
throw new AppException("For custom date you have to send SelectedDate",ApiResultStatusCode.BadRequest);
|
||||||
|
break;
|
||||||
|
case OrderQueryDateFilter.ThisMonth:
|
||||||
|
orders = orders.Where(o => o.CreatedAt.Date >= new DateTime(DateTime.Today.Year,DateTime.Today.Month,1));
|
||||||
|
break;
|
||||||
|
case OrderQueryDateFilter.ThisWeek:
|
||||||
|
orders = orders.Where(o => o.CreatedAt.Date >= DateTime.Today.AddDays(-7));
|
||||||
|
break;
|
||||||
|
case OrderQueryDateFilter.Today:
|
||||||
|
orders = orders.Where(o => o.CreatedAt.Date == DateTime.Today.Date);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.OrderStatus != null)
|
||||||
|
orders = orders.Where(o => o.OrderStatus == request.OrderStatus.Value);
|
||||||
|
|
||||||
|
return await orders
|
||||||
|
.OrderByDescending(o=>o.CreatedAt)
|
||||||
.Skip(request.Page * 15)
|
.Skip(request.Page * 15)
|
||||||
.Take(15)
|
.Take(15)
|
||||||
.Select(OrderMapper.ProjectToSDto)
|
.Select(OrderMapper.ProjectToSDto)
|
||||||
|
|
1573
NetinaShop.Repository/Migrations/20240210134749_EditOrderAddFactorCode.Designer.cs
generated
100644
1573
NetinaShop.Repository/Migrations/20240210134749_EditOrderAddFactorCode.Designer.cs
generated
100644
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,31 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NetinaShop.Repository.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class EditOrderAddFactorCode : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "FactorCode",
|
||||||
|
schema: "public",
|
||||||
|
table: "Orders",
|
||||||
|
type: "text",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "FactorCode",
|
||||||
|
schema: "public",
|
||||||
|
table: "Orders");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,78 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NetinaShop.Repository.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddPayment : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Payments",
|
||||||
|
schema: "public",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
FactorNumber = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Amount = table.Column<double>(type: "double precision", nullable: false),
|
||||||
|
Description = table.Column<string>(type: "text", nullable: false),
|
||||||
|
TransactionCode = table.Column<string>(type: "text", nullable: false),
|
||||||
|
CardPan = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Authority = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Type = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
OrderId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
UserId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
RemovedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
|
||||||
|
CreatedBy = table.Column<string>(type: "text", nullable: true),
|
||||||
|
IsRemoved = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
RemovedBy = table.Column<string>(type: "text", nullable: true),
|
||||||
|
ModifiedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
|
||||||
|
ModifiedBy = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Payments", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Payments_Orders_OrderId",
|
||||||
|
column: x => x.OrderId,
|
||||||
|
principalSchema: "public",
|
||||||
|
principalTable: "Orders",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Payments_Users_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalSchema: "public",
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Payments_OrderId",
|
||||||
|
schema: "public",
|
||||||
|
table: "Payments",
|
||||||
|
column: "OrderId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Payments_UserId",
|
||||||
|
schema: "public",
|
||||||
|
table: "Payments",
|
||||||
|
column: "UserId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Payments",
|
||||||
|
schema: "public");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -126,6 +126,77 @@ namespace NetinaShop.Repository.Migrations
|
||||||
b.ToTable("Tokens", "public");
|
b.ToTable("Tokens", "public");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NetinaShop.Domain.Entities.Accounting.Payment", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<double>("Amount")
|
||||||
|
.HasColumnType("double precision");
|
||||||
|
|
||||||
|
b.Property<string>("Authority")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("CardPan")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
|
b.Property<string>("CreatedBy")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("FactorNumber")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("IsRemoved")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTime>("ModifiedAt")
|
||||||
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
|
b.Property<string>("ModifiedBy")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RemovedAt")
|
||||||
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
|
b.Property<string>("RemovedBy")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("TransactionCode")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Payments", "public");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NetinaShop.Domain.Entities.Blogs.Blog", b =>
|
modelBuilder.Entity("NetinaShop.Domain.Entities.Blogs.Blog", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
|
@ -393,6 +464,10 @@ namespace NetinaShop.Repository.Migrations
|
||||||
b.Property<DateTime>("DoneAt")
|
b.Property<DateTime>("DoneAt")
|
||||||
.HasColumnType("timestamp without time zone");
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
|
b.Property<string>("FactorCode")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<bool>("IsPayed")
|
b.Property<bool>("IsPayed")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
@ -1300,6 +1375,23 @@ namespace NetinaShop.Repository.Migrations
|
||||||
.OnDelete(DeleteBehavior.Restrict);
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NetinaShop.Domain.Entities.Accounting.Payment", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NetinaShop.Domain.Entities.Orders.Order", "Order")
|
||||||
|
.WithMany("Payments")
|
||||||
|
.HasForeignKey("OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.HasOne("NetinaShop.Domain.Entities.Users.ApplicationUser", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NetinaShop.Domain.Entities.Blogs.Blog", b =>
|
modelBuilder.Entity("NetinaShop.Domain.Entities.Blogs.Blog", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("NetinaShop.Domain.Entities.Blogs.BlogCategory", "Category")
|
b.HasOne("NetinaShop.Domain.Entities.Blogs.BlogCategory", "Category")
|
||||||
|
@ -1531,6 +1623,8 @@ namespace NetinaShop.Repository.Migrations
|
||||||
b.Navigation("OrderDeliveries");
|
b.Navigation("OrderDeliveries");
|
||||||
|
|
||||||
b.Navigation("OrderProducts");
|
b.Navigation("OrderProducts");
|
||||||
|
|
||||||
|
b.Navigation("Payments");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NetinaShop.Domain.Entities.ProductCategories.ProductCategory", b =>
|
modelBuilder.Entity("NetinaShop.Domain.Entities.ProductCategories.ProductCategory", b =>
|
||||||
|
|
Loading…
Reference in New Issue