Generate All customers total Sales Statement - using Linq - c#

I have database with Customers.cs, Sales Here I'm stuck how to Generate All customers total Sales Statement.
Actually I want to calculate All Customers Account Receivables. if I will get that how to generate customers total sales I can generate account receivable report.
Sale.cs
public partial class Sale
{
public string SaleId { get; set; }
public Nullable<System.DateTime> Date { get; set; }
public string CustomerId { get; set; }
public string Description { get; set; }
public Nullable<double> Amount { get; set; }
public virtual Customer Customer { get; set; }
}
Customer.cs
public partial class Customer
{
public string CustId { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string TownCity { get; set; }
public int Contact { get; set; }
}
I want to get result like this..
Town/City CustomerName TotalSale

You can do it using GroupBy:
var res = _dbContext.Sales
.GroupBy(s => s.CustomerId)
.Select(s => new { CustomerId = s.Key, TotalSales = s.Sum(a => a.Amount) })
.ToList();

Related

Linq Group by relative entites

My scenario: Users will be able to create lists and add items to these lists. What I want to do is to find the items in the lists created by the users at most.
Item Entity
public class Item:BaseEntity
{
public string Name { get; set; }
public decimal Price { get; set; }
public decimal DiscountedPrice{ get; set; }
public virtual ICollection<ItemList> ItemLists { get; set; }
}
Item List Entity
public class ItemList:BaseEntity
{
public string Name { get; set; }
public string Description { get; set; }
public int UserId { get; set; }
public ICollection<Item> Items { get; set; }
[ForeignKey("UserId")]
public virtual User User { get; set; }
}
User Entity
public class User:BaseEntity
{
public string Name { get; set; }
public string Surname { get; set; }
public string Gsm { get; set; }
public string Email { get; set; }
public virtual ICollection<ItemList> ItemLists{ get; set; }
}
my DTO
public class TopItemsForUsers
{
[BsonRepresentation(BsonType.ObjectId)]
[BsonId]
public string ItemId { get; set; }
public string UserId { get; set; }
public int Quantity { get; set; }
}
My Item repository
var query = _context.Items.Include(l => l.ItemLists)
.GroupBy(g => g.ItemLists)
.Select(z => new TopItemsInLists { ItemId = z.Key.ToString(), Quantity = z.Count() })
.OrderByDescending(z => z.Quantity)
.Take(10);
I want to get products that are very present in users' lists
Where am I doing wrong? If anyone has any other suggestions
Try this query. I hope I understand question correctly.
var query =
from u in _context.Users
from il in u.ItemLists
from i in il.Items
group i by new { UserId = u.Id, ItemId = i.Id } into g
select new TopItemsInLists
{
UserId = g.Key.UserId.ToString(),
ItemId = g.Key.ItemId.ToString(),
Quantity = g.Count()
};
query = query
.OrderByDescending(z => z.Quantity)
.Take(10);

Get the less-sold items with LINQ

I have 2 objects (Order and Product) and a third (OrderDetail) that will be used as "navigation" between Products and Orders.
I'm trying to build a view that will show the less-sold products. For that I am "querying" the object OrderDetail and saving the result in a view model to later on be used in the view.
Model:
public class Product
{
public int ProductID { get; set; }
public string CodProduct { get; set; }
public string Nome { get; set; }
(...)
public ICollection<OrderDetail> OrderDetails { get; set; }
}
public class Order
{
public int OrderID { get; set; }
(...)
[BindNever]
public ICollection<OrderDetail> OrderDetails { get; set; }
}
public class OrderDetail
{
public int OrderDetailId { get; set; }
public int OrderId { get; set; }
public int ProductID { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public virtual Product Product { get; set; }
public virtual Order Order { get; set; }
}
ViewModel:
public class ProductSoldViewModel
{
//Data from the Product
public string ProductCode { get; set; }
public string ProductName { get; set; }
//Data from the OrderDetail
public int Qty { get; set; }
}
Controller:
public IActionResult LSProducts()
{
List<ProductSoldViewModel> model = new List<ProductSoldViewModel>();
model = _context.OrderDetail
.GroupBy(od => od.ProductID)
.Select(o => new ProductSoldViewModel
{
ProductCode = o.Select(s => s.Product.CodProduct).FirstOrDefault(),
ProductName = o.Select(s => s.Product.Nome).FirstOrDefault(),
Qty = o.Sum(s => s.Quantity)
})
.OrderBy(od => od.Qty)
.ToList();
return View(model);
}
With this code, I get only the less-sold products that are present in the orders. But I need to get all the products, even those that have never been sold.
Can you give me some advice about how can I do that?
You should query the product table if you need to get all products:
public IActionResult LSProducts()
{
List<ProductSoldViewModel> model = new List<ProductSoldViewModel>();
model = _context.Product
.Include(a => a.OrderDetails)
.Select(o => new ProductSoldViewModel
{
ProductCode = o.CodProduct,
ProductName = o.Nome,
Qty = o.OrderDetails.Sum(s => s.Qty)
})
.OrderBy(od => od.Qty)
.ToList();
return View(model);
}
To avoid a null exception you may want to add the following constructor to your model:
public class Product
{
public Product()
{
OrderDetails = new HashSet<OrderDetail>();
}
(...)
public ICollection<OrderDetail> OrderDetails { get; set; }
}

need to get id from IEnumerable<item>

So im trying to create a little website to help with my family's business.
I have two models, Jobs and Days.
public class Job
{
public int JobId { get; set; }
public int LotNum { get; set; }
public string Street { get; set; }
public string Suburb { get; set; }
public double PerHour { get; set; }
public string Description { get; set; }
}
public class Day
{
public int JobId { get; set; }
public int DayId { get; set; }
public DateTime Date { get; set; }
public double Hours { get; set; }
public string Details { get; set; }
public int Invoice { get; set; }
}
I need to make an Invoice, the invoice will be numbered. The days have the invoice number so ill be able to pick the days needed.
It would look something like this.
Date LotNum Street Suburb Hours
1/1/01 1 John Street Hurstville x hours
1/1/01 1 John Street Hurstville x hours
1/1/01 1 John Street Hurstville x hours
1/1/01 1 John Street Hurstville x hours
I am able to get the days with the specific invoice number using this:
vm.Days = _dayRepo.GetAll().Where(d => d.Invoice == id);
By doing so i have the date and hours of that day but now i need to get the job information. Both Day and Job have the JobId so i would be able to link them but i just dont know how.
This is what i have so far:
public IActionResult Invoice(int id)
{
CreateInvoiceViewModel vm = new CreateInvoiceViewModel();
vm.Days = _dayRepo.GetAll().Where(d => d.Invoice == id);
//vm.JobId =
vm.Jobs = _jobRepo.GetAll();
return View(vm);
}
My view looks like this:
#model CreateInvoiceViewModel
<table>
#foreach (var item in Model.)
{
<tr>
<td>#item.Date.Date.ToString("dd/MM/yy")</td>
<td>#item.Hours</td>
</tr>
}
</table>
I dont know what to put in for the foreach.
Thanks in advance!
you just need a join query. Define Your ViewModel like:
public class InvoiceViewModel
{
public DateTime Date { get; set; }
public int LotNum { get; set; }
public string Street { get; set; }
public string Suburb { get; set; }
public double Hours { get; set; }
}
Create a join query and convert it to ViewModel:
public IActionResult Invoice(int id)
{
var query = from d in _dayRepo.GetAll()
join job in _jobRepo.GetAll() on d.JobId equals job.JobId
select new { Date=d.Date, LotNum= job.job , Street =job.Street , Suburb =job.Suburb , Hours =d.Hours };
IEnumerable<InvoiceViewModel> viewModel = query.Select(c => new InvoiceViewModel()
{
Date=query.Date,
LotNum=query.LotNum,
Street=query.Street,
Suburb=query.Suburb,
Hours=query.Hours
});
return View(viewModel);
}
This should result in an IEnumerable with your ids
var ids = _dayRepo.GetAll().Where(d => d.Invoice == id).Select(x => x.JobId);
You can also add .ToList() to the end if you want it as a list.
This is more or less how I would set it up, or at least the beginnings of how.
(I'm using EntityFrameworkCore and yes I understand that you are using repos at the moment)
public class Job
{
public int Id { get; set; }
public int LotNum { get; set; }
public string Street { get; set; }
public string Suburb { get; set; }
public double PerHour { get; set; }
public string Description { get; set; }
// Navigation Helper
public virtual ICollection<InvoiceJobRelationship> Invoices { get; set; }
}
public class Day
{
public int Id { get; set; }
public DateTime Date { get; set; }
public double Hours { get; set; }
public string Details { get; set; }
// Navigation Helper
public virtual ICollection<InvoiceDayRelationship> Invoices { get; set; }
}
public class Invoice
{
public int Id { get; set; }
// Navigation Helpers
public virtual ICollection<InvoiceJobRelationship> Jobs { get; set; }
public virtual ICollection<InvoiceDayRelationship> Days { get; set; }
}
public class InvoiceDayRelationship
{
public int InvoiceId { get; set; }
// Navigation Helper
[ForeignKey("InvoiceId")]
public Invoice Invoice { get; set; }
public int DayId { get; set; }
// Navigation Helper
[ForeignKey("DayId")]
public Day Day { get; set; }
}
public class InvoiceJobRelationship
{
public int InvoiceId { get; set; }
// Navigation Helper
[ForeignKey("InvoiceId")]
public Invoice Invoice { get; set; }
public int JobId { get; set; }
// Navigation Helper
[ForeignKey("JobId")]
public Job Job { get; set; }
}
Then in your context
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<InvoiceDayRelationship>()
.HasKey(id => new { id.DayId, id.InvoiceId });
builder.Entity<InvoiceJobRelationship>()
.HasKey(ij => new { ij.JobId, ij.InvoiceId });
}
public DbSet<Invoice> Invoices { get; set; }
public DbSet<Day> Days { get; set; }
public DbSet<Job> Jobs { get; set; }
public DbSet<InvoiceDayRelationship> InvoiceDays { get; set; }
public DbSet<InvoiceJobRelationship> InvoiceJobs { get; set; }
Then you would be able to call pretty much anything you would like.
(Example Query)
(from x in context.Invoices where x.Id == id select x).Include(inv => inv.Days).Include(inv => inv.Jobs);

Pass a column value to model from a different table based on foreign key id

I have a products table which has a CategoryId which represents the respective primary key from the Categories table.
ProductViewModel
public ProductVM(ProductDTO productDTO)
{
Id = productDTO.Id;
Name = productDTO.Name;
Description = productDTO.Description;
Price = productDTO.Price;
CategoryId = productDTO.CategoryId;
ImageName = productDTO.ImageName;
}
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
[Required]
public decimal Price { get; set; }
public int? CategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
public string ImageName { get; set; }
public IEnumerable<string> GalleryImages { get; set; }
Product DTO
public class ProductDTO
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Slug { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public int CategoryId { get; set; }
public string ImageName { get; set; }
[ForeignKey("CategoryId")]
public virtual CategoryDTO Category { get; set; }
}
This is how I get a list of products:
List<ProductVM> productVM;
using (Db db = new Db())
{
productVM = db.Products
.ToArray()
.Select(x => new ProductVM(x))
.ToList();
}
As you can see I am passing the CategoryId around and I can display it in my views with the ProductVM ViewModel, but I also want to get the Name of the category in there as well.
I can think of some hacks, e.g. accessing the DB from the constructor in the ViewModel based on the CategoryId and assigning it that way, but I wanna see if there is a more elegant solution?
Bottom line - I have a Name column in my Categories table and I want to pass that name to the ProductVM in a most effective way.
Add a property to you model for the category name, say
public string CategoryName { get; set; }
and modify the constructor to populate it
public ProductVM(ProductDTO productDTO)
{
CategoryName = productDTO.Category.Name;
....
and modify the query to
List<ProductVM> productVM = db.Products.AsEnumerable().Include(x => x.Category)
.Select(x => new ProductVM(x)).ToList();
Note that you view model also required a parameterless constructor if your using this for editing otherwise an exception will be thrown in the POST method.
Note also that you do not need the using (Db db = new Db())
The best solution is the following (I removed all other answers)
namespace Test
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
internal class Program
{
private static void Main(string[] args)
{
List<ProductVM> productVM;
//It doesn't matter if you use a using block or not
using (Db db = new Db())
{
db.Database.Log = Console.WriteLine;//To see the generated SQL
productVM = db.Products
.Include(p => p.Category)
.Select(p => new ProductVM
{
Id = p.Id,
Name = p.Name,
Description = p.Description,
Price = p.Price,
CategoryId = p.CategoryId,
CategoryName = p.Category.Name,
ImageName = p.ImageName,
}).ToList();
}
Console.ReadKey();
}
}
public class Db : DbContext
{
public DbSet<ProductDTO> Products { get; set; }
public DbSet<CategoryDTO> Categories { get; set; }
}
public class ProductDTO
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Slug { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public int CategoryId { get; set; }
public string ImageName { get; set; }
[ForeignKey("CategoryId")]
public virtual CategoryDTO Category { get; set; }
}
public class CategoryDTO
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public class ProductVM
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
[Required]
public decimal Price { get; set; }
public int? CategoryId { get; set; }
public string CategoryName { get; set; }
public string ImageName { get; set; }
}
}

Sum Related Collection By Property in Entity Framework (Lazy Loaded)

I am in need of some assistance with an Entity Framework query. I have the following entities:
public class Invoice
{
public Guid Id { get; set; }
public DateTime CreateDate { get; set; }
[ForeignKey("CreatedById")]
public virtual ApplicationUser CreatedBy { get; set; }
public Guid CreatedById { get; set; }
public bool Approved { get; set; }
public virtual ICollection<InvoiceDetail> Details { get; set; }
}
public class InvoiceDetail
{
public Guid Id { get; set; }
[ForeignKey("InvoiceId")]
public virtual Invoice Invoice { get; set; }
public Guid InvoiceId { get; set; }
public string Item { get; set; }
public string Description { get; set; }
public decimal Quantity { get; set; }
public decimal UnitCost { get; set; }
public decimal Discount { get; set; }
}
I am trying to sum the total of all the items where an invoice is Approved. The problem I'm having is the syntax on getting to the InvoiceDetail level once I filter for the Approved = 1:
var myInvoices = context.Invoices.Where(i => i.CreatedById == userId).Include(i => i.CreatedBy).Include(i => i.Details);
var approvedTotal = myInvoices.Where(i => i.Approved == 1).Select([GET TO DETAILS???]);
// my goal is to get the following sum for each detail for all of the approved invoices:
// ((d.Quantity * d.UnitCost) - d.Discount)
Assuming that you wanted to get a sum total of all details after the given calculation had been performed you could do something like this:
var approvedTotal = invoices.Where(invoice => invoice.Approved)
.Select(invoice => invoice.Details.Sum(detail => ((detail.Quantity * detail.UnitCost) - detail.Discount)));
So this gives you one total per invoice.

Categories