Aktielista genereras och kan ses för valt datum i analysvy

This commit is contained in:
2026-05-22 08:30:51 +02:00
parent 80ace6f110
commit 64fe7aafaf
14 changed files with 426 additions and 74 deletions

View File

@ -25,5 +25,8 @@ public class AppDbContext : DbContext
modelBuilder.Entity<StockEquity>() modelBuilder.Entity<StockEquity>()
.HasIndex(s => new { s.Sold }) .HasIndex(s => new { s.Sold })
.IsUnique(false); .IsUnique(false);
modelBuilder.Entity<StockEquity>()
.HasIndex(s => new { s.Bought, s.StockCode, s.Quantity })
.IsUnique(false);
} }
} }

View File

@ -0,0 +1,102 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using StockHistory.Data;
#nullable disable
namespace StockHistory.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20260519083023_NewIndexInStockEquity")]
partial class NewIndexInStockEquity
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.6");
modelBuilder.Entity("StockHistory.Models.StockEquity", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("Bought")
.HasColumnType("TEXT");
b.Property<decimal>("BoughtPrice")
.HasColumnType("TEXT");
b.Property<int>("Quantity")
.HasColumnType("INTEGER");
b.Property<DateTime>("Sold")
.HasColumnType("TEXT");
b.Property<decimal>("SoldPrice")
.HasColumnType("TEXT");
b.Property<int>("SoldQuant")
.HasColumnType("INTEGER");
b.Property<string>("StockCode")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Bought");
b.HasIndex("Sold");
b.HasIndex("Bought", "StockCode", "Quantity");
b.ToTable("Stocks");
});
modelBuilder.Entity("StockHistory.Models.TransactionNote", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<decimal>("AmountToPay")
.HasColumnType("TEXT");
b.Property<decimal>("Commission")
.HasColumnType("TEXT");
b.Property<string>("StockCode")
.HasColumnType("TEXT");
b.Property<decimal>("StockPrice")
.HasColumnType("TEXT");
b.Property<int>("StockQuantity")
.HasColumnType("INTEGER");
b.Property<decimal>("TotalAmount")
.HasColumnType("TEXT");
b.Property<DateTime>("TransactionDate")
.HasColumnType("TEXT");
b.Property<string>("TransactionType")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("StockCode", "TransactionDate")
.IsUnique();
b.ToTable("TransactionNotes");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,27 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace StockHistory.Migrations
{
/// <inheritdoc />
public partial class NewIndexInStockEquity : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateIndex(
name: "IX_Stocks_Bought_StockCode_Quantity",
table: "Stocks",
columns: new[] { "Bought", "StockCode", "Quantity" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Stocks_Bought_StockCode_Quantity",
table: "Stocks");
}
}
}

View File

@ -51,6 +51,8 @@ namespace StockHistory.Migrations
b.HasIndex("Sold"); b.HasIndex("Sold");
b.HasIndex("Bought", "StockCode", "Quantity");
b.ToTable("Stocks"); b.ToTable("Stocks");
}); });

View File

@ -38,10 +38,11 @@ namespace StockHistory
ServiceLifetime.Transient); ServiceLifetime.Transient);
services.AddSingleton<frmStockHistoryInit>(); services.AddSingleton<frmStockHistoryInit>();
services.AddScoped<frmStockHistoryAnalyse1>(); services.AddScoped<frmStockHistoryAnalyse>();
services.AddTransient<IPdfOpener, PdfOpener>(); services.AddTransient<IPdfOpener, PdfOpener>();
services.AddTransient<IPdfFormatter, PdfFormatter>(); services.AddTransient<IPdfFormatter, PdfFormatter>();
services.AddTransient<ITransactionNotesServices, TransactionNotesServices>(); services.AddTransient<ITransactionNotesServices, TransactionNotesServices>();
services.AddTransient<IStockEquityServices, StockEquityServices>();
services.AddTransient<IHandleCsvNotes, HandleCsvNotes>(); services.AddTransient<IHandleCsvNotes, HandleCsvNotes>();
}); });

View File

@ -0,0 +1,11 @@
using StockHistory.Models;
namespace StockHistory.Services
{
public interface IStockEquityServices
{
Task GenerateStockVision();
Task<List<StockEquity>> GetAllAsync();
Task<List<StockEquity>> GetAllAsync(DateTime equityDate);
}
}

View File

