api.warehouse.php 229 KB

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