niedziela, 1 grudnia 2024

 Plan jest taki

Postanowiłem stworzyć projekt związany z webapi, na początek będą się tu znajdować luźne przemyślenia, na temat tego zdania. Ogólny zarys projektu i możliwe rozwiązania jakie zastosuje. Projekt ten będzie czystko szkoleniowy, chciałem spróbować nowego podejścia do tworzenia aplikacji, postanowiłem, że będę to dokumentował tutaj.

Dawno nie robiłem projektu prywatnego, dawno nie pisałem nic na blogu, tym czy poprzednim, miałem sporą przerwę. Teraz pojawiła się chęć odświeżenia dokumentowania pracy na blogu.

Projekt ma roboczą nazwę VehicleApi.

Aktualnie w pracy zajmujemy się aplikacją do obsługi wózków widłowych. Temat ten jest już mi dobrze znany, bo mija rok od momentu w którym dołączyłem do tego projektu. Został on przeze mnie mocno zrefaktoryzowany (zmieniony), zadecydowało o tym błędne zrozumienie domeny problemu.

Aplikacja, aktualnie działa na produkcji od kilku miesięcy, ale nie ma jeszcze pełnej funkcjonalności. Jest ciągle rozwijana. W tym projekcie pokusiłem się o zastosowanie architektury warstwowej idącej w kierunku DDD, z podziałem na warstwę

  •  aplikacji
  • domeny
  • infrastruktury
Temat wózków okazał się bardzie złożony niż na początku się wydawało. A same podejście do architektury nie weszło od razu w powyższy podział. Jak wspomniałem ten projekt powstał dużo wcześniej, a to co ja zaproponowałem to była głęboka zmiana istniejącego rozwiązania.
Tak więc w miarę przyrostu wiedzy, serwisy które oznaczały dany problem rozwarstwiały się tworząc architekturę trójwarstwową.

Dlaczego wspominam o tym projekcie? Gdyż będzie on moim punktem wyjścia, dla rozważań na temat architektury, jest to projekt, który działa i rozwiązuje rzeczywisty problem. VehicleApi będzie projektem który będzie nawiązywał do tamtego ale skupiał się nad przetestowaniem innych podejść, do problemów.

Opis projektu

Po tym przydługim wstępie, skupię się na głównym temacie tego posta.


Pierwszy krok za mną, projekt wrzucony na githuba ;-)

Założenia:
  • frontem będzie webapi,
  • każda warstwa będzie osobnym projektem,
  • podstawą wyjścia będzie warstwa aplikacji,
  • będzie warstwa domenowa z bardziej złożoną logiką,
  • warstwa infrastruktury dostępu do danych,
Z zastosowanych technologii:
  • .net 6,
  • MediatR,
  • FluentValidation,
  • EF core code first
Z czasem listy będą się powiększać, ale na początek to wystarczy. Projekt ma też za zadanie przećwiczenie technologii i przetestowanie innego podejścia.

Co do samej domeny, czyli jakieś głębszej logiki pojawi się ale później jak się uporam z postawieniem tego projektu. 
Co do testów też się pojawią będzie to Nunit i Xunit.

Do dzieła..... 

niedziela, 21 stycznia 2024

 Po wielu miesiącach przerwy


Czteroletnim exodusie do bloga ismartdev, który zdechł w zeszłym roku w listopadzie, na powrót wstąpiłem w ten zapomniany świat.

Tak sobie pomyślałem że napiszę coś tutaj, bo dawno tego nie robiłem, a ostatnio nawet na moim drugim bloku nie chciałem niczego produkować. 

Podobno nowy rok nowe postanowienia, to na ten rok kilka postanowień, żeby zacząć ponownie przygodę z tym miejscem:

  • webapi - zaprzyjaźnić się bardziej pracuje z tym ale od nie dawna, nie ma jeszcze takiej wprawy jak przy mvc kiedyś miałem, chce się zaprzyjaźnić z tym podejściem, bo je ono lepsze od MVC.net,
  • EF code first - robiłem kilka razy ale mam problemy dalej z relacjami, czy chciałbym lepiej zrozumieć tworzenie bazy na podstawie EF,
  • romans z angularem nie udał się za bardzo i nie ciągnie mnie w tę stronę już ale może by tak dla odmiany blazor, tam miałem krótką schadzkę przez którą poznałem dappera ale blazor jakoś poszedł na bok,
  • Co jeszcze ? hm na razie nie wiem ale może to na chwilę wystarczy
