From 64fe7aafaf545c641ec772b857dca464ef797584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tommy=20=C3=96man?= Date: Fri, 22 May 2026 08:30:51 +0200 Subject: [PATCH] =?UTF-8?q?Aktielista=20genereras=20och=20kan=20ses=20f?= =?UTF-8?q?=C3=B6r=20valt=20datum=20i=20analysvy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- StockHistory/Data/AppDbContext.cs | 3 + ...19083023_NewIndexInStockEquity.Designer.cs | 102 ++++++++++++ .../20260519083023_NewIndexInStockEquity.cs | 27 ++++ .../Migrations/AppDbContextModelSnapshot.cs | 2 + StockHistory/Program.cs | 3 +- StockHistory/Services/IStockEquityServices.cs | 11 ++ StockHistory/Services/StockEquityServices.cs | 84 ++++++++++ StockHistory/Stockbrokerage.db | Bin 61440 -> 65536 bytes .../frmStockHistoryAnalyse.Designer.cs | 146 ++++++++++++++++++ StockHistory/frmStockHistoryAnalyse.cs | 47 ++++++ ...lyse1.resx => frmStockHistoryAnalyse.resx} | 0 .../frmStockHistoryAnalyse1.Designer.cs | 61 -------- StockHistory/frmStockHistoryAnalyse1.cs | 10 -- StockHistory/frmStockHistoryInit.cs | 4 +- 14 files changed, 426 insertions(+), 74 deletions(-) create mode 100644 StockHistory/Migrations/20260519083023_NewIndexInStockEquity.Designer.cs create mode 100644 StockHistory/Migrations/20260519083023_NewIndexInStockEquity.cs create mode 100644 StockHistory/Services/IStockEquityServices.cs create mode 100644 StockHistory/Services/StockEquityServices.cs create mode 100644 StockHistory/frmStockHistoryAnalyse.Designer.cs create mode 100644 StockHistory/frmStockHistoryAnalyse.cs rename StockHistory/{frmStockHistoryAnalyse1.resx => frmStockHistoryAnalyse.resx} (100%) delete mode 100644 StockHistory/frmStockHistoryAnalyse1.Designer.cs delete mode 100644 StockHistory/frmStockHistoryAnalyse1.cs diff --git a/StockHistory/Data/AppDbContext.cs b/StockHistory/Data/AppDbContext.cs index 7ef5a88..5c1c913 100644 --- a/StockHistory/Data/AppDbContext.cs +++ b/StockHistory/Data/AppDbContext.cs @@ -25,5 +25,8 @@ public class AppDbContext : DbContext modelBuilder.Entity() .HasIndex(s => new { s.Sold }) .IsUnique(false); + modelBuilder.Entity() + .HasIndex(s => new { s.Bought, s.StockCode, s.Quantity }) + .IsUnique(false); } } diff --git a/StockHistory/Migrations/20260519083023_NewIndexInStockEquity.Designer.cs b/StockHistory/Migrations/20260519083023_NewIndexInStockEquity.Designer.cs new file mode 100644 index 0000000..f73fda4 --- /dev/null +++ b/StockHistory/Migrations/20260519083023_NewIndexInStockEquity.Designer.cs @@ -0,0 +1,102 @@ +// +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 + { + /// + 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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Bought") + .HasColumnType("TEXT"); + + b.Property("BoughtPrice") + .HasColumnType("TEXT"); + + b.Property("Quantity") + .HasColumnType("INTEGER"); + + b.Property("Sold") + .HasColumnType("TEXT"); + + b.Property("SoldPrice") + .HasColumnType("TEXT"); + + b.Property("SoldQuant") + .HasColumnType("INTEGER"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AmountToPay") + .HasColumnType("TEXT"); + + b.Property("Commission") + .HasColumnType("TEXT"); + + b.Property("StockCode") + .HasColumnType("TEXT"); + + b.Property("StockPrice") + .HasColumnType("TEXT"); + + b.Property("StockQuantity") + .HasColumnType("INTEGER"); + + b.Property("TotalAmount") + .HasColumnType("TEXT"); + + b.Property("TransactionDate") + .HasColumnType("TEXT"); + + b.Property("TransactionType") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("StockCode", "TransactionDate") + .IsUnique(); + + b.ToTable("TransactionNotes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/StockHistory/Migrations/20260519083023_NewIndexInStockEquity.cs b/StockHistory/Migrations/20260519083023_NewIndexInStockEquity.cs new file mode 100644 index 0000000..f424911 --- /dev/null +++ b/StockHistory/Migrations/20260519083023_NewIndexInStockEquity.cs @@ -0,0 +1,27 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace StockHistory.Migrations +{ + /// + public partial class NewIndexInStockEquity : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateIndex( + name: "IX_Stocks_Bought_StockCode_Quantity", + table: "Stocks", + columns: new[] { "Bought", "StockCode", "Quantity" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Stocks_Bought_StockCode_Quantity", + table: "Stocks"); + } + } +} diff --git a/StockHistory/Migrations/AppDbContextModelSnapshot.cs b/StockHistory/Migrations/AppDbContextModelSnapshot.cs index a0700b1..d8bbebd 100644 --- a/StockHistory/Migrations/AppDbContextModelSnapshot.cs +++ b/StockHistory/Migrations/AppDbContextModelSnapshot.cs @@ -51,6 +51,8 @@ namespace StockHistory.Migrations b.HasIndex("Sold"); + b.HasIndex("Bought", "StockCode", "Quantity"); + b.ToTable("Stocks"); }); diff --git a/StockHistory/Program.cs b/StockHistory/Program.cs index 14a5f36..9370249 100644 --- a/StockHistory/Program.cs +++ b/StockHistory/Program.cs @@ -38,10 +38,11 @@ namespace StockHistory ServiceLifetime.Transient); services.AddSingleton(); - services.AddScoped(); + services.AddScoped(); services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); }); diff --git a/StockHistory/Services/IStockEquityServices.cs b/StockHistory/Services/IStockEquityServices.cs new file mode 100644 index 0000000..368d5bd --- /dev/null +++ b/StockHistory/Services/IStockEquityServices.cs @@ -0,0 +1,11 @@ +using StockHistory.Models; + +namespace StockHistory.Services +{ + public interface IStockEquityServices + { + Task GenerateStockVision(); + Task> GetAllAsync(); + Task> GetAllAsync(DateTime equityDate); + } +} \ No newline at end of file diff --git a/StockHistory/Services/StockEquityServices.cs b/StockHistory/Services/StockEquityServices.cs new file mode 100644 index 0000000..f5642ad --- /dev/null +++ b/StockHistory/Services/StockEquityServices.cs @@ -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> GetAllAsync() + { + return await _dbContext.Stocks.ToListAsync(); + } + public async Task> 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(); + } + } + + } + } +} diff --git a/StockHistory/Stockbrokerage.db b/StockHistory/Stockbrokerage.db index 1b4deb1c49aa356332bf38f15ea8d7f93d733d45..4b92e820551eb65313da71643f254e47aa75347e 100644 GIT binary patch delta 364 zcmZp8z}(QlGC^99oq>Tt0El6LW1^0+B0Ga#RUt3G2?H0$1O|Q^K0dyeJi$DS+*X`7 zIqNyKIVNmu6yUIIl;C0)50+$X49v_+Nv-gVhz~BwPtGomcginK&nSWLobyvs;{!_* z^GY&HDk1U$lYKcQBylR5e2`OIN=HEntQe$S3CMw&prpB3n{%(2hNXgmg_W^^m8pfE zp^2%Xv4yF&fq|8Q0WZ)WEc}rS{I~cw^SARyZWa{qr V)R+SqC->+pZQg6|ykXG=0RTsiW_JJp delta 149 zcmZo@U}<>3JV9EJg@J*AABbUqeWH%BJPU(fRUt3G2?HmmHUqy6A0OXKo?sqEZY$24 zob{aAn*{~da%|S-+$*MLu3%_tWoTk$Xsl;oY-(w2Zmex!U}a#y3p9_Jzny{q7XN1c rcA$nz{>kn7wOq{n(;4_5@bBZF4ixL;XHjDgWSrciue5ouz4HbDGqND# diff --git a/StockHistory/frmStockHistoryAnalyse.Designer.cs b/StockHistory/frmStockHistoryAnalyse.Designer.cs new file mode 100644 index 0000000..e161237 --- /dev/null +++ b/StockHistory/frmStockHistoryAnalyse.Designer.cs @@ -0,0 +1,146 @@ +namespace StockHistory +{ + partial class frmStockHistoryAnalyse + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + 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; + } +} \ No newline at end of file diff --git a/StockHistory/frmStockHistoryAnalyse.cs b/StockHistory/frmStockHistoryAnalyse.cs new file mode 100644 index 0000000..a8634a3 --- /dev/null +++ b/StockHistory/frmStockHistoryAnalyse.cs @@ -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); + } + } + +} diff --git a/StockHistory/frmStockHistoryAnalyse1.resx b/StockHistory/frmStockHistoryAnalyse.resx similarity index 100% rename from StockHistory/frmStockHistoryAnalyse1.resx rename to StockHistory/frmStockHistoryAnalyse.resx diff --git a/StockHistory/frmStockHistoryAnalyse1.Designer.cs b/StockHistory/frmStockHistoryAnalyse1.Designer.cs deleted file mode 100644 index 474516e..0000000 --- a/StockHistory/frmStockHistoryAnalyse1.Designer.cs +++ /dev/null @@ -1,61 +0,0 @@ -namespace StockHistory -{ - partial class frmStockHistoryAnalyse1 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - 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; - } -} \ No newline at end of file diff --git a/StockHistory/frmStockHistoryAnalyse1.cs b/StockHistory/frmStockHistoryAnalyse1.cs deleted file mode 100644 index c1b4e8c..0000000 --- a/StockHistory/frmStockHistoryAnalyse1.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace StockHistory -{ - public partial class frmStockHistoryAnalyse1 : Form - { - public frmStockHistoryAnalyse1() - { - InitializeComponent(); - } - } -} diff --git a/StockHistory/frmStockHistoryInit.cs b/StockHistory/frmStockHistoryInit.cs index 8d58c3b..a180660 100644 --- a/StockHistory/frmStockHistoryInit.cs +++ b/StockHistory/frmStockHistoryInit.cs @@ -12,7 +12,7 @@ public partial class frmStockHistoryInit : Form private readonly IPdfFormatter _pdfFormatter; private readonly ITransactionNotesServices _transactionNotes; private readonly IHandleCsvNotes _handleCsvNotes; - private readonly frmStockHistoryAnalyse1 _analyseForm; + private readonly frmStockHistoryAnalyse _analyseForm; private List _pdfSidor = new(); private List localPdfSida = new(); private bool lstWait = false; @@ -26,7 +26,7 @@ public partial class frmStockHistoryInit : Form IPdfFormatter pdfFormatter, ITransactionNotesServices transactionNotes, IHandleCsvNotes handleCsvNotes, - frmStockHistoryAnalyse1 analyseForm + frmStockHistoryAnalyse analyseForm ) { InitializeComponent();