Table of Contents

Algoritam "važećeg perioda" (optmizacija)

Autor: Milan Oparnica (14.07.2009)
Revizija: Milan Oparnica (06.08.2017) Od sada zapisi koji ne trebaju imati uticaj na važeći period imaju NULL u vazod/vazdo

Algoritam iza zadatak da ukloni sledeća uska grla kod određivanja prodajne i cene koštanja:

  1. Utvrđivanje važećih cena prilikom izrade konkretnog dokumenta (na dan)
  2. Određivanje početne vrednosti za potrebe ažuriranje cena
  3. Utvrđivanje otpremnica i računa sa netačnim srednjim cenama i njihova ispravka

Određivanje početnih vrednosti za ažuriranje cena

Standardni algoritam

Standardni algoritam je uvek polazio od početnog stanja i obrađivao sve promene do kraja. Postojale su dve verzije, svi artikli, ili artikli po nekom dokumentu, pri čemu ova poslednja verzija nije pokretana u slučaju da dokument obuhvata više od 300 promena. Dakle program bi uvek povukao sve promene od početka godine što u slučaju velikih baza podataka nije bilo izvodljivo.

Algoritam važećeg perioda

Algoritam se oslanja na upotrebu LagerNaDanX metoda za dobijanje “početnog stanja” cena i količina prilikom obrade konkretnog dokumenta ili svih artikala i skladišta. Na taj način, nema potrebe da se obrađuju hiljade slogova već samo slogovi od datuma dokumenta do kraja perioda. U slučaju da se vrši obrada svih artikala i skladišta obrada se vrši od nekih “check-point” tačaka do kraja perioda.

Utvrđivanje otpremnica i računa sa netačnim srednjim cenama i nivelacijama

Standardni algoritam

Oslanja se na upit CS_OtpremniceUlazi koji pokušava da spoji otpremnice i ulaze sa validnim cenama za period u kom je otpremnica izdata.
Upitu je potrebno preko 20 min da vrati rezultat na srednjim (>300MB) i večnost na velikim bazama (>1GB).

Algoritam važećeg perioda

Uočio sam da je glavni problem u nedostatku efikasne strukture kroz koju bi lako određivao periode u kojim određena srednja ili prodajna cena važe za određeni artikal i određeno skladište.
Tabela SasUlaz se pokazala najzgodnijom za uvođenje ove strukture, koju sam nazvao “Struktura važećeg perioda cena”, ili kraće struktura “važećeg perioda”.

Realizacija strukture "važećeg perioda"

Strukturu čine tri polja u tabeli SasUlaz

PoljeTipSvrha
vazodINTEGERCelobrojno polje koje predstavlja datum početka perioda za koji srednja i prodajna cena u slogu SasUlaz važi.
vazdoINTEGERCelobrojno polje koje predstavlja datum kraja perioda (ne uključujući dan unet u VazDo) od kog srednja i prodajna cena u slogu SasUlaz više ne važi.
vazdtsDOUBLEDuplikat DTStamp polja iz Ulaz tabele kako bi se izbegao nepotreban JOIN u upitima koji će vraćati rezulate strukture.

Validne vrednosti polja VazOd i VazDo (logička provera)