Jak zamierzam się tym zająć? Na wczesniejszym blogu miałem dwa projekty z web api i angularem dla obydwu miałem temat apliakcji do salonu fryzjerskiego, nie chce już męczyć tego tematu po raz kolejny. Co wymyślę nowego.

Może ruszę tutaj z jakimiś zapiskami, bardzie w formie skrótów i prób, było by to lepsze. W końcu w pracy mam poligon do webapi o do sql-a, może być ciekawie.

Tak to dobry początek.

Więc wracam tu po kilku latach.

P.S.
Na Blogu kryjącym się pod nazwą ismartdev.pl miałem 130 postów, kopii nie zrobiłem, nie chciałem. Wzeszłym roku zacząłem go nawet nienawidzić jakkolwiek dziwnie to brzmi. Zakończyłem jego żywot, trochę szkoda ale tak będzie lepiej.

No i nic z tych powyższych rzeczy nie udało mi się zrealizować, życie kolejny raz pokazało że potrzebą chwili jest zrozumienie podejścia DDD, wzorca agregatu encji, modelu warstwowego.
Pomocna w tym okazała się książka Erica Evansa o DDD, którą kiedyś przeczytałem ale nie wzbudziła we mnie wtedy entuzjazmu, wręcz przeciwnie znudzenie.

Teraz po kilku latach wróciłem, bo potrzebowałem zrozumieć problem z którym się mierze, problem związany z architekturą wielowarstwową. Na tym się skupię w najbliższych miesiącach. Na tym blogu również.

piątek, 9 listopada 2018

Giełda - pCreateBuyTransaction - rozszerzenie

Przy okazji tworzenia procedury "Czyszczenia rynku" z przeterminowanych akcji, potrzeba zmusiła mnie do rozszerzenia procedury pCreateBuyTransaction o obsługę zleceń "kPKC" oraz "kCU". Wcześniejsza wersja robiła tylko inserta do  tabeli MarketSquare bez uwzględnienia różnic pomiędzy typami zleceń.
Poniżej wstawię calą procedurę gdyż zmian jest dość dużo.
Naj wązniejsza zmiana to rozróżnienie  zlecenia o statusie kPKC i kCU. Pokażdej cenie mamy cenę równą 0 (zero), cenę pobieramy z tabeli Stock i na tej podstawie wyliczamy ile pieniędzy potrzebujemy zabrać z portfela, a przy okazji czyszczenia rynku pieniądze będą zwracane (jeżeli zlecenie się przeterminuje) na podstawie wyliczonej wartości zlecenia przy składaniu transakcji ( pCreateBuyTransaction). Przy realizacji zlecenia na rynku istnieje rekord w którym mamy zarezerwowaną pewną kwotę  (to jakby zaliczka), wtedy będzie ponownie sprawdzona cena na rynku i z równania wyjdzie nam różnica którą użytkownik musi zapłacić lub zostanie mu zwrócona albo się wstrzeli w cenę i nie będzie musiał dopłacać.

KOD:


BEGIN
--pomocnicze
declare @wallet_id int
declare @stock_id int
declare @stockN_id int
declare @walletMoneyLimit money
declare @userLogin varchar(50)
--wyszukanie portfela oraz akcji
select @wallet_id = wal_id from UserTable where usr_id =@user_id
select @walletMoneyLimit = wal_MoneyLimit from Wallet where wal_id = @wallet_id
select @stockN_id = stockN_id from StockName where stockN_name = @stock_name
select @stock_id = stock_id from Stock where stockN_id = @stockN_id