@ -0,0 +1,84 @@
using Microsoft.EntityFrameworkCore;
using StockHistory.Data;
using StockHistory.Models;
namespace StockHistory.Services;
public class StockEquityServices : IStockEquityServices
{
private readonly AppDbContext _dbContext;
private readonly ITransactionNotesServices _notesServices;
public StockEquityServices(AppDbContext dbContext, ITransactionNotesServices notesServices)
{
_dbContext = dbContext;
_notesServices = notesServices;
}
public async Task<List<StockEquity>> GetAllAsync()
{
return await _dbContext.Stocks.ToListAsync();
}
public async Task<List<StockEquity>> GetAllAsync(DateTime equityDate)
{
return await _dbContext.Stocks
.Where(s => s.Bought <= equityDate && s.Sold > equityDate)
.ToListAsync();
}
public async Task GenerateStockVision()
{
var existingNotes = await _notesServices.GetAllAsync();
// foreach (var note in await _notesServices.GetAllAsync())
foreach (var note in existingNotes)
{
if (note.TransactionType == null) { }
else
if (note.TransactionType.ToLower() == "köp")
{
var equity = new StockEquity
{
StockCode = note.StockCode,
Bought = note.TransactionDate,
BoughtPrice = note.StockPrice,
Quantity = note.StockQuantity,
Sold = DateTime.MinValue,
SoldPrice = 0m,
SoldQuant = 0
};
_dbContext.Stocks.Add(equity);
await _dbContext.SaveChangesAsync();
}
else if (note.TransactionType.ToLower() == "sälj" || note.TransactionType.ToLower() == "försäljning")
{
var equity = await _dbContext.Stocks.FirstOrDefaultAsync(s => s.StockCode == note.StockCode && s.SoldQuant == 0);
if (equity != null)
{
if (note.StockQuantity < equity.Quantity)
{
var splitEquity = new StockEquity
{
StockCode = equity.StockCode,
Bought = equity.Bought,
BoughtPrice = equity.BoughtPrice,
Quantity = equity.Quantity - Math.Abs(note.StockQuantity),
Sold = DateTime.MinValue,
SoldPrice = 0m,
SoldQuant = 0
};
_dbContext.Stocks.Add(splitEquity);
await _dbContext.SaveChangesAsync();
}
equity.Quantity = Math.Abs(note.StockQuantity);
equity.Sold = note.TransactionDate;
equity.SoldPrice = note.StockPrice;
equity.SoldQuant = Math.Abs(note.StockQuantity);
_dbContext.Stocks.Update(equity);
await _dbContext.SaveChangesAsync();
}
}
}
}
}

Binary file not shown.

View File

@ -0,0 +1,146 @@
namespace StockHistory
{
partial class frmStockHistoryAnalyse
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
lblHistAnalyseHeader = new Label();
btnGenerateStockScheme = new Button();
dtpChosenDate = new DateTimePicker();
btnClose = new Button();
lwStocks = new ListView();
chStock = new ColumnHeader();
chBought = new ColumnHeader();
chPrize = new ColumnHeader();
chNumber = new ColumnHeader();
SuspendLayout();
//
// lblHistAnalyseHeader
//
lblHistAnalyseHeader.AutoSize = true;
lblHistAnalyseHeader.Font = new Font("Segoe UI", 13F, FontStyle.Bold);
lblHistAnalyseHeader.Location = new Point(22, 20);
lblHistAnalyseHeader.Name = "lblHistAnalyseHeader";
lblHistAnalyseHeader.Size = new Size(428, 25);
lblHistAnalyseHeader.TabIndex = 0;
lblHistAnalyseHeader.Text = "Analysera existerande Avräkningsnotor (Affärer)";
//
// btnGenerateStockScheme
//
btnGenerateStockScheme.BackColor = Color.Chartreuse;
btnGenerateStockScheme.FlatStyle = FlatStyle.Flat;
btnGenerateStockScheme.Font = new Font("Segoe UI", 11F, FontStyle.Bold);
btnGenerateStockScheme.ImageAlign = ContentAlignment.MiddleLeft;
btnGenerateStockScheme.Location = new Point(29, 65);
btnGenerateStockScheme.Name = "btnGenerateStockScheme";
btnGenerateStockScheme.Size = new Size(139, 29);
btnGenerateStockScheme.TabIndex = 1;
btnGenerateStockScheme.Text = "Generate Stocks";
btnGenerateStockScheme.UseVisualStyleBackColor = false;
btnGenerateStockScheme.Click += btnGenerateStockScheme_Click;
//
// dtpChosenDate
//
dtpChosenDate.Location = new Point(507, 67);
dtpChosenDate.Name = "dtpChosenDate";
dtpChosenDate.Size = new Size(200, 23);
dtpChosenDate.TabIndex = 2;
dtpChosenDate.ValueChanged += dtpChosenDate_ValueChanged;
//
// btnClose
//
btnClose.BackColor = Color.Chartreuse;
btnClose.FlatStyle = FlatStyle.Popup;
btnClose.Font = new Font("Segoe UI", 11F, FontStyle.Regular, GraphicsUnit.Point, 1, true);
btnClose.Location = new Point(680, 411);
btnClose.Margin = new Padding(3, 2, 3, 2);
btnClose.Name = "btnClose";
btnClose.Size = new Size(108, 28);
btnClose.TabIndex = 8;
btnClose.Text = "Stäng";
btnClose.UseVisualStyleBackColor = false;
btnClose.Click += btnClose_Click;
//
// lwStocks
//
lwStocks.Columns.AddRange(new ColumnHeader[] { chStock, chBought, chPrize, chNumber });
lwStocks.Location = new Point(31, 110);
lwStocks.Name = "lwStocks";
lwStocks.Size = new Size(676, 172);
lwStocks.TabIndex = 9;
lwStocks.UseCompatibleStateImageBehavior = false;
lwStocks.View = View.Details;
//
// chStock
//
chStock.Text = "Aktie";
chStock.Width = 100;
//
// chBought
//
chBought.Text = "Köpt";
chBought.Width = 100;
//
// chPrize
//
chPrize.Text = "Köpkurs";
chPrize.Width = 100;
//
// chNumber
//
chNumber.Text = "Antal";
chNumber.Width = 100;
//
// frmStockHistoryAnalyse
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(lwStocks);
Controls.Add(btnClose);
Controls.Add(dtpChosenDate);
Controls.Add(btnGenerateStockScheme);
Controls.Add(lblHistAnalyseHeader);
Name = "frmStockHistoryAnalyse";
Text = "frnStockHistoryAnalyse";
ResumeLayout(false);
PerformLayout();
}
#endregion
private Label lblHistAnalyseHeader;
private Button btnGenerateStockScheme;
private DateTimePicker dtpChosenDate;
private Button btnClose;
private ListView lwStocks;
private ColumnHeader chStock;
private ColumnHeader chBought;
private ColumnHeader chPrize;
private ColumnHeader chNumber;
}
}

