api.warehouse.php 229 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463
  1. <?php
  2. /**
  3. * Basic warehouse accounting implementation
  4. */
  5. class Warehouse {
  6. /**
  7. * Contains all available employee as employeeid=>name
  8. *
  9. * @var array
  10. */
  11. protected $allEmployee = array();
  12. /**
  13. * Contains all active employee as employeeid=>name
  14. *
  15. * @var array
  16. */
  17. protected $activeEmployee = array();
  18. /**
  19. * Contains available employee telegram chatid data as id=>chatid
  20. *
  21. * @var array
  22. */
  23. protected $allEmployeeTelegram = array();
  24. /**
  25. * Contains all available employee realnames as login=>name
  26. *
  27. * @var array
  28. */
  29. protected $allEmployeeLogins = array();
  30. /**
  31. * System alter.ini config stored as array key=>value
  32. *
  33. * @var array
  34. */
  35. protected $altCfg = array();
  36. /**
  37. * List of all available items categories as id=>category name
  38. *
  39. * @var array
  40. */
  41. protected $allCategories = array();
  42. /**
  43. * List of all available item types as id=>data
  44. *
  45. * @var array
  46. */
  47. protected $allItemTypes = array();
  48. /**
  49. * Contains all item type names as id=>name
  50. *
  51. * @var array
  52. */
  53. protected $allItemTypeNames = array();
  54. /**
  55. * All of available warehouse storages as id=>name
  56. *
  57. * @var array
  58. */
  59. protected $allStorages = array();
  60. /**
  61. * All of available warehouse contractors as id=>name
  62. *
  63. * @var array
  64. */
  65. protected $allContractors = array();
  66. /**
  67. * All available incoming operations
  68. *
  69. * @var array
  70. */
  71. protected $allIncoming = array();
  72. /**
  73. * All available outcoming operations as id=>outcomeData
  74. *
  75. * @var array
  76. */
  77. protected $allOutcoming = array();
  78. /**
  79. * Preloaded reserve entries as id=>reserve data
  80. *
  81. * @var array
  82. */
  83. protected $allReserve = array();
  84. /**
  85. * Contains previous reservation history
  86. *
  87. * @var array
  88. */
  89. protected $allReserveHistory = array();
  90. /**
  91. * Contains reserve creation dates as reserveId=>date string array
  92. *
  93. * @var array
  94. */
  95. protected $allReserveCreationDates = array();
  96. /**
  97. * Available unit types as unittype=>localized name
  98. *
  99. * @var array
  100. */
  101. protected $unitTypes = array();
  102. /**
  103. * Available outcoming destinations as destination=>localized name
  104. *
  105. * @var array
  106. */
  107. protected $outDests = array();
  108. /**
  109. * Contains previously detected tasks outcomings mappings
  110. *
  111. * @var array
  112. */
  113. protected $taskOutsCache = array();
  114. /**
  115. * System messages helper object placeholder
  116. *
  117. * @var object
  118. */
  119. protected $messages = '';
  120. /**
  121. * System telegram object placeholder
  122. *
  123. * @var object
  124. */
  125. protected $telegram = '';
  126. /**
  127. * Returns database abstraction layer placeholder
  128. *
  129. * @var object
  130. */
  131. protected $returnsDb = '';
  132. /**
  133. * Contains all returns operation as outcomeid=>returnData
  134. *
  135. * @var array
  136. */
  137. protected $allReturns = array();
  138. /**
  139. * Telegram force notification flag
  140. *
  141. * @var bool
  142. */
  143. protected $telegramNotify = false;
  144. /**
  145. * System caching object placeholder
  146. *
  147. * @var object
  148. */
  149. protected $cache = '';
  150. /**
  151. * Default asterisk required fields notifier
  152. *
  153. * @var string
  154. */
  155. protected $sup = '';
  156. /**
  157. * Recommended price flag
  158. *
  159. * @var bool
  160. */
  161. protected $recPriceFlag = false;
  162. /**
  163. * Contains array of cached middle itemtype prices as itemtypeId=>price
  164. *
  165. * @var array
  166. */
  167. protected $cachedPrices = array();
  168. /**
  169. * Default constants/routes/URLS etc..
  170. */
  171. const URL_ME = '?module=warehouse';
  172. const URL_CATEGORIES = 'categories=true';
  173. const URL_ITEMTYPES = 'itemtypes=true';
  174. const URL_STORAGES = 'storages=true';
  175. const URL_CONTRACTORS = 'contractors=true';
  176. const URL_IN = 'in=true';
  177. const URL_OUT = 'out=true';
  178. const URL_OUTAJREMAINS = 'ajaxremains=true';
  179. const URL_AJITSELECTOR = 'ajits=';
  180. const URL_AJODSELECTOR = 'ajods=';
  181. const URL_INAJLIST = 'ajaxinlist=true';
  182. const URL_REAJTREM = 'ajaxtremains=true';
  183. const URL_OUTAJLIST = 'ajaxoutlist=true';
  184. const URL_VIEWERS = 'viewers=true';
  185. const URL_REPORTS = 'reports=true';
  186. const URL_RESERVE = 'reserve=true';
  187. const ROUTE_DELOUT = 'outcomedelete';
  188. const ROUTE_DELIN = 'incomedelete';
  189. const PROUTE_MASSRESERVEOUT = 'massoutreserves';
  190. const PROUTE_MASSAGREEOUT = 'massoutagreement';
  191. const PROUTE_MASSNETWOUT = 'massoutnetwcb';
  192. const PROUTE_DOMASSRESOUT = 'runmassoutreserve';
  193. const PROUTE_RETURNOUTID = 'newreturnoutcomeid';
  194. const PROUTE_RETURNSTORAGE = 'newreturnstorageid';
  195. const PROUTE_RETURNPRICE = 'newreturnprice';
  196. const PROUTE_RETURNNOTE = 'newreturnnote';
  197. const PROUTE_EMPREPLACE = 'massoutemployeereplace';
  198. const PHOTOSTORAGE_SCOPE = 'WAREHOUSEITEMTYPE';
  199. /**
  200. * Default debug log path
  201. */
  202. const LOG_PATH = 'exports/whdebug.log';
  203. /**
  204. * Some caching default timeout
  205. */
  206. const CACHE_TIMEOUT = 2592000;
  207. /**
  208. * Creates new warehouse instance
  209. *
  210. * @param type $taskid
  211. *
  212. * @return void
  213. */
  214. public function __construct($taskid = '') {
  215. $this->loadAltCfg();
  216. $this->setOptions();
  217. $this->loadOutOperations($taskid);
  218. $this->setUnitTypes();
  219. $this->setOutDests();
  220. $this->setSup();
  221. $this->loadMessages();
  222. $this->loadAllEmployeeData();
  223. $this->loadCategories();
  224. $this->loadItemTypes();
  225. $this->loadStorages();
  226. $this->loadContractors();
  227. $this->initTelegram();
  228. $this->initCache();
  229. $this->loadTaskOutsCache();
  230. $this->initReturns();
  231. if (empty($taskid)) {
  232. $this->loadReserve();
  233. $this->loadInOperations();
  234. }
  235. }
  236. /**
  237. * Loads system alter config
  238. *
  239. * @global object $ubillingConfig
  240. *
  241. * @return void
  242. */
  243. protected function loadAltCfg() {
  244. global $ubillingConfig;
  245. $this->altCfg = $ubillingConfig->getAlter();
  246. }
  247. /**
  248. * Sets some config based options
  249. *
  250. * @return void
  251. */
  252. protected function setOptions() {
  253. if (isset($this->altCfg['WAREHOUSE_TELEGRAM']) and $this->altCfg['WAREHOUSE_TELEGRAM']) {
  254. $this->telegramNotify = true;
  255. }
  256. if (isset($this->altCfg['WAREHOUSE_RECPRICE']) and $this->altCfg['WAREHOUSE_RECPRICE']) {
  257. $this->recPriceFlag = true;
  258. }
  259. }
  260. /**
  261. * Creates system message helper object instance
  262. *
  263. * @return void
  264. */
  265. protected function loadMessages() {
  266. $this->messages = new UbillingMessageHelper();
  267. }
  268. /**
  269. * Inits telegram object as protected instance for further usage
  270. *
  271. * @return void
  272. */
  273. protected function initTelegram() {
  274. if ($this->altCfg['SENDDOG_ENABLED']) {
  275. $this->telegram = new UbillingTelegram();
  276. }
  277. }
  278. /**
  279. * Inits returns database abstraction layer
  280. *
  281. * @return void
  282. */
  283. protected function initReturns() {
  284. if (@$this->altCfg['WAREHOUSE_RETURNS_ENABLED']) {
  285. $this->returnsDb = new NyanORM('wh_returns');
  286. }
  287. }
  288. /**
  289. * Loads all existing return operations from database into protected prop
  290. *
  291. * @return void
  292. */
  293. protected function loadReturns() {
  294. if (@$this->altCfg['WAREHOUSE_RETURNS_ENABLED']) {
  295. $this->allReturns = $this->returnsDb->getAll('outid');
  296. }
  297. }
  298. /**
  299. * Inits system cache for further usage
  300. *
  301. * @return void
  302. */
  303. protected function initCache() {
  304. $this->cache = new UbillingCache();
  305. }
  306. /**
  307. * Loads tasks=>outcomings cache
  308. *
  309. * @return void
  310. */
  311. protected function loadTaskOutsCache() {
  312. $this->taskOutsCache = $this->cache->get('TASKSOUTS', self::CACHE_TIMEOUT);
  313. if (empty($this->taskOutsCache)) {
  314. $this->taskOutsCache = array();
  315. }
  316. }
  317. /**
  318. * Loads all existing employees from database
  319. *
  320. * @return void
  321. */
  322. protected function loadAllEmployeeData() {
  323. $query = "SELECT * from `employee`";
  324. $all = simple_queryall($query);
  325. if (!empty($all)) {
  326. foreach ($all as $io => $each) {
  327. $this->allEmployee[$each['id']] = $each['name'];
  328. if ($each['active']) {
  329. $this->activeEmployee[$each['id']] = $each['name'];
  330. }
  331. if (!empty($each['admlogin'])) {
  332. $this->allEmployeeLogins[$each['admlogin']] = $each['name'];
  333. }
  334. $this->allEmployeeTelegram[$each['id']] = $each['telegram'];
  335. }
  336. }
  337. }
  338. /**
  339. * Sets default unit types
  340. *
  341. * @return void
  342. */
  343. protected function setUnitTypes() {
  344. $this->unitTypes['quantity'] = __('quantity');
  345. $this->unitTypes['meter'] = __('meter');
  346. $this->unitTypes['kilometer'] = __('kilometer');
  347. $this->unitTypes['money'] = __('money');
  348. $this->unitTypes['time'] = __('time');
  349. $this->unitTypes['litre'] = __('litre');
  350. $this->unitTypes['pieces'] = __('pieces');
  351. $this->unitTypes['packing'] = __('packing');
  352. }
  353. /**
  354. * Sets default unit types
  355. *
  356. * @return void
  357. */
  358. protected function setOutDests() {
  359. $this->outDests['task'] = __('Task');
  360. $this->outDests['contractor'] = __('Contractor');
  361. $this->outDests['employee'] = __('Employee');
  362. $this->outDests['storage'] = __('Warehouse storage');
  363. $this->outDests['user'] = __('User');
  364. $this->outDests['sale'] = __('Sale');
  365. $this->outDests['cancellation'] = __('Cancellation');
  366. $this->outDests['mistake'] = __('Mistake');
  367. }
  368. /**
  369. * Sets default required fields notification
  370. *
  371. * @return void
  372. */
  373. protected function setSup() {
  374. $this->sup = wf_tag('sup') . '*' . wf_tag('sup', true);
  375. }
  376. /**
  377. * Loads existing warehouse categories from DB
  378. *
  379. * @return void
  380. */
  381. protected function loadCategories() {
  382. $query = "SELECT * from `wh_categories`";
  383. $all = simple_queryall($query);
  384. if (!empty($all)) {
  385. foreach ($all as $io => $each) {
  386. $this->allCategories[$each['id']] = $each['name'];
  387. }
  388. }
  389. }
  390. /**
  391. * Loads all existing warehouse item types
  392. *
  393. * @return void
  394. */
  395. protected function loadItemTypes() {
  396. $query = "SELECT* from `wh_itemtypes` ORDER BY `name` ASC";
  397. $all = simple_queryall($query);
  398. if (!empty($all)) {
  399. foreach ($all as $io => $each) {
  400. $this->allItemTypes[$each['id']] = $each;
  401. $this->allItemTypeNames[$each['id']] = $each['name'];
  402. }
  403. }
  404. }
  405. /**
  406. * Loads existing warehouse storages from DB
  407. *
  408. * @return void
  409. */
  410. protected function loadStorages() {
  411. $query = "SELECT * from `wh_storages`";
  412. $all = simple_queryall($query);
  413. if (!empty($all)) {
  414. foreach ($all as $io => $each) {
  415. $this->allStorages[$each['id']] = $each['name'];
  416. }
  417. }
  418. }
  419. /**
  420. * Loads existing warehouse contractors from DB
  421. *
  422. * @return void
  423. */
  424. protected function loadContractors() {
  425. $query = "SELECT * from `wh_contractors`";
  426. $all = simple_queryall($query);
  427. if (!empty($all)) {
  428. foreach ($all as $io => $each) {
  429. $this->allContractors[$each['id']] = $each['name'];
  430. }
  431. }
  432. }
  433. /**
  434. * Loads existing incoming operations from database
  435. *
  436. * @return void
  437. */
  438. protected function loadInOperations() {
  439. $query = "SELECT * from `wh_in`";
  440. $all = simple_queryall($query);
  441. if (!empty($all)) {
  442. foreach ($all as $io => $each) {
  443. $this->allIncoming[$each['id']] = $each;
  444. }
  445. }
  446. }
  447. /**
  448. * Loads existing outcoming operations from database
  449. *
  450. * @param int $taskid existing taskId
  451. *
  452. * @return void
  453. */
  454. protected function loadOutOperations($taskid = '') {
  455. $taskid = vf($taskid, 3);
  456. $where = (!empty($taskid)) ? "WHERE `desttype`='task' AND `destparam`='" . $taskid . "'" : '';
  457. $query = "SELECT * from `wh_out` " . $where . ";";
  458. $all = simple_queryall($query);
  459. if (!empty($all)) {
  460. foreach ($all as $io => $each) {
  461. $this->allOutcoming[$each['id']] = $each;
  462. }
  463. }
  464. }
  465. /**
  466. * Loads available reserved items from database
  467. *
  468. * @return void
  469. */
  470. protected function loadReserve() {
  471. $query = "SELECT * from `wh_reserve` ORDER BY `id` DESC";
  472. $all = simple_queryall($query);
  473. if (!empty($all)) {
  474. foreach ($all as $io => $each) {
  475. $this->allReserve[$each['id']] = $each;
  476. }
  477. }
  478. }
  479. /**
  480. * Loads reserve history logs from database
  481. *
  482. * @return void
  483. */
  484. protected function loadReserveHistory() {
  485. $query = "SELECT * from `wh_reshist` ORDER BY `id` DESC";
  486. $all = simple_queryall($query);
  487. if (!empty($all)) {
  488. foreach ($all as $io => $each) {
  489. $this->allReserveHistory[$each['id']] = $each;
  490. if (!empty($each['resid'])) {
  491. if ($each['type'] == 'create') {
  492. $this->allReserveCreationDates[$each['resid']] = $each['date'];
  493. }
  494. }
  495. }
  496. }
  497. }
  498. /**
  499. * Returns count of itemtypes reserved on storage if available
  500. *
  501. * @param int $storageId
  502. * @param int $itemtypeId
  503. *
  504. * @return float
  505. */
  506. protected function reserveGet($storageId, $itemtypeId) {
  507. $result = 0;
  508. $storageId = vf($storageId, 3);
  509. $itemtypeId = vf($itemtypeId, 3);
  510. if (!empty($this->allReserve)) {
  511. foreach ($this->allReserve as $io => $each) {
  512. if (($each['storageid'] == $storageId) and ($each['itemtypeid'] == $itemtypeId)) {
  513. $result += $each['count'];
  514. }
  515. }
  516. }
  517. return ($result);
  518. }
  519. /**
  520. * Returns existing reserve data
  521. *
  522. * @param int $reserveId
  523. *
  524. * @return array
  525. */
  526. protected function reserveGetData($reserveId) {
  527. $result = array();
  528. if (isset($this->allReserve[$reserveId])) {
  529. $result = $this->allReserve[$reserveId];
  530. }
  531. return ($result);
  532. }
  533. /**
  534. * Stores reservation history log record into database
  535. *
  536. * @param string $type - create/update/delete
  537. * @param int $storageId
  538. * @param int $itemtypeId
  539. * @param float $count
  540. * @param int $employeeId
  541. * @param int $reserveId
  542. */
  543. protected function reservePushLog($type, $storageId = '', $itemtypeId = '', $count = '', $employeeId = '', $reserveId = '') {
  544. $curdate = curdatetime();
  545. $type = vf($type);
  546. $adminLogin = mysql_real_escape_string(whoami());
  547. $storageId = "'" . vf($storageId, 3) . "'";
  548. $itemtypeId = "'" . vf($itemtypeId, 3) . "'";
  549. $count = "'" . mysql_real_escape_string($count) . "'";
  550. $employeeId = "'" . vf($employeeId, 3) . "'";
  551. $reserveId = vf($reserveId, 3);
  552. $query = "INSERT INTO `wh_reshist` (`id`,`resid`,`date`,`type`,`storageid`,`itemtypeid`,`count`,`employeeid`,`admin`) VALUES ";
  553. $query .= "(NULL,'" . $reserveId . "','" . $curdate . "','" . $type . "'," . $storageId . "," . $itemtypeId . "," . $count . "," . $employeeId . ",'" . $adminLogin . "');";
  554. nr_query($query);
  555. }
  556. /**
  557. * Stores Telegram message for some employee
  558. *
  559. * @param int $employeeid
  560. * @param string $message
  561. *
  562. * @return void
  563. */
  564. protected function sendTelegram($employeeId, $message) {
  565. if ($this->altCfg['SENDDOG_ENABLED']) {
  566. $chatId = @$this->allEmployeeTelegram[$employeeId];
  567. if (!empty($chatId)) {
  568. $this->telegram->sendMessage($chatId, $message, false, 'WAREHOUSE');
  569. }
  570. }
  571. }
  572. /**
  573. * Sends some notificaton about reserve creation to employee
  574. *
  575. * @param int $storageId
  576. * @param int $itemtypeId
  577. * @param float $count
  578. * @param int $employeeId
  579. * @param int $reserveId
  580. *
  581. * @return void
  582. */
  583. protected function reserveCreationNotify($storageId, $itemtypeId, $count, $employeeId, $reserveId = '') {
  584. if ($this->telegramNotify) {
  585. $message = '';
  586. $adminLogin = whoami();
  587. $adminName = (isset($this->allEmployeeLogins[$adminLogin])) ? $this->allEmployeeLogins[$adminLogin] : $adminLogin;
  588. $message .= __('From warehouse storage') . ' 📦 ' . $this->allStorages[$storageId] . '\r\n ';
  589. $message .= '👤 ' . $adminName . ' ' . __('reserved for you') . ' ' . '❤️️' . ' : ';
  590. $message .= $this->allItemTypeNames[$itemtypeId] . ' ' . $count . ' ' . $this->unitTypes[$this->allItemTypes[$itemtypeId]['unit']] . '\r\n ';
  591. $message .= __('Reserve') . '@' . $reserveId . ' 🔒';
  592. $this->sendTelegram($employeeId, $message);
  593. }
  594. }
  595. /**
  596. * Sends reserve remains daily notifications to employees
  597. *
  598. * @return void
  599. */
  600. public function telegramReserveDailyNotify() {
  601. if (!empty($this->allReserve)) {
  602. if ($this->altCfg['SENDDOG_ENABLED']) {
  603. $curdate = curdate();
  604. $sendTmp = array(); //employeeid => text aggregated
  605. $reserveTmp = array(); //employeeid=>reserve data with aggr
  606. foreach ($this->allReserve as $io => $eachReserve) {
  607. $employeeId = $eachReserve['employeeid'];
  608. $chatId = @$this->allEmployeeTelegram[$employeeId];
  609. $itemtypeId = $eachReserve['itemtypeid'];
  610. $itemCount = $eachReserve['count'];
  611. if (!empty($chatId)) {
  612. if (!isset($reserveTmp[$employeeId])) {
  613. $reserveTmp[$employeeId] = array();
  614. }
  615. if (isset($reserveTmp[$employeeId][$itemtypeId])) {
  616. $reserveTmp[$employeeId][$itemtypeId] += $itemCount;
  617. } else {
  618. $reserveTmp[$employeeId][$itemtypeId] = $itemCount;
  619. }
  620. }
  621. }
  622. if (!empty($reserveTmp)) {
  623. foreach ($reserveTmp as $eachEmployee => $reservedItems) {
  624. $totalCostSumm = 0;
  625. $message = __('Is reserved for you') . '\r\n ';;
  626. foreach ($reservedItems as $eachItemId => $eachItemCount) {
  627. $message .= @$this->allItemTypeNames[$eachItemId] . ': ' . $eachItemCount . ' ' . @$this->unitTypes[$this->allItemTypes[$eachItemId]['unit']] . '\r\n ';
  628. $itemCost = $this->getIncomeMiddlePrice($eachItemId);
  629. $totalCostSumm += $itemCost * $eachItemCount;
  630. }
  631. $message .= '📦📦📦📦' . '\r\n '; // very vsrate emoji
  632. $message .= __('Total cost') . ': ' . $totalCostSumm . '\r\n '; //pugalo inside
  633. $message .= '💸💸💸💸' . '\r\n '; // dont ask me why
  634. $sendTmp[$eachEmployee] = $message;
  635. }
  636. }
  637. if (!empty($sendTmp)) {
  638. foreach ($sendTmp as $io => $eachMessage) {
  639. $this->sendTelegram($io, $eachMessage);
  640. }
  641. }
  642. }
  643. }
  644. }
  645. /**
  646. * Creates new reserve record in database
  647. *
  648. * @param int $storageId
  649. * @param int $itemtypeId
  650. * @param float $count
  651. * @param int $employeeId
  652. *
  653. * @return void/string if succefull or error message
  654. */
  655. public function reserveCreate($storageId, $itemtypeId, $count, $employeeId) {
  656. $storageId = vf($storageId, 3);
  657. $itemtypeId = vf($itemtypeId, 3);
  658. $countF = mysql_real_escape_string($count);
  659. $countF = str_replace(',', '.', $countF);
  660. $employeeId = vf($employeeId, 3);
  661. $storageRemains = $this->remainsOnStorage($storageId);
  662. @$itemtypeRemains = $storageRemains[$itemtypeId];
  663. if (empty($itemtypeRemains)) {
  664. $itemtypeRemains = 0;
  665. }
  666. $alreadyReserved = $this->reserveGet($storageId, $itemtypeId);
  667. $realRemains = $itemtypeRemains - $alreadyReserved;
  668. $result = '';
  669. if (isset($this->allStorages[$storageId])) {
  670. if (isset($this->allItemTypes[$itemtypeId])) {
  671. if (isset($this->allEmployee[$employeeId])) {
  672. if ($realRemains >= $countF) {
  673. $query = "INSERT INTO `wh_reserve` (`id`,`storageid`,`itemtypeid`,`count`,`employeeid`) VALUES "
  674. . "(NULL,'" . $storageId . "','" . $itemtypeId . "','" . $countF . "','" . $employeeId . "')";
  675. nr_query($query);
  676. $newId = simple_get_lastid('wh_reserve');
  677. log_register('WAREHOUSE RESERVE CREATE [' . $newId . '] ITEM [' . $itemtypeId . '] COUNT `' . $count . '` EMPLOYEE [' . $employeeId . ']');
  678. $this->reservePushLog('create', $storageId, $itemtypeId, $count, $employeeId, $newId);
  679. $this->reserveCreationNotify($storageId, $itemtypeId, $count, $employeeId, $newId);
  680. } else {
  681. $result = $this->messages->getStyledMessage($this->allItemTypeNames[$itemtypeId] . '. ' . __('The balance of goods and materials in stock is less than the amount') . ' (' . $countF . ' > ' . $itemtypeRemains . '-' . $alreadyReserved . ')', 'error');
  682. }
  683. } else {
  684. $result = $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('No available workers for reserve creation'), 'error');
  685. }
  686. } else {
  687. $result = $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('No existing warehouse item types'), 'error');
  688. }
  689. } else {
  690. $result = $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('No existing warehouse storages'), 'error');
  691. }
  692. return ($result);
  693. }
  694. /**
  695. * Creates mass reservation if required and returns its results as formatted notifications
  696. *
  697. * @return string
  698. */
  699. public function reserveMassCreate() {
  700. $result = '';
  701. $successCount = 0;
  702. if (wf_CheckPost(array('newmassemployeeid', 'newmassstorageid', 'newmasscreation'))) {
  703. $employeeId = vf($_POST['newmassemployeeid'], 3);
  704. $storageId = vf($_POST['newmassstorageid']);
  705. $postTmp = $_POST;
  706. foreach ($postTmp as $io => $each) {
  707. if (ispos($io, 'newmassitemtype_')) {
  708. $rawData = explode('_', $io);
  709. $itemtypeId = $rawData[1];
  710. $itemCount = $each;
  711. if ($itemCount > 0) {
  712. $reserveResult = $this->reserveCreate($storageId, $itemtypeId, $itemCount, $employeeId);
  713. if (!empty($reserveResult)) {
  714. //some shit happened
  715. $result .= $reserveResult;
  716. } else {
  717. //success!
  718. $result .= $this->messages->getStyledMessage($this->allItemTypeNames[$itemtypeId] . '. ' . __('Reserved') . ' (' . $itemCount . ' ' . @$this->unitTypes[$this->allItemTypes[$itemtypeId]['unit']] . ')', 'success');
  719. $successCount++;
  720. }
  721. }
  722. }
  723. }
  724. //live data update
  725. if ($successCount > 0) {
  726. $this->loadReserve();
  727. }
  728. }
  729. return ($result);
  730. }
  731. /**
  732. * Renders current dayly items reserved for some employee
  733. *
  734. * @param int $employeeId
  735. *
  736. * @return string
  737. */
  738. protected function reserveRenderTodayReserved($employeeId) {
  739. $employeeId = vf($employeeId, 3);
  740. $result = '';
  741. $this->loadReserveHistory();
  742. if (!empty($this->allReserveHistory)) {
  743. $curDate = curdate();
  744. foreach ($this->allReserveHistory as $io => $each) {
  745. if ($each['employeeid'] == $employeeId) {
  746. if ($each['type'] == 'create') {
  747. if (ispos($each['date'], $curDate)) {
  748. $itemtypeId = $each['itemtypeid'];
  749. $label = @$this->allItemTypeNames[$itemtypeId] . '. ' . __('Already reserved today') . ' (' . $each['count'] . ' ' . @$this->unitTypes[$this->allItemTypes[$itemtypeId]['unit']] . ')';
  750. $result .= $this->messages->getStyledMessage($label, 'info');
  751. }
  752. }
  753. }
  754. }
  755. }
  756. return ($result);
  757. }
  758. /**
  759. * Renders mass reservation form
  760. *
  761. * @return string
  762. */
  763. public function reserveMassForm() {
  764. $result = '';
  765. $emptyWarehouse = false;
  766. $realRemains = array();
  767. $employeeTmp = array('' => '-');
  768. $employeeTmp += $this->activeEmployee;
  769. $storageTmp = array('' => '-');
  770. $storageTmp += $this->allStorages;
  771. if (!empty($this->allStorages)) {
  772. $inputs = wf_SelectorAC('newmassemployeeid', $employeeTmp, __('Employee'), @$_POST['newmassemployeeid'], true);
  773. if (wf_CheckPost(array('newmassemployeeid'))) {
  774. $inputs .= wf_SelectorAC('newmassstorageid', $storageTmp, __('Warehouse storage'), @$_POST['newmassstorageid'], true);
  775. if (wf_CheckPost(array('newmassstorageid'))) {
  776. $storageRemains = $this->remainsOnStorage($_POST['newmassstorageid']);
  777. if (!empty($storageRemains)) {
  778. foreach ($storageRemains as $io => $each) {
  779. $alreadyReserved = $this->reserveGet($_POST['newmassstorageid'], $io);
  780. $realCount = $each - $alreadyReserved;
  781. if ($realCount > 0) {
  782. $realRemains[$io] = $each - $alreadyReserved;
  783. }
  784. }
  785. if (empty($realRemains)) {
  786. $emptyWarehouse = true;
  787. } else {
  788. $cells = wf_TableCell(__('Category'));
  789. $cells .= wf_TableCell(__('Warehouse item types'));
  790. $cells .= wf_TableCell(__('Count'));
  791. $cells .= wf_TableCell(__('Reserve'));
  792. $rows = wf_TableRow($cells, 'row1');
  793. foreach ($realRemains as $itemtypeId => $itemCount) {
  794. $itemTypeLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $itemtypeId, @$this->allItemTypeNames[$itemtypeId]);
  795. $cells = wf_TableCell(@$this->allCategories[$this->allItemTypes[$itemtypeId]['categoryid']]);
  796. $cells .= wf_TableCell($itemTypeLink);
  797. $cells .= wf_TableCell($itemCount . ' ' . @$this->unitTypes[$this->allItemTypes[$itemtypeId]['unit']]);
  798. $cells .= wf_TableCell(wf_TextInput('newmassitemtype_' . $itemtypeId, '', '0', false, 4));
  799. $rows .= wf_TableRow($cells, 'row5');
  800. }
  801. $inputs .= wf_TableBody($rows, '100%', 0, '');
  802. $inputs .= wf_CheckInput('newmasscreation', __('I`m ready'), true, false);
  803. $inputs .= wf_tag('br');
  804. $inputs .= wf_Submit(__('Reservation'));
  805. }
  806. } else {
  807. $emptyWarehouse = true;
  808. }
  809. }
  810. }
  811. $result .= wf_Form('', 'POST', $inputs, '');
  812. if (wf_CheckPost(array('newmassemployeeid'))) {
  813. $result .= $this->reserveRenderTodayReserved(@$_POST['newmassemployeeid']);
  814. }
  815. if ($emptyWarehouse) {
  816. // ,_ /) (\ _,
  817. // >> <<,_,>> <<
  818. // // _0.-.0_ \\
  819. // \'._/ \_.'/
  820. // '-.\.--.--./.-'
  821. // __/ : :Y: : \ _
  822. //';, .-(_| : : | : : |_)-. ,:'
  823. // \\/.' |: : :|: : :| `.\//
  824. // (/ |: : :|: : :| \)
  825. // |: : :|: : :;
  826. // /\ : : | : : /\
  827. // (_/'.: :.: :.'\_)
  828. // \\ `""`""` //
  829. // \\ //
  830. // ':. .:'
  831. $result .= $this->messages->getStyledMessage(__('Warehouse storage is empty'), 'warning');
  832. }
  833. }
  834. return ($result);
  835. }
  836. /**
  837. * Returns itemtype reservation interface
  838. *
  839. * @param int $storageId
  840. * @param int $itemtypeId
  841. *
  842. * @return string
  843. */
  844. public function reserveCreateForm($storageId, $itemtypeId) {
  845. $storageId = vf($storageId, 3);
  846. $itemtypeId = vf($itemtypeId, 3);
  847. $result = '';
  848. if (isset($this->allStorages[$storageId])) {
  849. if (isset($this->allItemTypes[$itemtypeId])) {
  850. if (!empty($this->activeEmployee)) {
  851. $storageRemains = $this->remainsOnStorage($storageId);
  852. if (isset($storageRemains[$itemtypeId])) {
  853. $itemRemainsStorage = $storageRemains[$itemtypeId];
  854. } else {
  855. $itemRemainsStorage = 0;
  856. }
  857. $alreadyReserved = $this->reserveGet($storageId, $itemtypeId);
  858. $itemtypeData = $this->allItemTypes[$itemtypeId];
  859. $itemtypeName = $this->allItemTypeNames[$itemtypeId];
  860. $itemtypeUnit = $this->unitTypes[$itemtypeData['unit']];
  861. $inputs = wf_HiddenInput('newreserveitemtypeid', $itemtypeId);
  862. $inputs .= wf_HiddenInput('newreservestorageid', $storageId);
  863. $inputs .= wf_Selector('newreserveemployeeid', $this->activeEmployee, __('Worker'), '', true);
  864. $inputs .= wf_TextInput('newreservecount', $itemtypeUnit . ' (' . ($itemRemainsStorage - $alreadyReserved) . ' ' . __('maximum') . ')', '', true, 5);
  865. $inputs .= wf_Submit(__('Create'));
  866. $form = wf_Form('', 'POST', $inputs, 'glamour');
  867. $remainsText = __('At storage') . ' ' . $this->allStorages[$storageId] . ' ' . __('remains') . ' ' . $itemRemainsStorage . ' ' . $itemtypeUnit . ' ' . $itemtypeName;
  868. $remainsInfo = $this->messages->getStyledMessage($remainsText, 'success');
  869. if ($alreadyReserved) {
  870. $remainsInfo .= $this->messages->getStyledMessage(__('minus') . ' ' . $alreadyReserved . ' ' . __('already reserved'), 'info');
  871. }
  872. $cells = wf_TableCell($form, '40%');
  873. $cells .= wf_TableCell($remainsInfo, '', '', 'valign="top"');
  874. $rows = wf_TableRow($cells, '');
  875. $result = wf_TableBody($rows, '100%', 0, '');
  876. } else {
  877. $result = $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('No available workers for reserve creation'), 'error');
  878. }
  879. } else {
  880. $result = $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('No existing warehouse item types'), 'error');
  881. }
  882. } else {
  883. $result = $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('No existing warehouse storages'), 'error');
  884. }
  885. return ($result);
  886. }
  887. /**
  888. * Deletes existing reservation record from database
  889. *
  890. * @param int $id
  891. *
  892. * @return void
  893. */
  894. public function reserveDelete($id) {
  895. $id = vf($id, 3);
  896. if (isset($this->allReserve[$id])) {
  897. $reserveData = $this->allReserve[$id];
  898. if (!empty($reserveData)) {
  899. $this->reservePushLog('delete', $reserveData['storageid'], $reserveData['itemtypeid'], $reserveData['count'], $reserveData['employeeid'], $id);
  900. }
  901. $query = "DELETE from `wh_reserve` WHERE `id`='" . $id . "';";
  902. nr_query($query);
  903. log_register('WAREHOUSE RESERVE DELETE [' . $id . ']');
  904. }
  905. }
  906. /**
  907. * Returns reserve record editing form
  908. *
  909. * @param int $id
  910. * @param bool $hideEmployee
  911. *
  912. * @return string
  913. */
  914. public function reserveEditForm($id, $hideEmployee = false) {
  915. $id = vf($id, 3);
  916. $result = '';
  917. if (isset($this->allReserve[$id])) {
  918. $reserveData = $this->allReserve[$id];
  919. $reserveStorage = $reserveData['storageid'];
  920. @$itemName = $this->allItemTypeNames[$reserveData['itemtypeid']];
  921. @$itemData = $this->allItemTypes[$reserveData['itemtypeid']];
  922. @$itemUnit = $this->unitTypes[$itemData['unit']];
  923. if ($hideEmployee) {
  924. $inputs = wf_HiddenInput('editreserveemployeeid', $reserveData['employeeid']);
  925. } else {
  926. $inputs = wf_Selector('editreserveemployeeid', $this->activeEmployee, __('Worker'), $reserveData['employeeid'], true);
  927. }
  928. $inputs .= wf_TextInput('editreservecount', $itemUnit . ' ' . $itemName, $reserveData['count'], true, 5);
  929. $inputs .= wf_HiddenInput('editreserveid', $id);
  930. $inputs .= wf_Submit(__('Save'));
  931. $result = wf_Form('', 'POST', $inputs, 'glamour');
  932. }
  933. return ($result);
  934. }
  935. /**
  936. * Drain items from some reserve. If items count less than zero - deletes reserve.
  937. *
  938. * @param int $reserveId
  939. * @param float $count
  940. *
  941. * @return void
  942. */
  943. protected function reserveDrain($reserveId, $count) {
  944. $reserveId = vf($reserveId, 3);
  945. if (isset($this->allReserve[$reserveId])) {
  946. $reserveData = $this->allReserve[$reserveId];
  947. $oldCount = $reserveData['count'];
  948. if (empty($oldCount)) {
  949. $oldCount = 0;
  950. }
  951. if (empty($count)) {
  952. $count = 0;
  953. }
  954. $newCount = $oldCount - $count;
  955. $newCountF = mysql_real_escape_string($newCount);
  956. $where = " WHERE `id`='" . $reserveId . "';";
  957. if ($newCountF > 0) {
  958. simple_update_field('wh_reserve', 'count', $newCountF, $where);
  959. log_register('WAREHOUSE RESERVE DRAIN [' . $reserveId . '] COUNT `' . $newCount . '` EMPLOYEE [' . $reserveData['employeeid'] . ']');
  960. $this->reservePushLog('update', $reserveData['storageid'], $reserveData['itemtypeid'], $newCount, $reserveData['employeeid'], $reserveId);
  961. } else {
  962. $this->reserveDelete($reserveId);
  963. }
  964. }
  965. }
  966. /**
  967. * Saves reserve changes into database
  968. *
  969. * @return void
  970. */
  971. public function reserveSave() {
  972. if (wf_CheckPost(array('editreserveid', 'editreserveemployeeid', 'editreservecount'))) {
  973. $id = vf($_POST['editreserveid'], 3);
  974. if (isset($this->allReserve[$id])) {
  975. $reserveData = $this->allReserve[$id];
  976. if (!empty($reserveData)) {
  977. $reserveStorage = $reserveData['storageid'];
  978. $reserveItemtypeId = $reserveData['itemtypeid'];
  979. $count = $_POST['editreservecount'];
  980. $countF = mysql_real_escape_string($count);
  981. $countF = str_replace(',', '.', $countF);
  982. $employeeId = vf($_POST['editreserveemployeeid'], 3);
  983. $where = " WHERE `id`='" . $id . "';";
  984. $storageRemains = $this->remainsOnStorage($reserveStorage);
  985. @$itemtypeRemains = $storageRemains[$reserveItemtypeId];
  986. if (empty($itemtypeRemains)) {
  987. $itemtypeRemains = 0;
  988. }
  989. $alreadyReserved = $this->reserveGet($reserveStorage, $reserveData['itemtypeid']);
  990. $realRemains = $itemtypeRemains - $alreadyReserved;
  991. $controlRemains = $realRemains + $reserveData['count'];
  992. if ($controlRemains >= $countF) {
  993. simple_update_field('wh_reserve', 'employeeid', $employeeId, $where);
  994. simple_update_field('wh_reserve', 'count', $countF, $where);
  995. log_register('WAREHOUSE RESERVE EDIT [' . $id . '] COUNT `' . $count . '` EMPLOYEE [' . $employeeId . ']');
  996. $this->reservePushLog('update', $reserveStorage, $reserveItemtypeId, $count, $employeeId, $id);
  997. } else {
  998. log_register('WAREHOUSE RESERVE FAIL [' . $id . '] TO MANY COUNT `' . $count . '` EMPLOYEE [' . $employeeId . ']');
  999. }
  1000. } else {
  1001. log_register('WAREHOUSE RESERVE FAIL [' . $id . '] EMPTY DATA');
  1002. }
  1003. }
  1004. }
  1005. }
  1006. /**
  1007. * Returns reserve creation date extracted from log if exists
  1008. *
  1009. * @param int $resId
  1010. *
  1011. * @return string
  1012. */
  1013. protected function reserveGetCreationDate($resId) {
  1014. $result = __('Nothing');
  1015. if (isset($this->allReserveCreationDates[$resId])) {
  1016. $result = $this->allReserveCreationDates[$resId];
  1017. }
  1018. return ($result);
  1019. }
  1020. /**
  1021. * Renders list of available reserved items sorted by Employee with some controls
  1022. *
  1023. * @return string
  1024. */
  1025. public function reserveRenderList() {
  1026. $result = '';
  1027. $printFlag = (wf_CheckGet(array('printable'))) ? true : false;
  1028. if (!empty($this->allReserve)) {
  1029. $columns = array(
  1030. __('ID'),
  1031. __('Creation date'),
  1032. __('Warehouse storage'),
  1033. __('Category'),
  1034. __('Warehouse item type'),
  1035. __('Count'),
  1036. __('Worker'),
  1037. __('Actions')
  1038. );
  1039. $opts = '"order": [[ 0, "desc" ]]';
  1040. $callbackUrl = self::URL_ME . '&' . self::URL_RESERVE . '&reserveajlist=true';
  1041. if (ubRouting::checkGet('empidfilter')) {
  1042. $callbackUrl .= '&empidfilter=' . ubRouting::get('empidfilter', 'int');
  1043. }
  1044. $result = wf_JqDtLoader($columns, $callbackUrl, false, __('Reserved'), 50, $opts);
  1045. } else {
  1046. $result = $this->messages->getStyledMessage(__('Nothing found'), 'info');
  1047. }
  1048. if ($printFlag) {
  1049. $this->loadReserveHistory();
  1050. //Printable report here
  1051. if (!empty($this->allReserve)) {
  1052. $cells = wf_TableCell(__('ID'));
  1053. $cells .= wf_TableCell(__('Creation date'));
  1054. $cells .= wf_TableCell(__('Warehouse storage'));
  1055. $cells .= wf_TableCell(__('Category'));
  1056. $cells .= wf_TableCell(__('Warehouse item type'));
  1057. $cells .= wf_TableCell(__('Count'));
  1058. $cells .= wf_TableCell(__('Worker'));
  1059. $rows = wf_TableRow($cells, 'row1');
  1060. foreach ($this->allReserve as $io => $each) {
  1061. $itemTypeLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $each['itemtypeid'], @$this->allItemTypeNames[$each['itemtypeid']]);
  1062. $cells = wf_TableCell($each['id']);
  1063. $cells .= wf_TableCell($this->reserveGetCreationDate($each['id']));
  1064. $cells .= wf_TableCell(@$this->allStorages[$each['storageid']]);
  1065. $cells .= wf_TableCell(@$this->allCategories[$this->allItemTypes[$each['itemtypeid']]['categoryid']]);
  1066. $cells .= wf_TableCell($itemTypeLink);
  1067. $cells .= wf_TableCell($each['count'] . ' ' . @$this->unitTypes[$this->allItemTypes[$each['itemtypeid']]['unit']]);
  1068. $cells .= wf_TableCell(@$this->allEmployee[$each['employeeid']]);
  1069. $rows .= wf_TableRow($cells, 'row5');
  1070. }
  1071. $result = wf_TableBody($rows, '100%', 0, 'sortable');
  1072. }
  1073. $this->reportPrintable(__('Reserved'), $result);
  1074. } else {
  1075. return ($result);
  1076. }
  1077. }
  1078. /**
  1079. * Renders JSON of available reserves list
  1080. *
  1081. * @param int $employeeId
  1082. *
  1083. * @return void
  1084. */
  1085. public function reserveListAjaxReply($employeeId = '') {
  1086. $json = new wf_JqDtHelper();
  1087. $employeeId = ubRouting::filters($employeeId, 'int');
  1088. $hideEmployee = (empty($employeeId)) ? true : false;
  1089. $filtered = true;
  1090. if (!empty($this->allReserve)) {
  1091. $this->loadReserveHistory();
  1092. foreach ($this->allReserve as $io => $each) {
  1093. if ($employeeId) {
  1094. if ($each['employeeid'] == $employeeId) {
  1095. $filtered = true;
  1096. } else {
  1097. $filtered = false;
  1098. }
  1099. }
  1100. if ($filtered) {
  1101. $itemTypeLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $each['itemtypeid'], @$this->allItemTypeNames[$each['itemtypeid']]);
  1102. $data[] = $each['id'];
  1103. $data[] = $this->reserveGetCreationDate($each['id']);
  1104. $data[] = @$this->allStorages[$each['storageid']];
  1105. $data[] = @$this->allCategories[$this->allItemTypes[$each['itemtypeid']]['categoryid']];
  1106. $data[] = $itemTypeLink;
  1107. $data[] = $each['count'] . ' ' . @$this->unitTypes[$this->allItemTypes[$each['itemtypeid']]['unit']];
  1108. $employeeLinkUrl = self::URL_ME . '&' . self::URL_RESERVE . '&' . 'empidfilter=' . $each['employeeid'];
  1109. $employeeLinkAct = wf_Link($employeeLinkUrl, @$this->allEmployee[$each['employeeid']]);
  1110. $data[] = $employeeLinkAct;
  1111. $actLinks = wf_JSAlert(self::URL_ME . '&' . self::URL_RESERVE . '&deletereserve=' . $each['id'], web_delete_icon(), $this->messages->getEditAlert()) . ' ';
  1112. $actLinks .= wf_modalAuto(web_edit_icon(), __('Edit') . ' ' . __('Reservation'), $this->reserveEditForm($each['id'], $hideEmployee), '') . ' ';
  1113. if ($each['count'] > 0) {
  1114. if (cfr('WAREHOUSEOUTRESERVE')) {
  1115. $outcomeUrl = self::URL_ME . '&' . self::URL_OUT . '&storageid=' . $each['storageid'] . '&outitemid=' . $each['itemtypeid'] . '&reserveid=' . $each['id'];
  1116. $actLinks .= wf_Link($outcomeUrl, wf_img('skins/whoutcoming_icon.png') . ' ' . __('Outcoming'), false, '');
  1117. }
  1118. }
  1119. $data[] = $actLinks;
  1120. $json->addRow($data);
  1121. unset($data);
  1122. }
  1123. }
  1124. }
  1125. $json->getJson();
  1126. }
  1127. /**
  1128. * Returns employee name by its ID
  1129. *
  1130. * @param int $employeeId
  1131. *
  1132. * @return string
  1133. */
  1134. public function getEmployeeName($employeeId) {
  1135. $employeeId = ubRouting::filters($employeeId, 'int');
  1136. $result = '';
  1137. if (isset($this->allEmployee[$employeeId])) {
  1138. $result .= $this->allEmployee[$employeeId];
  1139. }
  1140. return ($result);
  1141. }
  1142. /**
  1143. * Renders mass out employee replacement form and performs some redirects if required.
  1144. *
  1145. * @param int $employeeId
  1146. *
  1147. * @return string
  1148. */
  1149. public function renderMassOutEmployyeReplaceForm($employeeId) {
  1150. $result = '';
  1151. //redirect to new employee reserve
  1152. if (ubRouting::checkPost(self::PROUTE_EMPREPLACE)) {
  1153. $newEmpId = ubRouting::post(self::PROUTE_EMPREPLACE, 'int');
  1154. $newRoute = self::URL_ME . '&' . self::URL_RESERVE . '&massoutemployee=' . $newEmpId;
  1155. if (ubRouting::checkGet('taskidpreset')) {
  1156. $taskId = ubRouting::get('taskidpreset', 'int');
  1157. $newRoute .= '&taskidpreset=' . $taskId;
  1158. }
  1159. ubRouting::nav($newRoute);
  1160. }
  1161. //build some form
  1162. if (!empty($this->activeEmployee)) {
  1163. $inputs = wf_Selector(self::PROUTE_EMPREPLACE, $this->activeEmployee, __('Worker'), $employeeId, false) . ' ';
  1164. $inputs .= wf_Submit(__('Change'));
  1165. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  1166. } else {
  1167. $result .= $this->messages->getStyledMessage(__('No job types and employee available'), 'error');
  1168. }
  1169. return ($result);
  1170. }
  1171. /**
  1172. * Renders mass outcome form for some employeeId reserved items
  1173. *
  1174. * @param int $employeeId
  1175. *
  1176. * @return string
  1177. */
  1178. public function renderMassOutForm($employeeId) {
  1179. $result = '';
  1180. $employeeId = ubRouting::filters($employeeId, 'int');
  1181. $employeeInventory = array();
  1182. $form = '';
  1183. $form .= wf_FormDisabler();
  1184. if (!empty($employeeId)) {
  1185. if (isset($this->allEmployee[$employeeId])) {
  1186. if (!empty($this->allReserve)) {
  1187. foreach ($this->allReserve as $reserveId => $reserveData) {
  1188. if ($reserveData['employeeid'] == $employeeId) {
  1189. $employeeInventory[$reserveId] = $reserveData;
  1190. }
  1191. }
  1192. }
  1193. if (!empty($employeeInventory)) {
  1194. $result .= wf_AjaxLoader();
  1195. //destination interface
  1196. $tmpDests = array();
  1197. foreach ($this->outDests as $destMark => $destName) {
  1198. $tmpDests[self::URL_ME . '&' . self::URL_OUT . '&' . self::URL_AJODSELECTOR . $destMark] = $destName;
  1199. }
  1200. $inputs = wf_HiddenInput(self::PROUTE_DOMASSRESOUT, $employeeId);
  1201. $inputs .= wf_AjaxSelectorAC('ajoutdestselcontainer', $tmpDests, __('Destination'), '', false);
  1202. $inputs .= wf_AjaxContainer('ajoutdestselcontainer', '', $this->outcomindAjaxDestSelector('task'));
  1203. $form .= $inputs;
  1204. $form .= wf_delimiter(0);
  1205. //reserves interface
  1206. $cells = wf_TableCell(__('Creation date'));
  1207. $cells .= wf_TableCell(__('Warehouse storage'));
  1208. $cells .= wf_TableCell(__('Category'));
  1209. $cells .= wf_TableCell(__('Warehouse item type'));
  1210. $cells .= wf_TableCell(__('Reserved'));
  1211. $cells .= wf_TableCell(__('Count'));
  1212. $cells .= wf_TableCell(__('Price'));
  1213. $cells .= wf_TableCell(__('Notes'));
  1214. $rows = wf_TableRow($cells, 'row1');
  1215. foreach ($employeeInventory as $eachInvId => $eachInvData) {
  1216. $itemTypeId = $eachInvData['itemtypeid'];
  1217. $itemTypeCategory = $this->allCategories[$this->allItemTypes[$itemTypeId]['categoryid']];
  1218. $itemTypeName = $this->allItemTypeNames[$itemTypeId];
  1219. $itemTypeStorageId = $this->allStorages[$eachInvData['storageid']];
  1220. $itemTypeUnit = $this->allItemTypes[$itemTypeId]['unit'];
  1221. $itemTypeRecPrice = $this->getIncomeMiddlePrice($itemTypeId);
  1222. $midPriceLabel = ($this->recPriceFlag) ? __('recommended') : __('middle price');
  1223. $midPriceNotice = wf_tag('abbr', false, '', 'title="' . $midPriceLabel . ': ' . $itemTypeRecPrice . '"') . '?' . wf_tag('abbr', true);
  1224. $cells = wf_TableCell($this->reserveGetCreationDate($eachInvId));
  1225. $cells .= wf_TableCell($itemTypeStorageId);
  1226. $cells .= wf_TableCell($itemTypeCategory);
  1227. $cells .= wf_TableCell($itemTypeName);
  1228. $cells .= wf_TableCell($eachInvData['count'] . ' ' . __($itemTypeUnit));
  1229. $cells .= wf_TableCell(wf_TextInput(self::PROUTE_MASSRESERVEOUT . '[' . $eachInvId . '][count]', $itemTypeUnit, '', false, 5, 'float'));
  1230. $cells .= wf_TableCell(wf_TextInput(self::PROUTE_MASSRESERVEOUT . '[' . $eachInvId . '][price]', $midPriceNotice, '', false, 3, 'finance'));
  1231. $defaultNotePreset = '';
  1232. $cells .= wf_TableCell(wf_TextInput(self::PROUTE_MASSRESERVEOUT . '[' . $eachInvId . '][note]', '', $defaultNotePreset, false, 15));
  1233. $rows .= wf_TableRow($cells, 'row5');
  1234. }
  1235. $form .= wf_TableBody($rows, '100%', 0, 'sortable');
  1236. $form .= wf_CheckInput(self::PROUTE_MASSNETWOUT, __('Network'), true, false);
  1237. $form .= wf_delimiter(0);
  1238. $massOutAgreement = __('I`m ready') . '. ';
  1239. $massOutAgreement .= __('I also understand well that no one will correct my mistakes for me and only I bear full financial responsibility for my mistakes') . '.';
  1240. $form .= wf_CheckInput(self::PROUTE_MASSAGREEOUT, $massOutAgreement, true, false);
  1241. $form .= wf_delimiter(0);
  1242. $form .= wf_Submit(__('Mass outcome'));
  1243. $result .= wf_Form('', 'POST', $form, '');
  1244. } else {
  1245. $result .= $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('Nothing reserved for this employee'), 'error');
  1246. }
  1247. } else {
  1248. $result .= $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('Worker') . ' [' . $employeeId . '] ' . __('Not exists'), 'error');
  1249. }
  1250. } else {
  1251. $result .= $this->messages->getStyledMessage(__('Strange exeption') . ' EX_EMPLOYEEID_EMPTY', 'error');
  1252. }
  1253. return ($result);
  1254. }
  1255. /**
  1256. * Runs batch outcome operations creation based on reserve
  1257. *
  1258. * @return void/string on error
  1259. */
  1260. public function runMassReserveOutcome() {
  1261. $result = '';
  1262. $outCount = 0;
  1263. if (ubRouting::checkPost(self::PROUTE_DOMASSRESOUT)) {
  1264. if (ubRouting::checkPost(self::PROUTE_MASSAGREEOUT)) {
  1265. if (ubRouting::checkPost(array('newoutdesttype', 'newoutdestparam', 'massoutreserves'))) {
  1266. $employeeId = ubRouting::post(self::PROUTE_DOMASSRESOUT);
  1267. $outDestType = ubRouting::post('newoutdesttype');
  1268. $outDestParam = ubRouting::post('newoutdestparam');
  1269. $outResArr = ubRouting::post(self::PROUTE_MASSRESERVEOUT);
  1270. $netwFlag = ubRouting::checkPost(self::PROUTE_MASSNETWOUT) ? true : false;
  1271. $curDate = curdate();
  1272. if (!empty($outResArr)) {
  1273. if (is_array($outResArr)) {
  1274. foreach ($outResArr as $eachReserveId => $eachReserveData) {
  1275. if (isset($this->allReserve[$eachReserveId])) {
  1276. if ($eachReserveData['count'] > 0) {
  1277. $reserveOpts = $this->allReserve[$eachReserveId];
  1278. $storageId = $reserveOpts['storageid'];
  1279. $itemtypeId = $reserveOpts['itemtypeid'];
  1280. $count = $eachReserveData['count'];
  1281. $price = $eachReserveData['price'];
  1282. $defaultNote = ' ' . __('from reserved on') . ' ' . @$this->allEmployee[$employeeId];
  1283. $outcomeNote = (!empty($eachReserveData['note'])) ? $defaultNote . ' ' . $eachReserveData['note'] : $defaultNote;
  1284. $eachOutcomeResult = $this->outcomingCreate($curDate, $outDestType, $outDestParam, $storageId, $itemtypeId, $count, $price, $outcomeNote, $eachReserveId, $netwFlag);
  1285. if (!empty($eachOutcomeResult)) {
  1286. $itemtypeIssueLabel = __('Problem') . ': ' . $this->allItemTypeNames[$itemtypeId];
  1287. $result .= $this->messages->getStyledMessage($itemtypeIssueLabel, 'warning');
  1288. $result .= $eachOutcomeResult;
  1289. log_register('WAREHOUSE RESMASSOUT FAIL ITEMID [' . $itemtypeId . '] COUNT `' . $count . '`');
  1290. //Saving debug log
  1291. file_put_contents(self::LOG_PATH, '==================' . PHP_EOL, FILE_APPEND);
  1292. file_put_contents(self::LOG_PATH, curdatetime() . PHP_EOL, FILE_APPEND);
  1293. file_put_contents(self::LOG_PATH, 'GET DATA:' . PHP_EOL, FILE_APPEND);
  1294. file_put_contents(self::LOG_PATH, print_r(ubRouting::rawGet(), true) . PHP_EOL, FILE_APPEND);
  1295. file_put_contents(self::LOG_PATH, 'POST DATA:' . PHP_EOL, FILE_APPEND);
  1296. file_put_contents(self::LOG_PATH, print_r(ubRouting::rawPost(), true) . PHP_EOL, FILE_APPEND);
  1297. file_put_contents(self::LOG_PATH, 'RESERVE OPTS:' . PHP_EOL, FILE_APPEND);
  1298. file_put_contents(self::LOG_PATH, print_r($reserveOpts, true) . PHP_EOL, FILE_APPEND);
  1299. file_put_contents(self::LOG_PATH, 'INVOKES:' . $itemtypeIssueLabel . ' ' . strip_tags($eachOutcomeResult) . PHP_EOL, FILE_APPEND);
  1300. }
  1301. $outCount++;
  1302. }
  1303. } else {
  1304. $result .= $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('Reserve') . ' [' . $eachReserveId . '] ' . __('Not exists'), 'error');
  1305. log_register('WAREHOUSE RESMASSOUT FAIL RESERVE [' . $eachReserveId . '] NOT EXISTS');
  1306. }
  1307. }
  1308. if ($outCount == 0) {
  1309. $result .= $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('Outcoming operations') . ' - 0', 'warning');
  1310. log_register('WAREHOUSE RESMASSOUT FAIL ZERO OUTCOMES');
  1311. }
  1312. } else {
  1313. $result .= $this->messages->getStyledMessage(__('Something went wrong') . ' EX_CORRUPT_RESARR', 'error');
  1314. log_register('WAREHOUSE RESMASSOUT FAIL CORRUPT_RESARR');
  1315. }
  1316. } else {
  1317. $result .= $this->messages->getStyledMessage(__('Something went wrong') . ' EX_EMPTY_RESARR', 'error');
  1318. log_register('WAREHOUSE RESMASSOUT FAIL EMPTY_RESARR');
  1319. }
  1320. }
  1321. } else {
  1322. $result .= $this->messages->getStyledMessage(__('You are not mentally prepared for this'), 'error');
  1323. log_register('WAREHOUSE RESMASSOUT FAIL NO_AGREEMENT');
  1324. }
  1325. }
  1326. return ($result);
  1327. }
  1328. /**
  1329. * Renders printable per-employee reserves summary.
  1330. *
  1331. * @param int $employeeId
  1332. *
  1333. * @return void
  1334. */
  1335. public function reportEmployeeInventrory($employeeId) {
  1336. $employeeId = ubRouting::filters($employeeId, 'int');
  1337. $reportTmp = array();
  1338. $result = '';
  1339. if (!empty($employeeId)) {
  1340. $filtered = true;
  1341. if (!empty($this->allReserve)) {
  1342. foreach ($this->allReserve as $io => $each) {
  1343. if ($each['employeeid'] == $employeeId) {
  1344. if (isset($reportTmp[$each['itemtypeid']])) {
  1345. $reportTmp[$each['itemtypeid']] += $each['count'];
  1346. } else {
  1347. $reportTmp[$each['itemtypeid']] = $each['count'];
  1348. }
  1349. }
  1350. }
  1351. }
  1352. if (!empty($reportTmp)) {
  1353. $cells = wf_TableCell(__('Category'));
  1354. $cells .= wf_TableCell(__('Warehouse item type'));
  1355. $cells .= wf_TableCell(__('Expected count') . ' (' . __('Reserved') . ')');
  1356. if (ubRouting::checkGet('invprintable')) {
  1357. $cells .= wf_TableCell(__('Notes'));
  1358. }
  1359. $rows = wf_TableRow($cells, 'row1');
  1360. foreach ($reportTmp as $itemTypeId => $count) {
  1361. $cells = wf_TableCell(@$this->allCategories[$this->allItemTypes[$itemTypeId]['categoryid']]);
  1362. $cells .= wf_TableCell(@$this->allItemTypeNames[$itemTypeId]);
  1363. $cells .= wf_TableCell($count . ' ' . @$this->unitTypes[$this->allItemTypes[$itemTypeId]['unit']]);
  1364. if (ubRouting::checkGet('invprintable')) {
  1365. $cells .= wf_TableCell('');
  1366. }
  1367. $rows .= wf_TableRow($cells, 'row3');
  1368. }
  1369. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  1370. if (ubRouting::checkGet('invprintable')) {
  1371. //printable inventory report
  1372. $this->reportPrintable(__('Employee inventory') . ': ' . @$this->allEmployee[$employeeId], $result);
  1373. } else {
  1374. //normal renderer
  1375. $inventoryUrl = self::URL_ME . '&' . self::URL_RESERVE . '&empinventory=' . $employeeId . '&invprintable=true';
  1376. $reportControls = wf_Link($inventoryUrl, web_icon_print());
  1377. show_window(__('Employee inventory') . ': ' . @$this->allEmployee[$employeeId] . ' ' . $reportControls, $result);
  1378. }
  1379. } else {
  1380. show_info(__('Nothing to show'));
  1381. }
  1382. } else {
  1383. show_error(__('Something went wrong') . ' EX_EMPLOYEEID_EMPTY');
  1384. }
  1385. }
  1386. /**
  1387. * Renders json list of available reservation history log entries
  1388. *
  1389. * @return void
  1390. */
  1391. public function reserveHistoryAjaxReply() {
  1392. $json = new wf_JqDtHelper();
  1393. $this->loadReserveHistory();
  1394. if (!empty($this->allReserveHistory)) {
  1395. $employeeLogins = unserialize(ts_GetAllEmployeeLoginsCached());
  1396. foreach ($this->allReserveHistory as $io => $each) {
  1397. $operationType = '';
  1398. $administratorName = (isset($employeeLogins[$each['admin']])) ? $employeeLogins[$each['admin']] : $each['admin'];
  1399. switch ($each['type']) {
  1400. case 'create':
  1401. $operationType = __('Created');
  1402. break;
  1403. case 'update':
  1404. $operationType = __('Updated');
  1405. break;
  1406. case 'delete':
  1407. $operationType = __('Deleted');
  1408. break;
  1409. }
  1410. if (!empty($each['resid'])) {
  1411. $resIdLabel = __('Reserve') . '@' . $each['resid'];
  1412. } else {
  1413. $resIdLabel = '';
  1414. }
  1415. $data[] = $resIdLabel;
  1416. $data[] = $each['date'];
  1417. $data[] = $operationType;
  1418. $data[] = @$this->allStorages[$each['storageid']];
  1419. $data[] = @$this->allCategories[$this->allItemTypes[$each['itemtypeid']]['categoryid']];
  1420. $data[] = wf_link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $each['itemtypeid'], @$this->allItemTypeNames[$each['itemtypeid']]);
  1421. $data[] = $each['count'] . ' ' . @$this->unitTypes[$this->allItemTypes[$each['itemtypeid']]['unit']];
  1422. $data[] = @$this->allEmployee[$each['employeeid']];
  1423. $data[] = $administratorName;
  1424. $json->addRow($data);
  1425. unset($data);
  1426. }
  1427. }
  1428. $json->getJson();
  1429. }
  1430. /**
  1431. * Returns array of available administrators as login=>name
  1432. *
  1433. * @return array
  1434. */
  1435. protected function getAdminNames() {
  1436. $result = array();
  1437. $all = rcms_scandir(USERS_PATH);
  1438. if (!empty($all)) {
  1439. $employeeLogins = unserialize(ts_GetAllEmployeeLoginsCached());
  1440. foreach ($all as $each) {
  1441. $administratorName = (isset($employeeLogins[$each])) ? $employeeLogins[$each] : $each;
  1442. $result[$each] = $administratorName;
  1443. }
  1444. }
  1445. return ($result);
  1446. }
  1447. /**
  1448. * Renders reserve history print filtering form
  1449. *
  1450. * @return string
  1451. */
  1452. public function reserveHistoryFilterForm() {
  1453. $result = '';
  1454. $adminNames = array('' => '-');
  1455. $adminNames += $this->getAdminNames();
  1456. $inputs = __('From') . ' ' . wf_DatePickerPreset('reshistfilterfrom', curdate()) . ' ';
  1457. $inputs .= __('To') . ' ' . wf_DatePickerPreset('reshistfilterto', curdate()) . ' ';
  1458. $inputs .= wf_Selector('reshistfilteremployeeid', $this->activeEmployee, __('Worker'), '', false);
  1459. $inputs .= wf_Selector('reshistfilteradminlogin', $adminNames, __('Admin'), '', false);
  1460. $inputs .= wf_Submit(__('Print'));
  1461. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  1462. return ($result);
  1463. }
  1464. /**
  1465. * Renders printable report of reserve operations history
  1466. *
  1467. * @return void
  1468. */
  1469. public function reserveHistoryPrintFiltered() {
  1470. $result = '';
  1471. $this->loadReserveHistory();
  1472. if (wf_CheckPost(array('reshistfilterfrom', 'reshistfilterto', 'reshistfilteremployeeid'))) {
  1473. $dateFrom = $_POST['reshistfilterfrom'];
  1474. $dateTo = $_POST['reshistfilterto'];
  1475. $employeeId = vf($_POST['reshistfilteremployeeid'], 3);
  1476. $adminLogin = @$_POST['reshistfilteradminlogin'];
  1477. if (zb_checkDate($dateFrom) and zb_checkDate($dateTo)) {
  1478. $dateFrom = $dateFrom . ' 00:00:00';
  1479. $dateTo = $dateTo . ' 23:59:59';
  1480. $dateFrom = strtotime($dateFrom);
  1481. $dateTo = strtotime($dateTo);
  1482. if (!empty($this->allReserveHistory)) {
  1483. $employeeLogins = unserialize(ts_GetAllEmployeeLoginsCached());
  1484. $cells = wf_TableCell(__('ID'));
  1485. $cells .= wf_TableCell(__('Date'));
  1486. $cells .= wf_TableCell(__('Type'));
  1487. $cells .= wf_TableCell(__('Warehouse storage'));
  1488. $cells .= wf_TableCell(__('Category'));
  1489. $cells .= wf_TableCell(__('Warehouse item type'));
  1490. $cells .= wf_TableCell(__('Count'));
  1491. $cells .= wf_TableCell(__('Employee'));
  1492. $cells .= wf_TableCell(__('Admin'));
  1493. $rows = wf_TableRow($cells, 'row1');
  1494. foreach ($this->allReserveHistory as $io => $each) {
  1495. $operationDate = strtotime($each['date']);
  1496. $filteredFlag = false;
  1497. //data filtering
  1498. if ($employeeId == $each['employeeid']) {
  1499. if ($operationDate >= $dateFrom and $operationDate <= $dateTo) {
  1500. $filteredFlag = true;
  1501. }
  1502. }
  1503. //optional admin filtering
  1504. if (!empty($adminLogin)) {
  1505. if ($filteredFlag) {
  1506. if ($each['admin'] != $adminLogin) {
  1507. $filteredFlag = false;
  1508. }
  1509. }
  1510. }
  1511. //report assembly
  1512. if ($filteredFlag) {
  1513. $operationType = '';
  1514. $administratorName = (isset($employeeLogins[$each['admin']])) ? $employeeLogins[$each['admin']] : $each['admin'];
  1515. switch ($each['type']) {
  1516. case 'create':
  1517. $operationType = __('Created');
  1518. break;
  1519. case 'update':
  1520. $operationType = __('Updated');
  1521. break;
  1522. case 'delete':
  1523. $operationType = __('Deleted');
  1524. break;
  1525. }
  1526. if (!empty($each['resid'])) {
  1527. $resIdLabel = __('Reserve') . '@' . $each['resid'];
  1528. } else {
  1529. $resIdLabel = '';
  1530. }
  1531. $cells = wf_TableCell($resIdLabel);
  1532. $cells .= wf_TableCell($each['date']);
  1533. $cells .= wf_TableCell($operationType);
  1534. $cells .= wf_TableCell(@$this->allStorages[$each['storageid']]);
  1535. $cells .= wf_TableCell(@$this->allCategories[$this->allItemTypes[$each['itemtypeid']]['categoryid']]);
  1536. $cells .= wf_TableCell(@$this->allItemTypeNames[$each['itemtypeid']]);
  1537. $cells .= wf_TableCell($each['count'] . ' ' . @$this->unitTypes[$this->allItemTypes[$each['itemtypeid']]['unit']]);
  1538. $cells .= wf_TableCell(@$this->allEmployee[$each['employeeid']]);
  1539. $cells .= wf_TableCell($administratorName);
  1540. $rows .= wf_TableRow($cells, 'row3');
  1541. }
  1542. }
  1543. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  1544. $result .= wf_tag('br');
  1545. $result .= __('Signature') . '______________________';
  1546. $this->reportPrintable(__('Act of issuance of goods from the warehouse'), $result);
  1547. } else {
  1548. show_warning(__('Nothing to show'));
  1549. }
  1550. } else {
  1551. show_error(__('Wrong date format'));
  1552. }
  1553. }
  1554. }
  1555. /**
  1556. * Renders reservation history log
  1557. *
  1558. * @return string
  1559. */
  1560. public function reserveRenderHistory() {
  1561. $result = '';
  1562. $colums = array('ID', 'Date', 'Type', 'Warehouse storage', 'Category', 'Warehouse item type', 'Count', 'Employee', 'Admin');
  1563. $opts = '"order": [[ 1, "desc" ]]';
  1564. $ajaxUrl = self::URL_ME . '&' . self::URL_RESERVE . '&reshistajlist=true';
  1565. $result .= wf_JqDtLoader($colums, $ajaxUrl, false, __('Reserve'), 50, $opts);
  1566. $result .= wf_delimiter();
  1567. $result .= $this->reserveHistoryFilterForm();
  1568. return ($result);
  1569. }
  1570. /**
  1571. * Returns cetegory creation form
  1572. *
  1573. * @return string
  1574. */
  1575. public function categoriesCreateForm() {
  1576. $result = '';
  1577. $inputs = wf_TextInput('newcategory', __('Name'), '', false, 20);
  1578. $inputs .= wf_Submit(__('Create'));
  1579. $result = wf_Form(self::URL_ME . '&' . self::URL_CATEGORIES, 'POST', $inputs, 'glamour');
  1580. return ($result);
  1581. }
  1582. /**
  1583. * Returns cetegory edit form
  1584. *
  1585. * @param int $categoryId
  1586. *
  1587. * @return string
  1588. */
  1589. protected function categoriesEditForm($categoryId) {
  1590. $result = '';
  1591. $inputs = wf_TextInput('editcategoryname', __('Name'), $this->allCategories[$categoryId], false, 20);
  1592. $inputs .= wf_HiddenInput('editcategoryid', $categoryId);
  1593. $inputs .= wf_Submit(__('Save'));
  1594. $result = wf_Form(self::URL_ME . '&' . self::URL_CATEGORIES, 'POST', $inputs, 'glamour');
  1595. return ($result);
  1596. }
  1597. /**
  1598. * Renders list of available categories with some controls
  1599. *
  1600. * @return string
  1601. */
  1602. public function categoriesRenderList() {
  1603. $result = '';
  1604. $cells = wf_TableCell(__('ID'));
  1605. $cells .= wf_TableCell(__('Name'));
  1606. $cells .= wf_TableCell(__('Actions'));
  1607. $rows = wf_TableRow($cells, 'row1');
  1608. if (!empty($this->allCategories)) {
  1609. foreach ($this->allCategories as $id => $name) {
  1610. $cells = wf_TableCell($id);
  1611. $cells .= wf_TableCell($name);
  1612. $actLinks = wf_JSAlert(self::URL_ME . '&' . self::URL_CATEGORIES . '&deletecategory=' . $id, web_delete_icon(), $this->messages->getDeleteAlert()) . ' ';
  1613. $actLinks .= wf_modalAuto(web_edit_icon(), __('Edit'), $this->categoriesEditForm($id));
  1614. $cells .= wf_TableCell($actLinks);
  1615. $rows .= wf_TableRow($cells, 'row3');
  1616. }
  1617. }
  1618. $result = wf_TableBody($rows, '100%', 0, 'sortable');
  1619. return ($result);
  1620. }
  1621. /**
  1622. * Creates new category in database
  1623. *
  1624. * @param string $name
  1625. *
  1626. * @return void
  1627. */
  1628. public function categoriesCreate($name) {
  1629. $nameF = mysql_real_escape_string($name);
  1630. $query = "INSERT INTO `wh_categories` (`id`,`name`) VALUES (NULL,'" . $nameF . "');";
  1631. nr_query($query);
  1632. $newId = simple_get_lastid('wh_categories');
  1633. log_register('WAREHOUSE CATEGORY ADD [' . $newId . '] `' . $name . '`');
  1634. }
  1635. /**
  1636. * Check is category used by some items?
  1637. *
  1638. * @param int $categoryId
  1639. *
  1640. * @return bool
  1641. */
  1642. protected function categoryProtected($categoryId) {
  1643. $categoryId = vf($categoryId, 3);
  1644. $result = false;
  1645. if (!empty($this->allItemTypes)) {
  1646. foreach ($this->allItemTypes as $io => $each) {
  1647. if ($each['categoryid'] == $categoryId) {
  1648. $result = true;
  1649. break;
  1650. }
  1651. }
  1652. }
  1653. return ($result);
  1654. }
  1655. /**
  1656. * Deletes existging category from database
  1657. *
  1658. * @param int $categoryId
  1659. *
  1660. * @return bool
  1661. */
  1662. public function categoriesDelete($categoryId) {
  1663. if (isset($this->allCategories[$categoryId])) {
  1664. if (!$this->categoryProtected($categoryId)) {
  1665. $query = "DELETE from `wh_categories` WHERE `id`='" . $categoryId . "';";
  1666. nr_query($query);
  1667. log_register('WAREHOUSE CATEGORY DELETE [' . $categoryId . ']');
  1668. $result = true;
  1669. } else {
  1670. $result = false;
  1671. }
  1672. } else {
  1673. $result = false;
  1674. }
  1675. return ($result);
  1676. }
  1677. /**
  1678. * Saves category changes in database by data recieved from form
  1679. *
  1680. * @return void
  1681. */
  1682. public function categoriesSave() {
  1683. if (wf_CheckPost(array('editcategoryname', 'editcategoryid'))) {
  1684. $categoryId = vf($_POST['editcategoryid']);
  1685. if (isset($this->allCategories[$categoryId])) {
  1686. simple_update_field('wh_categories', 'name', $_POST['editcategoryname'], "WHERE `id`='" . $categoryId . "'");
  1687. log_register('WAREHOUSE CATEGORY EDIT [' . $categoryId . '] `' . $_POST['editcategoryname'] . '`');
  1688. } else {
  1689. log_register('WAREHOUSE CATEGORY EDIT FAIL [' . $categoryId . '] NO_EXISTING');
  1690. }
  1691. }
  1692. }
  1693. /**
  1694. * Renders default back control
  1695. *
  1696. * @param string $url Optional URL
  1697. *
  1698. * @return void
  1699. */
  1700. public function backControl($url = '') {
  1701. if (empty($url)) {
  1702. show_window('', wf_BackLink(self::URL_ME));
  1703. } else {
  1704. show_window('', wf_BackLink($url));
  1705. }
  1706. }
  1707. /**
  1708. * returns report icon and link
  1709. *
  1710. * @return string
  1711. */
  1712. protected function buildReportTask($link, $icon, $text) {
  1713. $task_link = $link;
  1714. $task_icon = $icon;
  1715. $task_text = $text;
  1716. $tbiconsize = 128;
  1717. $template = wf_tag('div', false, 'dashtask', 'style="height:' . ($tbiconsize + 30) . 'px; width:' . ($tbiconsize + 30) . 'px;"');
  1718. $template .= wf_tag('a', false, '', 'href="' . $task_link . '"');
  1719. $template .= wf_img_sized($task_icon, $task_text, $tbiconsize, $tbiconsize);
  1720. $template .= wf_tag('a', true);
  1721. $template .= wf_tag('br');
  1722. $template .= wf_tag('br');
  1723. $template .= $task_text;
  1724. $template .= wf_tag('div', true);
  1725. return ($template);
  1726. }
  1727. /**
  1728. * Renders control panel for whole module
  1729. *
  1730. * @return string
  1731. */
  1732. public function renderPanel() {
  1733. $result = '';
  1734. $result .= wf_Link(self::URL_ME . '&' . self::URL_REPORTS . '&' . 'totalremains=true', wf_img_sized('skins/whstorage_icon.png') . ' ' . __('The remains in all storages'), false, 'ubButton');
  1735. if (cfr('WAREHOUSEIN')) {
  1736. $result .= wf_Link(self::URL_ME . '&' . self::URL_IN, wf_img_sized('skins/whincoming_icon.png') . ' ' . __('Incoming operations'), false, 'ubButton');
  1737. }
  1738. if ((cfr('WAREHOUSEOUT')) or (cfr('WAREHOUSEOUTRESERVE'))) {
  1739. $result .= wf_Link(self::URL_ME . '&' . self::URL_OUT, wf_img_sized('skins/whoutcoming_icon.png') . ' ' . __('Outcoming operations'), false, 'ubButton');
  1740. }
  1741. if (cfr('WAREHOUSERESERVE')) {
  1742. $result .= wf_Link(self::URL_ME . '&' . self::URL_RESERVE, wf_img('skins/whreservation.png') . ' ' . __('Reserved'), false, 'ubButton');
  1743. }
  1744. if (cfr('WAREHOUSEDIR')) {
  1745. $dirControls = '';
  1746. $dirControls .= $this->buildReportTask(self::URL_ME . '&' . self::URL_CATEGORIES, 'skins/taskbar/whcategories.png', __('Warehouse categories'));
  1747. $dirControls .= $this->buildReportTask(self::URL_ME . '&' . self::URL_ITEMTYPES, 'skins/taskbar/whitemtypes.png', __('Warehouse item types'));
  1748. $dirControls .= $this->buildReportTask(self::URL_ME . '&' . self::URL_STORAGES, 'skins/taskbar/whstorage.png', __('Warehouse storages'));
  1749. $dirControls .= $this->buildReportTask(self::URL_ME . '&' . self::URL_CONTRACTORS, 'skins/taskbar/whcontractors.png', __('Contractors'));
  1750. $result .= wf_modalAuto(web_icon_extended() . ' ' . __('Directories'), __('Directories'), $dirControls, 'ubButton');
  1751. }
  1752. if (cfr('WAREHOUSEREPORTS')) {
  1753. $reportControls = '';
  1754. if (@$this->altCfg['WAREHOUSE_RETURNS_ENABLED']) {
  1755. $reportControls .= $this->buildReportTask(self::URL_ME . '&' . self::URL_REPORTS . '&returns=true', 'skins/taskbar/whreturns.png', __('Returns'));
  1756. }
  1757. $reportControls .= $this->buildReportTask(self::URL_ME . '&' . self::URL_REPORTS . '&calendarops=true', 'skins/taskbar/whcalendar.png', __('Operations in the context of time'));
  1758. $reportControls .= $this->buildReportTask(self::URL_ME . '&' . self::URL_REPORTS . '&dateremains=true', 'skins/taskbar/whbat.png', __('Date remains'));
  1759. $reportControls .= $this->buildReportTask(self::URL_ME . '&' . self::URL_REPORTS . '&storagesremains=true', 'skins/taskbar/whremains.png', __('The remains in the warehouse storage'));
  1760. $reportControls .= $this->buildReportTask(self::URL_ME . '&' . self::URL_REPORTS . '&itemtypeoutcomes=true', 'skins/taskbar/whsaleold.png', __('Sales'));
  1761. $reportControls .= $this->buildReportTask(self::URL_ME . '&' . self::URL_REPORTS . '&purchases=true', 'skins/shopping_cart.png', __('Purchases'));
  1762. $reportControls .= $this->buildReportTask(self::URL_ME . '&' . self::URL_REPORTS . '&contractorincomes=true', 'skins/taskbar/whcontractors.png', __('Contractor'));
  1763. $reportControls .= $this->buildReportTask(self::URL_ME . '&' . self::URL_REPORTS . '&netwupgrade=true', 'skins/taskbar/whnetw.png', __('Network upgrade report'));
  1764. $reportControls .= $this->buildReportTask(WHSales::URL_ME, 'skins/taskbar/sales.png', __('Sales report'));
  1765. $result .= wf_modalAuto(wf_img('skins/ukv/report.png') . ' ' . __('Reports'), __('Reports'), $reportControls, 'ubButton');
  1766. }
  1767. return ($result);
  1768. }
  1769. /**
  1770. * Returns item types creation form
  1771. *
  1772. * @return string
  1773. */
  1774. public function itemtypesCreateForm() {
  1775. $result = '';
  1776. if (!empty($this->allCategories)) {
  1777. $inputs = wf_Selector('newitemtypecetegoryid', $this->allCategories, __('Category'), '', true);
  1778. $inputs .= wf_TextInput('newitemtypename', __('Name'), '', true, '20');
  1779. $inputs .= wf_Selector('newitemtypeunit', $this->unitTypes, __('Units'), '', true);
  1780. $inputs .= wf_TextInput('newitemtypereserve', __('Desired reserve'), '', true, 5);
  1781. $inputs .= wf_Submit(__('Create'));
  1782. $result = wf_Form(self::URL_ME . '&' . self::URL_ITEMTYPES, 'POST', $inputs, 'glamour');
  1783. } else {
  1784. $result = $this->messages->getStyledMessage(__('No existing categories'), 'warning');
  1785. }
  1786. return ($result);
  1787. }
  1788. /**
  1789. * Returns item types editing form
  1790. *
  1791. * @return string
  1792. */
  1793. public function itemtypesEditForm($itemtypeId) {
  1794. $result = '';
  1795. if (isset($this->allItemTypes[$itemtypeId])) {
  1796. $itemtypeData = $this->allItemTypes[$itemtypeId];
  1797. $inputs = wf_Selector('edititemtypecetegoryid', $this->allCategories, __('Category'), $itemtypeData['categoryid'], true);
  1798. $inputs .= wf_TextInput('edititemtypename', __('Name'), $itemtypeData['name'], true, '20');
  1799. $inputs .= wf_Selector('edititemtypeunit', $this->unitTypes, __('Units'), $itemtypeData['unit'], true);
  1800. $inputs .= wf_TextInput('edititemtypereserve', __('Desired reserve'), $itemtypeData['reserve'], true, 5);
  1801. $inputs .= wf_HiddenInput('edititemtypeid', $itemtypeId);
  1802. $inputs .= wf_Submit(__('Save'));
  1803. $result = wf_Form(self::URL_ME . '&' . self::URL_ITEMTYPES, 'POST', $inputs, 'glamour');
  1804. }
  1805. return ($result);
  1806. }
  1807. /**
  1808. * Saves item type changes in database by data recieved from form
  1809. *
  1810. * @return void
  1811. */
  1812. public function itemtypesSave() {
  1813. if (wf_CheckPost(array('edititemtypeid', 'edititemtypename', 'edititemtypecetegoryid', 'edititemtypeunit'))) {
  1814. $itemtypeId = vf($_POST['edititemtypeid']);
  1815. if (isset($this->allItemTypes[$itemtypeId])) {
  1816. $nameF = $_POST['edititemtypename'];
  1817. $nameF = str_replace('"', '``', $nameF);
  1818. $nameF = str_replace("'", '`', $nameF);
  1819. $where = " WHERE `id`='" . $itemtypeId . "'";
  1820. simple_update_field('wh_itemtypes', 'categoryid', $_POST['edititemtypecetegoryid'], $where);
  1821. simple_update_field('wh_itemtypes', 'name', $nameF, $where);
  1822. simple_update_field('wh_itemtypes', 'unit', $_POST['edititemtypeunit'], $where);
  1823. if (isset($_POST['edititemtypereserve'])) {
  1824. $unit = str_replace(',', '.', $_POST['edititemtypereserve']);
  1825. simple_update_field('wh_itemtypes', 'reserve', $unit, $where);
  1826. }
  1827. log_register('WAREHOUSE ITEMTYPES EDIT [' . $itemtypeId . '] `' . $_POST['edititemtypename'] . '`');
  1828. } else {
  1829. log_register('WAREHOUSE ITEMTYPES EDIT FAIL [' . $itemtypeId . '] NO_EXISTING');
  1830. }
  1831. }
  1832. }
  1833. /**
  1834. * Creates new items type
  1835. *
  1836. * @param int $categoryid
  1837. * @param string $name
  1838. * @param string $unit
  1839. * @param float $reserve
  1840. *
  1841. * @return void
  1842. */
  1843. public function itemtypesCreate($categoryid, $name, $unit, $reserve = 0) {
  1844. $categoryid = vf($categoryid, 3);
  1845. if (isset($this->allCategories[$categoryid])) {
  1846. $nameF = mysql_real_escape_string($name);
  1847. $nameF = str_replace('"', '``', $nameF);
  1848. $nameF = str_replace("'", '`', $nameF);
  1849. $unit = mysql_real_escape_string($unit);
  1850. $reserve = str_replace(',', '.', $reserve);
  1851. $reserve = str_replace('-', '', $reserve);
  1852. $reserve = mysql_real_escape_string($reserve);
  1853. $query = "INSERT INTO `wh_itemtypes` (`id`,`categoryid`,`name`,`unit`,`reserve`) VALUES "
  1854. . "(NULL,'" . $categoryid . "','" . $nameF . "','" . $unit . "','" . $reserve . "')";
  1855. nr_query($query);
  1856. $newId = simple_get_lastid('wh_itemtypes');
  1857. log_register('WAREHOUSE ITEMTYPES CREATE [' . $newId . '] `' . $name . '`');
  1858. } else {
  1859. log_register('WAREHOUSE ITEMTYPES CREATE FAIL NO_CATEGORY');
  1860. }
  1861. }
  1862. /**
  1863. * Renders of available warehouse item types
  1864. *
  1865. * @return string
  1866. */
  1867. public function itemtypesRenderList() {
  1868. $result = '';
  1869. $cells = wf_TableCell(__('ID'));
  1870. $cells .= wf_TableCell(__('Category'));
  1871. $cells .= wf_TableCell(__('Name'));
  1872. $cells .= wf_TableCell(__('Units'));
  1873. $cells .= wf_TableCell(__('Reserve'));
  1874. $cells .= wf_TableCell(__('Actions'));
  1875. $rows = wf_TableRow($cells, 'row1');
  1876. $photoStorageEnabled = ($this->altCfg['PHOTOSTORAGE_ENABLED']) ? true : false;
  1877. if ($photoStorageEnabled) {
  1878. $photoStorage = new PhotoStorage(self::PHOTOSTORAGE_SCOPE, 'nope');
  1879. }
  1880. if (!empty($this->allItemTypes)) {
  1881. $itemtypesList = $this->allItemTypes;
  1882. krsort($itemtypesList); //default order from newer to older instead of order by name
  1883. foreach ($itemtypesList as $io => $each) {
  1884. $itemTypeLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $each['id'], $each['name']);
  1885. $cells = wf_TableCell($each['id']);
  1886. $cells .= wf_TableCell(@$this->allCategories[$each['categoryid']]);
  1887. $cells .= wf_TableCell($itemTypeLink);
  1888. $cells .= wf_TableCell(@$this->unitTypes[$each['unit']]);
  1889. $cells .= wf_TableCell($each['reserve']);
  1890. $actLinks = wf_JSAlert(self::URL_ME . '&' . self::URL_ITEMTYPES . '&deleteitemtype=' . $each['id'], web_delete_icon(), $this->messages->getDeleteAlert());
  1891. $actLinks .= wf_JSAlert(self::URL_ME . '&' . self::URL_ITEMTYPES . '&edititemtype=' . $each['id'], web_edit_icon(), $this->messages->getEditAlert());
  1892. if ($photoStorageEnabled) {
  1893. $photostorageIcon = 'photostorage.png';
  1894. $itemIdImageCount = $photoStorage->getImagesCount($each['id']);
  1895. $photostorageUrl = '?module=photostorage&scope=' . self::PHOTOSTORAGE_SCOPE . '&itemid=' . $each['id'] . '&mode=list';
  1896. $photostorageCtrlLabel = __('Upload images');
  1897. if ($itemIdImageCount > 0) {
  1898. $photostorageIcon = 'photostorage_green.png';
  1899. $photostorageCtrlLabel .= ' (' . $itemIdImageCount . ')';
  1900. }
  1901. $photostorageControl = ' ' . wf_Link($photostorageUrl, wf_img_sized('skins/' . $photostorageIcon, $photostorageCtrlLabel, '16', '16'), false);
  1902. } else {
  1903. $photostorageControl = '';
  1904. }
  1905. $actLinks .= $photostorageControl;
  1906. $cells .= wf_TableCell($actLinks);
  1907. $rows .= wf_TableRow($cells, 'row5');
  1908. }
  1909. }
  1910. $result = wf_TableBody($rows, '100%', 0, 'sortable');
  1911. return ($result);
  1912. }
  1913. /**
  1914. * Checks is itemtype protected by some existing operations?
  1915. *
  1916. * @param type $itemtypeId
  1917. * @return bool
  1918. */
  1919. protected function itemtypeProtected($itemtypeId) {
  1920. $itemtypeId = vf($itemtypeId, 3);
  1921. $result = false;
  1922. if (!empty($this->allIncoming)) {
  1923. foreach ($this->allIncoming as $io => $each) {
  1924. if ($each['itemtypeid'] == $itemtypeId) {
  1925. $result = true;
  1926. break;
  1927. }
  1928. }
  1929. }
  1930. return ($result);
  1931. }
  1932. /**
  1933. * Deletes items type by its ID
  1934. *
  1935. *
  1936. * @param int $itemtypeId
  1937. *
  1938. * @return bool
  1939. */
  1940. public function itemtypesDelete($itemtypeId) {
  1941. $itemtypeId = vf($itemtypeId, 3);
  1942. if (!$this->itemtypeProtected($itemtypeId)) {
  1943. $query = "DELETE from `wh_itemtypes` WHERE `id`='" . $itemtypeId . "';";
  1944. nr_query($query);
  1945. log_register('WAREHOUSE ITEMTYPES DELETE [' . $itemtypeId . ']');
  1946. $result = true;
  1947. } else {
  1948. $result = false;
  1949. }
  1950. return ($result);
  1951. }
  1952. /**
  1953. * Returns itemtype name by its ID
  1954. *
  1955. * @param int $itemtypeId
  1956. * @return string
  1957. */
  1958. public function itemtypeGetName($itemtypeId) {
  1959. $itemtypeId = vf($itemtypeId, 3);
  1960. $result = '';
  1961. if (isset($this->allItemTypeNames[$itemtypeId])) {
  1962. $result = $this->allItemTypeNames[$itemtypeId];
  1963. }
  1964. return ($result);
  1965. }
  1966. /**
  1967. * Returns item type count unit
  1968. *
  1969. * @param int $itemtypeId
  1970. *
  1971. * @return string
  1972. */
  1973. public function itemtypeGetUnit($itemtypeId) {
  1974. $itemtypeId = vf($itemtypeId, 3);
  1975. $result = '';
  1976. $result = @$this->unitTypes[$this->allItemTypes[$itemtypeId]['unit']];
  1977. return ($result);
  1978. }
  1979. /**
  1980. * Returns item type count unit
  1981. *
  1982. * @param int $itemtypeId
  1983. *
  1984. * @return string
  1985. */
  1986. public function itemtypeGetCategory($itemtypeId) {
  1987. $itemtypeId = vf($itemtypeId, 3);
  1988. $result = '';
  1989. $result = @$this->allCategories[$this->allItemTypes[$itemtypeId]['categoryid']];
  1990. return ($result);
  1991. }
  1992. /**
  1993. * Returns storage creation form
  1994. *
  1995. * @return string
  1996. */
  1997. public function storagesCreateForm() {
  1998. $result = '';
  1999. $inputs = wf_TextInput('newstorage', __('Name'), '', false, 20);
  2000. $inputs .= wf_Submit(__('Create'));
  2001. $result = wf_Form(self::URL_ME . '&' . self::URL_STORAGES, 'POST', $inputs, 'glamour');
  2002. return ($result);
  2003. }
  2004. /**
  2005. * Creates new storage in database
  2006. *
  2007. * @param string $name
  2008. *
  2009. * @return void
  2010. */
  2011. public function storagesCreate($name) {
  2012. $nameF = mysql_real_escape_string($name);
  2013. $query = "INSERT INTO `wh_storages` (`id`,`name`) VALUES (NULL,'" . $nameF . "');";
  2014. nr_query($query);
  2015. $newId = simple_get_lastid('wh_storages');
  2016. log_register('WAREHOUSE STORAGES ADD [' . $newId . '] `' . $name . '`');
  2017. }
  2018. /**
  2019. * Check is storage used by some incoming operations?
  2020. *
  2021. * @param int $storageId
  2022. *
  2023. * @return bool
  2024. */
  2025. protected function storageProtected($storageId) {
  2026. $storageId = vf($storageId, 3);
  2027. $result = false;
  2028. if (!empty($this->allIncoming)) {
  2029. foreach ($this->allIncoming as $io => $each) {
  2030. if ($each['storageid'] == $storageId) {
  2031. $result = true;
  2032. break;
  2033. }
  2034. }
  2035. }
  2036. return ($result);
  2037. }
  2038. /**
  2039. * Returns storage name by its ID
  2040. *
  2041. * @param int $storageId
  2042. * @return string
  2043. */
  2044. public function storageGetName($storageId) {
  2045. $storageId = vf($storageId, 3);
  2046. $result = '';
  2047. if (isset($this->allStorages[$storageId])) {
  2048. $result = $this->allStorages[$storageId];
  2049. }
  2050. return ($result);
  2051. }
  2052. /**
  2053. * Deletes existing storage from database
  2054. *
  2055. * @param int $storageId
  2056. *
  2057. * @return bool
  2058. */
  2059. public function storagesDelete($storageId) {
  2060. $storageId = vf($storageId);
  2061. if (isset($this->allStorages[$storageId])) {
  2062. if (!$this->storageProtected($storageId)) {
  2063. $query = "DELETE from `wh_storages` WHERE `id`='" . $storageId . "';";
  2064. nr_query($query);
  2065. log_register('WAREHOUSE STORAGES DELETE [' . $storageId . ']');
  2066. $result = true;
  2067. } else {
  2068. $result = false;
  2069. }
  2070. } else {
  2071. $result = false;
  2072. }
  2073. return ($result);
  2074. }
  2075. /**
  2076. * Returns storages edit form
  2077. *
  2078. * @param int $storageId
  2079. *
  2080. * @return string
  2081. */
  2082. protected function storagesEditForm($storageId) {
  2083. $result = '';
  2084. $inputs = wf_TextInput('editstoragename', __('Name'), $this->allStorages[$storageId], false, 20);
  2085. $inputs .= wf_HiddenInput('editstorageid', $storageId);
  2086. $inputs .= wf_Submit(__('Save'));
  2087. $result = wf_Form(self::URL_ME . '&' . self::URL_STORAGES, 'POST', $inputs, 'glamour');
  2088. return ($result);
  2089. }
  2090. /**
  2091. * Saves storage changes in database by data recieved from form
  2092. *
  2093. * @return void
  2094. */
  2095. public function storagesSave() {
  2096. if (wf_CheckPost(array('editstoragename', 'editstorageid'))) {
  2097. $storageId = vf($_POST['editstorageid']);
  2098. if (isset($this->allStorages[$storageId])) {
  2099. simple_update_field('wh_storages', 'name', $_POST['editstoragename'], "WHERE `id`='" . $storageId . "'");
  2100. log_register('WAREHOUSE STORAGE EDIT [' . $storageId . '] `' . $_POST['editstoragename'] . '`');
  2101. } else {
  2102. log_register('WAREHOUSE STORAGE EDIT FAIL [' . $storageId . '] NO_EXISTING');
  2103. }
  2104. }
  2105. }
  2106. /**
  2107. * Renders list of available storages with some controls
  2108. *
  2109. * @return string
  2110. */
  2111. public function storagesRenderList() {
  2112. $result = '';
  2113. $cells = wf_TableCell(__('ID'));
  2114. $cells .= wf_TableCell(__('Name'));
  2115. $cells .= wf_TableCell(__('Actions'));
  2116. $rows = wf_TableRow($cells, 'row1');
  2117. if (!empty($this->allStorages)) {
  2118. foreach ($this->allStorages as $id => $name) {
  2119. $cells = wf_TableCell($id);
  2120. $cells .= wf_TableCell($name);
  2121. $actLinks = wf_JSAlert(self::URL_ME . '&' . self::URL_STORAGES . '&deletestorage=' . $id, web_delete_icon(), $this->messages->getDeleteAlert()) . ' ';
  2122. $actLinks .= wf_modalAuto(web_edit_icon(), __('Edit'), $this->storagesEditForm($id));
  2123. $cells .= wf_TableCell($actLinks);
  2124. $rows .= wf_TableRow($cells, 'row3');
  2125. }
  2126. }
  2127. $result = wf_TableBody($rows, '100%', 0, 'sortable');
  2128. return ($result);
  2129. }
  2130. /**
  2131. I count the falling tears
  2132. They fall before my eyes
  2133. Seems like a thousand years
  2134. Since we broke the ties
  2135. I call you on the phone
  2136. But never get a rise
  2137. So sit there all alone
  2138. It's time you realize
  2139. */
  2140. /**
  2141. * Returns contractor creation form
  2142. *
  2143. * @return string
  2144. */
  2145. public function contractorsCreateForm() {
  2146. $result = '';
  2147. $inputs = wf_TextInput('newcontractor', __('Name'), '', false, 20);
  2148. $inputs .= wf_Submit(__('Create'));
  2149. $result = wf_Form(self::URL_ME . '&' . self::URL_CONTRACTORS, 'POST', $inputs, 'glamour');
  2150. return ($result);
  2151. }
  2152. /**
  2153. * Creates new contractor in database
  2154. *
  2155. * @param string $name
  2156. *
  2157. * @return void
  2158. */
  2159. public function contractorCreate($name) {
  2160. $nameF = mysql_real_escape_string($name);
  2161. $nameF = ubRouting::filters($nameF, 'safe');
  2162. $query = "INSERT INTO `wh_contractors` (`id`,`name`) VALUES (NULL,'" . $nameF . "');";
  2163. nr_query($query);
  2164. $newId = simple_get_lastid('wh_contractors');
  2165. log_register('WAREHOUSE CONTRACTORS ADD [' . $newId . '] `' . $name . '`');
  2166. }
  2167. /**
  2168. * Check is contractor used by some incoming operations?
  2169. *
  2170. * @param int $contractorId
  2171. *
  2172. * @return bool
  2173. */
  2174. protected function contractorProtected($contractorId) {
  2175. $contractorId = vf($contractorId, 3);
  2176. $result = false;
  2177. if (!empty($this->allIncoming)) {
  2178. foreach ($this->allIncoming as $io => $each) {
  2179. if ($each['contractorid'] == $contractorId) {
  2180. $result = true;
  2181. break;
  2182. }
  2183. }
  2184. }
  2185. return ($result);
  2186. }
  2187. /**
  2188. * Deletes existing contractor from database
  2189. *
  2190. * @param int $contractorId
  2191. *
  2192. * @return bool
  2193. */
  2194. public function contractorsDelete($contractorId) {
  2195. $contractorId = vf($contractorId);
  2196. if (isset($this->allContractors[$contractorId])) {
  2197. if (!$this->contractorProtected($contractorId)) {
  2198. $query = "DELETE from `wh_contractors` WHERE `id`='" . $contractorId . "';";
  2199. nr_query($query);
  2200. log_register('WAREHOUSE CONTRACTORS DELETE [' . $contractorId . ']');
  2201. $result = true;
  2202. } else {
  2203. $result = false;
  2204. }
  2205. } else {
  2206. $result = false;
  2207. }
  2208. return ($result);
  2209. }
  2210. /**
  2211. * Returns contractors edit form
  2212. *
  2213. * @param int $contractorId
  2214. *
  2215. * @return string
  2216. */
  2217. protected function contractorsEditForm($contractorId) {
  2218. $result = '';
  2219. $inputs = wf_TextInput('editcontractorname', __('Name'), $this->allContractors[$contractorId], false, 20);
  2220. $inputs .= wf_HiddenInput('editcontractorid', $contractorId);
  2221. $inputs .= wf_Submit(__('Save'));
  2222. $result = wf_Form(self::URL_ME . '&' . self::URL_CONTRACTORS, 'POST', $inputs, 'glamour');
  2223. return ($result);
  2224. }
  2225. /**
  2226. * Saves contractor changes in database by data recieved from form
  2227. *
  2228. * @return void
  2229. */
  2230. public function contractorsSave() {
  2231. if (wf_CheckPost(array('editcontractorname', 'editcontractorid'))) {
  2232. $contractorId = vf($_POST['editcontractorid'], 3);
  2233. if (isset($this->allContractors[$contractorId])) {
  2234. simple_update_field('wh_contractors', 'name', ubRouting::post('editcontractorname', 'safe'), "WHERE `id`='" . $contractorId . "'");
  2235. log_register('WAREHOUSE CONTRACTORS EDIT [' . $contractorId . '] `' . ubRouting::post('editcontractorname') . '`');
  2236. } else {
  2237. log_register('WAREHOUSE CONTRACTORS EDIT FAIL [' . $contractorId . '] NO_EXISTING');
  2238. }
  2239. }
  2240. }
  2241. /**
  2242. * Renders list of available contractors with some controls
  2243. *
  2244. * @return string
  2245. */
  2246. public function contractorsRenderList() {
  2247. $result = '';
  2248. $cells = wf_TableCell(__('ID'));
  2249. $cells .= wf_TableCell(__('Name'));
  2250. $cells .= wf_TableCell(__('Actions'));
  2251. $rows = wf_TableRow($cells, 'row1');
  2252. if (!empty($this->allContractors)) {
  2253. foreach ($this->allContractors as $id => $name) {
  2254. $cells = wf_TableCell($id);
  2255. $cells .= wf_TableCell($name);
  2256. $actLinks = wf_JSAlert(self::URL_ME . '&' . self::URL_CONTRACTORS . '&deletecontractor=' . $id, web_delete_icon(), $this->messages->getDeleteAlert()) . ' ';
  2257. $actLinks .= wf_modalAuto(web_edit_icon(), __('Edit'), $this->contractorsEditForm($id));
  2258. $cells .= wf_TableCell($actLinks);
  2259. $rows .= wf_TableRow($cells, 'row3');
  2260. }
  2261. }
  2262. $result = wf_TableBody($rows, '100%', 0, 'sortable');
  2263. return ($result);
  2264. }
  2265. /**
  2266. * Performs itemtypes per category filtering. Returns array id=>name
  2267. *
  2268. * @param int $categoryId
  2269. * @return array
  2270. */
  2271. protected function itemtypesFilterCategory($categoryId) {
  2272. $result = array();
  2273. if (!empty($this->allItemTypes)) {
  2274. foreach ($this->allItemTypes as $io => $each) {
  2275. if ($each['categoryid'] == $categoryId) {
  2276. $result[$each['id']] = $each['name'];
  2277. }
  2278. }
  2279. }
  2280. return ($result);
  2281. }
  2282. /**
  2283. * Returns itemtype selector filtered by category
  2284. *
  2285. * @param string $name
  2286. * @param int $categoryId
  2287. * @return string
  2288. */
  2289. public function itemtypesCategorySelector($name, $categoryId) {
  2290. $result = '';
  2291. $searchableFlag = $this->altCfg['WAREHOUSE_INCOP_SEARCHBL'];
  2292. $categoryItemtypes = $this->itemtypesFilterCategory($categoryId);
  2293. if ($searchableFlag) {
  2294. $result = wf_SelectorSearchable($name, $categoryItemtypes, __('Warehouse item types'), '', false);
  2295. } else {
  2296. $result = wf_Selector($name, $categoryItemtypes, __('Warehouse item types'), '', false);
  2297. }
  2298. if (cfr('WAREHOUSEDIR')) {
  2299. $result .= wf_Link(self::URL_ME . '&' . self::URL_ITEMTYPES, wf_img_sized('skins/folder_icon.png', '', '10', '10'), false);
  2300. }
  2301. return ($result);
  2302. }
  2303. /**
  2304. * Returns incoming operation creation form
  2305. *
  2306. * @return string
  2307. */
  2308. public function incomingCreateForm() {
  2309. if ((!empty($this->allItemTypes)) and (!empty($this->allCategories)) and (!empty($this->allContractors)) and (!empty($this->allStorages))) {
  2310. $searchableFlag = $this->altCfg['WAREHOUSE_INCOP_SEARCHBL'];
  2311. //ajax selector URL-s preprocessing
  2312. $tmpCat = array();
  2313. $firstCateKey = key($this->allCategories);
  2314. foreach ($this->allCategories as $categoryId => $categoryName) {
  2315. $tmpCat[self::URL_ME . '&' . self::URL_IN . '&' . self::URL_AJITSELECTOR . $categoryId] = $categoryName;
  2316. }
  2317. $result = wf_AjaxLoader();
  2318. $inputs = wf_DatePickerPreset('newindate', curdate());
  2319. $inputs .= wf_tag('br');
  2320. if ($searchableFlag) {
  2321. $inputs .= wf_AjaxSelectorSearchableAC('ajItemtypesContainer', $tmpCat, __('Warehouse categories'), '', false);
  2322. } else {
  2323. $inputs .= wf_AjaxSelectorAC('ajItemtypesContainer', $tmpCat, __('Warehouse categories'), '', false);
  2324. }
  2325. if (cfr('WAREHOUSEDIR')) {
  2326. $inputs .= wf_Link(self::URL_ME . '&' . self::URL_CATEGORIES, wf_img_sized('skins/categories_icon.png', '', '10', '10'), false);
  2327. }
  2328. $inputs .= wf_tag('br');
  2329. $inputs .= wf_AjaxContainer('ajItemtypesContainer', '', $this->itemtypesCategorySelector('newinitemtypeid', $firstCateKey));
  2330. if ($searchableFlag) {
  2331. $inputs .= wf_SelectorSearchable('newincontractorid', $this->allContractors, __('Contractor'), '', false);
  2332. } else {
  2333. $inputs .= wf_Selector('newincontractorid', $this->allContractors, __('Contractor'), '', false);
  2334. }
  2335. if (cfr('WAREHOUSEDIR')) {
  2336. $inputs .= wf_Link(self::URL_ME . '&' . self::URL_CONTRACTORS, wf_img_sized('skins/whcontractor_icon.png', '', '10', '10'), false);
  2337. }
  2338. $inputs .= wf_tag('br');
  2339. if ($searchableFlag) {
  2340. $inputs .= wf_SelectorSearchable('newinstorageid', $this->allStorages, __('Warehouse storage'), '', false);
  2341. } else {
  2342. $inputs .= wf_Selector('newinstorageid', $this->allStorages, __('Warehouse storage'), '', false);
  2343. }
  2344. if (cfr('WAREHOUSEDIR')) {
  2345. $inputs .= wf_Link(self::URL_ME . '&' . self::URL_STORAGES, wf_img_sized('skins/whstorage_icon.png', '', '10', '10'), false);
  2346. }
  2347. $inputs .= wf_tag('br');
  2348. $inputs .= wf_TextInput('newincount', __('Count'), '', false, 5, 'float');
  2349. $inputs .= wf_tag('br');
  2350. $inputs .= wf_TextInput('newinprice', __('Price per unit'), '', false, 5, 'finance');
  2351. $inputs .= wf_tag('br');
  2352. $inputs .= wf_TextInput('newinbarcode', __('Barcode'), '', false, 15);
  2353. $inputs .= wf_tag('br');
  2354. $inputs .= wf_TextInput('newinnotes', __('Notes'), '', false, 30);
  2355. $inputs .= wf_tag('br');
  2356. $inputs .= wf_Submit(__('Create'));
  2357. $result .= wf_Form(self::URL_ME . '&' . self::URL_IN, 'POST', $inputs, 'glamour');
  2358. } else {
  2359. $result = $this->messages->getStyledMessage(__('You did not fill all the necessary directories'), 'error');
  2360. }
  2361. return ($result);
  2362. }
  2363. /**
  2364. * Creates new incoming operation in database
  2365. *
  2366. * @param string $date
  2367. * @param int $itemtypeid
  2368. * @param int $contractorid
  2369. * @param int $storageid
  2370. * @param float $count
  2371. * @param float $price
  2372. * @param string $barcode
  2373. * @param string $notes
  2374. *
  2375. * @return void
  2376. */
  2377. public function incomingCreate($date, $itemtypeid, $contractorid, $storageid, $count, $price, $barcode, $notes) {
  2378. $dateF = mysql_real_escape_string($date);
  2379. $itemtypeid = vf($itemtypeid, 3);
  2380. $contractorid = vf($contractorid, 3);
  2381. $storageid = vf($storageid, 3);
  2382. $countF = str_replace(',', '.', $count);
  2383. $countF = str_replace('-', '', $countF);
  2384. $countF = mysql_real_escape_string($countF);
  2385. $priceF = str_replace(',', '.', $price);
  2386. $priceF = mysql_real_escape_string($priceF);
  2387. $notes = mysql_real_escape_string($notes);
  2388. $barcode = mysql_real_escape_string($barcode);
  2389. $admin = mysql_real_escape_string(whoami());
  2390. $query = "INSERT INTO `wh_in` (`id`, `date`, `itemtypeid`, `contractorid`, `count`, `barcode`, `price`, `storageid`, `notes`,`admin`) "
  2391. . "VALUES (NULL, '" . $dateF . "', '" . $itemtypeid . "', '" . $contractorid . "', '" . $countF . "', '" . $barcode . "', '" . $priceF . "', '" . $storageid . "', '" . $notes . "','" . $admin . "');";
  2392. nr_query($query);
  2393. $newId = simple_get_lastid('wh_in');
  2394. log_register('WAREHOUSE INCOME CREATE [' . $newId . '] ITEM [' . $itemtypeid . '] COUNT `' . $count . '` PRICE `' . $price . '`');
  2395. }
  2396. /**
  2397. * Returns income operations list available at storages
  2398. *
  2399. * @return string
  2400. */
  2401. public function incomingOperationsList() {
  2402. $result = '';
  2403. if (!empty($this->allIncoming)) {
  2404. $opts = '"order": [[ 0, "desc" ]]';
  2405. $columns = array('ID', 'Date', 'Category', 'Warehouse item types', 'Count', 'Price per unit', 'Sum', 'Warehouse storage', 'Notes', 'Actions');
  2406. $result = wf_JqDtLoader($columns, self::URL_ME . '&' . self::URL_IN . '&' . self::URL_INAJLIST, false, 'Incoming operations', 50, $opts);
  2407. } else {
  2408. $result = $this->messages->getStyledMessage(__('Nothing found'), 'warning');
  2409. }
  2410. return ($result);
  2411. }
  2412. /**
  2413. * Returns JQuery datatables reply for incoming operations list
  2414. *
  2415. * @return string
  2416. */
  2417. public function incomingListAjaxReply() {
  2418. $json = new wf_JqDtHelper();
  2419. if (!empty($this->allIncoming)) {
  2420. foreach ($this->allIncoming as $io => $each) {
  2421. $actLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&showinid=' . $each['id'], wf_img_sized('skins/whincoming_icon.png', '', '10', '10') . ' ' . __('Show'));
  2422. $data[] = $each['id'];
  2423. $data[] = $each['date'];
  2424. $data[] = @$this->allCategories[$this->allItemTypes[$each['itemtypeid']]['categoryid']];
  2425. $data[] = wf_link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $each['itemtypeid'], $this->allItemTypeNames[$each['itemtypeid']]);
  2426. $data[] = $each['count'] . ' ' . @$this->unitTypes[$this->allItemTypes[$each['itemtypeid']]['unit']];
  2427. $data[] = $each['price'];
  2428. $data[] = round($each['price'] * $each['count'], 2);
  2429. $data[] = @$this->allStorages[$each['storageid']];
  2430. $data[] = $each['notes'];
  2431. $data[] = $actLink;
  2432. $json->addRow($data);
  2433. unset($data);
  2434. }
  2435. }
  2436. $json->getJson();
  2437. }
  2438. /**
  2439. * Returns default contol for QR code view interface
  2440. *
  2441. * @param string $type
  2442. * @param int $id
  2443. * @return string
  2444. */
  2445. protected function qrControl($type, $id) {
  2446. $result = '';
  2447. $qrUrl = self::URL_ME . '&' . self::URL_VIEWERS . '&qrcode=' . $type . '&renderid=' . $id;
  2448. $result = wf_modalAuto(wf_img_sized('skins/qrcode.png', __('QR code'), '16', '16'), __('QR code'), wf_img($qrUrl), '');
  2449. return ($result);
  2450. }
  2451. /**
  2452. * Renders incoming operation view interface
  2453. *
  2454. * @param int $id
  2455. * @return string
  2456. */
  2457. public function incomingView($id) {
  2458. $id = vf($id, 3);
  2459. $result = '';
  2460. if (isset($this->allIncoming[$id])) {
  2461. $operationData = $this->allIncoming[$id];
  2462. $employeeLogins = unserialize(ts_GetAllEmployeeLoginsCached());
  2463. $administratorName = (isset($employeeLogins[$operationData['admin']])) ? $employeeLogins[$operationData['admin']] : $operationData['admin'];
  2464. $cells = wf_TableCell(__('ID') . ' ' . $this->qrControl('in', $id), '30%', 'row2');
  2465. $cells .= wf_TableCell($id);
  2466. $rows = wf_TableRow($cells, 'row3');
  2467. $cells = wf_TableCell(__('Date'), '30%', 'row2');
  2468. $cells .= wf_TableCell($operationData['date']);
  2469. $rows .= wf_TableRow($cells, 'row3');
  2470. $cells = wf_TableCell(__('Contractor'), '30%', 'row2');
  2471. //storage movement
  2472. if ($operationData['contractorid'] == 0) {
  2473. $contractorName = $operationData['notes'];
  2474. } else {
  2475. $contractorName = @$this->allContractors[$operationData['contractorid']];
  2476. }
  2477. $itemTypeLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $operationData['itemtypeid'], @$this->allItemTypeNames[$operationData['itemtypeid']]);
  2478. $cells .= wf_TableCell($contractorName);
  2479. $rows .= wf_TableRow($cells, 'row3');
  2480. $cells = wf_TableCell(__('Category'), '30%', 'row2');
  2481. $cells .= wf_TableCell(@$this->allCategories[$this->allItemTypes[$operationData['itemtypeid']]['categoryid']]);
  2482. $rows .= wf_TableRow($cells, 'row3');
  2483. $cells = wf_TableCell(__('Warehouse item type'), '30%', 'row2');
  2484. $cells .= wf_TableCell($itemTypeLink);
  2485. $rows .= wf_TableRow($cells, 'row3');
  2486. $cells = wf_TableCell(__('Count'), '30%', 'row2');
  2487. $cells .= wf_TableCell($operationData['count'] . ' ' . $this->unitTypes[$this->allItemTypes[$operationData['itemtypeid']]['unit']]);
  2488. $rows .= wf_TableRow($cells, 'row3');
  2489. $cells = wf_TableCell(__('Price per unit'), '30%', 'row2');
  2490. $cells .= wf_TableCell($operationData['price']);
  2491. $rows .= wf_TableRow($cells, 'row3');
  2492. $cells = wf_TableCell(__('Sum'), '30%', 'row2');
  2493. $cells .= wf_TableCell(($operationData['price'] * $operationData['count']));
  2494. $rows .= wf_TableRow($cells, 'row3');
  2495. $cells = wf_TableCell(__('Warehouse storage'), '30%', 'row2');
  2496. $cells .= wf_TableCell($this->allStorages[$operationData['storageid']]);
  2497. $rows .= wf_TableRow($cells, 'row3');
  2498. $cells = wf_TableCell(__('Barcode'), '30%', 'row2');
  2499. $cells .= wf_TableCell($operationData['barcode']);
  2500. $rows .= wf_TableRow($cells, 'row3');
  2501. $cells = wf_TableCell(__('Worker'), '30%', 'row2');
  2502. $cells .= wf_TableCell($administratorName);
  2503. $rows .= wf_TableRow($cells, 'row3');
  2504. $cells = wf_TableCell(__('Notes'), '30%', 'row2');
  2505. $cells .= wf_TableCell($operationData['notes']);
  2506. $rows .= wf_TableRow($cells, 'row3');
  2507. $result .= wf_TableBody($rows, '100%', 0, 'wh_viewer');
  2508. //optional income editing controls
  2509. if (cfr('WAREHOUSEINEDT')) {
  2510. if ($this->altCfg['WAREHOUSE_INEDT_ENABLED']) {
  2511. if ($this->isIncomeEditable($id)) {
  2512. //editing form
  2513. $editForm = $this->incomingEditForm($id);
  2514. $result .= wf_modalAuto(web_edit_icon() . ' ' . __('Edit'), __('Edit'), $editForm, 'ubButton');
  2515. //deletion form
  2516. $inDelUrl = self::URL_ME . '&' . self::URL_VIEWERS . '&showinid=' . $id . '&' . self::ROUTE_DELIN . '=' . $id;
  2517. $inDelCancelUrl = self::URL_ME . '&' . self::URL_VIEWERS . '&showinid=' . $id;
  2518. $inDelLabel = $this->messages->getDeleteAlert();
  2519. $result .= wf_ConfirmDialog($inDelUrl, web_delete_icon() . ' ' . __('Delete'), $inDelLabel, 'ubButton', $inDelCancelUrl, __('Delete') . '?');
  2520. } else {
  2521. $result .= $this->messages->getStyledMessage(__('This operation cannot be edited or deleted'), 'warning');
  2522. $result .= wf_delimiter();
  2523. }
  2524. $result .= wf_delimiter(0);
  2525. }
  2526. }
  2527. if ($this->altCfg['PHOTOSTORAGE_ENABLED']) {
  2528. $photoStorage = new PhotoStorage(self::PHOTOSTORAGE_SCOPE, $operationData['itemtypeid']);
  2529. $result .= $photoStorage->renderImagesRaw();
  2530. }
  2531. } else {
  2532. $result = $this->messages->getStyledMessage(__('Strange exeption') . ' NO_EXISTING_INCOME_ID', 'error');
  2533. }
  2534. //File storage
  2535. if (@$this->altCfg['FILESTORAGE_ENABLED']) {
  2536. $fileStorage = new FileStorage('WAREHOUSEINCOME', $id);
  2537. $result .= wf_tag('h3') . __('Uploaded files') . wf_tag('h3', true);
  2538. $result .= $fileStorage->renderFilesPreview(true, '', 'ubButton', 64, '&callback=whin');
  2539. }
  2540. //ADcomments support
  2541. if ($this->altCfg['ADCOMMENTS_ENABLED']) {
  2542. $adcomments = new ADcomments('WAREHOUSEINCOME');
  2543. $result .= wf_tag('h3') . __('Additional comments') . wf_tag('h3', true);
  2544. $result .= $adcomments->renderComments($id);
  2545. }
  2546. return ($result);
  2547. }
  2548. /**
  2549. * Renders incoming operation editing form
  2550. *
  2551. * @param int $id
  2552. *
  2553. * @return string
  2554. */
  2555. protected function incomingEditForm($id) {
  2556. $result = '';
  2557. if (isset($this->allIncoming[$id])) {
  2558. $inData = $this->allIncoming[$id];
  2559. $inputs = '<!--ugly hack to prevent datepicker autoopen -->';
  2560. $inputs .= wf_tag('input', false, '', 'type="text" name="shittyhack" style="width: 0; height: 0; top: -100px; position: absolute;"');
  2561. $inputs .= wf_DatePickerPreset('newindate', $inData['date']);
  2562. $inputs .= wf_tag('br');
  2563. $inputs .= wf_HiddenInput('editincomeid', $id);
  2564. if ($inData['contractorid'] != 0) {
  2565. //normal income
  2566. $inputs .= wf_Selector('edincontractorid', $this->allContractors, __('Contractor'), $inData['contractorid'], false);
  2567. $inputs .= wf_tag('br');
  2568. $inputs .= wf_Selector('edinstorageid', $this->allStorages, __('Warehouse storage'), $inData['storageid'], false);
  2569. } else {
  2570. //storage move operation
  2571. $inputs .= wf_HiddenInput('edincontractorid', $inData['contractorid']) . ' ' . __('Contractor') . ': ' . $inData['notes'];
  2572. $inputs .= wf_tag('br');
  2573. $inputs .= wf_HiddenInput('edinstorageid', $inData['storageid']) . ' ' . __('Storage') . ': ' . $this->allStorages[$inData['storageid']];
  2574. }
  2575. $inputs .= wf_tag('br');
  2576. $inputs .= wf_TextInput('edincount', __('Count'), $inData['count'], false, 5, 'float');
  2577. $inputs .= wf_tag('br');
  2578. $inputs .= wf_TextInput('edinprice', __('Price per unit'), $inData['price'], false, 5, 'finance');
  2579. $inputs .= wf_tag('br');
  2580. $inputs .= wf_TextInput('edinbarcode', __('Barcode'), $inData['barcode'], false, 15);
  2581. $inputs .= wf_tag('br');
  2582. $inputs .= wf_TextInput('edinnotes', __('Notes'), $inData['notes'], false, 30);
  2583. $inputs .= wf_tag('br');
  2584. $inputs .= wf_Submit(__('Save'));
  2585. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  2586. }
  2587. return ($result);
  2588. }
  2589. /**
  2590. * Catches and performs incoming operation editing request
  2591. *
  2592. * @return void/string
  2593. */
  2594. public function incomingSaveChanges() {
  2595. $result = '';
  2596. if (ubRouting::checkPost(array('editincomeid', 'newindate', 'edinstorageid', 'edincount'))) {
  2597. $id = ubRouting::post('editincomeid', 'int');
  2598. if ($this->isIncomeEditable($id)) {
  2599. if ($this->altCfg['WAREHOUSE_INEDT_ENABLED']) {
  2600. $inData = $this->allIncoming[$id];
  2601. $newDate = ubRouting::post('newindate');
  2602. $newContractor = ubRouting::post('edincontractorid', 'int');
  2603. $newStorage = ubRouting::post('edinstorageid', 'int');
  2604. $newCount = ubRouting::post('edincount', 'mres');
  2605. $newCount = str_replace(',', '.', $newCount);
  2606. $newCount = str_replace('-', '', $newCount);
  2607. $newPrice = ubRouting::post('edinprice', 'mres');
  2608. $newPrice = str_replace(',', '.', $newPrice);
  2609. $newPrice = str_replace('-', '', $newPrice);
  2610. $newBarcode = ubRouting::post('edinbarcode', 'mres');
  2611. $newNotes = ubRouting::post('edinnotes', 'mres');
  2612. if (zb_checkDate($newDate)) {
  2613. $incomeDb = new NyanORM('wh_in');
  2614. $incomeDb->data('date', $newDate);
  2615. $incomeDb->data('contractorid', $newContractor);
  2616. $incomeDb->data('storageid', $newStorage);
  2617. $incomeDb->data('count', $newCount);
  2618. $incomeDb->data('price', $newPrice);
  2619. $incomeDb->data('barcode', $newBarcode);
  2620. $incomeDb->data('notes', $newNotes);
  2621. $incomeDb->where('id', '=', $id);
  2622. $incomeDb->save();
  2623. log_register('WAREHOUSE INCOME EDIT [' . $id . '] ITEM [' . $inData['itemtypeid'] . '] COUNT `' . $inData['count'] . '`=>`' . $newCount . '` PRICE `' . $inData['price'] . '`=>`' . $newPrice . '`');
  2624. } else {
  2625. $result .= __('Wrong date format');
  2626. }
  2627. } else {
  2628. $result .= __('Disabled');
  2629. }
  2630. } else {
  2631. $result .= __('This operation cannot be edited or deleted');
  2632. }
  2633. }
  2634. return ($result);
  2635. }
  2636. /**
  2637. * Deletes existing incoming operation
  2638. *
  2639. * @param int $id
  2640. *
  2641. * @return void/string
  2642. */
  2643. public function incomingDelete($id) {
  2644. $result = '';
  2645. $id = ubRouting::filters($id, 'int');
  2646. if ($this->isIncomeEditable($id)) {
  2647. if (@$this->altCfg['WAREHOUSE_INEDT_ENABLED']) {
  2648. $incomeData = $this->allIncoming[$id];
  2649. $itemtypeId = $incomeData['itemtypeid'];
  2650. $count = $incomeData['count'];
  2651. $price = $incomeData['price'];
  2652. $incomeDb = new NyanORM('wh_in');
  2653. $incomeDb->where('id', '=', $id);
  2654. $incomeDb->delete();
  2655. log_register('WAREHOUSE INCOME DELETE [' . $id . '] ITEM [' . $itemtypeId . '] COUNT `' . $count . '` PRICE `' . $price . '`');
  2656. } else {
  2657. $result .= __('Disabled');
  2658. }
  2659. } else {
  2660. $result .= __('This operation cannot be edited or deleted');
  2661. }
  2662. return ($result);
  2663. }
  2664. /**
  2665. * Checks is incoming operation existing and editable?
  2666. *
  2667. * @param int $id
  2668. *
  2669. * @return bool
  2670. */
  2671. public function isIncomeEditable($id) {
  2672. $result = true;
  2673. if (isset($this->allIncoming[$id])) {
  2674. $operationData = $this->allIncoming[$id];
  2675. $date = $operationData['date'];
  2676. $storageId = $operationData['storageid'];
  2677. $itemtypeId = $operationData['itemtypeid'];
  2678. //checking outcomes
  2679. if (!empty($this->allOutcoming)) {
  2680. foreach ($this->allOutcoming as $io => $eachOut) {
  2681. if (($eachOut['itemtypeid'] == $itemtypeId) and ($eachOut['storageid'] == $storageId)) {
  2682. if ($eachOut['date'] >= $date) {
  2683. //this itemtype on this storage is already touched by outcoming operations
  2684. $result = false;
  2685. break;
  2686. }
  2687. }
  2688. }
  2689. }
  2690. } else {
  2691. //not exists
  2692. $result = false;
  2693. }
  2694. return ($result);
  2695. }
  2696. /**
  2697. * Returns outcoming operation creation form
  2698. *
  2699. * @param bool $noOutControls not render storages outcoming controls
  2700. *
  2701. * @return string
  2702. */
  2703. public function outcomingStoragesList($noOutControls = false) {
  2704. $result = '';
  2705. if (!empty($this->allStorages)) {
  2706. $cells = wf_TableCell(__('Warehouse storage'));
  2707. $cells .= wf_TableCell(__('Actions'));
  2708. $rows = wf_TableRow($cells, 'row1');
  2709. foreach ($this->allStorages as $io => $each) {
  2710. $storageId = $io;
  2711. if ($noOutControls) {
  2712. $conrolLink = $each;
  2713. } else {
  2714. $conrolLink = wf_Link(self::URL_ME . '&' . self::URL_OUT . '&storageid=' . $storageId, $each, false, '');
  2715. }
  2716. $remainsLabel = wf_img('skins/icon_print.png', __('The remains in the warehouse storage') . ': ' . $each);
  2717. $remainsPrintControls = ' ' . wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&printremainsstorage=' . $storageId, $remainsLabel);
  2718. $cells = wf_TableCell($conrolLink);
  2719. $cells .= wf_TableCell($remainsPrintControls);
  2720. $rows .= wf_TableRow($cells, 'row5');
  2721. }
  2722. $result = wf_TableBody($rows, '100%', 0, 'sortable');
  2723. } else {
  2724. $result = $this->messages->getStyledMessage(__('You did not fill all the necessary directories'), 'error');
  2725. }
  2726. return ($result);
  2727. }
  2728. /**
  2729. * Returns array of items remains on some storage
  2730. *
  2731. * @param int $storageId
  2732. *
  2733. * @return array
  2734. */
  2735. protected function remainsOnStorage($storageId) {
  2736. $storageId = vf($storageId, 3);
  2737. $result = array();
  2738. //counting income operations
  2739. if (!empty($this->allIncoming)) {
  2740. foreach ($this->allIncoming as $io => $each) {
  2741. if ($each['storageid'] == $storageId) {
  2742. if (isset($result[$each['itemtypeid']])) {
  2743. $result[$each['itemtypeid']] += $each['count'];
  2744. } else {
  2745. $result[$each['itemtypeid']] = $each['count'];
  2746. }
  2747. }
  2748. }
  2749. }
  2750. //counting outcome operations
  2751. if (!empty($this->allOutcoming)) {
  2752. foreach ($this->allOutcoming as $io => $each) {
  2753. if ($each['storageid'] == $storageId) {
  2754. if (isset($result[$each['itemtypeid']])) {
  2755. $result[$each['itemtypeid']] -= $each['count'];
  2756. }
  2757. }
  2758. }
  2759. }
  2760. return ($result);
  2761. }
  2762. /**
  2763. * Returns array of all itemtypes available on all storages
  2764. *
  2765. * @return array
  2766. */
  2767. public function remainsAll() {
  2768. $result = array();
  2769. if (!empty($this->allStorages)) {
  2770. foreach ($this->allStorages as $storageId => $storageName) {
  2771. $tmpArr = $this->remainsOnStorage($storageId);
  2772. if (!empty($tmpArr)) {
  2773. foreach ($tmpArr as $itemtypeId => $itemtypeCount) {
  2774. if (isset($result[$itemtypeId])) {
  2775. $result[$itemtypeId] += $itemtypeCount;
  2776. } else {
  2777. $result[$itemtypeId] = $itemtypeCount;
  2778. }
  2779. }
  2780. }
  2781. }
  2782. }
  2783. return ($result);
  2784. }
  2785. /**
  2786. Туди не страшно йти
  2787. Тому хто відчує
  2788. І усвідомить це -
  2789. Смерть перед очима,
  2790. Та гірше за плечима -
  2791. Там небуття сумирно жде
  2792. */
  2793. /**
  2794. * Returns JQuery datatables reply for storage remains itemtypes
  2795. *
  2796. * @param int $storageId
  2797. * @return string
  2798. */
  2799. public function outcomingRemainsAjaxReply($storageId) {
  2800. $storageId = vf($storageId, 3);
  2801. $remainItems = $this->remainsOnStorage($storageId);
  2802. $json = new wf_JqDtHelper();
  2803. if (!empty($remainItems)) {
  2804. foreach ($remainItems as $itemtypeid => $count) {
  2805. if ($count > 0) {
  2806. $actLink = '';
  2807. if (cfr('WAREHOUSEOUT')) {
  2808. $actLink .= wf_Link(self::URL_ME . '&' . self::URL_OUT . '&storageid=' . $storageId . '&outitemid=' . $itemtypeid, wf_img_sized('skins/whoutcoming_icon.png', '', '10', '10') . ' ' . __('Outcoming')) . ' ';
  2809. }
  2810. if (cfr('WAREHOUSERESERVE')) {
  2811. $actLink .= wf_Link(self::URL_ME . '&' . self::URL_RESERVE . '&storageid=' . $storageId . '&itemtypeid=' . $itemtypeid, wf_img_sized('skins/whreservation.png', '', '10', '10') . ' ' . __('Reservation'));
  2812. }
  2813. $reservedCount = $this->reserveGet($storageId, $itemtypeid);
  2814. $data[] = @$this->allCategories[$this->allItemTypes[$itemtypeid]['categoryid']];
  2815. $data[] = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $itemtypeid, @$this->allItemTypeNames[$itemtypeid]);
  2816. $itemtypeUnit = @$this->unitTypes[$this->allItemTypes[$itemtypeid]['unit']];
  2817. $data[] = ($count - $reservedCount) . ' ' . $itemtypeUnit;
  2818. $data[] = $reservedCount . ' ' . $itemtypeUnit;
  2819. $data[] = $count;
  2820. $data[] = $actLink;
  2821. $json->addRow($data);
  2822. unset($data);
  2823. }
  2824. }
  2825. }
  2826. $json->getJson();
  2827. }
  2828. /**
  2829. * Returns items list available at storage for further outcoming operation
  2830. *
  2831. * @param int $storageId
  2832. * @return string
  2833. */
  2834. public function outcomingItemsList($storageId) {
  2835. $storageId = vf($storageId, 3);
  2836. $result = '';
  2837. if (!empty($this->allIncoming)) {
  2838. $columns = array('Category', 'Warehouse item types', 'Count', 'Reserved', 'Total', 'Actions');
  2839. $result = wf_JqDtLoader($columns, self::URL_ME . '&' . self::URL_OUT . '&storageid=' . $storageId . '&' . self::URL_OUTAJREMAINS, true, 'Warehouse item types', 50);
  2840. } else {
  2841. $result = $this->messages->getStyledMessage(__('Nothing found'), 'warning');
  2842. }
  2843. return ($result);
  2844. }
  2845. /**
  2846. * Returns outcoming operations list
  2847. *
  2848. * @return string
  2849. */
  2850. public function outcomingOperationsList() {
  2851. $result = '';
  2852. if (!empty($this->allOutcoming)) {
  2853. $notesFlag = ubRouting::checkGet('withnotes') ? true : false;
  2854. $urlParams = '';
  2855. $opts = '"order": [[ 0, "desc" ]]';
  2856. $columns = array('ID', 'Date', 'Destination', 'Warehouse storage', 'Category', 'Warehouse item types', 'Count', 'Price per unit', 'Sum', 'Actions');
  2857. if ($notesFlag) {
  2858. $columns = array('ID', 'Date', 'Destination', 'Warehouse storage', 'Category', 'Warehouse item types', 'Count', 'Price per unit', 'Sum', 'Notes', 'Actions');
  2859. $urlParams = '&withnotes=true';
  2860. }
  2861. $result = wf_JqDtLoader($columns, self::URL_ME . '&' . self::URL_OUT . '&' . self::URL_OUTAJLIST . $urlParams, false, 'Outcoming operations', 50, $opts);
  2862. } else {
  2863. $result = $this->messages->getStyledMessage(__('Nothing found'), 'warning');
  2864. }
  2865. return ($result);
  2866. }
  2867. /**
  2868. * Returns outcoming operation destination link
  2869. *
  2870. * @param string $desttype
  2871. * @param string $destparam
  2872. *
  2873. * @return string
  2874. */
  2875. protected function outDestControl($desttype, $destparam) {
  2876. $result = '';
  2877. switch ($desttype) {
  2878. case 'task':
  2879. $result = ' : ' . wf_Link('?module=taskman&edittask=' . $destparam, $destparam);
  2880. break;
  2881. case 'contractor':
  2882. $result = ' : ' . $this->allContractors[$destparam];
  2883. break;
  2884. case 'employee':
  2885. $result = ' : ' . wf_Link('?module=employee', @$this->allEmployee[$destparam]);
  2886. break;
  2887. case 'storage':
  2888. $result = ' : ' . $this->allStorages[$destparam];
  2889. break;
  2890. case 'user':
  2891. $result = ' : ' . wf_Link('?module=userprofile&username=' . $destparam, $destparam);
  2892. break;
  2893. case 'sale':
  2894. $result = '';
  2895. break;
  2896. case 'cancellation':
  2897. $result = '';
  2898. break;
  2899. case 'mistake':
  2900. $result = '';
  2901. break;
  2902. }
  2903. $result = str_replace('"', '', $result);
  2904. $result = trim($result);
  2905. return ($result);
  2906. }
  2907. /**
  2908. * Returns JQuery datatables reply for incoming operations list
  2909. *
  2910. * @param int $storageId
  2911. * @return string
  2912. */
  2913. public function outcomingListAjaxReply() {
  2914. $json = new wf_JqDtHelper();
  2915. $notesFlag = ubRouting::checkGet('withnotes') ? true : false;
  2916. if (!empty($this->allOutcoming)) {
  2917. foreach ($this->allOutcoming as $io => $each) {
  2918. $actLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&showoutid=' . $each['id'], wf_img_sized('skins/whoutcoming_icon.png', '', '10', '10') . ' ' . __('Show'));
  2919. $data[] = $each['id'];
  2920. $data[] = $each['date'];
  2921. $data[] = $this->outDests[$each['desttype']] . $this->outDestControl($each['desttype'], $each['destparam']);
  2922. $data[] = @$this->allStorages[$each['storageid']];
  2923. $data[] = @$this->allCategories[$this->allItemTypes[$each['itemtypeid']]['categoryid']];
  2924. $data[] = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $each['itemtypeid'], $this->allItemTypeNames[$each['itemtypeid']]);
  2925. $data[] = $each['count'] . ' ' . @$this->unitTypes[$this->allItemTypes[$each['itemtypeid']]['unit']];
  2926. $data[] = $each['price'];
  2927. $data[] = ($each['price'] * $each['count']);
  2928. if ($notesFlag) {
  2929. $data[] = $each['notes'];
  2930. }
  2931. $data[] = $actLink;
  2932. $json->addRow($data);
  2933. unset($data);
  2934. }
  2935. }
  2936. $json->getJson();
  2937. }
  2938. /**
  2939. * Returns ajax selector reply for outcoming operation creation form
  2940. *
  2941. * @param string $destMark
  2942. * @return string
  2943. */
  2944. public function outcomindAjaxDestSelector($destMark) {
  2945. $result = '';
  2946. $destMark = vf($destMark);
  2947. $result .= wf_HiddenInput('newoutdesttype', $destMark);
  2948. switch ($destMark) {
  2949. case 'task':
  2950. $tasksTmp = array();
  2951. $allJobTypes = ts_GetAllJobtypes();
  2952. $allUndoneTasks = ts_GetUndoneTasksArray();
  2953. $taskOutDateFlag = (@$this->altCfg['WAREHOUSE_TASKOUTDATE']) ? true : false;
  2954. $taskOutEmpFlag = (@$this->altCfg['WAREHOUSE_TASKOUTEMPLOYEE']) ? true : false;
  2955. $anyOneEmployeeId = (@$this->altCfg['TASKMAN_ANYONE_EMPLOYEEID']) ? $this->altCfg['TASKMAN_ANYONE_EMPLOYEEID'] : 0;
  2956. $taskHideAnyoneFlag = ($anyOneEmployeeId) ? true : false;
  2957. if (!empty($allUndoneTasks)) {
  2958. foreach ($allUndoneTasks as $io => $each) {
  2959. $taskJobType = (isset($allJobTypes[$each['jobtype']])) ? $allJobTypes[$each['jobtype']] : __('Something went wrong') . ': EX_NO_JOBTYPEID';
  2960. $jobLabel = $each['address'] . ' - ' . $taskJobType;
  2961. if ($taskOutDateFlag) {
  2962. $jobLabel .= ', ' . $each['startdate'];
  2963. }
  2964. if ($taskOutEmpFlag) {
  2965. $jobLabel .= ', ' . $this->allEmployee[$each['employee']];
  2966. }
  2967. if ($taskHideAnyoneFlag) {
  2968. if ($each['employee'] != $anyOneEmployeeId) {
  2969. $tasksTmp[$io] = $jobLabel;
  2970. }
  2971. } else {
  2972. $tasksTmp[$io] = $jobLabel;
  2973. }
  2974. }
  2975. }
  2976. $taskIdPreset = (ubRouting::checkGet('taskidpreset')) ? ubRouting::get('taskidpreset', 'int') : '';
  2977. if (!empty($taskIdPreset)) {
  2978. if (!isset($tasksTmp[$taskIdPreset])) {
  2979. $taskPresetFailLabel = __('Fail') . ': ' . __('Task') . ' [' . $taskIdPreset . '] ' . __('Not found');
  2980. $result .= $this->messages->getStyledMessage($taskPresetFailLabel, 'warning') . wf_delimiter(0);
  2981. }
  2982. }
  2983. $result .= wf_Selector('newoutdestparam', $tasksTmp, __('Undone tasks'), $taskIdPreset, false);
  2984. break;
  2985. case 'contractor':
  2986. $result .= wf_Selector('newoutdestparam', $this->allContractors, __('Contractor'), '', false);
  2987. break;
  2988. case 'employee':
  2989. $result .= wf_Selector('newoutdestparam', $this->activeEmployee, __('Worker'), '', false);
  2990. break;
  2991. case 'storage':
  2992. $result .= wf_Selector('newoutdestparam', $this->allStorages, __('Warehouse storage'), '', false);
  2993. break;
  2994. case 'user':
  2995. $allUsers = zb_UserGetAllIPs();
  2996. if (!empty($allUsers)) {
  2997. $allUsers = array_flip($allUsers);
  2998. }
  2999. $result .= wf_AutocompleteTextInput('newoutdestparam', $allUsers, __('Login'), '', false);
  3000. break;
  3001. case 'sale':
  3002. $result .= wf_HiddenInput('newoutdestparam', 'true');
  3003. break;
  3004. case 'cancellation':
  3005. $result .= wf_HiddenInput('newoutdestparam', 'true');
  3006. break;
  3007. case 'mistake':
  3008. $result .= wf_HiddenInput('newoutdestparam', 'true');
  3009. break;
  3010. default:
  3011. $result = __('Strange exeption');
  3012. break;
  3013. }
  3014. return ($result);
  3015. }
  3016. /**
  3017. * Returns outcoming operation creation form
  3018. *
  3019. * @param int $storageid
  3020. * @param int $itemtypeid
  3021. * @param int $reserveid
  3022. *
  3023. * @return string
  3024. */
  3025. public function outcomingCreateForm($storageid, $itemtypeid, $reserveid = '') {
  3026. $result = '';
  3027. $storageid = vf($storageid, 3);
  3028. $itemtypeid = vf($itemtypeid, 3);
  3029. $reserveid = vf($reserveid, 3);
  3030. $tmpDests = array();
  3031. if ((isset($this->allStorages[$storageid])) and (isset($this->allItemTypes[$itemtypeid]))) {
  3032. $itemData = $this->allItemTypes[$itemtypeid];
  3033. $itemUnit = $this->unitTypes[$itemData['unit']];
  3034. $storageRemains = $this->remainsOnStorage($storageid);
  3035. $allRemains = $this->remainsAll();
  3036. if (isset($storageRemains[$itemtypeid])) {
  3037. $itemRemainsStorage = $storageRemains[$itemtypeid];
  3038. } else {
  3039. $itemRemainsStorage = 0;
  3040. }
  3041. if (isset($allRemains[$itemtypeid])) {
  3042. $itemRemainsTotal = $allRemains[$itemtypeid];
  3043. } else {
  3044. $itemRemainsTotal = 0;
  3045. }
  3046. if (!empty($reserveid)) {
  3047. $reserveData = $this->reserveGetData($reserveid);
  3048. $fromReserve = true;
  3049. } else {
  3050. $fromReserve = false;
  3051. }
  3052. $isReserved = $this->reserveGet($storageid, $itemtypeid);
  3053. foreach ($this->outDests as $destMark => $destName) {
  3054. $tmpDests[self::URL_ME . '&' . self::URL_OUT . '&' . self::URL_AJODSELECTOR . $destMark] = $destName;
  3055. }
  3056. //displayed maximum items count
  3057. $maxItemCount = ($fromReserve) ? @$reserveData['count'] : ($itemRemainsStorage - $isReserved);
  3058. //fix deleted reserve issue
  3059. if (empty($maxItemCount)) {
  3060. $maxItemCount = 0;
  3061. }
  3062. //form construct
  3063. $inputs = wf_AjaxLoader();
  3064. $inputs .= wf_HiddenInput('newoutdate', curdate());
  3065. $inputs .= wf_AjaxSelectorAC('ajoutdestselcontainer', $tmpDests, __('Destination'), '', false);
  3066. $inputs .= wf_AjaxContainer('ajoutdestselcontainer', '', $this->outcomindAjaxDestSelector('task'));
  3067. $inputs .= wf_HiddenInput('newoutitemtypeid', $itemtypeid);
  3068. $inputs .= wf_HiddenInput('newoutstorageid', $storageid);
  3069. $inputs .= wf_TextInput('newoutcount', $itemUnit . ' (' . __('maximum') . ' ' . $maxItemCount . ')', '', true, '4', 'finance');
  3070. $midPriceLabel = ($this->recPriceFlag) ? __('recommended') : __('middle price');
  3071. $inputs .= wf_TextInput('newoutprice', __('Price') . ' (' . $midPriceLabel . ': ' . $this->getIncomeMiddlePrice($itemtypeid) . ')', '', true, '4', 'finance');
  3072. if ($fromReserve) {
  3073. $inputs .= wf_HiddenInput('newoutfromreserve', $reserveid);
  3074. $notesPreset = ' ' . __('from reserved on') . ' ' . @$this->allEmployee[$reserveData['employeeid']];
  3075. } else {
  3076. $notesPreset = '';
  3077. }
  3078. $inputs .= wf_TextInput('newoutnotes', __('Notes'), $notesPreset, true, 45);
  3079. $inputs .= wf_CheckInput('newoutnetw', __('Network'), true, false);
  3080. $inputs .= wf_tag('br');
  3081. $inputs .= wf_Submit(__('Create'));
  3082. $form = wf_Form('', 'POST', $inputs, 'glamour');
  3083. //notifications
  3084. if ($itemRemainsTotal < $itemData['reserve']) {
  3085. $remainsAlert = __('The balance of goods and materials in stock is less than the amount') . ' ' . $itemData['reserve'] . ' ' . $itemUnit;
  3086. } else {
  3087. $remainsAlert = '';
  3088. }
  3089. $remainsNotification = __('At storage') . ' ' . @$this->allStorages[$storageid] . ' ' . __('remains') . ' ' . $itemRemainsStorage . ' ' . $itemUnit . ' ' . $itemData['name'];
  3090. $notifications = $this->messages->getStyledMessage($remainsNotification, 'success');
  3091. if ($isReserved) {
  3092. $notifications .= $this->messages->getStyledMessage(__('Reserved') . ' ' . $isReserved . ' ' . $itemUnit, 'info');
  3093. }
  3094. if ($remainsAlert) {
  3095. $notifications .= $this->messages->getStyledMessage($remainsAlert, 'warning');
  3096. }
  3097. $notifications .= wf_CleanDiv();
  3098. if (cfr('WAREHOUSERESERVE')) {
  3099. $reserveLink = self::URL_ME . '&' . self::URL_RESERVE . '&itemtypeid=' . $itemtypeid . '&storageid=' . $storageid;
  3100. $notifications .= wf_tag('div', false, '', 'style="margin: 20px 3% 0 3%;"') . wf_Link($reserveLink, wf_img('skins/whreservation.png') . ' ' . __('Reservation'), false, 'ubButton') . wf_tag('div', true);
  3101. $notifications .= wf_CleanDiv();
  3102. }
  3103. $cells = wf_TableCell($form, '40%');
  3104. $cells .= wf_TableCell($notifications, '', '', 'valign="top"');
  3105. $rows = wf_TableRow($cells);
  3106. $result = wf_TableBody($rows, '100%', 0, '');
  3107. $result .= wf_FormDisabler();
  3108. //photostorage integration
  3109. if ($this->altCfg['PHOTOSTORAGE_ENABLED']) {
  3110. $photostorage = new PhotoStorage(self::PHOTOSTORAGE_SCOPE, $itemtypeid);
  3111. $result .= $photostorage->renderImagesRaw();
  3112. }
  3113. } else {
  3114. $result = $this->messages->getStyledMessage(__('Strange exeption'), 'error');
  3115. }
  3116. return ($result);
  3117. }
  3118. /**
  3119. * Renders outcoming operation view interface
  3120. *
  3121. * @param int $id
  3122. * @return string
  3123. */
  3124. public function outcomingView($id) {
  3125. $id = vf($id, 3);
  3126. $result = '';
  3127. if (isset($this->allOutcoming[$id])) {
  3128. $operationData = $this->allOutcoming[$id];
  3129. $employeeLogins = unserialize(ts_GetAllEmployeeLoginsCached());
  3130. $administratorName = (isset($employeeLogins[$operationData['admin']])) ? $employeeLogins[$operationData['admin']] : $operationData['admin'];
  3131. $itemTypeLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $operationData['itemtypeid'], @$this->allItemTypeNames[$operationData['itemtypeid']]);
  3132. $cells = wf_TableCell(__('ID') . ' ' . $this->qrControl('out', $id), '30%', 'row2');
  3133. $cells .= wf_TableCell($id);
  3134. $rows = wf_TableRow($cells, 'row3');
  3135. $cells = wf_TableCell(__('Date'), '30%', 'row2');
  3136. $cells .= wf_TableCell($operationData['date']);
  3137. $rows .= wf_TableRow($cells, 'row3');
  3138. $cells = wf_TableCell(__('Destination'), '30%', 'row2');
  3139. $cells .= wf_TableCell($this->outDests[$operationData['desttype']] . $this->outDestControl($operationData['desttype'], $operationData['destparam']));
  3140. $rows .= wf_TableRow($cells, 'row3');
  3141. $cells = wf_TableCell(__('Category'), '30%', 'row2');
  3142. $cells .= wf_TableCell(@$this->allCategories[$this->allItemTypes[$operationData['itemtypeid']]['categoryid']]);
  3143. $rows .= wf_TableRow($cells, 'row3');
  3144. $cells = wf_TableCell(__('Warehouse item type'), '30%', 'row2');
  3145. $cells .= wf_TableCell($itemTypeLink);
  3146. $rows .= wf_TableRow($cells, 'row3');
  3147. $cells = wf_TableCell(__('Count'), '30%', 'row2');
  3148. $cells .= wf_TableCell($operationData['count'] . ' ' . $this->unitTypes[$this->allItemTypes[$operationData['itemtypeid']]['unit']]);
  3149. $rows .= wf_TableRow($cells, 'row3');
  3150. $cells = wf_TableCell(__('Price per unit'), '30%', 'row2');
  3151. $cells .= wf_TableCell($operationData['price']);
  3152. $rows .= wf_TableRow($cells, 'row3');
  3153. $cells = wf_TableCell(__('Sum'), '30%', 'row2');
  3154. $cells .= wf_TableCell(($operationData['price'] * $operationData['count']));
  3155. $rows .= wf_TableRow($cells, 'row3');
  3156. $cells = wf_TableCell(__('Warehouse storage'), '30%', 'row2');
  3157. $cells .= wf_TableCell($this->allStorages[$operationData['storageid']]);
  3158. $rows .= wf_TableRow($cells, 'row3');
  3159. $cells = wf_TableCell(__('Network'), '30%', 'row2');
  3160. $netLabel = ($operationData['netw']) ? wf_img_sized('skins/icon_active.gif', '', 12) . ' ' . __('Yes') : wf_img_sized('skins/icon_inactive.gif', '', 12) . ' ' . __('No');
  3161. $cells .= wf_TableCell($netLabel);
  3162. $rows .= wf_TableRow($cells, 'row3');
  3163. $cells = wf_TableCell(__('Worker'), '30%', 'row2');
  3164. $cells .= wf_TableCell($administratorName);
  3165. $rows .= wf_TableRow($cells, 'row3');
  3166. $cells = wf_TableCell(__('Notes'), '30%', 'row2');
  3167. $cells .= wf_TableCell($operationData['notes']);
  3168. $rows .= wf_TableRow($cells, 'row3');
  3169. $result .= wf_TableBody($rows, '100%', 0, 'wh_viewer');
  3170. //returns controls here
  3171. if (@$this->altCfg['WAREHOUSE_RETURNS_ENABLED']) {
  3172. $this->loadReturns();
  3173. $outReturnData = (isset($this->allReturns[$id])) ? $this->allReturns[$id] : array();
  3174. if (empty($outReturnData)) {
  3175. //specific rights check
  3176. if (cfr('WAREHOUSERETURNS')) {
  3177. //return controller here
  3178. if (ubRouting::checkPost(array(self::PROUTE_RETURNOUTID, self::PROUTE_RETURNSTORAGE))) {
  3179. $this->createReturnOperation();
  3180. ubRouting::nav(self::URL_ME . '&' . self::URL_VIEWERS . '&showoutid=' . $id);
  3181. }
  3182. $returnDialogLabel = __('Return items to warehouse storage');
  3183. $result .= wf_modalAuto(wf_img('skins/return.png') . ' ' . $returnDialogLabel, $returnDialogLabel, $this->renderReturnForm($id), 'ubButton');
  3184. }
  3185. } else {
  3186. $returnAdmName = (isset($employeeLogins[$outReturnData['admin']])) ? $employeeLogins[$outReturnData['admin']] : $outReturnData['admin'];
  3187. $returnedLabel = $outReturnData['date'] . ' ' . __('All items from this outcoming operation is already returned to warehouse storage') . ' ';
  3188. $returnedLabel .= $this->allStorages[$outReturnData['storageid']] . ', ';
  3189. $returnedLabel .= __('by administrator') . ' ' . $returnAdmName;
  3190. $result .= $this->messages->getStyledMessage($returnedLabel, 'warning');
  3191. }
  3192. }
  3193. //outcome deletion controls here
  3194. if (@$this->altCfg['WAREHOUSE_OUTDEL_ENABLED']) {
  3195. if (cfr('ROOT')) {
  3196. $outDelUrl = self::URL_ME . '&' . self::URL_VIEWERS . '&showoutid=' . $id . '&' . self::ROUTE_DELOUT . '=' . $id;
  3197. $outDelCancelUrl = self::URL_ME . '&' . self::URL_VIEWERS . '&showoutid=' . $id;
  3198. $outDelLabel = $this->messages->getDeleteAlert();
  3199. $result .= wf_ConfirmDialog($outDelUrl, web_delete_icon() . ' ' . __('Delete'), $outDelLabel, 'ubButton', $outDelCancelUrl, __('Delete') . '?');
  3200. }
  3201. }
  3202. $result .= wf_delimiter(0);
  3203. //photostorage renderer
  3204. if ($this->altCfg['PHOTOSTORAGE_ENABLED']) {
  3205. $photoStorage = new PhotoStorage(self::PHOTOSTORAGE_SCOPE, $operationData['itemtypeid']);
  3206. $result .= $photoStorage->renderImagesRaw();
  3207. }
  3208. } else {
  3209. $result = $this->messages->getStyledMessage(__('Strange exeption') . ' NO_EXISTING_OUTCOME_ID', 'error');
  3210. }
  3211. //ADcomments support
  3212. if ($this->altCfg['ADCOMMENTS_ENABLED']) {
  3213. $adcomments = new ADcomments('WAREHOUSEOUTCOME');
  3214. $result .= wf_tag('h3') . __('Additional comments') . wf_tag('h3', true);
  3215. $result .= $adcomments->renderComments($id);
  3216. }
  3217. return ($result);
  3218. }
  3219. /**
  3220. * Deletes existing outcoming operation
  3221. *
  3222. * @param int $outId
  3223. *
  3224. * @return void
  3225. */
  3226. public function outcomingDelete($outId) {
  3227. $outId = ubRouting::filters($outId, 'int');
  3228. if (isset($this->allOutcoming[$outId])) {
  3229. if (cfr('ROOT')) {
  3230. if (@$this->altCfg['WAREHOUSE_OUTDEL_ENABLED']) {
  3231. $outcomeData = $this->allOutcoming[$outId];
  3232. $itemtypeId = $outcomeData['itemtypeid'];
  3233. $count = $outcomeData['count'];
  3234. $price = $outcomeData['price'];
  3235. $outcomesDb = new NyanORM('wh_out');
  3236. $outcomesDb->where('id', '=', $outId);
  3237. $outcomesDb->delete();
  3238. log_register('WAREHOUSE OUTCOME DELETE [' . $outId . '] ITEM [' . $itemtypeId . '] COUNT `' . $count . '` PRICE `' . $price . '`');
  3239. }
  3240. }
  3241. }
  3242. }
  3243. /**
  3244. * Renders return operation form
  3245. *
  3246. * @param int $outId
  3247. *
  3248. * @return string
  3249. */
  3250. protected function renderReturnForm($outId) {
  3251. $outId = ubRouting::filters($outId, 'int');
  3252. $result = '';
  3253. if (isset($this->allOutcoming[$outId])) {
  3254. $outcomeData = $this->allOutcoming[$outId];
  3255. $inputs = wf_HiddenInput(self::PROUTE_RETURNOUTID, $outId);
  3256. $inputs .= wf_Selector(self::PROUTE_RETURNSTORAGE, $this->allStorages, __('Warehouse storage'), $outcomeData['storageid'], true);
  3257. $inputs .= wf_TextInput(self::PROUTE_RETURNPRICE, __('Price'), $outcomeData['price'], true, 5, 'finance');
  3258. $defaultNote = __('Return of an outcoming operation') . ' ID:' . $outId;
  3259. $inputs .= wf_TextInput(self::PROUTE_RETURNNOTE, __('Notes'), $defaultNote, true, 30);
  3260. $inputs .= wf_Submit(__('Return items to warehouse storage'));
  3261. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  3262. } else {
  3263. $result .= $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('Outcoming operation') . ' [' . $outId . '] ' . __('Not exists'), 'error');
  3264. }
  3265. return ($result);
  3266. }
  3267. /**
  3268. * Creates new outcome return operation
  3269. *
  3270. * @return void
  3271. */
  3272. protected function createReturnOperation() {
  3273. if (ubRouting::checkPost(array(self::PROUTE_RETURNOUTID, self::PROUTE_RETURNSTORAGE))) {
  3274. $outId = ubRouting::post(self::PROUTE_RETURNOUTID, 'int');
  3275. if (isset($this->allOutcoming[$outId])) {
  3276. $outcomeData = $this->allOutcoming[$outId];
  3277. $curDate = curdate();
  3278. $curDateTime = curdatetime();
  3279. $whoami = whoami();
  3280. $itemtypeId = $outcomeData['itemtypeid'];
  3281. $count = $outcomeData['count'];
  3282. $storageId = ubRouting::post(self::PROUTE_RETURNSTORAGE, 'int');
  3283. $price = ubRouting::post(self::PROUTE_RETURNPRICE);
  3284. $notes = ubRouting::post(self::PROUTE_RETURNNOTE);
  3285. $barcode = '';
  3286. $contractorId = 0;
  3287. //push database record about this return
  3288. $this->returnsDb->data('outid', $outId);
  3289. $this->returnsDb->data('storageid', $storageId);
  3290. $this->returnsDb->data('itemtypeid', $itemtypeId);
  3291. $this->returnsDb->data('count', $count);
  3292. $this->returnsDb->data('price', $price);
  3293. $this->returnsDb->data('date', $curDateTime);
  3294. $this->returnsDb->data('admin', $whoami);
  3295. $this->returnsDb->data('note', $notes);
  3296. $this->returnsDb->create();
  3297. //cast some incoming operation on this return
  3298. $this->incomingCreate($curDate, $itemtypeId, $contractorId, $storageId, $count, $price, $barcode, $notes);
  3299. log_register('WAREHOUSE RETURN CREATE [' . $outId . '] ITEM [' . $itemtypeId . '] COUNT `' . $count . '` PRICE `' . $price . '`');
  3300. }
  3301. }
  3302. }
  3303. /**
  3304. * Creates new outcoming operation record in database
  3305. *
  3306. * @param string $date
  3307. * @param string $desttype
  3308. * @param string $destparam
  3309. * @param int $storageid
  3310. * @param int $itemtypeid
  3311. * @param float $count
  3312. * @param float $price
  3313. * @param string $notes
  3314. * @param int $reserveid
  3315. * @param bool $netw
  3316. *
  3317. * @return string not emplty if something went wrong
  3318. */
  3319. public function outcomingCreate($date, $desttype, $destparam, $storageid, $itemtypeid, $count, $price = '', $notes = '', $reserveid = '', $netw = false) {
  3320. $result = '';
  3321. $date = mysql_real_escape_string($date);
  3322. $desttype = mysql_real_escape_string($desttype);
  3323. $destparam = mysql_real_escape_string($destparam);
  3324. $storageid = vf($storageid, 3);
  3325. $itemtypeid = vf($itemtypeid, 3);
  3326. $reserveid = vf($reserveid, 3);
  3327. $countF = mysql_real_escape_string($count);
  3328. $countF = str_replace('-', '', $countF);
  3329. $countF = str_replace(',', '.', $countF);
  3330. $priceF = mysql_real_escape_string($price);
  3331. $priceF = str_replace(',', '.', $priceF);
  3332. if (is_numeric($priceF)) {
  3333. $priceF = round($priceF, 2);
  3334. } else {
  3335. $priceF = 0;
  3336. }
  3337. $notes = mysql_real_escape_string($notes);
  3338. $admin = mysql_real_escape_string(whoami());
  3339. $fromReserve = (!empty($reserveid)) ? true : false;
  3340. if ($fromReserve) {
  3341. $reserveData = $this->reserveGetData($reserveid);
  3342. }
  3343. $netwF = ($netw) ? 1 : 0;
  3344. if (isset($this->allStorages[$storageid])) {
  3345. if (isset($this->allItemTypes[$itemtypeid])) {
  3346. $allItemRemains = $this->remainsOnStorage($storageid);
  3347. @$itemRemains = $allItemRemains[$itemtypeid];
  3348. $itemsReserved = $this->reserveGet($storageid, $itemtypeid);
  3349. if ($fromReserve) {
  3350. if (!empty($reserveData)) {
  3351. $realRemains = $reserveData['count'];
  3352. } else {
  3353. //reserve deleted?
  3354. $realRemains = 0;
  3355. }
  3356. } else {
  3357. $realRemains = $itemRemains - $itemsReserved;
  3358. }
  3359. if ($countF <= $realRemains) {
  3360. //removing items from reserve
  3361. if ($fromReserve) {
  3362. $this->reserveDrain($reserveid, $count);
  3363. }
  3364. //creating new outcome
  3365. $query = "INSERT INTO `wh_out` (`id`,`date`,`desttype`,`destparam`,`storageid`,`itemtypeid`,`count`,`price`,`notes`,`netw`,`admin`) VALUES "
  3366. . "(NULL,'" . $date . "','" . $desttype . "','" . $destparam . "','" . $storageid . "','" . $itemtypeid . "','" . $countF . "','" . $priceF . "','" . $notes . "','" . $netwF . "','" . $admin . "')";
  3367. nr_query($query);
  3368. $newId = simple_get_lastid('wh_out');
  3369. log_register('WAREHOUSE OUTCOME CREATE [' . $newId . '] ITEM [' . $itemtypeid . '] COUNT `' . $count . '` PRICE `' . $price . '` NET `' . $netwF . '`');
  3370. //movement of items between different storages
  3371. if ($desttype == 'storage') {
  3372. $this->incomingCreate($date, $itemtypeid, 0, $destparam, $count, $price, '', __('from') . ' ' . __('Warehouse storage') . ' `' . $this->allStorages[$storageid] . '`');
  3373. }
  3374. } else {
  3375. if ($fromReserve) {
  3376. $quantityFailNotice = __('The balance of goods and materials in stock is less than the reserved');
  3377. $quantityFailReason = ' (' . $countF . ' > ' . $realRemains . ')';
  3378. } else {
  3379. $quantityFailNotice = __('The balance of goods and materials in stock is less than the amount');
  3380. $quantityFailReason = ' (' . $countF . ' > ' . $itemRemains . '-' . $itemsReserved . ')';
  3381. }
  3382. $result = $this->messages->getStyledMessage($quantityFailNotice . $quantityFailReason, 'error');
  3383. }
  3384. } else {
  3385. $result = $this->messages->getStyledMessage(__('Strange exeption') . ' EX_WRONG_ITEMTYPE_ID', 'error');
  3386. }
  3387. } else {
  3388. $result = $this->messages->getStyledMessage(__('Strange exeption') . ' EX_WRONG_STORAGE_ID', 'error');
  3389. }
  3390. return ($result);
  3391. }
  3392. /**
  3393. * Returns income operations list available at storages
  3394. *
  3395. * @return string
  3396. */
  3397. public function reportAllStoragesRemains() {
  3398. $result = '';
  3399. if (!empty($this->allIncoming)) {
  3400. $columns = array('Category', 'Warehouse item types', 'At storage', 'Reserved', 'Total', 'Actions');
  3401. $options = ' "dom": \'<"F"lfB>rti<"F"ps>\', buttons: [\'csv\', \'excel\', \'pdf\', \'print\']';
  3402. $result = wf_JqDtLoader($columns, self::URL_ME . '&' . self::URL_REPORTS . '&' . self::URL_REAJTREM, true, 'Warehouse item types', 50, $options);
  3403. } else {
  3404. $result = $this->messages->getStyledMessage(__('Nothing found'), 'warning');
  3405. }
  3406. return ($result);
  3407. }
  3408. /**
  3409. * Returns JQuery datatables reply for total remains report
  3410. *
  3411. * @return string
  3412. */
  3413. public function reportAllStoragesRemainsAjaxReply() {
  3414. $all = $this->remainsAllWithReserves();
  3415. $json = new wf_JqDtHelper();
  3416. if (!empty($all)) {
  3417. foreach ($all as $itemtypeId => $remains) {
  3418. $itemUnits = $this->unitTypes[$this->allItemTypes[$itemtypeId]['unit']];
  3419. $realRemains = $remains['count'] - $remains['reserved'];
  3420. if (($remains['count'] > 0) or ($remains['reserved'] > 0) or $realRemains > 0) {
  3421. $actLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&showremains=' . $itemtypeId, wf_img_sized('skins/icon_search_small.gif', '', '10', '10') . ' ' . __('Show'));
  3422. $data[] = $this->allCategories[$this->allItemTypes[$itemtypeId]['categoryid']];
  3423. $data[] = wf_link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $itemtypeId, $this->allItemTypeNames[$itemtypeId]);
  3424. $data[] = $realRemains . ' ' . $itemUnits;
  3425. $data[] = $remains['reserved'] . ' ' . $itemUnits;
  3426. $data[] = $remains['count'];
  3427. $data[] = $actLink;
  3428. $json->addRow($data);
  3429. unset($data);
  3430. }
  3431. }
  3432. }
  3433. $json->getJson();
  3434. }
  3435. /**
  3436. * Returns array of all itemtypes available on all storages with their reserved counts
  3437. *
  3438. * @return array
  3439. */
  3440. public function remainsAllWithReserves() {
  3441. $result = array();
  3442. if (!empty($this->allStorages)) {
  3443. foreach ($this->allStorages as $storageId => $storageName) {
  3444. $tmpArr = $this->remainsOnStorage($storageId);
  3445. if (!empty($tmpArr)) {
  3446. /**
  3447. * When you do wrong, no one forgives
  3448. * When you do good, no one will care
  3449. */
  3450. foreach ($tmpArr as $itemtypeId => $itemtypeCount) {
  3451. $reserved = $this->reserveGet($storageId, $itemtypeId);
  3452. if (isset($result[$itemtypeId])) {
  3453. $result[$itemtypeId]['count'] += $itemtypeCount;
  3454. $result[$itemtypeId]['reserved'] += $reserved;
  3455. } else {
  3456. $result[$itemtypeId]['count'] = $itemtypeCount;
  3457. $result[$itemtypeId]['reserved'] = $reserved;
  3458. }
  3459. }
  3460. }
  3461. }
  3462. }
  3463. return ($result);
  3464. }
  3465. /**
  3466. * Renders itemtype storage availability view
  3467. *
  3468. * @param int $itemtypeId
  3469. * @return string
  3470. */
  3471. public function reportAllStoragesRemainsView($itemtypeId) {
  3472. $itemtypeId = vf($itemtypeId, 3);
  3473. $result = '';
  3474. $tmpArr = array();
  3475. if (isset($this->allItemTypes[$itemtypeId])) {
  3476. $itemtypeData = $this->allItemTypes[$itemtypeId];
  3477. $itemtypeUnit = $this->unitTypes[$itemtypeData['unit']];
  3478. $itemtypeName = $this->allItemTypeNames[$itemtypeId];
  3479. $cells = wf_TableCell(__('Warehouse item types'));
  3480. $cells .= wf_TableCell(__('Warehouse storage'));
  3481. $cells .= wf_TableCell(__('Count'));
  3482. $cells .= wf_TableCell(__('Actions'));
  3483. $rows = wf_TableRow($cells, 'row1');
  3484. if (!empty($this->allStorages)) {
  3485. foreach ($this->allStorages as $storageId => $StorageName) {
  3486. $tmpArr = $this->remainsOnStorage($storageId);
  3487. if (!empty($tmpArr)) {
  3488. foreach ($tmpArr as $io => $count) {
  3489. if ($io == $itemtypeId) {
  3490. if ($count > 0) {
  3491. $actLinks = '';
  3492. if (cfr('WAREHOUSEOUT')) {
  3493. $actLinks .= wf_Link(self::URL_ME . '&' . self::URL_OUT . '&storageid=' . $storageId . '&outitemid=' . $itemtypeId, wf_img_sized('skins/whoutcoming_icon.png', '', '10', '10') . ' ' . __('Outcoming')) . ' ';
  3494. }
  3495. if (cfr('WAREHOUSERESERVE')) {
  3496. $actLinks .= wf_Link(self::URL_ME . '&' . self::URL_RESERVE . '&storageid=' . $storageId . '&itemtypeid=' . $itemtypeId, wf_img_sized('skins/whreservation.png', '', '10', '10') . ' ' . __('Reservation'));
  3497. }
  3498. $cells = wf_TableCell($itemtypeName);
  3499. $cells .= wf_TableCell($StorageName);
  3500. $cells .= wf_TableCell($count . ' ' . $itemtypeUnit);
  3501. $cells .= wf_TableCell($actLinks);
  3502. $rows .= wf_TableRow($cells, 'row3');
  3503. }
  3504. }
  3505. }
  3506. }
  3507. }
  3508. }
  3509. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  3510. if ($this->altCfg['PHOTOSTORAGE_ENABLED']) {
  3511. $photoStorage = new PhotoStorage(self::PHOTOSTORAGE_SCOPE, $itemtypeId);
  3512. $result .= $photoStorage->renderImagesRaw();
  3513. }
  3514. } else {
  3515. $result = $this->messages->getStyledMessage(__('Something went wrong') . ' EX_WRONG_ITEMTYPE_ID', 'error');
  3516. }
  3517. return ($result);
  3518. }
  3519. /**
  3520. * Returns low reserve alert
  3521. *
  3522. * @return string
  3523. */
  3524. protected function reserveAlert() {
  3525. $result = '';
  3526. if ((!empty($this->allItemTypes)) and (!empty($this->allStorages)) and (!empty($this->allIncoming))) {
  3527. $allRemains = $this->remainsAll();
  3528. foreach ($this->allItemTypes as $itemtypeId => $itemData) {
  3529. $itemReserve = $itemData['reserve'];
  3530. $itemName = $this->allItemTypeNames[$itemtypeId];
  3531. $itemUnit = $this->unitTypes[$itemData['unit']];
  3532. if ($itemReserve > 0) {
  3533. if ((!isset($allRemains[$itemtypeId])) or ($allRemains[$itemtypeId] < $itemReserve)) {
  3534. $result .= $this->messages->getStyledMessage(__('In warehouses remains less than') . ' ' . $itemReserve . ' ' . $itemUnit . ' ' . $itemName, 'warning');
  3535. }
  3536. }
  3537. }
  3538. }
  3539. return ($result);
  3540. }
  3541. /**
  3542. * Returns low reserve alert
  3543. *
  3544. * @return string
  3545. */
  3546. protected function reserveShoppingAlert() {
  3547. $result = '';
  3548. $photoStorageEnabled = ($this->altCfg['PHOTOSTORAGE_ENABLED']) ? true : false;
  3549. if ($photoStorageEnabled) {
  3550. $photoStorage = new PhotoStorage(self::PHOTOSTORAGE_SCOPE, 'nope');
  3551. }
  3552. if ((!empty($this->allItemTypes)) and (!empty($this->allStorages)) and (!empty($this->allIncoming))) {
  3553. $allRemains = $this->remainsAll();
  3554. foreach ($this->allItemTypes as $itemtypeId => $itemData) {
  3555. $itemReserve = $itemData['reserve'];
  3556. $itemName = $this->allItemTypeNames[$itemtypeId];
  3557. $itemUnit = $this->unitTypes[$itemData['unit']];
  3558. if ($itemReserve > 0) {
  3559. if ((!isset($allRemains[$itemtypeId])) or ($allRemains[$itemtypeId] < $itemReserve)) {
  3560. $itemImage = 'skins/shopping.png';
  3561. if ($photoStorageEnabled) {
  3562. $itemImagesList = $photoStorage->getImagesList($itemtypeId);
  3563. if (!empty($itemImagesList)) {
  3564. $itemImage = $itemImagesList[0]; //just 1st image for item
  3565. }
  3566. }
  3567. $itemLabel = __('In warehouses remains less than') . ' ' . $itemReserve . ' ' . $itemUnit . ' ' . $itemName;
  3568. $itemImagePreview = wf_img_sized($itemImage, $itemLabel, '200', '200');
  3569. $result .= wf_tag('div', false, 'dashtask', 'style="height:230px; width:230px;"');
  3570. $result .= $itemImagePreview;
  3571. $result .= wf_delimiter(0);
  3572. $result .= $itemName . ' < ' . ' ' . $itemReserve . ' ' . $itemUnit;
  3573. $result .= wf_tag('div', true);
  3574. }
  3575. }
  3576. }
  3577. $result .= wf_CleanDiv();
  3578. }
  3579. return ($result);
  3580. }
  3581. /**
  3582. * Shows warehouse summary report
  3583. *
  3584. * @return void
  3585. */
  3586. public function summaryReport() {
  3587. $result = '';
  3588. if ($_SERVER['QUERY_STRING'] == 'module=warehouse&warehousestats=true') {
  3589. $curMonth = curmonth();
  3590. $result .= $this->reserveAlert();
  3591. if (empty($this->allCategories)) {
  3592. $result .= $this->messages->getStyledMessage(__('No existing categories'), 'warning');
  3593. } else {
  3594. $result .= $this->messages->getStyledMessage(__('Available categories') . ': ' . sizeof($this->allCategories), 'info');
  3595. }
  3596. if (empty($this->allItemTypes)) {
  3597. $result .= $this->messages->getStyledMessage(__('No existing warehouse item types'), 'warning');
  3598. } else {
  3599. $result .= $this->messages->getStyledMessage(__('Available item types') . ': ' . sizeof($this->allItemTypes), 'info');
  3600. }
  3601. if (empty($this->allStorages)) {
  3602. $result .= $this->messages->getStyledMessage(__('No existing warehouse storages'), 'warning');
  3603. } else {
  3604. $result .= $this->messages->getStyledMessage(__('Available warehouse storages') . ': ' . sizeof($this->allStorages), 'info');
  3605. }
  3606. if (empty($this->allContractors)) {
  3607. $result .= $this->messages->getStyledMessage(__('No existing contractors'), 'warning');
  3608. } else {
  3609. $result .= $this->messages->getStyledMessage(__('Available contractors') . ': ' . sizeof($this->allContractors), 'info');
  3610. }
  3611. if (empty($this->allIncoming)) {
  3612. $result .= $this->messages->getStyledMessage(__('No incoming operations yet'), 'warning');
  3613. } else {
  3614. $result .= $this->messages->getStyledMessage(__('Total incoming operations') . ': ' . sizeof($this->allIncoming), 'success');
  3615. $monthInCount = 0;
  3616. $monthInSumm = 0;
  3617. foreach ($this->allIncoming as $io => $each) {
  3618. if (ispos($each['date'], $curMonth)) {
  3619. $monthInCount++;
  3620. $monthInSumm += $each['price'] * $each['count'];
  3621. }
  3622. }
  3623. $monthTotalsLabel = __('Current month') . ': ' . $monthInCount . ' ' . __('Incoming operations') . ' ' . __('on') . ' ' . zb_CashBigValueFormat($monthInSumm) . ' ' . __('money');
  3624. $result .= $this->messages->getStyledMessage($monthTotalsLabel, 'success');
  3625. }
  3626. if (empty($this->allOutcoming)) {
  3627. $result .= $this->messages->getStyledMessage(__('No outcoming operations yet'), 'warning');
  3628. } else {
  3629. $result .= $this->messages->getStyledMessage(__('Total outcoming operations') . ': ' . sizeof($this->allOutcoming), 'success');
  3630. }
  3631. if (!empty($result)) {
  3632. $winControl = wf_Link(self::URL_ME, wf_img('skins/shopping_cart_small.png', __('Necessary purchases')));
  3633. show_window(__('Stats') . ' ' . $winControl, $result);
  3634. zb_BillingStats(true);
  3635. }
  3636. } else {
  3637. if ($_SERVER['QUERY_STRING'] == 'module=warehouse') {
  3638. //shopping grid
  3639. $result .= $this->reserveShoppingAlert();
  3640. if (empty($result)) {
  3641. $result .= $this->messages->getStyledMessage(__('It looks like your warehouse is fine'), 'success');
  3642. }
  3643. $winControl = wf_Link(self::URL_ME . '&warehousestats=true', web_icon_charts());
  3644. show_window(__('Necessary purchases') . ' ' . $winControl, $result);
  3645. zb_BillingStats(true);
  3646. }
  3647. }
  3648. }
  3649. /**
  3650. * Renders QR code label of some type
  3651. *
  3652. * @param string $type
  3653. * @param int $id
  3654. */
  3655. public function qrCodeDraw($type, $id) {
  3656. $type = vf($type);
  3657. $id = vf($id, 3);
  3658. switch ($type) {
  3659. case 'in':
  3660. if (isset($this->allIncoming[$id])) {
  3661. $itemName = $this->allItemTypeNames[$this->allIncoming[$id]['itemtypeid']];
  3662. $qrText = $itemName . ' ' . __('Incoming operation') . '# ' . $id;
  3663. } else {
  3664. $qrText = ('Wrong ID');
  3665. }
  3666. break;
  3667. case 'out':
  3668. if (isset($this->allOutcoming[$id])) {
  3669. $itemName = $this->allItemTypeNames[$this->allOutcoming[$id]['itemtypeid']];
  3670. $qrText = $itemName . ' ' . __('Outcoming operation') . '# ' . $id;
  3671. } else {
  3672. $qrText = 'Wrong ID';
  3673. }
  3674. break;
  3675. case 'itemtype':
  3676. if (isset($this->allItemTypeNames[$id])) {
  3677. $qrText = ($this->allItemTypeNames[$id]);
  3678. } else {
  3679. $qrText = 'Wrong ID';
  3680. }
  3681. break;
  3682. default:
  3683. $qrText = 'Wrong type';
  3684. break;
  3685. }
  3686. $qr = new QRCode($qrText);
  3687. $qr->output_image();
  3688. }
  3689. /**
  3690. * Renders available operations in calendar widget
  3691. *
  3692. * @return string
  3693. */
  3694. public function reportCalendarOps() {
  3695. $calendarData = '';
  3696. if (!empty($this->allIncoming)) {
  3697. foreach ($this->allIncoming as $io => $each) {
  3698. $timestamp = strtotime($each['date']);
  3699. $date = date("Y, n-1, j", $timestamp);
  3700. $itemName = @$this->allItemTypeNames[$each['itemtypeid']];
  3701. $itemName = str_replace("'", '`', $itemName);
  3702. $itemCount = @$each['count'];
  3703. $itemUnit = @$this->unitTypes[$this->allItemTypes[$each['itemtypeid']]['unit']];
  3704. $calendarData .= "
  3705. {
  3706. title: '" . $itemName . " - " . $itemCount . ' ' . $itemUnit . "',
  3707. url: '" . self::URL_ME . '&' . self::URL_VIEWERS . '&showinid=' . $each['id'] . "',
  3708. start: new Date(" . $date . "),
  3709. end: new Date(" . $date . "),
  3710. },
  3711. ";
  3712. }
  3713. }
  3714. if (!empty($this->allOutcoming)) {
  3715. foreach ($this->allOutcoming as $io => $each) {
  3716. $timestamp = strtotime($each['date']);
  3717. $date = date("Y, n-1, j", $timestamp);
  3718. $itemName = @$this->allItemTypeNames[$each['itemtypeid']];
  3719. $itemCount = @$each['count'];
  3720. $itemUnit = @$this->unitTypes[$this->allItemTypes[$each['itemtypeid']]['unit']];
  3721. $calendarData .= "
  3722. {
  3723. title: '" . $itemName . " - " . $itemCount . ' ' . $itemUnit . "',
  3724. url: '" . self::URL_ME . '&' . self::URL_VIEWERS . '&showoutid=' . $each['id'] . "',
  3725. start: new Date(" . $date . "),
  3726. end: new Date(" . $date . "),
  3727. className : 'undone',
  3728. },
  3729. ";
  3730. }
  3731. }
  3732. $result = wf_FullCalendar($calendarData);
  3733. return ($result);
  3734. }
  3735. /**
  3736. * Returns additionally spent materials list for some task
  3737. *
  3738. * @param int $taskid
  3739. *
  3740. * @return string
  3741. */
  3742. public function taskMaterialsReport($taskid) {
  3743. $taskid = vf($taskid, 3);
  3744. $result = '';
  3745. $tmpArr = array();
  3746. $sum = 0;
  3747. $outcomesCount = 0;
  3748. $notesFlag = (@$this->altCfg['WAREHOUSE_TASKMANNOTES']) ? true : false;
  3749. $returnsFlag = (@$this->altCfg['WAREHOUSE_RETURNS_ENABLED']) ? true : false;
  3750. if ($returnsFlag) {
  3751. $this->loadReturns();
  3752. }
  3753. if (!empty($this->allOutcoming)) {
  3754. $tmpArr = $this->allOutcoming;
  3755. if (!empty($tmpArr)) {
  3756. $cells = wf_TableCell(__('Date'));
  3757. $cells .= wf_TableCell(__('Warehouse storage'));
  3758. $cells .= wf_TableCell(__('Category'));
  3759. $cells .= wf_TableCell(__('Warehouse item type'));
  3760. $cells .= wf_TableCell(__('Count'));
  3761. $cells .= wf_TableCell(__('Price'));
  3762. $cells .= wf_TableCell(__('Sum'));
  3763. if ($notesFlag) {
  3764. $cells .= wf_TableCell(__('Notes'));
  3765. }
  3766. if (cfr('WAREHOUSEOUT')) {
  3767. $cells .= wf_TableCell(__('Actions'));
  3768. }
  3769. $rows = wf_TableRow($cells, 'row1');
  3770. foreach ($tmpArr as $io => $each) {
  3771. $operationReturned = false;
  3772. if ($returnsFlag) {
  3773. if (isset($this->allReturns[$each['id']])) {
  3774. $operationReturned = true;
  3775. }
  3776. }
  3777. @$itemUnit = $this->unitTypes[$this->allItemTypes[$each['itemtypeid']]['unit']];
  3778. $rowClass = 'row5';
  3779. if ($operationReturned) {
  3780. $rowClass = 'ukvbankstadup';
  3781. $itemUnit .= ' ' . wf_img_sized('skins/return.png', __('All items from this outcoming operation is already returned to warehouse storage'), '12');
  3782. }
  3783. $cells = wf_TableCell($each['date']);
  3784. $cells .= wf_TableCell(@$this->allStorages[$each['storageid']]);
  3785. $cells .= wf_TableCell(@$this->allCategories[$this->allItemTypes[$each['itemtypeid']]['categoryid']]);
  3786. $cells .= wf_TableCell(@$this->allItemTypeNames[$each['itemtypeid']]);
  3787. $cells .= wf_TableCell($each['count'] . ' ' . $itemUnit);
  3788. $cells .= wf_TableCell($each['price']);
  3789. $cells .= wf_TableCell($each['price'] * $each['count']);
  3790. if (cfr('WAREHOUSEOUT')) {
  3791. $actLinks = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&showoutid=' . $each['id'], wf_img_sized('skins/whoutcoming_icon.png', '', '12') . ' ' . __('Show'));
  3792. } else {
  3793. $actLinks = '';
  3794. }
  3795. if ($notesFlag) {
  3796. $cells .= wf_TableCell($each['notes']);
  3797. }
  3798. if (cfr('WAREHOUSEOUT')) {
  3799. $cells .= wf_TableCell($actLinks);
  3800. }
  3801. $rows .= wf_TableRow($cells, $rowClass);
  3802. $sum = $sum + ($each['price'] * $each['count']);
  3803. $outcomesCount++;
  3804. }
  3805. $cells = wf_TableCell(__('Total') . ': ' . $outcomesCount);
  3806. $cells .= wf_TableCell('');
  3807. $cells .= wf_TableCell('');
  3808. $cells .= wf_TableCell('');
  3809. $cells .= wf_TableCell('');
  3810. $cells .= wf_TableCell('');
  3811. $cells .= wf_TableCell($sum);
  3812. if ($notesFlag) {
  3813. $cells .= wf_TableCell('');
  3814. }
  3815. if (cfr('WAREHOUSEOUT')) {
  3816. $cells .= wf_TableCell('');
  3817. }
  3818. $rows .= wf_TableRow($cells, 'row2');
  3819. $result = wf_TableBody($rows, '100%', 0, '');
  3820. } else {
  3821. $result = $this->messages->getStyledMessage(__('Nothing found'), 'info');
  3822. }
  3823. }
  3824. return ($result);
  3825. }
  3826. /**
  3827. * Renders materials list spent on some tasks from array
  3828. *
  3829. * @param array $tasksArr
  3830. * @param string $userLogin
  3831. *
  3832. * @return string
  3833. */
  3834. public function userSpentMaterialsReport($tasksArr = array(), $userLogin = '') {
  3835. $result = '';
  3836. $tmpArr = array();
  3837. $sum = 0;
  3838. $outcomesCount = 0;
  3839. $notesFlag = (@$this->altCfg['WAREHOUSE_TASKMANNOTES']) ? true : false;
  3840. $onlyTaskFilterFlag = (ubRouting::checkGet('onlytasks')) ? true : false;
  3841. $onlyUserFilterFlag = (ubRouting::checkGet('onlyuser')) ? true : false;
  3842. $returnsFlag = (@$this->altCfg['WAREHOUSE_RETURNS_ENABLED']) ? true : false;
  3843. if ($returnsFlag) {
  3844. $this->loadReturns();
  3845. }
  3846. if (!empty($this->allOutcoming)) {
  3847. //prefiltering outcome operations
  3848. foreach ($this->allOutcoming as $io => $each) {
  3849. if (!$onlyUserFilterFlag) {
  3850. //filter by taskId
  3851. if ($each['desttype'] == 'task' and isset($tasksArr[$each['destparam']])) {
  3852. $tmpArr[] = $each;
  3853. }
  3854. }
  3855. if (!$onlyTaskFilterFlag) {
  3856. //filter by direct user outcome operation
  3857. if ($userLogin) {
  3858. if ($each['desttype'] == 'user' and $each['destparam'] == $userLogin) {
  3859. $tmpArr[] = $each;
  3860. }
  3861. }
  3862. }
  3863. }
  3864. //rendering result
  3865. if (!empty($tmpArr)) {
  3866. $cells = wf_TableCell(__('Date'));
  3867. $cells .= wf_TableCell(__('Warehouse storage'));
  3868. $cells .= wf_TableCell(__('Category'));
  3869. $cells .= wf_TableCell(__('Warehouse item type'));
  3870. $cells .= wf_TableCell(__('Count'));
  3871. $cells .= wf_TableCell(__('Price'));
  3872. $cells .= wf_TableCell(__('Sum'));
  3873. if ($notesFlag) {
  3874. $cells .= wf_TableCell(__('Notes'));
  3875. }
  3876. if (cfr('WAREHOUSEOUT')) {
  3877. $cells .= wf_TableCell(__('Actions'));
  3878. }
  3879. $rows = wf_TableRow($cells, 'row1');
  3880. foreach ($tmpArr as $io => $each) {
  3881. $operationReturned = false;
  3882. if ($returnsFlag) {
  3883. if (isset($this->allReturns[$each['id']])) {
  3884. $operationReturned = true;
  3885. }
  3886. }
  3887. @$itemUnit = $this->unitTypes[$this->allItemTypes[$each['itemtypeid']]['unit']];
  3888. $rowClass = 'row5';
  3889. if ($operationReturned) {
  3890. $rowClass = 'ukvbankstadup';
  3891. $itemUnit .= ' ' . wf_img_sized('skins/return.png', __('All items from this outcoming operation is already returned to warehouse storage'), '12');
  3892. }
  3893. $cells = wf_TableCell($each['date']);
  3894. $cells .= wf_TableCell(@$this->allStorages[$each['storageid']]);
  3895. $cells .= wf_TableCell(@$this->allCategories[$this->allItemTypes[$each['itemtypeid']]['categoryid']]);
  3896. $cells .= wf_TableCell(@$this->allItemTypeNames[$each['itemtypeid']]);
  3897. $cells .= wf_TableCell($each['count'] . ' ' . $itemUnit);
  3898. $cells .= wf_TableCell($each['price']);
  3899. $cells .= wf_TableCell($each['price'] * $each['count']);
  3900. if (cfr('WAREHOUSEOUT')) {
  3901. $actUrl = self::URL_ME . '&' . self::URL_VIEWERS . '&showoutid=' . $each['id'];
  3902. $actLinks = wf_Link($actUrl, wf_img_sized('skins/whoutcoming_icon.png', '', '12') . ' ' . __('Show'));
  3903. } else {
  3904. $actLinks = '';
  3905. }
  3906. if ($notesFlag) {
  3907. $cells .= wf_TableCell($each['notes']);
  3908. }
  3909. if (cfr('WAREHOUSEOUT')) {
  3910. $cells .= wf_TableCell($actLinks);
  3911. }
  3912. $rows .= wf_TableRow($cells, $rowClass);
  3913. $sum = $sum + ($each['price'] * $each['count']);
  3914. $outcomesCount++;
  3915. }
  3916. $cells = wf_TableCell(__('Total') . ': ' . $outcomesCount);
  3917. $cells .= wf_TableCell('');
  3918. $cells .= wf_TableCell('');
  3919. $cells .= wf_TableCell('');
  3920. $cells .= wf_TableCell('');
  3921. $cells .= wf_TableCell('');
  3922. $cells .= wf_TableCell($sum);
  3923. if ($notesFlag) {
  3924. $cells .= wf_TableCell('');
  3925. }
  3926. if (cfr('WAREHOUSEOUT')) {
  3927. $cells .= wf_TableCell('');
  3928. }
  3929. $rows .= wf_TableRow($cells, 'row2');
  3930. $result = wf_TableBody($rows, '100%', 0, '');
  3931. } else {
  3932. $result = $this->messages->getStyledMessage(__('Nothing found'), 'info');
  3933. }
  3934. //append some controls here
  3935. $result .= wf_delimiter(0);
  3936. $filterLabelAll = wf_img('skins/icon_ok.gif') . ' ' . __('All together');
  3937. $filterUrlAll = '?module=warehouselookup&username=' . $userLogin;
  3938. $result .= wf_Link($filterUrlAll, $filterLabelAll, false, 'ubButton') . ' ';
  3939. $filterLabelTasks = wf_img('skins/icon_calendar.gif') . ' ' . __('Only tasks');
  3940. $filterUrlTasks = '?module=warehouselookup&username=' . $userLogin . '&onlytasks=true';
  3941. $result .= wf_Link($filterUrlTasks, $filterLabelTasks, false, 'ubButton') . ' ';
  3942. $filterLabelUser = wf_img('skins/icons/userprofile.png') . ' ' . __('Only user');
  3943. $filterUrlUser = '?module=warehouselookup&username=' . $userLogin . '&onlyuser=true';
  3944. $result .= wf_Link($filterUrlUser, $filterLabelUser, false, 'ubButton') . ' ';
  3945. }
  3946. return ($result);
  3947. }
  3948. /**
  3949. * Returns additionally spent materials price for some task
  3950. *
  3951. * @param int $taskid
  3952. *
  3953. * @return array sum=>float & items=>data
  3954. */
  3955. public function taskMaterialsSpentPrice($taskid) {
  3956. $taskid = vf($taskid, 3);
  3957. $result = array();
  3958. $sum = 0;
  3959. if (!empty($this->allOutcoming)) {
  3960. if (!isset($this->taskOutsCache[$taskid])) {
  3961. foreach ($this->allOutcoming as $io => $each) {
  3962. if (($each['desttype'] == 'task') and ($each['destparam'] == $taskid)) {
  3963. $sum = $sum + ($each['price'] * $each['count']);
  3964. $result['items'][] = $each;
  3965. }
  3966. }
  3967. $this->taskOutsCache[$taskid] = $result;
  3968. $this->cache->set('TASKSOUTS', $this->taskOutsCache, self::CACHE_TIMEOUT);
  3969. } else {
  3970. $result = $this->taskOutsCache[$taskid];
  3971. if (!empty($this->taskOutsCache[$taskid]['items'])) {
  3972. foreach ($this->taskOutsCache[$taskid]['items'] as $io => $each) {
  3973. $sum = $sum + ($each['price'] * $each['count']);
  3974. }
  3975. }
  3976. }
  3977. }
  3978. $result['sum'] = $sum;
  3979. return ($result);
  3980. }
  3981. /**
  3982. * shows printable report content
  3983. *
  3984. * @param $title report title
  3985. * @param $data report data to printable transform
  3986. *
  3987. * @return void
  3988. */
  3989. public function reportPrintable($title, $data) {
  3990. $style = file_get_contents(CONFIG_PATH . "ukvprintable.css");
  3991. $header = wf_tag('!DOCTYPE', false, '', 'html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"');
  3992. $header .= wf_tag('html', false, '', 'xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru"');
  3993. $header .= wf_tag('head', false);
  3994. $header .= wf_tag('title') . $title . wf_tag('title', true);
  3995. $header .= wf_tag('meta', false, '', 'http-equiv="Content-Type" content="text/html; charset=UTF-8" /');
  3996. $header .= wf_tag('style', false, '', 'type="text/css"');
  3997. $header .= $style;
  3998. $header .= wf_tag('style', true);
  3999. $header .= wf_tag('script', false, '', 'src="modules/jsc/sorttable.js" language="javascript"') . wf_tag('script', true);
  4000. $header .= wf_tag('head', true);
  4001. $header .= wf_tag('body', false);
  4002. $footer = wf_tag('body', true);
  4003. $footer .= wf_tag('html', true);
  4004. $title = (!empty($title)) ? wf_tag('h2') . $title . wf_tag('h2', true) : '';
  4005. $data = $header . $title . $data . $footer;
  4006. die($data);
  4007. }
  4008. /**
  4009. * Renders storage remains printable report
  4010. *
  4011. * @param int $storageid
  4012. *
  4013. * @return void
  4014. */
  4015. public function reportStorageRemainsPrintable($storageId) {
  4016. $storageId = vf($storageId, 3);
  4017. $result = '';
  4018. if (isset($this->allStorages[$storageId])) {
  4019. $storageName = $this->allStorages[$storageId];
  4020. $allRemains = $this->remainsOnStorage($storageId);
  4021. $cells = wf_TableCell(__('Category'));
  4022. $cells .= wf_TableCell(__('Warehouse item types'));
  4023. $cells .= wf_TableCell(__('Count') . ' ' . __('On') . ' ' . $storageName);
  4024. $cells .= wf_TableCell(__('Reserved'));
  4025. $cells .= wf_TableCell(__('Total'));
  4026. $rows = wf_TableRow($cells, 'row1');
  4027. if (!empty($allRemains)) {
  4028. foreach ($allRemains as $itemtypeId => $count) {
  4029. //hide itemtypes with zero ramains
  4030. if ($count > 0) {
  4031. $reservedCount = $this->reserveGet($storageId, $itemtypeId);
  4032. $cells = wf_TableCell(@$this->allCategories[$this->allItemTypes[$itemtypeId]['categoryid']]);
  4033. $cells .= wf_TableCell(@$this->allItemTypeNames[$itemtypeId]);
  4034. $itemUnit = @$this->unitTypes[$this->allItemTypes[$itemtypeId]['unit']];
  4035. $cells .= wf_TableCell(($count - $reservedCount) . ' ' . $itemUnit);
  4036. $cells .= wf_TableCell($reservedCount . ' ' . $itemUnit);
  4037. $cells .= wf_TableCell($count . ' ' . $itemUnit);
  4038. $rows .= wf_TableRow($cells, 'row3');
  4039. }
  4040. }
  4041. }
  4042. $result = wf_TableBody($rows, '100%', 0, 'sortable');
  4043. $this->reportPrintable(__('The remains in the warehouse storage') . ': ' . $storageName, $result);
  4044. } else {
  4045. show_error(__('Something went wrong') . ': EX_WRONG_STORAGE_ID');
  4046. show_window('', $this->backControl(self::URL_ME . '&' . self::URL_OUT));
  4047. }
  4048. }
  4049. /**
  4050. * Returns date remains report header
  4051. *
  4052. * @param int $year selected year
  4053. * @param string $monthNumber selected month with leading zero
  4054. *
  4055. * @return string
  4056. */
  4057. protected function reportDateRemainsHeader($year, $monthNumber) {
  4058. $monthArr = months_array();
  4059. $monthName = rcms_date_localise($monthArr[$monthNumber]);
  4060. $result = '';
  4061. $result .= wf_tag('table', false, '', 'border="0" cellspacing="2" width="100%" class="printable"');
  4062. $result .= wf_tag('colgroup', false, '', 'span="4" width="80"');
  4063. $result .= wf_tag('colgroup', true);
  4064. $result .= wf_tag('colgroup', false, '', 'width="79"');
  4065. $result .= wf_tag('colgroup', true);
  4066. $result .= wf_tag('colgroup', false, '', 'span="6" width="80"');
  4067. $result .= wf_tag('colgroup', true);
  4068. $result .= wf_tag('tbody', false);
  4069. $result .= wf_tag('tr', false, 'row2');
  4070. $result .= wf_tag('td', false, '', 'colspan="3" rowspan="3" align="center" valign="bottom"');
  4071. $result .= __('Warehouse item types');
  4072. $result .= wf_tag('td', true);
  4073. $result .= wf_tag('td', false, '', 'colspan="2" rowspan="2" align="center" valign="bottom"');
  4074. $result .= __('Remains at the beginning of the month');
  4075. $result .= wf_tag('td', true);
  4076. $result .= wf_tag('td', false, '', 'colspan="4" align="center" valign="bottom"') . $monthName . ' ' . $year . wf_tag('td', true);
  4077. $result .= wf_tag('td', false, '', 'colspan="2" rowspan="2" align="center" valign="bottom"');
  4078. $result .= __('Remains at end of the month');
  4079. $result .= wf_tag('td', true);
  4080. $result .= wf_tag('tr', true);
  4081. $result .= wf_tag('tr', false, 'row2');
  4082. $result .= wf_tag('td', false, '', 'colspan="2" align="center" valign="bottom"') . __('Incoming') . wf_tag('td', true);
  4083. $result .= wf_tag('td', false, '', 'colspan="2" align="center" valign="bottom"') . __('Outcoming') . ' (' . __('Signups') . '/' . __('Other') . ')' . wf_tag('td', true);
  4084. $result .= wf_tag('tr', true);
  4085. $result .= wf_tag('tr', false, 'row2');
  4086. $result .= wf_TableCell(__('Count'));
  4087. $result .= wf_TableCell(__('Sum'));
  4088. $result .= wf_TableCell(__('Count'));
  4089. $result .= wf_TableCell(__('Sum'));
  4090. $result .= wf_TableCell(__('Count'));
  4091. $result .= wf_TableCell(__('Sum'));
  4092. $result .= wf_TableCell(__('Count'));
  4093. $result .= wf_TableCell(__('Sum'));
  4094. $result .= wf_tag('tr', true);
  4095. $result .= wf_tag('tr', false);
  4096. return ($result);
  4097. }
  4098. /**
  4099. * Returns valid formatted table row form date remains report
  4100. *
  4101. * @param int $itemtypeId
  4102. * @param array $data
  4103. *
  4104. * @return string
  4105. */
  4106. protected function reportDateRemainsAddRow($itemtypeId, $data) {
  4107. if ($itemtypeId != '') {
  4108. $itemData = $this->allItemTypeNames[$itemtypeId] . ' (' . $this->unitTypes[$this->allItemTypes[$itemtypeId]['unit']] . ')';
  4109. } else {
  4110. $itemData = '';
  4111. }
  4112. $cells = wf_TableCell($itemData, '', '', 'colspan="3" align="center"');
  4113. $cells .= wf_TableCell($data[0]);
  4114. $cells .= wf_TableCell($data[1]);
  4115. $cells .= wf_TableCell($data[2]);
  4116. $cells .= wf_TableCell($data[3]);
  4117. $cells .= wf_TableCell($data[4]);
  4118. $cells .= wf_TableCell($data[5]);
  4119. $cells .= wf_TableCell($data[6]);
  4120. $cells .= wf_TableCell($data[7]);
  4121. $result = wf_TableRow($cells, 'row3');
  4122. return ($result);
  4123. }
  4124. /**
  4125. * Returns middle price for some itemtype based of all incoming operations
  4126. *
  4127. * @param int $itemtypeId
  4128. *
  4129. * @return float
  4130. */
  4131. public function getIncomeMiddlePrice($itemtypeId) {
  4132. $cacheTimeout = 2592000;
  4133. if (empty($this->cachedPrices)) {
  4134. $this->cachedPrices = $this->cache->get('WH_ITMPRICES', $cacheTimeout);
  4135. if (empty($this->cachedPrices)) {
  4136. $this->cachedPrices = array();
  4137. }
  4138. }
  4139. if (isset($this->cachedPrices[$itemtypeId])) {
  4140. //just return from cached data
  4141. $result = $this->cachedPrices[$itemtypeId];
  4142. } else {
  4143. //cache update is required
  4144. $itemsCount = 0;
  4145. $totalSumm = 0;
  4146. if (!empty($this->allIncoming)) {
  4147. foreach ($this->allIncoming as $io => $each) {
  4148. if ($each['itemtypeid'] == $itemtypeId) {
  4149. if ($each['price'] != 0) {
  4150. if ($each['contractorid'] != 0) { //ignoring move ops
  4151. $totalSumm += ($each['price'] * $each['count']);
  4152. $itemsCount += $each['count'];
  4153. }
  4154. }
  4155. }
  4156. }
  4157. }
  4158. if ($this->recPriceFlag) {
  4159. if (!empty($this->allOutcoming)) {
  4160. foreach ($this->allOutcoming as $io => $each) {
  4161. if ($each['itemtypeid'] == $itemtypeId) {
  4162. if ($each['price'] != 0) {
  4163. $totalSumm -= (abs($each['price']) * $each['count']);
  4164. $itemsCount -= $each['count'];
  4165. }
  4166. }
  4167. }
  4168. }
  4169. }
  4170. if ($itemsCount != 0) {
  4171. $result = round($totalSumm / $itemsCount, 2);
  4172. } else {
  4173. $result = round($totalSumm, 2);
  4174. }
  4175. $this->cachedPrices[$itemtypeId] = $result;
  4176. //cache update
  4177. $this->cache->set('WH_ITMPRICES', $this->cachedPrices, $cacheTimeout);
  4178. }
  4179. return ($result);
  4180. }
  4181. /**
  4182. * Returns list of all signup typed tasks as id=>id
  4183. *
  4184. * @param int $year
  4185. *
  4186. * @return array
  4187. */
  4188. protected function getAllSignupTasks($year = '') {
  4189. $result = array();
  4190. $signupJobTypes = array();
  4191. $signupJobTypesTmp = $this->altCfg['TASKREPORT_SIGNUPJOBTYPES'];
  4192. if (!empty($signupJobTypesTmp)) {
  4193. $signupJobTypesTmp = explode(',', $signupJobTypesTmp);
  4194. if (!empty($signupJobTypesTmp)) {
  4195. foreach ($signupJobTypesTmp as $io => $each) {
  4196. $signupJobTypes[$each] = $each;
  4197. }
  4198. }
  4199. }
  4200. $allTasks = ts_GetAllTasks($year);
  4201. if (!empty($allTasks)) {
  4202. foreach ($allTasks as $io => $each) {
  4203. if (isset($signupJobTypes[$each['jobtype']])) {
  4204. $result[$each['id']] = $each['id'];
  4205. }
  4206. }
  4207. }
  4208. return ($result);
  4209. }
  4210. /**
  4211. * Renders report with list of controls to view some storages remains
  4212. *
  4213. * @return string
  4214. */
  4215. public function reportStoragesRemains() {
  4216. $result = '';
  4217. $result .= $this->outcomingStoragesList(true);
  4218. return ($result);
  4219. }
  4220. /**
  4221. * Renders date remains report
  4222. *
  4223. * @return string
  4224. */
  4225. public function reportDateRemains() {
  4226. $result = '';
  4227. $curyear = (ubRouting::checkPost('yearsel')) ? ubRouting::post('yearsel', 'int') : date("Y");
  4228. $curmonth = (ubRouting::checkPost('monthsel')) ? ubRouting::post('monthsel', 'int') : date("m");
  4229. $hideNoMoveFlag = (ubRouting::checkPost('ignorenotmoving')) ? true : false;
  4230. $storageIdFilter = (ubRouting::checkPost('storageidfilter')) ? ubRouting::post('storageidfilter') : 0;
  4231. $taskReportFlag = (@$this->altCfg['TASKREPORT_ENABLED']) ? true : false;
  4232. $allSignupTasks = array();
  4233. if ($taskReportFlag) {
  4234. $allSignupTasks = $this->getAllSignupTasks($curyear);
  4235. }
  4236. //report form inputs
  4237. $inputs = wf_YearSelector('yearsel', __('Year')) . ' ';
  4238. $inputs .= wf_MonthSelector('monthsel', __('Month'), $curmonth) . ' ';
  4239. $storageFilters = array('0' => __('Any'));
  4240. $storageFilters += $this->allStorages;
  4241. $inputs .= wf_Selector('storageidfilter', $storageFilters, __('Warehouse storage'), $storageIdFilter, false);
  4242. $inputs .= wf_CheckInput('ignorenotmoving', __('Hide without movement'), false, $hideNoMoveFlag) . ' ';
  4243. $inputs .= wf_CheckInput('printmode', __('Print'), false, false) . ' ';
  4244. $inputs .= wf_Submit(__('Show'));
  4245. $searchForm = wf_Form('', 'POST', $inputs, 'glamour');
  4246. $searchForm .= wf_CleanDiv();
  4247. //append form to result
  4248. if (!ubRouting::checkPost('printmode')) {
  4249. $result .= $searchForm;
  4250. }
  4251. //in-out properties copies for further report generation
  4252. $allIncoming = $this->allIncoming;
  4253. $allOutcoming = $this->allOutcoming;
  4254. //optional storage-id filter here
  4255. if ($storageIdFilter) {
  4256. foreach ($allIncoming as $io => $each) {
  4257. if ($each['storageid'] != $storageIdFilter) {
  4258. unset($allIncoming[$io]);
  4259. }
  4260. }
  4261. foreach ($allOutcoming as $io => $each) {
  4262. if ($each['storageid'] != $storageIdFilter) {
  4263. unset($allOutcoming[$io]);
  4264. }
  4265. }
  4266. }
  4267. $lowerOffset = strtotime($curyear . '-' . $curmonth . '-01');
  4268. $upperOffset = strtotime($curyear . '-' . $curmonth . '-01');
  4269. $upperOffset = date("t", $upperOffset);
  4270. $upperOffset = strtotime($curyear . '-' . $curmonth . '-' . $upperOffset);
  4271. $incomingLower = array();
  4272. $outcomingLower = array();
  4273. if (!empty($allIncoming)) {
  4274. foreach ($allIncoming as $io => $each) {
  4275. $incomingDate = strtotime($each['date']);
  4276. if ($incomingDate <= $lowerOffset) {
  4277. if ($each['contractorid'] != 0) { //ignoring move ops
  4278. $incomingLower[$each['id']] = $each;
  4279. }
  4280. }
  4281. }
  4282. }
  4283. if (!empty($allOutcoming)) {
  4284. foreach ($allOutcoming as $io => $each) {
  4285. $outcomingDate = strtotime($each['date']);
  4286. if ($outcomingDate <= $lowerOffset) {
  4287. if ($each['desttype'] != 'storage') { // ignoring move ops
  4288. $outcomingLower[$each['id']] = $each;
  4289. }
  4290. }
  4291. }
  4292. }
  4293. $lowerIncome = array();
  4294. if (!empty($incomingLower)) {
  4295. foreach ($incomingLower as $io => $each) {
  4296. if (isset($lowerIncome[$each['itemtypeid']])) {
  4297. $lowerIncome[$each['itemtypeid']]['count'] = $lowerIncome[$each['itemtypeid']]['count'] + $each['count'];
  4298. $lowerIncome[$each['itemtypeid']]['price'] = $lowerIncome[$each['itemtypeid']]['price'] + ($each['count'] * $each['price']);
  4299. } else {
  4300. $lowerIncome[$each['itemtypeid']]['count'] = $each['count'];
  4301. $lowerIncome[$each['itemtypeid']]['price'] = $each['count'] * $each['price'];
  4302. }
  4303. }
  4304. }
  4305. $lowerOutcome = array();
  4306. if (!empty($outcomingLower)) {
  4307. foreach ($outcomingLower as $io => $each) {
  4308. if ($each['price'] == 0) {
  4309. $each['price'] = $this->getIncomeMiddlePrice($each['itemtypeid']);
  4310. }
  4311. if (isset($lowerOutcome[$each['itemtypeid']])) {
  4312. $lowerOutcome[$each['itemtypeid']]['count'] = $lowerOutcome[$each['itemtypeid']]['count'] + $each['count'];
  4313. $lowerOutcome[$each['itemtypeid']]['price'] = $lowerOutcome[$each['itemtypeid']]['price'] + ($each['count'] * $each['price']);
  4314. } else {
  4315. $lowerOutcome[$each['itemtypeid']]['count'] = $each['count'];
  4316. $lowerOutcome[$each['itemtypeid']]['price'] = $each['count'] * $each['price'];
  4317. }
  4318. }
  4319. }
  4320. //first report column here
  4321. $lowerRemains = array();
  4322. if (!empty($incomingLower)) {
  4323. foreach ($incomingLower as $io => $each) {
  4324. $outcomeCount = (isset($lowerOutcome[$each['itemtypeid']])) ? $lowerOutcome[$each['itemtypeid']]['count'] : 0;
  4325. $outcomePrice = (isset($lowerOutcome[$each['itemtypeid']])) ? $lowerOutcome[$each['itemtypeid']]['price'] : 0;
  4326. $lowerRemains[$each['itemtypeid']]['count'] = $lowerIncome[$each['itemtypeid']]['count'] - $outcomeCount;
  4327. $lowerRemains[$each['itemtypeid']]['price'] = $lowerIncome[$each['itemtypeid']]['price'] - $outcomePrice;
  4328. }
  4329. }
  4330. //second column
  4331. $upperIncome = array();
  4332. if (!empty($allIncoming)) {
  4333. foreach ($allIncoming as $io => $each) {
  4334. $incomeDate = strtotime($each['date']);
  4335. if (($incomeDate >= $lowerOffset) and ($incomeDate) <= $upperOffset) {
  4336. if ($each['contractorid'] != 0) { //ignoring move ops
  4337. if (isset($upperIncome[$each['itemtypeid']])) {
  4338. $upperIncome[$each['itemtypeid']]['count'] = $upperIncome[$each['itemtypeid']]['count'] + $each['count'];
  4339. $upperIncome[$each['itemtypeid']]['price'] = $upperIncome[$each['itemtypeid']]['price'] + ($each['count'] * $each['price']);
  4340. } else {
  4341. $upperIncome[$each['itemtypeid']]['count'] = $each['count'];
  4342. $upperIncome[$each['itemtypeid']]['price'] = $each['count'] * $each['price'];
  4343. }
  4344. }
  4345. }
  4346. }
  4347. }
  4348. //third column
  4349. $upperOutcome = array();
  4350. if (!empty($allOutcoming)) {
  4351. foreach ($allOutcoming as $io => $each) {
  4352. $outcomeDate = strtotime($each['date']);
  4353. if (($outcomeDate >= $lowerOffset) and ($outcomeDate) <= $upperOffset) {
  4354. if ($each['desttype'] != 'storage') { //ignoring move ops
  4355. if ($each['price'] == 0) {
  4356. $each['price'] = $this->getIncomeMiddlePrice($each['itemtypeid']);
  4357. }
  4358. if (isset($upperOutcome[$each['itemtypeid']])) {
  4359. $upperOutcome[$each['itemtypeid']]['count'] = $upperOutcome[$each['itemtypeid']]['count'] + $each['count'];
  4360. $upperOutcome[$each['itemtypeid']]['price'] = $upperOutcome[$each['itemtypeid']]['price'] + ($each['count'] * $each['price']);
  4361. if ($each['desttype'] == 'task' and isset($allSignupTasks[$each['destparam']])) {
  4362. $upperOutcome[$each['itemtypeid']]['sigcount'] = $upperOutcome[$each['itemtypeid']]['sigcount'] + $each['count'];
  4363. $upperOutcome[$each['itemtypeid']]['sigprice'] = $upperOutcome[$each['itemtypeid']]['sigprice'] + ($each['count'] * $each['price']);
  4364. }
  4365. } else {
  4366. $upperOutcome[$each['itemtypeid']]['count'] = $each['count'];
  4367. $upperOutcome[$each['itemtypeid']]['price'] = $each['count'] * $each['price'];
  4368. if ($each['desttype'] == 'task' and isset($allSignupTasks[$each['destparam']])) {
  4369. $upperOutcome[$each['itemtypeid']]['sigcount'] = $each['count'];
  4370. $upperOutcome[$each['itemtypeid']]['sigprice'] = $each['count'] * $each['price'];
  4371. } else {
  4372. $upperOutcome[$each['itemtypeid']]['sigcount'] = 0;
  4373. $upperOutcome[$each['itemtypeid']]['sigprice'] = 0;
  4374. }
  4375. }
  4376. }
  4377. }
  4378. }
  4379. }
  4380. //mixing earlier non exists items into lower remains array
  4381. if (!empty($upperIncome)) {
  4382. foreach ($upperIncome as $io => $each) {
  4383. if (!isset($lowerRemains[$io])) {
  4384. $lowerRemains[$io]['count'] = 0;
  4385. $lowerRemains[$io]['price'] = 0;
  4386. }
  4387. }
  4388. }
  4389. $result .= $this->reportDateRemainsHeader($curyear, $curmonth);
  4390. if (!empty($lowerRemains)) {
  4391. $firstColumnTotal = 0;
  4392. $secondColumnTotal = 0;
  4393. $thirdColumnTotal = 0;
  4394. $fourthColumnTotal = 0;
  4395. foreach ($lowerRemains as $io => $each) {
  4396. $appendResultsFlag = true;
  4397. if ($hideNoMoveFlag) {
  4398. $appendResultsFlag = false;
  4399. }
  4400. $itemtypeId = $io;
  4401. $firstColumnCount = (isset($lowerRemains[$itemtypeId])) ? $lowerRemains[$itemtypeId]['count'] : 0;
  4402. $firstColumnPrice = (isset($lowerRemains[$itemtypeId])) ? $lowerRemains[$itemtypeId]['price'] : 0;
  4403. $secondColumnCount = (isset($upperIncome[$itemtypeId])) ? $upperIncome[$itemtypeId]['count'] : 0;
  4404. $secondColumnPrice = (isset($upperIncome[$itemtypeId])) ? $upperIncome[$itemtypeId]['price'] : 0;
  4405. $thirdColumnCount = (isset($upperOutcome[$itemtypeId])) ? $upperOutcome[$itemtypeId]['count'] : 0;
  4406. $thirdColumnPrice = (isset($upperOutcome[$itemtypeId])) ? $upperOutcome[$itemtypeId]['price'] : 0;
  4407. if (isset($upperOutcome[$itemtypeId]['sigcount']) and isset($upperOutcome[$itemtypeId]['sigprice'])) {
  4408. $thirdColumnCountSig = (isset($upperOutcome[$itemtypeId])) ? $upperOutcome[$itemtypeId]['sigcount'] : 0;
  4409. $thirdColumnPriceSig = (isset($upperOutcome[$itemtypeId])) ? $upperOutcome[$itemtypeId]['sigprice'] : 0;
  4410. } else {
  4411. $thirdColumnCountSig = 0;
  4412. $thirdColumnPriceSig = 0;
  4413. }
  4414. $fourthColumnCount = $lowerRemains[$itemtypeId]['count'] + $secondColumnCount - $thirdColumnCount;
  4415. $fourthColumnPrice = $lowerRemains[$itemtypeId]['price'] + $secondColumnPrice - $thirdColumnPrice;
  4416. //some movements is there?
  4417. if ($hideNoMoveFlag) {
  4418. if ($secondColumnCount or $thirdColumnCount) {
  4419. $appendResultsFlag = true;
  4420. }
  4421. }
  4422. //appending row to results
  4423. if ($appendResultsFlag) {
  4424. $result .= $this->reportDateRemainsAddRow($itemtypeId, array(
  4425. $firstColumnCount,
  4426. round($firstColumnPrice, 2),
  4427. $secondColumnCount,
  4428. round($secondColumnPrice, 2),
  4429. $thirdColumnCount . ' (' . $thirdColumnCountSig . '/' . ($thirdColumnCount - $thirdColumnCountSig) . ')',
  4430. round($thirdColumnPrice, 2) . ' (' . $thirdColumnPriceSig . '/' . ($thirdColumnPrice - $thirdColumnPriceSig) . ')',
  4431. $fourthColumnCount,
  4432. round($fourthColumnPrice, 2)
  4433. ));
  4434. $firstColumnTotal += $firstColumnPrice;
  4435. $secondColumnTotal += $secondColumnPrice;
  4436. $thirdColumnTotal += $thirdColumnPrice;
  4437. $fourthColumnTotal += $fourthColumnPrice;
  4438. }
  4439. }
  4440. //table summary append
  4441. $result .= $this->reportDateRemainsAddRow('', array('', $firstColumnTotal, '', $secondColumnTotal, '', $thirdColumnTotal, '', $fourthColumnTotal));
  4442. }
  4443. $result .= wf_tag('tbody', true);
  4444. $result .= wf_tag('table', true);
  4445. if (wf_CheckPost(array('printmode'))) {
  4446. die($this->reportPrintable(__('Date remains'), $result));
  4447. }
  4448. return ($result);
  4449. }
  4450. /**
  4451. * Renders itemtype history with income, outcome and reservation operations
  4452. *
  4453. * @param int $itemtypeId
  4454. *
  4455. * @return void
  4456. */
  4457. public function renderItemHistory($itemtypeId) {
  4458. $itemtypeId = vf($itemtypeId, 3);
  4459. $result = '';
  4460. $tmpArr = array();
  4461. if (isset($this->allItemTypeNames[$itemtypeId])) {
  4462. $this->loadReserveHistory();
  4463. $itemTypeName = $this->allItemTypeNames[$itemtypeId];
  4464. $itemTypeCategory = $this->allCategories[$this->allItemTypes[$itemtypeId]['categoryid']];
  4465. if (!empty($this->allIncoming)) {
  4466. foreach ($this->allIncoming as $io => $each) {
  4467. if ($each['itemtypeid'] == $itemtypeId) {
  4468. $tmpArr[$each['date']]['in'][] = $each;
  4469. }
  4470. }
  4471. }
  4472. if (!empty($this->allOutcoming)) {
  4473. foreach ($this->allOutcoming as $io => $each) {
  4474. if ($each['itemtypeid'] == $itemtypeId) {
  4475. $tmpArr[$each['date']]['out'][] = $each;
  4476. }
  4477. }
  4478. }
  4479. if (!empty($this->allReserveHistory)) {
  4480. foreach ($this->allReserveHistory as $io => $each) {
  4481. $reserveDate = strtotime($each['date']);
  4482. $reserveDate = date("Y-m-d", $reserveDate);
  4483. if ($each['itemtypeid'] == $itemtypeId) {
  4484. $tmpArr[$reserveDate]['res'][] = $each;
  4485. }
  4486. }
  4487. }
  4488. if (!empty($tmpArr)) {
  4489. krsort($tmpArr);
  4490. $employeeLogins = unserialize(ts_GetAllEmployeeLoginsCached());
  4491. $cells = wf_TableCell(__('Date'));
  4492. $cells .= wf_TableCell(__('Type'));
  4493. $cells .= wf_TableCell(__('Warehouse storage'));
  4494. $cells .= wf_TableCell(__('Count'));
  4495. $cells .= wf_TableCell(__('Price'));
  4496. $cells .= wf_TableCell(__('Actions'));
  4497. $cells .= wf_TableCell(__('Admin'));
  4498. $rows = wf_TableRow($cells, 'row1');
  4499. foreach ($tmpArr as $io => $eachDate) {
  4500. if (!empty($eachDate)) {
  4501. foreach ($eachDate as $opType => $eachPack) {
  4502. if (!empty($eachPack)) {
  4503. foreach ($eachPack as $ix => $eachOp) {
  4504. $administratorName = (isset($employeeLogins[$eachOp['admin']])) ? $employeeLogins[$eachOp['admin']] : $eachOp['admin'];
  4505. $from = '';
  4506. $to = '';
  4507. $opTypeName = '';
  4508. $opLink = '';
  4509. $itemUnitType = @$this->unitTypes[$this->allItemTypes[$eachOp['itemtypeid']]['unit']];
  4510. //incoming ops
  4511. if ($opType == 'in') {
  4512. if ($eachOp['contractorid'] == 0) {
  4513. $from = $eachOp['notes'];
  4514. } else {
  4515. $from = @$this->allContractors[$eachOp['contractorid']];
  4516. }
  4517. $to = $this->allStorages[$eachOp['storageid']];
  4518. $opTypeName = __('Incoming');
  4519. $rowColor = '#009f04';
  4520. $opLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&showinid=' . $eachOp['id'], wf_img_sized('skins/whincoming_icon.png', __('Show'), '10', '10'));
  4521. }
  4522. //outcoming ops
  4523. if ($opType == 'out') {
  4524. $from = $this->allStorages[$eachOp['storageid']];
  4525. $to = $this->outDests[$eachOp['desttype']] . $this->outDestControl($eachOp['desttype'], $eachOp['destparam']);
  4526. $opTypeName = __('Outcoming');
  4527. $rowColor = '#b50000';
  4528. $opLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&showoutid=' . $eachOp['id'], wf_img_sized('skins/whoutcoming_icon.png', __('Show'), '10', '10'));
  4529. }
  4530. //reservation ops
  4531. if ($opType == 'res') {
  4532. $from = $this->allStorages[$eachOp['storageid']];
  4533. $to = @$this->allEmployee[$eachOp['employeeid']];
  4534. $opTypeName = __('Reservation');
  4535. if ($eachOp['type'] == 'create') {
  4536. $opTypeName .= ' (' . __('Created') . ')';
  4537. }
  4538. if ($eachOp['type'] == 'update') {
  4539. $opTypeName .= ' (' . __('Updated') . ')';
  4540. }
  4541. if ($eachOp['type'] == 'delete') {
  4542. $opTypeName .= ' (' . __('Deleted') . ')';
  4543. }
  4544. $rowColor = '#ff8a00';
  4545. }
  4546. //itemtype price calculation
  4547. if (isset($eachOp['price'])) {
  4548. $opPrice = $eachOp['price'] * $eachOp['count'];
  4549. } else {
  4550. $opPrice = 0;
  4551. }
  4552. $cells = wf_TableCell(wf_tag('font', false, '', 'color="' . $rowColor . '"') . $eachOp['date'] . wf_tag('font', true));
  4553. $cells .= wf_TableCell(wf_tag('font', false, '', 'color="' . $rowColor . '"') . $opTypeName . wf_tag('font', true) . ' ' . $opLink);
  4554. $cells .= wf_TableCell(@$this->allStorages[$eachOp['storageid']]);
  4555. $cells .= wf_TableCell($eachOp['count'] . ' ' . $itemUnitType);
  4556. $cells .= wf_TableCell($opPrice);
  4557. $cells .= wf_TableCell($from . ' ' . wf_img('skins/arrow_right_green.png') . ' ' . $to);
  4558. $cells .= wf_TableCell($administratorName);
  4559. $rows .= wf_TableRow($cells, 'row3');
  4560. }
  4561. }
  4562. }
  4563. }
  4564. }
  4565. $result = wf_TableBody($rows, '100%', 0, 'sortable');
  4566. if ($this->altCfg['PHOTOSTORAGE_ENABLED']) {
  4567. $photoStorage = new PhotoStorage(self::PHOTOSTORAGE_SCOPE, $itemtypeId);
  4568. $result .= $photoStorage->renderImagesRaw();
  4569. }
  4570. }
  4571. show_window(__('History') . ': ' . $itemTypeCategory . ', ' . $itemTypeName, $result);
  4572. } else {
  4573. show_error(__('Something went wrong'));
  4574. }
  4575. }
  4576. /**
  4577. * Renders itemtypes report spent on network upgrades
  4578. *
  4579. * @return string
  4580. */
  4581. public function renderNetwUpgradeReport() {
  4582. $result = '';
  4583. $reportDataTmp = array();
  4584. $totalPrice = 0;
  4585. $dateFrom = (ubRouting::checkPost('datefrom')) ? ubRouting::post('datefrom', 'mres') : date("Y-m") . '-01';
  4586. $dateTo = (ubRouting::checkPost('dateto')) ? ubRouting::post('dateto', 'mres') : date("Y-m-d");
  4587. $inputs = wf_DatePickerPreset('datefrom', $dateFrom, true) . ' ' . __('From') . ' ';
  4588. $inputs .= wf_DatePickerPreset('dateto', $dateTo, true) . ' ' . __('To') . ' ';
  4589. $inputs .= wf_Submit(__('Show'));
  4590. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  4591. $result .= wf_delimiter();
  4592. if ($dateFrom and $dateTo) {
  4593. if (!empty($this->allOutcoming)) {
  4594. foreach ($this->allOutcoming as $io => $each) {
  4595. if ($each['netw'] and zb_isDateBetween($dateFrom, $dateTo, $each['date'])) {
  4596. $itemtypeName = $this->allItemTypeNames[$each['itemtypeid']];
  4597. if (isset($reportDataTmp[$itemtypeName])) {
  4598. $reportDataTmp[$itemtypeName]['count'] += $each['count'];
  4599. $reportDataTmp[$itemtypeName]['price'] += $each['price'];
  4600. } else {
  4601. $reportDataTmp[$itemtypeName]['count'] = $each['count'];
  4602. $reportDataTmp[$itemtypeName]['price'] = $each['price'];
  4603. $reportDataTmp[$itemtypeName]['itemtypeid'] = $each['itemtypeid'];
  4604. }
  4605. }
  4606. }
  4607. if (!empty($reportDataTmp)) {
  4608. $cells = wf_TableCell(__('Category'));
  4609. $cells .= wf_TableCell(__('Warehouse item types'));
  4610. $cells .= wf_TableCell(__('Count'));
  4611. $cells .= wf_TableCell(__('Price'));
  4612. $rows = wf_TableRow($cells, 'row1');
  4613. foreach ($reportDataTmp as $eachItemType => $eachOutData) {
  4614. $eachItemCatetogy = $this->allCategories[$this->allItemTypes[$eachOutData['itemtypeid']]['categoryid']];
  4615. $cells = wf_TableCell($eachItemCatetogy);
  4616. $cells .= wf_TableCell($eachItemType);
  4617. $cells .= wf_TableCell($eachOutData['count']);
  4618. $cells .= wf_TableCell($eachOutData['price']);
  4619. $rows .= wf_TableRow($cells, 'row5');
  4620. $totalPrice += $eachOutData['price'];
  4621. }
  4622. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  4623. $result .= __('Total cost') . ': ' . round($totalPrice, 2);
  4624. } else {
  4625. $result .= $this->messages->getStyledMessage(__('Nothing found'), 'warning');
  4626. }
  4627. } else {
  4628. $result .= $this->messages->getStyledMessage(__('No outcoming operations yet'), 'error');
  4629. }
  4630. } else {
  4631. $result .= $this->messages->getStyledMessage(__('Something went wrong'), 'error');
  4632. }
  4633. return ($result);
  4634. }
  4635. /**
  4636. * Renders some itemtype outomes history for some finance accounting purposes. Yep. I dont know what for.
  4637. *
  4638. * @return string
  4639. */
  4640. public function renderItemtypeOutcomesHistory() {
  4641. $result = '';
  4642. $tmpArr = array();
  4643. $filterYear = (ubRouting::checkPost('filtersomeyear')) ? ubRouting::post('filtersomeyear') : curyear();
  4644. $yearMask = $filterYear . '-';
  4645. $itemtypeId = (ubRouting::checkPost('showsomeitemtypeid')) ? ubRouting::post('showsomeitemtypeid', 'int') : 0; // Yeah. Come get some.
  4646. $messages = new UbillingMessageHelper();
  4647. $totalPrice = 0;
  4648. $totalCount = 0;
  4649. $countUnit = '';
  4650. ///search form construction
  4651. $inputs = wf_YearSelectorPreset('filtersomeyear', __('Year'), false, $filterYear, true) . ' ';
  4652. $inputs .= wf_Selector('showsomeitemtypeid', $this->allItemTypeNames, __('Warehouse item type'), $itemtypeId, false) . ' ';
  4653. $inputs .= wf_Submit(__('Show'));
  4654. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  4655. if ($itemtypeId and $filterYear) {
  4656. if (isset($this->allItemTypeNames[$itemtypeId])) {
  4657. $itemTypeName = $this->allItemTypeNames[$itemtypeId];
  4658. $itemTypeCategory = $this->allCategories[$this->allItemTypes[$itemtypeId]['categoryid']];
  4659. if (!empty($this->allOutcoming)) {
  4660. foreach ($this->allOutcoming as $io => $each) {
  4661. if ($each['itemtypeid'] == $itemtypeId) {
  4662. if ($each['desttype'] == 'task') {
  4663. if (ispos($each['date'], $yearMask)) {
  4664. $tmpArr[$each['date']]['out'][] = $each;
  4665. }
  4666. }
  4667. }
  4668. }
  4669. }
  4670. if (!empty($tmpArr)) {
  4671. krsort($tmpArr);
  4672. $employeeLogins = unserialize(ts_GetAllEmployeeLoginsCached());
  4673. $allTasksAddress = ts_GetAllTasksAddress();
  4674. $cells = wf_TableCell(__('Date'));
  4675. $cells .= wf_TableCell(__('Type'));
  4676. $cells .= wf_TableCell(__('Warehouse storage'));
  4677. $cells .= wf_TableCell(__('Count'));
  4678. $cells .= wf_TableCell(__('Price'));
  4679. $cells .= wf_TableCell(__('Actions'));
  4680. $cells .= wf_TableCell(__('Address'));
  4681. $cells .= wf_TableCell(__('Admin'));
  4682. $rows = wf_TableRow($cells, 'row1');
  4683. foreach ($tmpArr as $io => $eachDate) {
  4684. if (!empty($eachDate)) {
  4685. foreach ($eachDate as $opType => $eachPack) {
  4686. if (!empty($eachPack)) {
  4687. foreach ($eachPack as $ix => $eachOp) {
  4688. $administratorName = (isset($employeeLogins[$eachOp['admin']])) ? $employeeLogins[$eachOp['admin']] : $eachOp['admin'];
  4689. $from = '';
  4690. $to = '';
  4691. $opTypeName = '';
  4692. $opLink = '';
  4693. $itemUnitType = @$this->unitTypes[$this->allItemTypes[$eachOp['itemtypeid']]['unit']];
  4694. //outcoming ops
  4695. if ($opType == 'out') {
  4696. $from = $this->allStorages[$eachOp['storageid']];
  4697. $to = $this->outDests[$eachOp['desttype']] . $this->outDestControl($eachOp['desttype'], $eachOp['destparam']);
  4698. $opTypeName = __('Outcoming');
  4699. $rowColor = '#b50000';
  4700. $opLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&showoutid=' . $eachOp['id'], wf_img_sized('skins/whoutcoming_icon.png', __('Show'), '10', '10'));
  4701. }
  4702. //itemtype price calculation
  4703. if (isset($eachOp['price'])) {
  4704. $opPrice = $eachOp['price'] * $eachOp['count'];
  4705. } else {
  4706. $opPrice = 0;
  4707. }
  4708. $cells = wf_TableCell(wf_tag('font', false, '', 'color="' . $rowColor . '"') . $eachOp['date'] . wf_tag('font', true));
  4709. $cells .= wf_TableCell(wf_tag('font', false, '', 'color="' . $rowColor . '"') . $opTypeName . wf_tag('font', true) . ' ' . $opLink);
  4710. $cells .= wf_TableCell(@$this->allStorages[$eachOp['storageid']]);
  4711. $cells .= wf_TableCell($eachOp['count'] . ' ' . $itemUnitType);
  4712. $cells .= wf_TableCell($opPrice);
  4713. $cells .= wf_TableCell($from . ' ' . wf_img('skins/arrow_right_green.png') . ' ' . $to);
  4714. $taskAddress = (isset($allTasksAddress[$eachOp['destparam']])) ? $allTasksAddress[$eachOp['destparam']] : '';
  4715. $cells .= wf_TableCell($taskAddress);
  4716. $cells .= wf_TableCell($administratorName);
  4717. $rows .= wf_TableRow($cells, 'row3');
  4718. $totalCount += $eachOp['count'];
  4719. $totalPrice += $opPrice;
  4720. $countUnit = $itemUnitType;
  4721. }
  4722. }
  4723. }
  4724. }
  4725. }
  4726. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  4727. $result .= __('Total') . ' ' . __('Count') . ': ' . $totalCount . ' ' . $countUnit;
  4728. $result .= wf_tag('br');
  4729. $result .= __('Total') . ' ' . __('Price') . ': ' . $totalPrice;
  4730. } else {
  4731. $result .= $messages->getStyledMessage(__('Nothing found'), 'info');
  4732. }
  4733. } else {
  4734. $result .= $messages->getStyledMessage(__('Something went wrong'), 'error');
  4735. }
  4736. } else {
  4737. $result .= $messages->getStyledMessage(__('Nothing to show'), 'warning');
  4738. }
  4739. return ($result);
  4740. }
  4741. /**
  4742. * Renders per year purchases report
  4743. *
  4744. * @return string
  4745. */
  4746. public function renderPurchasesReport() {
  4747. $result = '';
  4748. $tmpResult = array();
  4749. $totalSumm = 0;
  4750. $showYear = (ubRouting::checkPost('purchasesyear')) ? ubRouting::post('purchasesyear', 'int') . '-' : curyear() . '-';
  4751. $inputs = wf_YearSelectorPreset('purchasesyear', __('Year'), false, ubRouting::post('purchasesyear'), false) . ' ';
  4752. $inputs .= wf_Submit(__('Show'));
  4753. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  4754. if (!empty($this->allIncoming)) {
  4755. foreach ($this->allIncoming as $io => $each) {
  4756. if ($each['contractorid'] != 0) {
  4757. if (ispos($each['date'], $showYear)) {
  4758. $opMonth = strtotime($each['date']);
  4759. $opMonth = date("m", $opMonth);
  4760. $opPrice = $each['price'] * $each['count'];
  4761. if (isset($tmpResult[$opMonth])) {
  4762. $tmpResult[$opMonth]['count']++;
  4763. $tmpResult[$opMonth]['price'] += $opPrice;
  4764. } else {
  4765. $tmpResult[$opMonth]['count'] = 1;
  4766. $tmpResult[$opMonth]['price'] = $opPrice;
  4767. }
  4768. $totalSumm += $opPrice;
  4769. }
  4770. }
  4771. }
  4772. if (!empty($tmpResult)) {
  4773. $yearTotalCount = 0;
  4774. $yearTotalSumm = 0;
  4775. $monthArr = months_array_localized();
  4776. $cells = wf_TableCell('');
  4777. $cells .= wf_TableCell(__('Month'));
  4778. $cells .= wf_TableCell(__('Count'));
  4779. $cells .= wf_TableCell(__('Sum'));
  4780. $cells .= wf_TableCell(__('Visual'), '50%');
  4781. $rows = wf_TableRow($cells, 'row1');
  4782. foreach ($monthArr as $monthNum => $monthName) {
  4783. if (isset($tmpResult[$monthNum])) {
  4784. $monthCount = $tmpResult[$monthNum]['count'];
  4785. $monthSumm = $tmpResult[$monthNum]['price'];
  4786. $yearTotalCount += $monthCount;
  4787. $yearTotalSumm += $monthSumm;
  4788. } else {
  4789. $monthCount = 0;
  4790. $monthSumm = 0;
  4791. }
  4792. $cells = wf_TableCell($monthNum);
  4793. $cells .= wf_TableCell($monthName);
  4794. $cells .= wf_TableCell($monthCount);
  4795. $cells .= wf_TableCell(zb_CashBigValueFormat($monthSumm));
  4796. $cells .= wf_TableCell(web_bar($monthSumm, $totalSumm));
  4797. $rows .= wf_TableRow($cells, 'row3');
  4798. }
  4799. $cells = wf_TableCell('');
  4800. $cells .= wf_TableCell(__('Total'));
  4801. $cells .= wf_TableCell($yearTotalCount);
  4802. $cells .= wf_TableCell(zb_CashBigValueFormat($yearTotalSumm));
  4803. $cells .= wf_TableCell('');
  4804. $rows .= wf_TableRow($cells, 'row2');
  4805. $result .= wf_TableBody($rows, '100%', 0, '');
  4806. } else {
  4807. $result .= $this->messages->getStyledMessage(__('Nothing found'), 'info');
  4808. }
  4809. } else {
  4810. $result .= $this->messages->getStyledMessage(__('Nothing to show'), 'warning');
  4811. }
  4812. return ($result);
  4813. }
  4814. /**
  4815. * Renders incomes by contractor report
  4816. *
  4817. * @return string
  4818. */
  4819. public function renderContractorIncomesReport() {
  4820. $result = '';
  4821. $tmpResult = array();
  4822. $totalSumm = 0;
  4823. if (ubRouting::checkPost('conincomesyear')) {
  4824. $rawYear = ubRouting::post('conincomesyear', 'int');
  4825. if ($rawYear != '1488') {
  4826. $showYear = $rawYear . '-';
  4827. } else {
  4828. $showYear = '-';
  4829. }
  4830. } else {
  4831. $showYear = curyear() . '-';
  4832. }
  4833. $showContractor = (ubRouting::checkPost('conincomesid')) ? ubRouting::post('conincomesid', 'int') : '';
  4834. $inputs = wf_YearSelectorPreset('conincomesyear', __('Year'), false, ubRouting::post('conincomesyear'), true) . ' ';
  4835. $inputs .= wf_Selector('conincomesid', $this->allContractors, __('Contractor'), $showContractor, false);
  4836. $inputs .= wf_Submit(__('Show'));
  4837. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  4838. if ($showContractor) {
  4839. if (!empty($this->allIncoming)) {
  4840. foreach ($this->allIncoming as $io => $each) {
  4841. if ($each['contractorid'] != 0 and $each['contractorid'] == $showContractor) {
  4842. if (ispos($each['date'], $showYear)) {
  4843. $opPrice = $each['price'] * $each['count'];
  4844. $tmpResult[$each['id']] = $each;
  4845. $totalSumm += $opPrice;
  4846. }
  4847. }
  4848. }
  4849. if (!empty($tmpResult)) {
  4850. rsort($tmpResult); //from newest
  4851. $cells = wf_TableCell(__('ID'));
  4852. $cells .= wf_TableCell(__('Date'));
  4853. $cells .= wf_TableCell(__('Category'));
  4854. $cells .= wf_TableCell(__('Warehouse item types'));
  4855. $cells .= wf_TableCell(__('Count'));
  4856. $cells .= wf_TableCell(__('Price per unit'));
  4857. $cells .= wf_TableCell(__('Sum'));
  4858. $cells .= wf_TableCell(__('Warehouse storage'));
  4859. $cells .= wf_TableCell(__('Admin'));
  4860. $cells .= wf_TableCell(__('Notes'));
  4861. $cells .= wf_TableCell(__('Actions'));
  4862. $rows = wf_TableRow($cells, 'row1');
  4863. foreach ($tmpResult as $io => $each) {
  4864. $actLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&showinid=' . $each['id'], wf_img_sized('skins/whincoming_icon.png', '', '10', '10') . ' ' . __('Show'));
  4865. $cells = wf_TableCell($each['id']);
  4866. $cells .= wf_TableCell($each['date']);
  4867. $cells .= wf_TableCell(@$this->allCategories[$this->allItemTypes[$each['itemtypeid']]['categoryid']]);
  4868. $cells .= wf_TableCell(wf_link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $each['itemtypeid'], $this->allItemTypeNames[$each['itemtypeid']]));
  4869. $cells .= wf_TableCell($each['count'] . ' ' . @$this->unitTypes[$this->allItemTypes[$each['itemtypeid']]['unit']]);
  4870. $cells .= wf_TableCell($each['price']);
  4871. $cells .= wf_TableCell(round($each['price'] * $each['count'], 2));
  4872. $cells .= wf_TableCell(@$this->allStorages[$each['storageid']]);
  4873. $cells .= wf_TableCell($each['admin']);
  4874. $cells .= wf_TableCell($each['notes']);
  4875. $cells .= wf_TableCell($actLink);
  4876. $rows .= wf_TableRow($cells, 'row5');
  4877. }
  4878. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  4879. $result .= wf_tag('b') . __('Total') . ': ' . zb_CashBigValueFormat($totalSumm) . wf_tag('b', true);
  4880. } else {
  4881. $result .= $this->messages->getStyledMessage(__('Nothing found'), 'info');
  4882. }
  4883. } else {
  4884. $result .= $this->messages->getStyledMessage(__('Nothing to show'), 'warning');
  4885. }
  4886. }
  4887. return ($result);
  4888. }
  4889. /**
  4890. * Renders returns list container
  4891. *
  4892. * @return string
  4893. */
  4894. public function renderReturnsReport() {
  4895. $result = '';
  4896. $columns = array('Date', 'Outcoming operation', 'Warehouse storage', 'Category', 'Warehouse item type', 'Count', 'Price', 'Admin', 'Notes');
  4897. $opts = '"order": [[ 0, "desc" ]]';
  4898. $ajUrl = self::URL_ME . '&' . self::URL_REPORTS . '&returns=true&ajreturnslist=true';
  4899. $result .= wf_JqDtLoader($columns, $ajUrl, false, __('Outcoming operations'), 50, $opts);
  4900. return ($result);
  4901. }
  4902. /**
  4903. * Renders returned operations list
  4904. *
  4905. * @return void
  4906. */
  4907. public function ajReturnsList() {
  4908. $json = new wf_JqDtHelper();
  4909. $this->loadReturns();
  4910. if (!empty($this->allReturns)) {
  4911. foreach ($this->allReturns as $io => $each) {
  4912. $itemtypeId = $each['itemtypeid'];
  4913. $itemtypeName = $this->allItemTypeNames[$itemtypeId];
  4914. $itemCategory = $this->allCategories[$this->allItemTypes[$itemtypeId]['categoryid']];
  4915. $itemtypeUnit = $this->allItemTypes[$itemtypeId]['unit'];
  4916. $outOpLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&showoutid=' . $each['outid'], $each['outid']);
  4917. $data[] = $each['date'];
  4918. $data[] = $outOpLink;
  4919. $data[] = $this->allStorages[$each['storageid']];
  4920. $data[] = $itemCategory;
  4921. $itemHistLink = wf_Link(self::URL_ME . '&' . self::URL_VIEWERS . '&itemhistory=' . $itemtypeId, $itemtypeName);
  4922. $data[] = $itemHistLink;
  4923. $data[] = $each['count'] . ' ' . __($itemtypeUnit);
  4924. $data[] = $each['price'];
  4925. $data[] = $each['admin'];
  4926. $data[] = $each['note'];
  4927. $json->addRow($data);
  4928. unset($data);
  4929. }
  4930. }
  4931. $json->getJson();
  4932. }
  4933. /**
  4934. * Returns array of all existing item types
  4935. *
  4936. * @return array
  4937. */
  4938. public function getAllItemTypes() {
  4939. $result = array();
  4940. if (!empty($this->allItemTypes)) {
  4941. $result = $this->allItemTypes;
  4942. }
  4943. return ($result);
  4944. }
  4945. /**
  4946. * Returns array of all existing item type categories
  4947. *
  4948. * @return array
  4949. */
  4950. public function getAllItemCategories() {
  4951. $result = array();
  4952. if (!empty($this->allCategories)) {
  4953. $result = $this->allCategories;
  4954. }
  4955. return ($result);
  4956. }
  4957. /**
  4958. * Returns all available income operations
  4959. *
  4960. * @return array
  4961. */
  4962. public function getAllIncomes() {
  4963. return ($this->allIncoming);
  4964. }
  4965. /**
  4966. * Returns all available outcome operations
  4967. *
  4968. * @return array
  4969. */
  4970. public function getAllOutcomes() {
  4971. return ($this->allOutcoming);
  4972. }
  4973. }