if (@priceStatusId = 1)
        begin
        -- sprawdzenie portfela
        declare @result money
        declare @PriceTransaction money
        set @result = @numberBuyStock * @stockPrice
        --transakcja na rynek
                        if(@result <= @walletMoneyLimit)
                        begin
                          INSERT INTO [dbo].[MarketSquare]
                                  ([stock_id],[wal_id],[mark_numberOfShares]
                                  ,[mark_aktywny],[mark_sharePriceBuy]
                                  ,[bs_id],[mark_sharePriceSell]
                                   ,[mark_dataStart],[mark_dataEnd]
                                   ,[mark_TransactionPrice],[priceStatus_id])
                                VALUES                                                         (@stock_id,@wallet_id,@numberBuyStock,1,@stockPrice,2,0,GETDATE(),@dataEnd,@result,@priceStatusId)
                        --get money from wallet and set to transaction
                               set @PriceTransaction = @walletMoneyLimit - @result
                               update Wallet set
                                       wal_MoneyLimit = @PriceTransaction
                               where
                                       wal_id = @wallet_id
                        end
                        else
                        begin
                               select @userLogin = usr_login 
                                from UserTable 
                                where 
                                     usr_id = @user_id
                               exec pAddInfoToLog 2,@userLogin,
                                    'zamałe srodki na zakup akcji, zmniejsz liczbe akcji, kCU'
                        end
        end
        if(@priceStatusId = 3)
        begin
        declare @stockPriceFromStockTable money
        declare @priceInThisTime money
                --priceStatus = kPKC stockPrice = 0, get price of stock from Stock Table
                select @stockPriceFromStockTable = stock_priceBuy 
                 from Stock 
                      where stock_id = @stock_id
                set @priceInThisTime = @stockPriceFromStockTable * @numberBuyStock
                        if(@result <= @walletMoneyLimit)
                        begin
                               INSERT INTO [dbo].[MarketSquare]
                                          ([stock_id],[wal_id],[mark_numberOfShares]
                                          ,[mark_aktywny],[mark_sharePriceBuy]
                                          ,[bs_id],[mark_sharePriceSell]
                                          ,[mark_dataStart],[mark_dataEnd]
                                          ,[mark_TransactionPrice],[priceStatus_id])
                                VALUES
                                          (@stock_id,@wallet_id,@numberBuyStock,1,0e,2,0,GETDATE(),@dataEnd,@priceInThisTime,@priceStatusId)
                        --get money from wallet and set to transaction
                               set @PriceTransaction = @walletMoneyLimit - @result
                               update Wallet set
                                       wal_MoneyLimit = @PriceTransaction
                               where
                                       wal_id = @wallet_id
                        end
                        else
                        begin
                               select @userLogin = usr_login 
                               from UserTable 
                               where 
                                    usr_id = @user_id
                               exec pAddInfoToLog 2,@userLogin
                                    ,'zamałe srodki na zakup akcji, zmniejsz liczbe akcji, kPKC'
                        end
        end
end


czwartek, 8 listopada 2018

Giełda - Usunięcie przeterminowanych zleceń


Procedury nie ma sensu omawiać gdyż jest za prosta. W założeniu ma czyścić rynek z przeterminowanych zleceń.
Dodatkowo używam tu funkcji fDateDiff, która sprawdza dwa czasy i zwraca wynik z odejmowania dat, jeżeli mniejsze od zera to przeterminowany jeżeli większy to nieprzeterminowany
Mam dwa parametry, pomyślałem o jobie w nim będę puszczał tę procedurę, jeden to id tabeli MarketSquare drugi to interwał czasowy (mamy trzy do wyboru minuta, godzina, dzień), wszystko zależy jaki cykl giełdy che mieć. 
Procedura pOrderOverdue musi również zadbać o to żeby nastąpił zwrot środków do portfela przy zleceniu kupna ilości środków pieniężnych a przy zleceniu sprzedaży ilość akcji.
Problem widzę gdy mam zlecenia PKC czy  to kupna czy sprzedaży.


  • Przy kPKC chę kupić okręloną ilość akcji ale nie podaje ceny.
  • Przy sPKC chcę sprzedać określoną ilość akcji ale nie podaje ceny.
Zaglądając na procedury zlecenie kupna widzę że nie ma tam uwzględnionego statusu kPKC oraz sPKC.
Jakie jest rozwiązanie na teraz?
  1. Przy sprzedaży po każdej cenie mogę brać cenę z tabeli Stock i przeliczać wartość zakupionych (zlecenia kupna) akcji i ujmować odpowiednią kwotę z portfela.
  2. W zleceniu wpisuje tylko ilość akcji jaką chcę kupić nie odejmuje z portfela wartości bo póki nie jest zrealizowane nie wiem jaka aktualnie cena jest i w konsekwencji wartość zlecenia.
  3. Ostatnie co przychodzi mi na myśl to połączenie tych dwóch punktów czyli wystawiam zlecenie na pewną ilość akcji po cenie jak jest aktualnie na rynku, zabieram tę kwotę z portfela (rezerwuje ją), następnie jak zlecenie się przeterminowywuje (nowe słowo do słownika) to kwotę tą zwracam do portfela, w przeciwnym wypadku realizuje zlecenie ale cena w tedy już jest inna (bądź będzie inna) w tabeli Stock  dla danej akcji. Aby otrzymać kwotę jaką należy zabrać z portfela składającego zlecenie, powinienem pobrać ilość akcji ze zlecenia na rynku oraz znaleźć różnicę  w wartości akcji. W skład tego równania wejdzie ilość wartość zlecenia kupna w chwili jego składania (ilość akcji i cena akcji według tabeli Stock na tamtą chwilę) oraz ilość akcji razy aktualna cena z tabeli Stock.Jeżeli otrzymam wartość ujemną to oznacza że muszę pobrać dodatkową kwotę z portfela, w przeciwnym wypadku muszę do portfela dodać, a jeżeli zero to nic nie robię. Przed założeniem takiego zlecenia trzeba użytkownika ostrzec przed konsekwencjami, tylko co jeżeli braknie mu kasy na razie dług i komornik.   

