Proceso basico de pedidos
This commit is contained in:
parent
065effae3d
commit
ab74433b70
@ -21,6 +21,41 @@ namespace WebVentaCoche.Controllers
|
|||||||
_context = context;
|
_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//GET:/Account/Details/{id}
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> Details(string id)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(id))
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
var user = await _userHelper.GetUserByIdAsync(id);
|
||||||
|
if (user == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
var addresses = await _context.Addresses.Where(a => a.UserId == id).ToListAsync();
|
||||||
|
|
||||||
|
var vm = new UserDetailsViewModel
|
||||||
|
{
|
||||||
|
Id = user.Id,
|
||||||
|
Name = user.Name,
|
||||||
|
Surname = user.Surname,
|
||||||
|
Email = user.Email,
|
||||||
|
PhoneNumber = user.PhoneNumber,
|
||||||
|
UserType = user.UserType,
|
||||||
|
Addresses = addresses.Select(a => new AddressViewModel
|
||||||
|
{
|
||||||
|
Id = a.Id,
|
||||||
|
Street = a.Street,
|
||||||
|
City = a.City,
|
||||||
|
State = a.State,
|
||||||
|
ZipCode = a.ZipCode,
|
||||||
|
Country = a.Country
|
||||||
|
}).ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(vm);
|
||||||
|
}
|
||||||
|
|
||||||
//GET:/Account/Settings
|
//GET:/Account/Settings
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> Settings()
|
public async Task<IActionResult> Settings()
|
||||||
@ -29,9 +64,7 @@ namespace WebVentaCoche.Controllers
|
|||||||
var user = await _userHelper.GetUserByIdAsync(userId);
|
var user = await _userHelper.GetUserByIdAsync(userId);
|
||||||
if (user == null) return NotFound();
|
if (user == null) return NotFound();
|
||||||
|
|
||||||
var addresses = await _context.Addresses
|
var addresses = await _context.Addresses.Where(a => a.UserId == userId).ToListAsync();
|
||||||
.Where(a => a.UserId == userId)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var vm = new UserDetailsViewModel
|
var vm = new UserDetailsViewModel
|
||||||
{
|
{
|
||||||
|
|||||||
@ -4,6 +4,8 @@ using WebVentaCoche.DataBase;
|
|||||||
using WebVentaCoche.Helpers;
|
using WebVentaCoche.Helpers;
|
||||||
using WebVentaCoche.Models;
|
using WebVentaCoche.Models;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using WebVentaCoche.Enums;
|
||||||
|
|
||||||
namespace WebVentaCoche.Controllers
|
namespace WebVentaCoche.Controllers
|
||||||
{
|
{
|
||||||
@ -16,8 +18,7 @@ namespace WebVentaCoche.Controllers
|
|||||||
_context = context;
|
_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET: /Cart/Index
|
//GET:/Cart/Index
|
||||||
// Muestra la lista de productos del carrito y el total.
|
|
||||||
public IActionResult Index()
|
public IActionResult Index()
|
||||||
{
|
{
|
||||||
// Diccionario de IDs -> Cantidades desde sesión (o cualquier fuente)
|
// Diccionario de IDs -> Cantidades desde sesión (o cualquier fuente)
|
||||||
@ -45,8 +46,63 @@ namespace WebVentaCoche.Controllers
|
|||||||
return View(viewModel);
|
return View(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST: /Cart/AddProductToCart
|
// POST: /Cart/Purchase
|
||||||
// Añade el producto al carrito y devuelve un JSON con el nuevo contador
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> Purchase()
|
||||||
|
{
|
||||||
|
// 1) Obtén el carrito de la sesión
|
||||||
|
var items = CartSessionHelper.GetCartItems(HttpContext.Session);
|
||||||
|
if (!items.Any())
|
||||||
|
{
|
||||||
|
TempData["Error"] = "El carrito está vacío.";
|
||||||
|
return RedirectToAction("Index");
|
||||||
|
}
|
||||||
|
|
||||||
|
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier)!;
|
||||||
|
|
||||||
|
var addr = await _context.Addresses.Where(a => a.UserId == userId).FirstOrDefaultAsync();
|
||||||
|
if (addr == null)
|
||||||
|
{
|
||||||
|
TempData["Error"] = "No tienes ninguna dirección guardada. Primero añade una dirección en tu perfil.";
|
||||||
|
return RedirectToAction("Addresses", "Account");
|
||||||
|
}
|
||||||
|
var shippingAddress = $"{addr.Street}, {addr.City}, {addr.State}, {addr.ZipCode}, {addr.Country}";
|
||||||
|
|
||||||
|
var order = new Order
|
||||||
|
{
|
||||||
|
UserId = userId,
|
||||||
|
OrderDate = DateTime.UtcNow,
|
||||||
|
Status = OrderStatus.Pending,
|
||||||
|
ShippingAddress = shippingAddress
|
||||||
|
};
|
||||||
|
|
||||||
|
decimal total = 0m;
|
||||||
|
foreach (var (productId, quantity) in items)
|
||||||
|
{
|
||||||
|
var product = await _context.Products.FindAsync(productId);
|
||||||
|
if (product == null) continue;
|
||||||
|
|
||||||
|
var detail = new OrderDetail
|
||||||
|
{
|
||||||
|
ProductId = product.Id,
|
||||||
|
Quantity = quantity,
|
||||||
|
UnitPrice = product.Price
|
||||||
|
};
|
||||||
|
total += detail.Subtotal;
|
||||||
|
order.OrderDetails.Add(detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
order.TotalAmount = total;
|
||||||
|
_context.Orders.Add(order);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
CartSessionHelper.ClearCart(HttpContext.Session);
|
||||||
|
|
||||||
|
return RedirectToAction("Details", "Order", new { id = order.Id });
|
||||||
|
}
|
||||||
|
|
||||||
|
//POST:/Cart/AddProductToCart
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult AddProductToCart(int id)
|
public IActionResult AddProductToCart(int id)
|
||||||
{
|
{
|
||||||
@ -66,8 +122,7 @@ namespace WebVentaCoche.Controllers
|
|||||||
return Json(new { success = true, cartCount = count });
|
return Json(new { success = true, cartCount = count });
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST: /Cart/Remove
|
//POST:/Cart/Remove
|
||||||
// Elimina un producto según su ID
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult Remove(int id)
|
public IActionResult Remove(int id)
|
||||||
{
|
{
|
||||||
@ -75,8 +130,7 @@ namespace WebVentaCoche.Controllers
|
|||||||
return RedirectToAction("Index");
|
return RedirectToAction("Index");
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST: /Cart/Clear
|
//POST:/Cart/Clear
|
||||||
// Vacía todo el carrito (la sesión)
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult Clear()
|
public IActionResult Clear()
|
||||||
{
|
{
|
||||||
@ -84,8 +138,7 @@ namespace WebVentaCoche.Controllers
|
|||||||
return RedirectToAction("Index");
|
return RedirectToAction("Index");
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET: /Cart/Checkout
|
//GET:/Cart/Checkout
|
||||||
// (Opcional) Muestra un formulario o datos para la compra/pago.
|
|
||||||
public IActionResult Checkout()
|
public IActionResult Checkout()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.Security.Claims;
|
||||||
using WebVentaCoche.DataBase;
|
using WebVentaCoche.DataBase;
|
||||||
using WebVentaCoche.Models;
|
using WebVentaCoche.Models;
|
||||||
|
|
||||||
namespace WebVentaCoche.Controllers
|
namespace WebVentaCoche.Controllers
|
||||||
{
|
{
|
||||||
[Authorize] // Requiere autenticación para acceder al controlador
|
[Authorize]
|
||||||
public class OrderController : Controller
|
public class OrderController : Controller
|
||||||
{
|
{
|
||||||
private readonly ApplicationDbContext _context;
|
private readonly ApplicationDbContext _context;
|
||||||
@ -19,28 +20,31 @@ namespace WebVentaCoche.Controllers
|
|||||||
//GET:Order/Index
|
//GET:Order/Index
|
||||||
public async Task<IActionResult> Index()
|
public async Task<IActionResult> Index()
|
||||||
{
|
{
|
||||||
var orders = await _context.Orders
|
var orders = await _context.Orders.Include(o => o.User).ToListAsync();
|
||||||
.Include(o => o.User) // Cargar la relación con el usuario
|
|
||||||
.ToListAsync();
|
|
||||||
return View(orders);
|
return View(orders);
|
||||||
}
|
}
|
||||||
|
//GET:/Order/MyOrders
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> UserOrders()
|
||||||
|
{
|
||||||
|
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier)!;
|
||||||
|
var myOrders = await _context.Orders.Where(o => o.UserId == userId).Include(o => o.OrderDetails).ThenInclude(d => d.Product).OrderByDescending(o => o.OrderDate).ToListAsync();
|
||||||
|
|
||||||
//GET:Order/Details/5
|
return View(myOrders);
|
||||||
|
}
|
||||||
|
//GET:Order/Details/{id}
|
||||||
|
[HttpGet]
|
||||||
public async Task<IActionResult> Details(int? id)
|
public async Task<IActionResult> Details(int? id)
|
||||||
{
|
{
|
||||||
if (id == null)
|
if (id == null)
|
||||||
{
|
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
|
||||||
|
|
||||||
var order = await _context.Orders
|
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier)!;
|
||||||
.Include(o => o.User) // Cargar la relación con el usuario
|
|
||||||
.FirstOrDefaultAsync(o => o.Id == id);
|
var order = await _context.Orders.Include(o => o.OrderDetails).ThenInclude(d => d.Product).FirstOrDefaultAsync(o => o.Id == id && o.UserId == userId);
|
||||||
|
|
||||||
if (order == null)
|
if (order == null)
|
||||||
{
|
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
|
||||||
|
|
||||||
return View(order);
|
return View(order);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
{
|
{
|
||||||
public enum OrderStatus
|
public enum OrderStatus
|
||||||
{
|
{
|
||||||
Pending, // Orden pendiente
|
Pending,
|
||||||
Processing, // Orden en proceso
|
Processing,
|
||||||
Shipped, // Orden enviada
|
Shipped,
|
||||||
Delivered, // Orden entregada
|
Delivered,
|
||||||
Cancelled // Orden cancelada
|
Cancelled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
478
WebVentaCoche/Migrations/20250430123732_AddOrderAndDetails.Designer.cs
generated
Normal file
478
WebVentaCoche/Migrations/20250430123732_AddOrderAndDetails.Designer.cs
generated
Normal file
@ -0,0 +1,478 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using WebVentaCoche.DataBase;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace WebVentaCoche.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20250430123732_AddOrderAndDetails")]
|
||||||
|
partial class AddOrderAndDetails
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "8.0.11")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||||
|
|
||||||
|
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("RoleNameIndex")
|
||||||
|
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey")
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WebVentaCoche.Models.Address", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(50)");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(50)");
|
||||||
|
|
||||||
|
b.Property<string>("State")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(50)");
|
||||||
|
|
||||||
|
b.Property<string>("Street")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(100)");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<string>("ZipCode")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnType("nvarchar(20)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Addresses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WebVentaCoche.Models.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime>("OrderDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ShippedDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<string>("ShippingAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<decimal>("TotalAmount")
|
||||||
|
.HasColumnType("decimal(18,2)");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Orders");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WebVentaCoche.Models.OrderDetail", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("OrderId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("ProductId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Quantity")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<decimal>("UnitPrice")
|
||||||
|
.HasColumnType("decimal(18,2)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("OrderDetails");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WebVentaCoche.Models.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("ImagePath")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("LongDescription")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price")
|
||||||
|
.HasColumnType("decimal(18,2)");
|
||||||
|
|
||||||
|
b.Property<string>("ShortDescription")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Products");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WebVentaCoche.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||||
|
.HasColumnType("datetimeoffset");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("Surname")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.Property<int>("UserType")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasDatabaseName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("UserNameIndex")
|
||||||
|
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("WebVentaCoche.Models.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("WebVentaCoche.Models.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("WebVentaCoche.Models.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("WebVentaCoche.Models.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WebVentaCoche.Models.Address", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("WebVentaCoche.Models.User", "User")
|
||||||
|
.WithMany("Addresses")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WebVentaCoche.Models.Order", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("WebVentaCoche.Models.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WebVentaCoche.Models.OrderDetail", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("WebVentaCoche.Models.Order", "Order")
|
||||||
|
.WithMany("OrderDetails")
|
||||||
|
.HasForeignKey("OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("WebVentaCoche.Models.Product", "Product")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WebVentaCoche.Models.Order", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("OrderDetails");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WebVentaCoche.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Addresses");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace WebVentaCoche.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddOrderAndDetails : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,27 +9,19 @@ namespace WebVentaCoche.Models
|
|||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public string UserId { get; set; }
|
public string UserId { get; set; }
|
||||||
|
|
||||||
[ForeignKey("UserId")]
|
[ForeignKey("UserId")]
|
||||||
public virtual User User { get; set; }
|
public virtual User User { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public DateTime OrderDate { get; set; } // Fecha y hora en que se realizó la orden
|
public DateTime OrderDate { get; set; }
|
||||||
|
public DateTime? ShippedDate { get; set; }
|
||||||
public DateTime? ShippedDate { get; set; } // Fecha de envío (opcional)
|
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public decimal TotalAmount { get; set; } // Monto total de la orden
|
public decimal TotalAmount { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public OrderStatus Status { get; set; } // Estado de la orden (Pendiente, Enviado, Completado, Cancelado)
|
public OrderStatus Status { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public string ShippingAddress { get; set; } // Dirección de envío del pedido
|
public string ShippingAddress { get; set; }
|
||||||
|
public virtual List<OrderDetail> OrderDetails { get; set; } = new List<OrderDetail>();
|
||||||
public virtual List<OrderDetail> OrderDetails { get; set; } // Relación con los detalles de la orden
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,23 +7,15 @@ namespace WebVentaCoche.Models
|
|||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
[Required]
|
|
||||||
public int OrderId { get; set; }
|
public int OrderId { get; set; }
|
||||||
|
|
||||||
[ForeignKey("OrderId")]
|
[ForeignKey("OrderId")]
|
||||||
public virtual Order Order { get; set; } // Relación con la orden
|
public virtual Order Order { get; set; }
|
||||||
|
|
||||||
[Required]
|
|
||||||
public int ProductId { get; set; }
|
public int ProductId { get; set; }
|
||||||
|
|
||||||
[ForeignKey("ProductId")]
|
[ForeignKey("ProductId")]
|
||||||
public virtual Product Product { get; set; } // Relación con el producto
|
public virtual Product Product { get; set; }
|
||||||
|
public int Quantity { get; set; }
|
||||||
[Required]
|
public decimal UnitPrice { get; set; }
|
||||||
public int Quantity { get; set; } // Cantidad del producto en la orden
|
public decimal Subtotal => Quantity * UnitPrice;
|
||||||
|
|
||||||
[Required]
|
|
||||||
public decimal UnitPrice { get; set; } // Precio unitario del producto en el momento de la compra
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,6 @@ namespace WebVentaCoche.Services
|
|||||||
|
|
||||||
public EmailService(IConfiguration configuration)
|
public EmailService(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
// Leer configuraciones desde appsettings.json
|
|
||||||
_apiKey = configuration["SendGrid:ApiKey"];
|
_apiKey = configuration["SendGrid:ApiKey"];
|
||||||
_fromEmail = configuration["SendGrid:FromEmail"];
|
_fromEmail = configuration["SendGrid:FromEmail"];
|
||||||
_fromName = configuration["SendGrid:FromName"];
|
_fromName = configuration["SendGrid:FromName"];
|
||||||
@ -20,23 +19,17 @@ namespace WebVentaCoche.Services
|
|||||||
|
|
||||||
public async Task SendEmailAsync(string to, string subject, string htmlContent)
|
public async Task SendEmailAsync(string to, string subject, string htmlContent)
|
||||||
{
|
{
|
||||||
// Crear cliente SendGrid
|
|
||||||
var client = new SendGridClient(_apiKey);
|
var client = new SendGridClient(_apiKey);
|
||||||
|
|
||||||
// Configurar remitente y destinatario
|
|
||||||
var from = new EmailAddress(_fromEmail, _fromName);
|
var from = new EmailAddress(_fromEmail, _fromName);
|
||||||
var toEmail = new EmailAddress(to);
|
var toEmail = new EmailAddress(to);
|
||||||
|
|
||||||
// Convertir el contenido HTML a texto plano eliminando etiquetas
|
|
||||||
var plainTextContent = System.Text.RegularExpressions.Regex.Replace(htmlContent, "<[^>]+>", string.Empty);
|
var plainTextContent = System.Text.RegularExpressions.Regex.Replace(htmlContent, "<[^>]+>", string.Empty);
|
||||||
|
|
||||||
// Crear el mensaje
|
|
||||||
var message = MailHelper.CreateSingleEmail(from, toEmail, subject, plainTextContent, htmlContent);
|
var message = MailHelper.CreateSingleEmail(from, toEmail, subject, plainTextContent, htmlContent);
|
||||||
|
|
||||||
// Enviar el mensaje
|
|
||||||
var response = await client.SendEmailAsync(message);
|
var response = await client.SendEmailAsync(message);
|
||||||
|
|
||||||
// Manejar errores en caso de que el envío falle
|
|
||||||
if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
|
if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
|
||||||
{
|
{
|
||||||
throw new Exception("Error: Solicitud inválida al enviar el correo.");
|
throw new Exception("Error: Solicitud inválida al enviar el correo.");
|
||||||
|
|||||||
10
WebVentaCoche/ViewModels/OrderSummaryViewModel.cs
Normal file
10
WebVentaCoche/ViewModels/OrderSummaryViewModel.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace WebVentaCoche.ViewModels
|
||||||
|
{
|
||||||
|
public class OrderSummaryViewModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public DateTime OrderDate { get; set; }
|
||||||
|
public decimal TotalAmount { get; set; }
|
||||||
|
public string Status { get; set; } = null!;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -88,9 +88,14 @@
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<a class="btn btn-primary ms-2" href="#">
|
<form asp-action="Purchase" asp-controller="Cart" method="post" class="d-inline">
|
||||||
|
@Html.AntiForgeryToken()
|
||||||
|
<button type="submit" class="btn btn-primary ms-2">
|
||||||
Proceder al Pago
|
Proceder al Pago
|
||||||
</a>
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,60 @@
|
|||||||
@model WebVentaCoche.Models.Order
|
@model WebVentaCoche.Models.Order
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Detalles de la Orden";
|
ViewData["Title"] = "Detalle de Pedido";
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="container mt-5">
|
<div class="container mt-4">
|
||||||
<h2 class="mb-4">Detalles de la Orden</h2>
|
<h2 class="mb-4">Pedido #@Model.Id</h2>
|
||||||
<div class="card shadow">
|
|
||||||
<div class="card-body">
|
<div class="row mb-4">
|
||||||
<h5 class="card-title">Orden #@Model.Id</h5>
|
<div class="col-md-6">
|
||||||
<p class="card-text"><strong>Fecha del Pedido:</strong> @Model.OrderDate.ToString("dd/MM/yyyy")</p>
|
<p><strong>Fecha del pedido:</strong> @Model.OrderDate.ToString("g")</p>
|
||||||
<p class="card-text"><strong>Cliente:</strong> @Model.User.Name @Model.User.Surname</p>
|
<p><strong>Estado:</strong> @Model.Status</p>
|
||||||
<p class="card-text"><strong>Estado:</strong> @Model.Status</p>
|
|
||||||
<p class="card-text"><strong>Total:</strong> @Model.TotalAmount.ToString("C")</p>
|
|
||||||
<p class="card-text"><strong>Dirección de Envío:</strong> @Model.ShippingAddress</p>
|
|
||||||
<a href="@Url.Action("Index", "Order")" class="btn btn-primary mt-3">Volver a la Lista</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<p><strong>Dirección de envío:</strong><br />@Model.ShippingAddress</p>
|
||||||
|
<p>
|
||||||
|
<strong>Fecha de envío:</strong> @(Model.ShippedDate.HasValue ? Model.ShippedDate.Value.ToString("g") : "Pendiente")
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4 class="mb-3">Productos del Pedido</h4>
|
||||||
|
<table class="table table-striped align-middle">
|
||||||
|
<thead class="table-dark">
|
||||||
|
<tr>
|
||||||
|
<th style="width:100px;">Imagen</th>
|
||||||
|
<th>Nombre</th>
|
||||||
|
<th>Cantidad</th>
|
||||||
|
<th>Precio unidad</th>
|
||||||
|
<th>Subtotal</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var detalle in Model.OrderDetails)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
@if (!string.IsNullOrEmpty(detalle.Product.ImagePath))
|
||||||
|
{
|
||||||
|
<img src="@detalle.Product.ImagePath" alt="@detalle.Product.Name" class="img-fluid rounded" style="max-height:80px;" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<img src="/images/default.png" alt="Sin imagen" class="img-fluid rounded" style="max-height:80px;" />
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td>@detalle.Product.Name</td>
|
||||||
|
<td>@detalle.Quantity</td>
|
||||||
|
<td>@detalle.UnitPrice.ToString("0.00") €</td>
|
||||||
|
<td>@detalle.Subtotal.ToString("0.00") €</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="text-end mt-4">
|
||||||
|
<h4>Total del pedido: @Model.TotalAmount.ToString("0.00") €</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
40
WebVentaCoche/Views/Order/UserOrders.cshtml
Normal file
40
WebVentaCoche/Views/Order/UserOrders.cshtml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
@model IEnumerable<WebVentaCoche.Models.Order>
|
||||||
|
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Mis Pedidos";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="container mt-4">
|
||||||
|
<h2 class="mb-4 text-center">Mis Pedidos</h2>
|
||||||
|
|
||||||
|
@if (!Model.Any())
|
||||||
|
{
|
||||||
|
<p class="text-center">Aún no has realizado ningún pedido.</p>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
@foreach (var order in Model)
|
||||||
|
{
|
||||||
|
<div class="col-md-4 mb-4">
|
||||||
|
<div class="card h-100 shadow-sm">
|
||||||
|
<div class="card-body d-flex flex-column">
|
||||||
|
<h5 class="card-title">Pedido #@order.Id</h5>
|
||||||
|
<p class="card-text mb-1"><strong>Fecha:</strong> @order.OrderDate.ToString("g")</p>
|
||||||
|
<p class="card-text mb-1"><strong>Total:</strong> @order.TotalAmount.ToString("0.00") €</p>
|
||||||
|
<p class="card-text mb-1"><strong>Estado:</strong> @order.Status</p>
|
||||||
|
<p class="card-text mt-auto"><strong>Envío:</strong><br />@order.ShippingAddress</p>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer bg-transparent border-0 text-end">
|
||||||
|
<a asp-action="Details"
|
||||||
|
asp-route-id="@order.Id"
|
||||||
|
class="btn btn-sm btn-primary">
|
||||||
|
Ver detalles
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
@ -76,7 +76,7 @@
|
|||||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
|
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
|
||||||
<li> <a class="dropdown-item" asp-controller="Account" asp-action="Details" asp-route-id="@userId">Detalles Cuenta</a></li>
|
<li> <a class="dropdown-item" asp-controller="Account" asp-action="Details" asp-route-id="@userId">Detalles Cuenta</a></li>
|
||||||
<li><a class="dropdown-item" asp-controller="Account" asp-action="Settings">Configuración</a></li>
|
<li><a class="dropdown-item" asp-controller="Account" asp-action="Settings">Configuración</a></li>
|
||||||
<li><a class="dropdown-item" href="@Url.Action("Index", "Order")">Pedidos</a></li>
|
<li><a class="dropdown-item" asp-controller="Order" asp-action="UserOrders">Mis Pedidos</a></li>
|
||||||
<li><hr class="dropdown-divider"></li>
|
<li><hr class="dropdown-divider"></li>
|
||||||
<li>
|
<li>
|
||||||
<form method="post" asp-action="Logout" asp-controller="User" class="d-inline">
|
<form method="post" asp-action="Logout" asp-controller="User" class="d-inline">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user