View File

@ -0,0 +1,47 @@
using StockHistory.Services;
namespace StockHistory;
public partial class frmStockHistoryAnalyse : Form
{
private readonly IStockEquityServices _equityServices;
public frmStockHistoryAnalyse(IStockEquityServices equityServices)
{
InitializeComponent();
_equityServices = equityServices;
}
private void btnGenerateStockScheme_Click(object sender, EventArgs e)
{
_equityServices.GenerateStockVision().Wait();
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
private void dtpChosenDate_ValueChanged(object sender, EventArgs e)
{
LoadStockListAsync(dtpChosenDate.Value).Wait();
}
private async Task LoadStockListAsync(DateTime equityDate)
{
var stocks = await _equityServices.GetAllAsync(equityDate);
// var stocks = await _equityServices.GetAllAsync();
lwStocks.Items.Clear();
foreach (var t in stocks)
{
var item = new ListViewItem(t.StockCode);
item.SubItems.Add(t.Bought.ToString());
item.SubItems.Add(t.BoughtPrice.ToString());
item.SubItems.Add(t.Quantity.ToString());
lwStocks.Items.Add(item);
}
}
}

View File

@ -1,61 +0,0 @@
namespace StockHistory
{
partial class frmStockHistoryAnalyse1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
label1 = new Label();
SuspendLayout();
//
// label1
//
label1.AutoSize = true;
label1.Font = new Font("Segoe UI", 13F, FontStyle.Bold);
label1.Location = new Point(12, 9);
label1.Name = "label1";
label1.Size = new Size(428, 25);
label1.TabIndex = 0;
label1.Text = "Analysera existerande Avräkningsnotor (Affärer)";
//
// frmStockHistoryAnalyse1
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
BackColor = Color.Gainsboro;
ClientSize = new Size(922, 481);
Controls.Add(label1);
Name = "frmStockHistoryAnalyse1";
Text = "Form1frmStockHistoryAnalyse1";
ResumeLayout(false);
PerformLayout();
}
#endregion
private Label label1;
}
}

View File

@ -1,10 +0,0 @@
namespace StockHistory
{
public partial class frmStockHistoryAnalyse1 : Form
{
public frmStockHistoryAnalyse1()
{
InitializeComponent();
}
}
}

View File

@ -12,7 +12,7 @@ public partial class frmStockHistoryInit : Form
private readonly IPdfFormatter _pdfFormatter; private readonly IPdfFormatter _pdfFormatter;
private readonly ITransactionNotesServices _transactionNotes; private readonly ITransactionNotesServices _transactionNotes;
private readonly IHandleCsvNotes _handleCsvNotes; private readonly IHandleCsvNotes _handleCsvNotes;
private readonly frmStockHistoryAnalyse1 _analyseForm; private readonly frmStockHistoryAnalyse _analyseForm;
private List<PdfSida> _pdfSidor = new(); private List<PdfSida> _pdfSidor = new();
private List<PdfSida> localPdfSida = new(); private List<PdfSida> localPdfSida = new();
private bool lstWait = false; private bool lstWait = false;
@ -26,7 +26,7 @@ public partial class frmStockHistoryInit : Form
IPdfFormatter pdfFormatter, IPdfFormatter pdfFormatter,
ITransactionNotesServices transactionNotes, ITransactionNotesServices transactionNotes,
IHandleCsvNotes handleCsvNotes, IHandleCsvNotes handleCsvNotes,
frmStockHistoryAnalyse1 analyseForm frmStockHistoryAnalyse analyseForm
) )
{ {
InitializeComponent(); InitializeComponent();