PROCEDURE [dbo].[pOrderOverdue](
   @mark_id int,
   @interval int
)
AS
BEGIN
declare @dateEnd Datetime
declare @result int
declare @walId int
declare @info varchar(50)
--wallet state before order deactivate
declare @wallCountStocks int
declare @wallCountAllMoney decimal

--market square value
declare @marketSquareCountStocks int
declare @marketSquareCountMoney decimal
declare @marketSqureOrderStatusId int
--
declare @userLogin varchar(50) = 'baza-pOrderOverdue'
select @dateEnd = mark_dataEnd, @walId = wal_id,@marketSqureOrderStatusId = bs_id  
from MarketSquare
where
mark_id = @mark_id
-- wazna uwaga zlecenia kupna roznia sie od zlecen sprzedazy
-- kupno daje pieniadze nie trace ilosci
-- sprzedaz trace ilosc pieniadze bez zmian

select @result = dbo.fDateDiff(1,@dateEnd)
        if(@result < 0)
        begin
                declare @userLoginWallet varchar(50)
                --get login from user table
                select @userLoginWallet = usr_login  from UserTable where wal_id = @walId

                update MarketSquare set
                mark_aktywny = 0
                where
                mark_id = @mark_id
                --get old value from wallet
                select @wallCountStocks = wal_numberOfShares
                     , @wallCountAllMoney = wal_MoneyLimit
                from Wallet
                where
                        wal_id = @walId
                --overdue transaction in status = 2
                --buy
                if(@marketSqureOrderStatusId = 2)
                begin
                        declare @resultMoneyFromStock money
                        --get value from market square
                        select @marketSquareCountMoney = mark_TransactionPrice 
                        from MarketSquare 
                        where mark_id = @mark_id
                        set @resultMoneyFromStock = @marketSquareCountMoney 
                                                  + @wallCountAllMoney
                        update Wallet set
                               wal_MoneyLimit = @resultMoneyFromStock
                        where
                                wal_id = @walId

                        set @info = 'kupno, zwrot pieniedzy = ' 
                                  + CAST(@marketSquareCountMoney as varchar(10))
                        exec pAddInfoToLog 2,@userLoginWallet, @info
                end
                --sell
                if(@marketSqureOrderStatusId = 3)
                begin
                        declare @resultCountStock int
                        --get how many stock i sell transaction in market square
                        select @marketSquareCountStocks = mark_numberOfShares 
                        from MarketSquare 
                        where mark_id = @mark_id
                        set @resultCountStock = @marketSquareCountStocks 
                                              + @wallCountStocks   
                        update Wallet set
                               wal_numberOfShares = @resultCountStock
                        where
                               wal_id = @walId

                        set @info = 'sprzedaz, zwrot akcji = ' 
                                  + CAST(@marketSquareCountMoney as varchar(10))
                        exec pAddInfoToLog 2,@userLoginWallet, @info
                end
                --emission
                if(@marketSqureOrderStatusId = 4)
                begin
                              
                       exec pAddInfoToLog 2,@userLogin,'emisja akcji'
                end
                --return
                if(@marketSqureOrderStatusId = 5)
                begin
                              
                      exec pAddInfoToLog 2,@userLogin,'skup akcji'
                end
  end
END


FUNCTION [dbo].[fDateDiff]
(
   @interval int,
   @dateEnd datetime
)
RETURNS int
AS
 BEGIN
  DECLARE @result int

  if(@interval = 1)
  begin
      SELECT @result = DATEDIFF(minute, GetDAte(),@dateEnd)
   end
  if(@interval = 2)
  begin
     SELECT @result = DATEDIFF(HOUR, GetDAte(),@dateEnd)
  end
  if(@interval = 3)
  begin
    SELECT @result = DATEDIFF(DAY, GetDAte(),@dateEnd)
  end
RETURN @result

END

  Plan jest taki Postanowiłem stworzyć projekt związany z webapi, na początek będą się tu znajdować luźne przemyślenia, na temat tego zdania...