Primeri su dati nad sledećim vrednostima (#m/dd/yyyy#):
39875 - brojčana vrednost datuma #3/3/09#
39885 - brojčana vrednost datuma #3/13/09#
401769 - brojčana vrednost datuma #1/1/3000#

Sledeće kombinacije vrednosti ovih polja za isti ElID i SklID sloga SasUlaz su ispravne:

vazodvazdoOpis situacije
39875401769Ovo je normalno kod prvog i jedinog ulaza artikla koji tada važi od datuma ulaza do kraja (1/1/3000)
3987539885vo je normalno za artikal koji je ponovo nabaljen za 10 dana, pri čemu bi drugi slog izgledao…
39885401769…ovako
3987539875Ovo je normalno za artikal koji je u toku jednog dana više puta ulazio. Mogući scenario sledećih polja je…
3987539875…ponovo je ušao, ali ima još jedan ulaz od istog dana
3987539885…sledeći ulaz od istog dana važi narednih 9 dana
39885401769…a 10-tog dana je artikal ponovo ušao, i od tada se više nije pojavljivao

Iz ovih vrednosti mogu se izvući sledeći logički zaključci:

  1. Polja sa vazod = vazdo ne uzimaju se u obzir prilikom odabira cena jer je pravilo Balansa da svi ulazi uvek ide pre bilo kog izlaza. Izuzetak je jedino popis, koji je zadnji dokument nekog dana. Nama su dakle interesantni samo poslednji ulazi dana tj oni gde je vazod < vazdo.
  2. Ni jedan par [elid, sklid] gde je vazod < vazdone može da ima dva ista vazoddatuma. To bi značilo da postoji “preklapanje” perioda u okviru istorije promena cena.
  3. Ni jedan par [elid, sklid] gde je vazod < vazdone može da ima dva ista vazoddatuma. To bi značilo da postoji “preklapanje” perioda u okviru istorije promena cena.
  4. Ni jedan par [elid, sklid] ne može da ima vazodili vazdoizmeđu vazodi vazdo (> vazodAND < vazdo) bilo kojeg drugog para istih[elid, sklid].
    Napomena ! Upit koji bi ovo proveravao ne postoji, ali postoji pretpostavka da će takva situacija uvek dovesti do pojave duplikata u vazodili vazdo.

Popisi

Izuzetno je važno da se popisi više ne tretiraju kao poslednji dokumenti u danu, ako već nisu tako i snimljeni. Periodi vazod i vazdo ne smeju postati netačni. Ovo tretiranje popisi imaju samo u procedurama za obradu srednjih cena i nivelacija, i to zato što svi ulazi pomeraju DTStamp svih otpremnica tako da ove uvek dolaze iza njih.

Popisima se na DTStamp dodaje 20000 tako da se oni veštački postave iza svih ulaznih dokumenata. Ovo je prvenstveno urađeno zbog uprošćavanja detekcije trenutnih količina u trenutku ulaza i formiranja srednje nabavne cene.

Pošto su svi izlazi agregirani pod jednim danom i smešteni na njegov kraj, jedini podatak koji nam informaciju može pružiti jeste TKol prethodnog ulaza. Stvar, nažalost, nije nimalo jednostavna. Ulazi pre popisa će u TKol da smeste sve ulaze do tog momenta minus količinu robe prodatu do kraja prethodnog dana. Popis će uzeti stanje u trenutku popisa i u svoj TKol upisati stanje posle popisa uključujući izlaze do momenta popisa.
Ulazi napravljeni posle popisa će uzeti:

zbir svih ulaza do pre popisa + izmene po popisu – zbir izlaza do kraja prošlog dana.

Tablica koja demonstrira problem:

Iz ovoga se vidi da će prethodni TKol biti isti kao i stanje lagera po obračunu SC ali će se razlikovati od stvarnog stanja koje je bilo u trenutku popisa.

Rešenje

Razlog za usaglašavanje dokumenta Popis može biti samo promena u stanju (ili ceni, ali ako to nema veze sa količinom radi se o drugoj priči) pre popisa. Do promene stanja može doći samo izmenom tabele Ulaz ili Otpremnice.

U prvom slučaju, izmena će se odraziti na TKol makar poslednjeg Ulaza pre popisa. U drugom slučaju desiće se isto sem ako je došlo do promene baš one otpremnice koja se nalazila između poslednjeg ulaza i popisa, odnosno popisa i prvog sledećeg ulaza, a to će se reflektovati tek na TKol-u prvog sledećeg Ulaza.

Problem je kako razlikovati da li je do razlike u izlazima došlo pre ili posle popisa ?

Jedino rešenje je ipak da popis u okviru zapisa u Popis unese i podatak o ukupnom ulazu i izlazu do trenutka izrade popisa. U tu svrhu su dodata polja inkol i outkol. Prilikom sakupljanja informacija o prometu artikala (CS_UlaziSumIzlazi i sl.), dodat je podupit koji za slogove popisa testira trenutno važeći izlaz do momenta popisa i posle popisa (potonje za sada ne trebaju, ali pošto ne utiču na performanse ostavio sam ih).

Implementacija u BLSCNIV biblioteci

U strukturu uMag dodaću dva nova polja InKol i OutKol, ali i u matricu popisa isto to. Slog u SasUlaz će u polju ExtLink pamtiti PopID polje iz tabele Popis.

Matrica popisa

Matrica popisa se formira prilikom prebacivanja podataka iz recordseta sa prometom artikala. Tada se za sve slogove, za koje se otkrije da predstavljaju slog popisa, umetne zapis u matricu popisa koja ima sledeći format:

Naziv poljaVrstaOpis
iIndexLongOvde se upisuje broj reda iz osnovne matrice gde se čuvaju svi podaci o slogu popisa. Pošto je taj broj unikatan poslužiće nam kao unikatan index.
iElIDLongID artikla na koji se popis odnosi
iSklIDLongID skladišta na kom je popis urađen
dDatumTDateTimeDatum i vreme izrade popisa
nLoTKolDoubleOriginalna TKol vrednost učitana iz baze
nLoKolDoubleKoličina uneta kroz popis
nChTKol1DoubleVrednost TKol-a iz poslednjeg Ulaza pre popisa
nChTKol2DoubleVrednost TKol-a iz Ulaza posle popisa
< ima još polja u ovoj matrici…potrebno je updateovati ovaj dokument >

Implementacija

Izmene se dešavaju u modulu za obračun srednjih cena i nivelacija BLSCNIV.
Koraci bitni za implementaciju:

  1. Sve izmene uMag.TKol (trenutna količina po faktičkom stanju) su preusmereni na jednu proceduru mSetNewTKol.
    Izuzetak je jedino promena koja se dešava pod uicajem izlaza (Otpremnice) jer ona ne podleže analizi.
  2. TUlazRec strukturi dodato je novo polje LastUlDocTip. U to polje se smešta tip ulaznog dokumenta u trenutku izmene/potvrde TKol-a, kako bi u narednj izmeni mogao da posluži kao informacija o prethodnom tipu dokumenta.
    Suština ovog polja je da ukaže da li je pre konkretnog Ulaza bio dokument Popisa. Tu je samo u cilju optimizacije, tj. da ne bi svaka izmena morala da traži unazad koji joj je bio prethodni dokument. Pošto nas samo zanima da li je to bio Popis, moguće je da se u ovom polju pojavi i 0. Otpremnice neće uticati na ovo polje.
    Problem predstavljaju Ulazi po osnovu premeštaja. Tada se ne preduzima ništa, već se nit tekućeg obračuna prekida. Pošto će u budućnosti nit biti nastavljena pozivom mGetNeobradjen funkcije, logično je da ta funkcija postavi i koji je to dokument prethodio ovom koji će se obrađivati (za sve pozive, ne samo za ovaj slučaj). Pošto se u okviru ove funkcije poziva i mGetPrevMCen kako bi se utvrdila prethodna prodajna cena, proširio sam tu funkcija da setuje mbLastPrevDocTip u prvi prethodni DocTip. Vrednost mbLastPrevDocTip mora da se pročita odmah po izlasku iz mGetPrevMCen funkcije.

Izuzetci iz strukture "važećeg perioda"

Inetrni nalozi za prijem i prenos robe

U strukturu se ne unose slogovi iz SasUlaz koji imaju sklid = 0. U Balansu jedino interni nalozi za prijem ili prenos robe snimaju u Ulaz > SasUlaz pod sklid = 0.
Pošto ti podaci ionako ne učestvuju u formiranju cena i količina sasvim je ispravno da ne koriste strukturu važećeg perioda.

Dokumenti koji ne utiču na obračun prodajne ili cene koštanja

Od 06.08.2017 zapisi koji ne trebaju imati uticaj na važeći period (defDocTip.FNivelTot = false i defDocTip.FSCObrac = false) imaju NULL u vazod/vazdo

Važni upiti

UpitOpis
CS_UlaziDDDocNovi upit za dobijanje obracunskog peroda sc i nivel po predatom dokumentu
CS_UlaziSumIzlazi_TstCS_UlaziSumIzlazi samo bez UNIONA po Ulaz tabelama
zCalc_INKOLByDoc_xxUpiti za dobijanje stanja svih lagera artikala predatog dokumenta na trenutak pre izrade predatog dokumenta
CS2_GetPer4Del
CS2_GetPer4New
CS2_GetPerErr_1