MInventory.Class.php 249 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296
  1. <?php
  2. /**
  3. * 库存管理Model
  4. * Created by PhpStorm.
  5. * User: 小威
  6. * Date: 2019/11/12
  7. * Time: 10:00
  8. */
  9. namespace JinDouYun\Model\Stock;
  10. use Mall\Framework\Core\ErrorCode;
  11. use Mall\Framework\Core\StatusCode;
  12. use Mall\Framework\Core\ResultWrapper;
  13. use JinDouYun\Cache\GoodsBasicRelevant;
  14. use JinDouYun\Cache\InventoryCache;
  15. use JinDouYun\Cache\OverviewCache;
  16. use JinDouYun\Controller\Common\Logger;
  17. use JinDouYun\Model\MBaseModel;
  18. use JinDouYun\Model\Common\MCommon;
  19. use JinDouYun\Model\GoodsManage\MSku;
  20. use JinDouYun\Model\GoodsManage\MGoodsBasic;
  21. use JinDouYun\Model\Goods\MGoods;
  22. use JinDouYun\Model\System\MBasicSetup;
  23. use JinDouYun\Model\Message\MMessage;
  24. use JinDouYun\Model\Enterprise\MEnterprise;
  25. use JinDouYun\Model\Order\MOrder;
  26. use JinDouYun\Model\Purchase\MSupplier;
  27. use JinDouYun\Model\Shop\MShop;
  28. use JinDouYun\Model\Merchant\MMerchantSettlement;
  29. use JinDouYun\Model\Price\MCustomerPriceAdjustment;
  30. use JinDouYun\Dao\Stock\DInventory;
  31. use JinDouYun\Dao\Stock\DInventoryWarehouse;
  32. use Jindouyun\Dao\Stock\DInventoryArea;
  33. use JinDouYun\Dao\Stock\DLockingShop;
  34. use JinDouYun\Dao\Stock\DInventoryDetails;
  35. use JinDouYun\Dao\Stock\DInventoryLocking;
  36. use JinDouYun\Dao\Stock\DInventoryOutDetails;
  37. use JinDouYun\Dao\Stock\DInventoryBatch;
  38. use JinDouYun\Dao\GoodsManage\DGoodsBasic;
  39. class MInventory extends MBaseModel
  40. {
  41. private $objDInventory;
  42. private $objDInventoryWarehouse;
  43. private $objDLockingShop;
  44. private $objDInventoryDetails;
  45. private $objDInventoryLocking;
  46. private $objDInventoryOutDetails;
  47. private $enterpriseId;
  48. private $onLineUserCenterId;
  49. private $objDInventoryBatch;
  50. private $objOverviewCache;
  51. private $objInventoryCache;
  52. /**
  53. * @var bool 是否更新缓存
  54. */
  55. public $updateCache = false;
  56. public function __construct($enterpriseId, $userCenterId)
  57. {
  58. $this->enterpriseId = $enterpriseId;
  59. $this->onLineUserCenterId = $userCenterId;
  60. $this->objDInventory = new DInventory('stock');
  61. $this->objDInventoryWarehouse = new DInventoryWarehouse('stock');
  62. $this->objDLockingShop = new DLockingShop('stock');
  63. $this->objDInventoryDetails = new DInventoryDetails('stock');
  64. $this->objDInventoryLocking = new DInventoryLocking('stock');
  65. $this->objDInventoryOutDetails = new DInventoryOutDetails('stock');
  66. $this->objDInventoryBatch = new DInventoryBatch('stock');
  67. $this->objOverviewCache = new OverviewCache();
  68. $this->objInventoryCache = new InventoryCache($this->enterpriseId, $this->onLineUserCenterId);
  69. $this->objDInventory->setTable( 'qianniao_inventory_' . $enterpriseId);
  70. $this->objDInventoryWarehouse->setTable( 'qianniao_inventory_warehouse_' . $enterpriseId);
  71. $this->objDLockingShop->setTable( 'qianniao_locking_shop_' . $enterpriseId);
  72. $this->objDInventoryDetails->setSearchIndex('inventory_details_search')->setType('inventory_details');
  73. $this->objDInventoryBatch->setSearchIndex('inventory_batch_search')->setType('inventory_batch');
  74. }
  75. /**
  76. * 库存流水按照仓库+季度分表
  77. * @param $enterpriseId //公司id
  78. * @param $warehouseId //仓库id
  79. * @param $tableName
  80. * @param int $createTime
  81. * @param bool $isReturnTableName //是否返回表名
  82. * @return string
  83. * @throws Exception
  84. */
  85. public function setDetailsTable($enterpriseId, $warehouseId, $tableName = false, $createTime = 0, $isReturnTableName = false)
  86. {
  87. if($tableName == false || empty($tableName)){
  88. $tableName = 'qianniao_inventory_details';
  89. }
  90. if(!$createTime){
  91. $createTime = time();
  92. }
  93. $tableName = $tableName . '_' . $enterpriseId . '_' . $warehouseId . '_' . substr(date('Y', $createTime), -2) . ceil(date('m', $createTime) / 3);
  94. if($isReturnTableName) return $tableName;
  95. $this->objDInventoryDetails->setTable($tableName);
  96. }
  97. public function setDetailsTableTerm($createTime = 0)
  98. {
  99. if(!$createTime) $createTime = time();
  100. return substr(date('Y', $createTime), -2) . ceil(date('m', $createTime) / 3);
  101. }
  102. /**
  103. * 库存批次按照企业商铺分表
  104. * @param $enterpriseId //公司id
  105. * @param $warehouseId //仓库id
  106. * @param $tableName
  107. * @throws Exception
  108. */
  109. public function setBatchTable($enterpriseId, $warehouseId, $tableName = false)
  110. {
  111. if(empty($tableName) || $tableName == false){
  112. $tableName = 'qianniao_inventory_batch';
  113. }
  114. $tableName = $tableName . '_' . $enterpriseId . '_' . $warehouseId;
  115. $this->objDInventoryBatch->setTable($tableName);
  116. }
  117. /**
  118. * 锁定记录按照季度分表
  119. * @param int $enterpriseId //公司id
  120. * @param string $tableName // false 默认
  121. * @param string $time
  122. * @throws Exception
  123. */
  124. public function setLockingTable($enterpriseId = 0, $tableName = '', $time = '')
  125. {
  126. if (!$enterpriseId) {
  127. $enterpriseId = $this->enterpriseId;
  128. }
  129. if (empty($tableName) || $tableName == false) {
  130. $tableName = 'qianniao_inventory_locking';
  131. }
  132. if(!$time){
  133. $time = time();
  134. }
  135. $tableName = $tableName . '_' . $enterpriseId . '_' . substr(date('Y', $time), -2) . ceil(date('m', $time) / 3);
  136. $this->objDInventoryLocking->setTable($tableName);
  137. }
  138. /***
  139. * 移动加权计算成本算法
  140. * @param $selectMaterielData array 当前仓库库存数据
  141. * @param $md5Key string md5值
  142. * @param $params array 单据数据
  143. * @param $value array 当前处理的单据明细数据
  144. * @return array
  145. */
  146. private function averageCostPrice($selectMaterielData, $md5Key, $params, $value)
  147. {
  148. //移动加权:(剩余库存数量 * 当前加权成本价 + 本次入库数量 * 本次入库单价) / (剩余库存数量 + 本次入库数量) = 加权成本价
  149. // 判断是否存在库存
  150. if (isset($selectMaterielData[$md5Key])) {
  151. //修改库存
  152. $id = $selectMaterielData[$md5Key]['id'];
  153. //当前库存数量
  154. $nowInventoryNum = max($selectMaterielData[$md5Key]['inventoryNum'],0);
  155. //当前成本
  156. $nowCostPrise = $selectMaterielData[$md5Key]['costPrice'];
  157. //当前总价
  158. $nowTotal = bcmul($nowInventoryNum, $nowCostPrise, 4);
  159. //入库数量
  160. $inInventoryNum = $value['num'];
  161. //入库成本
  162. $inCostPrice = $value['unitPrice'];
  163. //入库总价
  164. $inTotal = $value['totalPrice'];
  165. //均价成本
  166. $costPrice = bcdiv(bcadd($nowTotal, $inTotal, 4), bcadd($nowInventoryNum, $inInventoryNum, 4), 4);
  167. //库存数量
  168. $inventoryNum = bcadd($selectMaterielData[$md5Key]['inventoryNum'], $value['num'], 8);
  169. $merchantId = $selectMaterielData[$md5Key]['merchantId'];
  170. $otherNum = bcadd($selectMaterielData[$md5Key]['otherNum'], $value['otherNum'], 8);
  171. $createTime = $selectMaterielData[$md5Key]['createTime'];
  172. $sort = $selectMaterielData[$md5Key]['sort'];
  173. } else {
  174. //新增库存
  175. $id = null;
  176. //当前库存数量
  177. $nowInventoryNum = 0;
  178. //当前成本
  179. $nowCostPrise = 0;
  180. //当前总价
  181. $nowTotal = 0;
  182. //入库数量
  183. $inInventoryNum = $value['num'];
  184. //入库成本
  185. $inCostPrice = $value['unitPrice'];
  186. //入库总价
  187. $inTotal = $value['totalPrice'];
  188. //均价成本
  189. $costPrice = $inCostPrice;
  190. //库存数量
  191. $inventoryNum = $value['num'];
  192. $merchantId = getArrayItem($params, 'merchantId', 0);
  193. $otherNum = $value['otherNum'];
  194. $sort = 0;
  195. $createTime = time();
  196. }
  197. $updateInventoryData = [
  198. 'id' => $id,
  199. 'merchantId' => $merchantId,
  200. 'inventoryNum' => $inventoryNum, // 累加之后库存
  201. 'otherNum' => $otherNum,
  202. 'costPrice' => $costPrice, // 移动加权平均单价
  203. 'materielId' => $value['materielId'],
  204. 'materielCode' => $value['materielCode'],
  205. 'warehouseId' => $params['warehouseId'],
  206. 'skuId' => $value['inventorySkuId'],
  207. 'sort' => $sort,
  208. 'createTime' => $createTime,
  209. 'updateTime' => time(),
  210. ];
  211. return $updateInventoryData;
  212. }
  213. /**
  214. * 需要计算成本的入库方式
  215. * @param $params array 单据数据
  216. * @param $inventoreMaster array 物料主库存数据
  217. * @param $selectMaterielData array 物料仓库库存数据
  218. * @param $source int 单据来源
  219. * @param $costType
  220. * @return ResultWrapper
  221. */
  222. public function calculateCostPrice($params, $inventoryMaster, $selectMaterielData, $source, $costType)
  223. {
  224. /**
  225. * 成本价 = (采购单价 * 采购数量 + (剩余库存数 + 锁定库存数) * 成本价) / (采购数量 + 剩余库存数 + 锁定库存数)
  226. * 移动加权平均单价= (本次收入前结存商品金额+本次收入商品金额)/(本次收入前结存商品数量+本次收入商品数量 )
  227. */
  228. $updateInventoryMaster = []; // 更新的主库存数据
  229. $updateWarehouseInventory = [];//更新的仓库库存数据
  230. $addInventoryDetails = []; // 新增的库存流水数据
  231. $addBatchData = []; // 新增批次数据git
  232. $inventorySkuIds = [];
  233. foreach ($params['Details'] as $key => $value) {
  234. //组成md5Key
  235. $md5Key = md5($params['warehouseId'] .'+'. $value['inventorySkuId']);
  236. // 主库存数据
  237. if( !isset($updateInventoryMaster[$value['inventorySkuId']]) ){
  238. $updateInventoryMaster[$value['inventorySkuId']] = [
  239. 'id' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['id'] : null,
  240. 'merchantId' => $params['merchantId'],
  241. 'materielId' => $value['materielId'],
  242. 'materielCode' => $value['materielCode'],
  243. 'inventoryNum' => isset($inventoryMaster[$value['inventorySkuId']]) ? bcadd($inventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num']) : $value['num'],
  244. 'otherNum' => isset($inventoryMaster[$value['inventorySkuId']]) ? bcadd($inventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum']) : $value['otherNum'],
  245. 'lockInventory' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['lockInventory'] : 0,
  246. 'skuId' => $value['inventorySkuId'],
  247. 'costPrice' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['costPrice'] : 0,
  248. 'updateTime' => time(),
  249. 'createTime' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['createTime'] : time(),
  250. ];
  251. }else{ // 相同skuid 不同批次的进行合并操作
  252. $updateInventoryMaster[$value['inventorySkuId']]['inventoryNum'] = bcadd($updateInventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num']);
  253. $updateInventoryMaster[$value['inventorySkuId']]['otherNum'] = bcadd($updateInventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum']);
  254. }
  255. // 每个仓库库存数据 (按照移动加权计算成本)
  256. if( isset($updateWarehouseInventory[$md5Key]) ) {
  257. $selectMaterielData[$md5Key] = $updateWarehouseInventory[$md5Key];
  258. }
  259. $updateWarehouseInventory[$md5Key] = self::averageCostPrice($selectMaterielData, $md5Key, $params, $value);
  260. // 主仓库成本 = 各个仓库成本之和
  261. $updateInventoryMaster[$value['inventorySkuId']]['costPrice'] = bcadd($updateInventoryMaster[$value['inventorySkuId']]['costPrice'], $value['totalPrice'], 4);
  262. // 生成入库批次号 有生产日期的用生产日期作为批次号,没有的用系统默认生产的
  263. if( isset($value['productionData']) && !empty($value['productionData']) ){
  264. $batchNo = date('Ymd', $value['productionData']);
  265. }else{
  266. $batchNo = createOrderSn(StatusCode::$source['manage'], StatusCode::$orderType['batch'], $this->enterpriseId);
  267. }
  268. //流水入库批次数据
  269. $batch = json_encode([['batch' => $batchNo, 'num' => $value['num'], 'batchCost' => $value['unitPrice']]]);
  270. //流水数据
  271. $addInventoryDetails[] = [
  272. 'warehouseId' => $params['warehouseId'],
  273. 'merchantId' => getArrayItem($params, 'merchantId', 0),
  274. 'materielId' => $value['materielId'],
  275. 'materielCode' => $value['materielCode'],
  276. 'materielName' => $value['materielName'],
  277. 'originId' => $params['originId'],
  278. 'originNo' => $params['originNo'],
  279. 'sourceNo' => $value['linkNo'],
  280. 'source' => $source,
  281. 'operatorId' => $params['auditId'],
  282. 'operatorName' => $params['auditName'],
  283. 'skuId' => $value['inventorySkuId'],
  284. 'unitName' => $value['inventoryUnitName'],
  285. 'skuName' => $value['skuName'],
  286. 'inventoryNum' => $value['num'],
  287. 'otherNum' => $value['otherNum'],
  288. 'areaId' => $value['areaId'], //库区id
  289. 'areaName' => $value['areaName'], //库区名称
  290. 'areaCode' => $value['areaCode'], //库区编码
  291. 'storageLocationId' => $value['storageLocationId'],//库位id
  292. 'storageLocationName' => $value['storageLocationName'],//库位名称
  293. 'storageLocationCode' => $value['storageLocationCode'],//库位编码
  294. 'inventoryChangeNum' => isset($selectMaterielData[$md5Key]) ? $updateWarehouseInventory[$md5Key]['inventoryNum'] : $value['num'], // 变动后仓库库存数量
  295. 'batch' => $batch, // 批次数据
  296. 'averageCost' => $updateWarehouseInventory[$md5Key]['costPrice'],
  297. 'actionType' => StatusCode::$standard,
  298. 'createTime' => time(),
  299. 'updateTime' => time(),
  300. 'costType' => $costType,
  301. ];
  302. //入库批次数据
  303. $addBatchData[] = [
  304. 'merchantId' => $params['merchantId'],
  305. 'originId' => $params['originId'],
  306. 'originNo' => $params['originNo'],
  307. 'warehouseId' => $params['warehouseId'],
  308. 'materielId' => $value['materielId'],
  309. 'materielCode' => $value['materielCode'],
  310. 'sourceNo' => $value['linkNo'],
  311. 'skuId' => $value['inventorySkuId'],
  312. 'batchNo' => $batchNo,
  313. 'num' => $value['num'],
  314. 'otherNum' => $value['otherNum'],
  315. 'areaId' => $value['areaId'], //库区id
  316. 'areaName' => $value['areaName'], //库区名称
  317. 'areaCode' => $value['areaCode'], //库区编码
  318. 'storageLocationId' => $value['storageLocationId'],//库位id
  319. 'storageLocationName' => $value['storageLocationName'],//库位名称
  320. 'storageLocationCode' => $value['storageLocationCode'],//库位编码
  321. 'averageCost' => $updateWarehouseInventory[$md5Key]['costPrice'],
  322. 'batchCost' => $value['unitPrice'],
  323. 'productionData' => $value['productionData'],//生产日期
  324. 'shelfLife' => getArrayItem($value, 'shelfLife', 0),//保质期
  325. 'batchStatus' => StatusCode::$standard,
  326. 'createTime' => time(),
  327. 'updateTime' => time(),
  328. ];
  329. }
  330. return ResultWrapper::success([
  331. 'updateInventoryData' => array_values($updateInventoryMaster),
  332. 'updateWarehouseInventoryData' => array_values($updateWarehouseInventory),
  333. 'addInventoryDetails' => $addInventoryDetails,
  334. 'addBatchData' => $addBatchData,
  335. ]);
  336. }
  337. /**
  338. * 调拨入库方式
  339. * @param $params array 单据数据
  340. * @param $selectMaterielData array 单据中物料已有库存数据
  341. * @param $source int 单据来源
  342. * @param $costType
  343. * @return ResultWrapper
  344. * @throws Exception
  345. */
  346. public function allocateIn($params, $inventoryMaster, $selectMaterielData, $source, $costType)
  347. {
  348. $updateInventoryMaster = []; // 更新的主库存数据
  349. $updateWarehouseInventory = []; // 更新的仓库库存数据
  350. $addInventoryDetails = []; // 新增得库存流水数据
  351. $updateBatchData = []; // 修改批次数据
  352. $addBatchData = []; // 新增批次数据
  353. // 提取所有单据编号
  354. $allsourceNo = [];
  355. $allSkuIds = [];
  356. foreach ($params['Details'] as $key => $value) {
  357. $allsourceNo[] = $value['linkNo'];
  358. $allSkuIds[] = $value['inventorySkuId'];
  359. }
  360. //切换库存流水表
  361. //要查询调拨出库的流水信息 需要知道调拨出库单的审核时间 = 入库单的创建时间 所以这里用入库单的创建时间
  362. $tableName = 'qianniao_inventory_details_' . $this->enterpriseId . '_' . $params['outWarehouseId'] . '_' . substr(date('Y', $params['createTime']), -2) . ceil(date('m', $params['createTime']) / 3);
  363. $this->objDInventoryDetails->setTable($tableName);
  364. // 查询出库单对应的出库批次
  365. $condition = [
  366. 'warehouseId' => $params['outWarehouseId'],
  367. 'originId' => $params['originId'],
  368. 'skuId' => $allSkuIds,
  369. 'actionType' => StatusCode::$delete,
  370. ];
  371. $dbResult = $this->objDInventoryDetails->select($condition, 'materielName,skuId,sourceNo,inventoryNum,batch,originId');
  372. if ($dbResult === false) {
  373. $this->objDInventoryDetails->rollBack();
  374. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  375. }
  376. if (empty($dbResult)) {
  377. return ResultWrapper::fail('当前这批物料没有出库记录', ErrorCode::$notAllowAccess);
  378. }
  379. $outBatchData = [];
  380. $outAllBatchNos = [];
  381. foreach ($dbResult as $key => $value) {
  382. $md5Key = md5($value['originId'] . $value['skuId']);
  383. $valueBatch = json_decode($value['batch'], true);
  384. $outBatchData[$md5Key] = $valueBatch;
  385. foreach ($valueBatch as $k => $v) {
  386. $outAllBatchNos[] = $v['batch'];
  387. }
  388. }
  389. // 在入库仓库查询批次数据
  390. $dbResult = $this->objDInventoryBatch->select(['batchNo' => $outAllBatchNos], 'batchNo,id,originId,num,skuId,averageCost,batchCost');
  391. if ($dbResult === false) {
  392. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  393. }
  394. $batchData = [];
  395. if (!empty($dbResult)) {
  396. foreach ($dbResult as $key => $value) {
  397. $batchData[$value['batchNo']] = $value;
  398. }
  399. }
  400. // 提取出来所有的物料id
  401. $inventorySkuIds = array_column($params['Details'],'inventorySkuId');
  402. // 查询当前这批物料在出库仓库的库存数
  403. $InventoryInfos = $this->objDInventoryWarehouse->select(['skuId' => $inventorySkuIds, 'warehouseId' => $params['outWarehouseId']]);
  404. if ($InventoryInfos === false) {
  405. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  406. }
  407. // 格式化当前查询出的库存数据
  408. $selectMaterielOutData = [];
  409. foreach ($InventoryInfos as $key => $value) {
  410. $selectMaterielOutData[md5($value['warehouseId'] .'+'. $value['skuId'])] = $value;
  411. }
  412. foreach ($params['Details'] as $key => $value) {
  413. // 判断在出库仓库中是否有库存记录
  414. $outMd5Key = md5($params['outWarehouseId'] .'+'. $value['inventorySkuId']);
  415. if (!isset($selectMaterielOutData[$outMd5Key])) {
  416. return ResultWrapper::fail('物料id:' . $value['materielId'] . ' skuId: '.$value['inventorySkuId'].' 在仓库id' . $params['outWarehouseId'] . '中没有库存记录!', ErrorCode::$notAllowAccess);
  417. }
  418. // 判断在入库仓库中是否有记录
  419. $inMd5Key = md5($params['warehouseId'] .'+'. $value['inventorySkuId']);
  420. //仓库数据
  421. $updateWarehouseInventory[] = self::averageCostPrice($selectMaterielData, $inMd5Key, $params, $value);
  422. // 生成入库批次号
  423. $batchMd5Key = md5($params['originId'] . $value['inventorySkuId']);
  424. if (!isset($outBatchData[$batchMd5Key])) {
  425. return ResultWrapper::fail('物料id:' . $value['materielId'] . ' skuId: '.$value['inventorySkuId'].' 在仓库id' . $params['warehouseId'] . '中未出库过!', ErrorCode::$notAllowAccess);
  426. }
  427. //修改主库存数据
  428. $updateInventoryMaster[] = [
  429. 'id' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['id'] : null,
  430. 'merchantId' => isset($inventoryMaster[$value['inventorySkuId']]['merchantId']) ? $inventoryMaster[$value['inventorySkuId']]['merchantId'] : 0,
  431. 'materielId' => $value['materielId'],
  432. 'materielCode' => $value['materielCode'],
  433. 'inventoryNum' => isset($inventoryMaster[$value['inventorySkuId']]) ? bcadd($inventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num']) : $value['num'],
  434. 'otherNum' => isset($inventoryMaster[$value['inventorySkuId']]) ? bcadd($inventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum']) : $value['otherNum'],
  435. 'lockInventory' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['lockInventory'] : 0,
  436. 'skuId' => $value['inventorySkuId'],
  437. 'costPrice' => bcadd($inventoryMaster[$value['inventorySkuId']]['costPrice'],bcmul($updateWarehouseInventory[$key]['costPrice'], $value['num'], 4),4) , //仓库总成本 = 当前总成本 + 调拨入库总成本
  438. 'updateTime' => time(),
  439. 'createTime' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['createTime'] : time(),
  440. ];
  441. //流水数据
  442. $addInventoryDetails[] = [
  443. 'merchantId' => isset($selectMaterielData[$inMd5Key]['inventoryNum']) ? $selectMaterielData[$inMd5Key]['inventoryNum'] : 0,
  444. 'warehouseId' => $params['warehouseId'],
  445. 'materielId' => $value['materielId'],
  446. 'materielCode' => $value['materielCode'],
  447. 'materielName' => $value['materielName'],
  448. 'sourceNo' => $params['no'],
  449. 'source' => $source,
  450. 'originId' => $params['originId'],
  451. 'originNo' => $params['originNo'],
  452. 'operatorId' => $params['auditId'],
  453. 'operatorName' => $params['auditName'],
  454. 'skuId' => $value['inventorySkuId'],
  455. 'unitName' => $value['inventoryUnitName'],
  456. 'skuName' => $value['skuName'],
  457. 'inventoryNum' => $value['num'],
  458. 'otherNum' => $value['otherNum'],
  459. 'areaId' => $value['areaId'], //库区id
  460. 'areaName' => $value['areaName'], //库区名称
  461. 'areaCode' => $value['areaCode'], //库区编码
  462. 'storageLocationId' => $value['storageLocationId'],//库位id
  463. 'storageLocationName' => $value['storageLocationName'],//库位名称
  464. 'storageLocationCode' => $value['storageLocationCode'],//库位编码
  465. 'inventoryChangeNum' => isset($updateWarehouseInventory[$key]['id']) ? bcadd($selectMaterielData[$inMd5Key]['inventoryNum'], $value['num'], 8) : $value['num'], // 变动后库存数量
  466. 'averageCost' => $updateWarehouseInventory[$key]['costPrice'],
  467. 'batch' => json_encode($outBatchData[$batchMd5Key]), // 批次数据
  468. 'actionType' => StatusCode::$standard,
  469. 'createTime' => time(),
  470. 'updateTime' => time(),
  471. 'costType' => $costType,
  472. ];
  473. // 判断当前出库批次在入库批次是否存在
  474. foreach ($outBatchData[$batchMd5Key] as $batchValue) {
  475. if (isset($batchData[$batchValue['batch']])) {
  476. //存在 累加
  477. $updateBatchData[] = [
  478. 'id' => $batchData[$batchValue['batch']]['id'],
  479. 'num' => bcadd($batchData[$batchValue['batch']]['num'], $value['num'], 8),
  480. 'otherNum' => bcadd($batchData[$batchValue['batch']]['otherNum'], $value['otherNum'], 8),
  481. 'areaId' => $value['areaId'], //库区id
  482. 'areaName' => $value['areaName'], //库区名称
  483. 'areaCode' => $value['areaCode'], //库区编码
  484. 'storageLocationId' => $value['storageLocationId'],//库位id
  485. 'storageLocationName' => $value['storageLocationName'],//库位名称
  486. 'storageLocationCode' => $value['storageLocationCode'],//库位编码
  487. 'averageCost' => $updateWarehouseInventory[$key]['costPrice'],
  488. 'updateTime' => time(),
  489. ];
  490. } else {
  491. //不存在 新增
  492. $addBatchData[] = [
  493. 'merchantId' => $params['merchantId'],
  494. 'originId' => $params['originId'],
  495. 'originNo' => $params['originNo'],
  496. 'warehouseId' => $params['warehouseId'],
  497. 'materielId' => $value['materielId'],
  498. 'materielCode' => $value['materielCode'],
  499. 'sourceNo' => $value['linkNo'],
  500. 'skuId' => $value['inventorySkuId'],
  501. 'batchNo' => $batchValue['batch'],
  502. 'num' => $value['num'],
  503. 'otherNum' => $value['otherNum'],
  504. 'areaId' => $value['areaId'], //库区id
  505. 'areaName' => $value['areaName'], //库区名称
  506. 'areaCode' => $value['areaCode'], //库区编码
  507. 'storageLocationId' => $value['storageLocationId'],//库位id
  508. 'storageLocationName' => $value['storageLocationName'],//库位名称
  509. 'storageLocationCode' => $value['storageLocationCode'],//库位编码
  510. 'averageCost' => $value['unitPrice'],
  511. 'batchCost' => $value['unitPrice'],
  512. 'productionData' => isset($value['productionData']) ? $value['productionData'] : 0,
  513. 'shelfLife' => $value['shelfLife'],
  514. 'batchStatus' => StatusCode::$standard,
  515. 'createTime' => time(),
  516. 'updateTime' => time(),
  517. ];
  518. }
  519. }
  520. }
  521. return ResultWrapper::success([
  522. 'updateInventoryData' => $updateInventoryMaster,
  523. 'updateWarehouseInventoryData' => $updateWarehouseInventory,
  524. 'addInventoryDetails' => $addInventoryDetails,
  525. 'updateBatchData' => $updateBatchData,
  526. 'addBatchData' => $addBatchData,
  527. ]);
  528. }
  529. /**
  530. * 原路返回入库方式
  531. * @param $params array 单据数据
  532. * @param $selectMaterielData array 单据中物料已有库存数据
  533. * @param $source int 单据来源
  534. * @param $costType
  535. * @return ResultWrapper
  536. * @throws \Exception
  537. */
  538. public function goBack($params, $inventoryMaster, $selectMaterielData, $source, $costType)
  539. {
  540. $updateInventoryMaster = []; // 更新的主库存数据
  541. $updateWarehouseInventory = []; // 更新的仓库库存数据
  542. $addInventoryDetails = []; // 新增得库存流水数据
  543. $updateBatchData = []; // 修改批次数据
  544. // 提取所有单据编号
  545. $allsourceNo = [];
  546. $allSkuIds = [];
  547. foreach ($params['Details'] as $key => $value) {
  548. $allsourceNo[] = $value['linkNo'];
  549. $allSkuIds[] = $value['inventorySkuId'];
  550. }
  551. //销售退货需要查询 销售出库时生成的流水单据 故按照该销售订单的出库单审核时间 计算表名
  552. if($source == StatusCode::$orderType['saleReturnIn']){
  553. $objMInventoryOut = new MInventoryOut($this->enterpriseId, $this->onLineUserCenterId);
  554. $selectInventoryOutWhere = [
  555. 'originId' => $params['originId'],
  556. 'deleteStatus' => StatusCode::$standard,
  557. 'auditStatus' => StatusCode::$auditStatus['auditPass'],
  558. ];
  559. $modelResult = $objMInventoryOut->getInventoryOutData($selectInventoryOutWhere);
  560. if(!$modelResult->isSuccess()){
  561. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  562. }
  563. $result = $modelResult->getData();
  564. $inventoryOutData = array_shift($result);
  565. if(empty($inventoryOutData)){
  566. return ResultWrapper::fail($params['originId'].'出库单据查询失败', ErrorCode::$paramError);
  567. }
  568. //计算流水表表名
  569. self::setDetailsTable($this->enterpriseId, $params['warehouseId'], false, $inventoryOutData['auditTime']);
  570. }
  571. // 查询出库单对应的出库批次
  572. $condition = [
  573. 'warehouseId' => $params['warehouseId'],
  574. 'originId' => $params['originId'],
  575. 'skuId' => $allSkuIds,
  576. 'actionType' => StatusCode::$delete,
  577. ];
  578. $dbResult = $this->objDInventoryDetails->select($condition, 'materielName,skuId,sourceNo,inventoryNum,batch,originId');
  579. if ($dbResult === false) {
  580. $this->objDInventoryDetails->rollBack();
  581. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  582. }
  583. if (empty($dbResult)) {
  584. return ResultWrapper::fail('当前这批物料没有出库记录', ErrorCode::$notAllowAccess);
  585. }
  586. //格式化批次数据
  587. $outBatchData = [];
  588. foreach ($dbResult as $key => $value) {
  589. $md5Key = md5($value['originId'] .'+'. $value['skuId']);
  590. $outBatchData[$md5Key] = json_decode($value['batch'], true);
  591. }
  592. foreach ($params['Details'] as $key => $value) {
  593. $md5Key = md5($params['warehouseId'] .'+'. $value['inventorySkuId']);
  594. //判断仓库库存是否存在
  595. if (!isset($selectMaterielData[$md5Key])) {
  596. return ResultWrapper::fail('物料id:' . $value['materielId'] . ' skuId: '.$value['inventorySkuId'].' 在仓库id' . $params['warehouseId'] . '中没有库存!', ErrorCode::$notAllowAccess);
  597. }
  598. //修改主库存
  599. $updateInventoryMaster[] = [
  600. 'id' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['id'] : null,
  601. 'merchantId' => $params['merchantId'],
  602. 'materielId' => $value['materielId'],
  603. 'materielCode' => $value['materielCode'],
  604. 'inventoryNum' => isset($inventoryMaster[$value['inventorySkuId']]) ? bcadd($inventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num'],8) : $value['num'],
  605. 'otherNum' => isset($inventoryMaster[$value['inventorySkuId']]) ? bcadd($inventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum'], 8) : $value['otherNum'],
  606. 'lockInventory' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['lockInventory'] : 0,
  607. 'skuId' => $value['inventorySkuId'],
  608. 'costPrice' => bcadd($inventoryMaster[$value['inventorySkuId']]['costPrice'], bcmul($selectMaterielData[$md5Key]['costPrice'], $value['num']), 4), // 总成本 = 当前总成本 + 退货总成本
  609. 'updateTime' => time(),
  610. 'createTime' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['createTime'] : time(),
  611. ];
  612. //修改仓库库存
  613. $updateWarehouseInventory[] = [
  614. 'id' => $selectMaterielData[$md5Key]['id'],
  615. 'merchantId' => $params['merchantId'],
  616. 'materielId' => $value['materielId'],
  617. 'warehouseId' => $params['warehouseId'],
  618. 'materielCode' => $value['materielCode'],
  619. 'inventoryNum' => bcadd($selectMaterielData[$md5Key]['inventoryNum'], $value['num'], 8), // 累加之后库存
  620. 'otherNum' => bcadd($selectMaterielData[$md5Key]['otherNum'], $value['otherNum'], 8), // 累加之后库存
  621. 'costPrice' => $selectMaterielData[$md5Key]['costPrice'],
  622. 'skuId' => $value['inventorySkuId'],
  623. 'sort' => $selectMaterielData[$md5Key]['sort'],
  624. 'updateTime' => time(),
  625. 'createTime' => $selectMaterielData[$md5Key]['createTime'],
  626. ];
  627. // 生成入库批次号
  628. $batchMd5Key = md5($params['originId'] .'+'.$value['inventorySkuId']);
  629. if (!isset($outBatchData[$batchMd5Key])) {
  630. return ResultWrapper::fail('物料id:' . $value['materielId'] . ' skuId: '.$value['inventorySkuId'].' 在仓库id' . $params['warehouseId'] . '中未出库过!', ErrorCode::$notAllowAccess);
  631. }
  632. // 入库批次 = 出库批次
  633. $addInventoryDetails[] = [
  634. 'merchantId' => $params['merchantId'],
  635. 'warehouseId' => $params['warehouseId'],
  636. 'materielId' => $value['materielId'],
  637. 'materielCode' => $value['materielCode'],
  638. 'materielName' => $value['materielName'],
  639. 'sourceNo' => $params['no'],
  640. 'source' => $source,
  641. 'originId' => $params['originId'],
  642. 'originNo' => $params['originNo'],
  643. 'operatorId' => $params['auditId'],
  644. 'operatorName' => $params['auditName'],
  645. 'skuId' => $value['inventorySkuId'],
  646. 'unitName' => $value['inventoryUnitName'],
  647. 'skuName' => $value['skuName'],
  648. 'inventoryNum' => $value['num'],
  649. 'otherNum' => $value['otherNum'],
  650. 'inventoryChangeNum' => bcadd($selectMaterielData[$md5Key]['inventoryNum'], $value['num'], 8), // 变动后库存数量
  651. 'averageCost' => $selectMaterielData[$md5Key]['costPrice'], // 出库批次成本价 = 当前库存成本价(最后批次成本价)
  652. 'batch' => json_encode($outBatchData[$batchMd5Key]), // 批次数据
  653. 'actionType' => StatusCode::$standard,
  654. 'createTime' => time(),
  655. 'updateTime' => time(),
  656. 'costType' => $selectMaterielData[$md5Key]['costPrice'],
  657. ];
  658. $updateBatchData[] = [
  659. 'batchData' => $outBatchData[$batchMd5Key],
  660. 'num' => $value['num'],
  661. 'otherNum' => $value['otherNum'],
  662. 'updateTime' => time(),
  663. ];
  664. }
  665. return ResultWrapper::success([
  666. 'updateInventoryData' => $updateInventoryMaster,
  667. 'updateWarehouseInventoryData' => $updateWarehouseInventory,
  668. 'addInventoryDetails' => $addInventoryDetails,
  669. 'updateBatchData' => $updateBatchData,
  670. ]);
  671. }
  672. /**
  673. * 销售出库回写出库成本
  674. * @param $data
  675. * @param $className
  676. */
  677. protected static function backOutCostPrise($data, $className)
  678. {
  679. file_put_contents('/www/wwwroot/logs/api.junhailan.com/66666666.log', date('Y-m-d H:i:s') . '出库成本回写数据' . var_export($data, true) . PHP_EOL, FILE_APPEND);
  680. $i = 1;
  681. do {
  682. $postData = [
  683. 'topicName' => 'MyJob',
  684. 'topicClass' => "Jobs\Model\MTopic\Order\\".$className,
  685. 'topicMethon' => 'backOrderOutCostPrise',
  686. 'topicMethonParams' => [
  687. 'data' => $data
  688. ],
  689. ];
  690. $url = QIANNIAO_QUEUE . '/CAddJob/add';
  691. $result = request($url, $postData);
  692. $i++;
  693. } while ($result['httpcode'] != 200 && $i <= 3);
  694. }
  695. /**
  696. * 库存不足预警
  697. * @param $data
  698. * @param $className
  699. */
  700. protected static function inventoryNumWarning($data, $className)
  701. {
  702. $i = 1;
  703. do {
  704. $postData = [
  705. 'topicName' => 'MyJob',
  706. 'topicClass' => "Jobs\Model\MTopic\Message\\".$className,
  707. 'topicMethon' => 'inventoryNumWarning',
  708. 'topicMethonParams' => [
  709. 'data' => $data
  710. ],
  711. ];
  712. $url = QIANNIAO_QUEUE . '/CAddJob/add';
  713. $result = request($url, $postData);
  714. $i++;
  715. } while ($result['httpcode'] != 200 && $i <= 3);
  716. }
  717. /**
  718. * 走锁定得出库方式
  719. * @param $params array 单据数据
  720. * @param $selectMaterielData array 单据中物料已有库存数据
  721. * @param $shopLock array 商铺锁定数据
  722. * @param $source int 单据来源
  723. * @param $costType
  724. * @param $outBatchStrategy
  725. * @return ResultWrapper
  726. * @throws Exception
  727. * @throws \Exception
  728. */
  729. public function outByLocking($params, $inventoryMaster, $selectMaterielData, $shopLock, $source = 0, $costType, $outBatchStrategy)
  730. {
  731. // 查询订单创建时间,计算锁定表分表
  732. if(empty($params)){
  733. return ResultWrapper::fail('出库单记录为空', ErrorCode::$contentNotExists);
  734. }
  735. //计算锁定记录表表名
  736. //查询订单创建时间
  737. $objMOrder = new MOrder($this->onLineUserCenterId, $this->enterpriseId);
  738. $result = $objMOrder->getOrderCreateTime($params['originId']);
  739. if(!$result->isSuccess()){
  740. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  741. }
  742. $orderIndexData = $result->getData();
  743. if(!isset($orderIndexData['createTime'])){
  744. return ResultWrapper::fail($params['originId'].'的订单创建时间为空', ErrorCode::$notAllowAccess);
  745. }
  746. // 切换锁定表
  747. self::setLockingTable($this->enterpriseId, false, $orderIndexData['createTime']);
  748. //查询锁定记录
  749. $lockingData = [];
  750. $dbResult = $this->objDInventoryLocking->select(['shopId' => $params['shopId'], 'originId' => $params['originId'], 'source' => StatusCode::$orderType['saleOrder'], 'lockStatus' => StatusCode::$delete]);
  751. if($dbResult === false){
  752. return ResultWrapper::fail($this->objDInventoryLocking->error(), ErrorCode::$dberror);
  753. }
  754. foreach($dbResult as $value){
  755. $lockingData[$value['skuId']] = $value;
  756. }
  757. $updateInventoryMaster = []; // 更新的主库存数据
  758. $updateWarehouseInventory = [];//更新的仓库库存数据
  759. $updateShopLock = [];//更新的店铺锁定数据
  760. $addInventoryDetails = []; // 新增得库存流水数据
  761. $downMaterielData = [];//下架商品数据
  762. $updateLockDetailsData = [];//单据锁定记录数据
  763. foreach ($params['Details'] as $key => $value) {
  764. $md5Key = md5($params['warehouseId'] .'+'.$value['inventorySkuId']);
  765. //判断锁定数量
  766. if(!isset($lockingData[$value['inventorySkuId']]['lockingNum'])){
  767. return ResultWrapper::fail($value['materielName'].'未查询到锁定数据', ErrorCode::$paramError);
  768. }
  769. if($value['num'] > $lockingData[$value['inventorySkuId']]['lockingNum']){
  770. return ResultWrapper::fail($value['materielName'].'出库数量不能大于锁定数量', ErrorCode::$paramError);
  771. }
  772. //主库存修改数据
  773. $updateInventoryMaster[] = [
  774. 'id' => $inventoryMaster[$value['inventorySkuId']]['id'],
  775. 'merchantId' => $inventoryMaster[$value['inventorySkuId']]['merchantId'],
  776. 'materielId' => $inventoryMaster[$value['inventorySkuId']]['materielId'],
  777. 'materielCode' => $inventoryMaster[$value['inventorySkuId']]['materielCode'],
  778. 'inventoryNum' => $inventoryMaster[$value['inventorySkuId']]['inventoryNum'],
  779. 'otherNum' => bcsub($inventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum'], 8),
  780. 'lockInventory' => bcsub($inventoryMaster[$value['inventorySkuId']]['lockInventory'], $value['num'], 8),
  781. 'costPrice' => bcsub($inventoryMaster[$value['inventorySkuId']]['costPrice'],bcmul($selectMaterielData[$md5Key]['costPrice'], $value['num'], 4), 4), //出库后总成本 = 仓库总成本 - 出库总成本
  782. 'skuId' => $value['inventorySkuId'],
  783. 'updateTime' => time(),
  784. 'createTime' => $inventoryMaster[$value['inventorySkuId']]['createTime'],
  785. ];
  786. //仓库库存修改数据
  787. $updateWarehouseInventory[] = [
  788. 'id' => isset($selectMaterielData[$md5Key]) ? $selectMaterielData[$md5Key]['id'] : null,
  789. 'merchantId' => isset($selectMaterielData[$md5Key]['merchantId']) ? $selectMaterielData[$md5Key]['merchantId'] : $inventoryMaster[$value['inventorySkuId']]['merchantId'],
  790. 'inventoryNum' => isset($selectMaterielData[$md5Key]) ? bcsub($selectMaterielData[$md5Key]['inventoryNum'], $value['num']) : bcsub(0, $value['num']), //仓库库存=当前仓库库存-出库数量
  791. 'otherNum' => isset($selectMaterielData[$md5Key]) ? bcsub($selectMaterielData[$md5Key]['otherNum'], $value['otherNum']) : bcsub(0, $value['otherNum']), //仓库库存=当前仓库库存-出库数量
  792. 'costPrice' => isset($selectMaterielData[$md5Key]) ? $selectMaterielData[$md5Key]['costPrice'] : 0, // 移动加权平均单价
  793. 'materielId' => $value['materielId'],
  794. 'materielCode' => $value['materielCode'],
  795. 'warehouseId' => $params['warehouseId'],
  796. 'skuId' => $value['inventorySkuId'],
  797. ];
  798. //店铺锁定数据修改
  799. $updateShopLock[] = [
  800. 'id' => $shopLock[$value['inventorySkuId']]['id'],
  801. 'shopId' => $shopLock[$value['inventorySkuId']]['shopId'],
  802. 'materielId' => $shopLock[$value['inventorySkuId']]['materielId'],
  803. 'materielCode' => $shopLock[$value['inventorySkuId']]['materielCode'],
  804. 'skuId' => $shopLock[$value['inventorySkuId']]['skuId'],
  805. 'lockInventory' => bcsub($shopLock[$value['inventorySkuId']]['lockInventory'], $value['num'], 8),
  806. 'updateTime' => time(),
  807. 'createTime' => $shopLock[$value['inventorySkuId']]['createTime'],
  808. ];
  809. //删除店铺锁定缓存
  810. $this->objInventoryCache->delShopLock($value['inventorySkuId'], $params['shopId']);
  811. //单据锁定记录修改
  812. $updateLockDetailsData[] = [
  813. 'id' => $lockingData[$value['inventorySkuId']]['id'],
  814. 'shopId' => $lockingData[$value['inventorySkuId']]['shopId'],
  815. 'materielId' => $value['materielId'],
  816. 'operatorId' => $lockingData[$value['inventorySkuId']]['operatorId'],
  817. 'operatorName' => $lockingData[$value['inventorySkuId']]['operatorName'],
  818. 'materielCode' => $lockingData[$value['inventorySkuId']]['materielCode'],
  819. 'originId' => $lockingData[$value['inventorySkuId']]['originId'],
  820. 'originNo' => $lockingData[$value['inventorySkuId']]['originNo'],
  821. 'source' => $lockingData[$value['inventorySkuId']]['source'],
  822. 'sourceNo' => $lockingData[$value['inventorySkuId']]['sourceNo'],
  823. 'lockingNum' => bcsub($lockingData[$value['inventorySkuId']]['lockingNum'], $value['num'], 8),
  824. 'unlockNum' => bcadd($lockingData[$value['inventorySkuId']]['unlockNum'], $value['num'], 8),
  825. 'totalNum' => $lockingData[$value['inventorySkuId']]['totalNum'],
  826. 'skuId' => $lockingData[$value['inventorySkuId']]['skuId'],
  827. 'lockStatus' => bcmul($lockingData[$value['inventorySkuId']]['lockingNum'], $value['num'], 8) > 0 ? 4 : 5,
  828. 'unlockTime' => bcmul($lockingData[$value['inventorySkuId']]['lockingNum'], $value['num'], 8) > 0 ? $lockingData[$value['inventorySkuId']]['unlockTime'] : time(),
  829. 'createTime' => $lockingData[$value['inventorySkuId']]['createTime'],
  830. 'updateTime' => time(),
  831. 'extend' => $lockingData[$value['inventorySkuId']]['extend'],
  832. ];
  833. //库存为空 下架商品
  834. if ($inventoryMaster[$value['inventorySkuId']]['inventoryNum'] <= 0) {
  835. $downMaterielData[] = [
  836. 'shopId' => $params['shopId'],
  837. 'materielId' => $value['materielId']
  838. ];
  839. }
  840. // 出库策略
  841. $order = 'createTime asc';
  842. if ($outBatchStrategy == 2) {
  843. $order = 'createTime desc';
  844. }
  845. // 查询当前物料该属性的可用批次记录
  846. $sql = ' warehouseId = ' . $params['warehouseId'] . ' and skuId = ' . $value['inventorySkuId'] . ' and num > 0';
  847. $inventoryBatchData = $this->objDInventoryBatch->select($sql, 'id,batchNo,num,otherNum,skuId,batchCost', $order);
  848. if ($inventoryBatchData === false) {
  849. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  850. }
  851. $outNum = $value['num'];// 出库数量
  852. $batch = []; // 当前出库用到的所有批次数据
  853. $updateBatchData = []; // 要修改的批次数据
  854. //判断是否有可用批次数据
  855. if(!empty($inventoryBatchData)){
  856. //有可用批次
  857. // 从多个批次中扣除批次可用库存
  858. foreach ($inventoryBatchData as $k => $v) {
  859. // 出库数量 = 当前批次数量
  860. if (bccomp($value['num'], $v['num'], 8) == 0) {
  861. $batch[] = ['batch' => $v['batchNo'], 'num' => $value['num'], 'batchCost' => $v['batchCost']];
  862. $updateBatchData[] = [
  863. 'id' => $v['id'],
  864. 'num' => 0,
  865. 'otherNum' => 0,
  866. 'updateTime' => time(),
  867. ];
  868. break;
  869. }
  870. // 出库数量 < 当前批次数量
  871. if (bccomp($value['num'], $v['num'], 8) == -1) {
  872. $batch[] = ['batch' => $v['batchNo'], 'num' => $value['num'], 'batchCost' => $v['batchCost']];
  873. $updateBatchData[] = [
  874. 'id' => $v['id'],
  875. 'num' => bcsub($v['num'], $value['num'], 8),
  876. 'otherNum' => bcsub($v['otherNum'], $value['otherNum'], 8),
  877. 'updateTime' => time(),
  878. ];
  879. break;
  880. }
  881. // 出库数量 > 当前批次数量
  882. if (bccomp($value['num'], $v['num'], 8) == 1) {
  883. $batch[] = ['batch' => $v['batchNo'], 'num' => $v['num'], 'batchCost' => $v['batchCost']];
  884. $updateBatchData[] = [
  885. 'id' => $v['id'],
  886. 'num' => '0.00000000',
  887. 'otherNum' => '0.00000000',
  888. 'updateTime' => time(),
  889. ];
  890. $value['num'] = bcsub($value['num'], $v['num'], 8);
  891. $value['otherNum'] = bcsub($value['otherNum'], $v['otherNum'], 8);
  892. }
  893. }
  894. }
  895. $batch = json_encode($batch);
  896. $addInventoryDetails[] = [
  897. 'merchantId' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['merchantId'] : 0,
  898. 'warehouseId' => $params['warehouseId'],
  899. 'materielId' => $value['materielId'],
  900. 'materielCode' => $value['materielCode'],
  901. 'materielName' => $value['materielName'],
  902. 'sourceNo' => $params['no'],
  903. 'source' => $params['type'],
  904. 'originId' => $params['originId'],
  905. 'originNo' => $params['originNo'],
  906. 'operatorId' => $params['auditId'],
  907. 'operatorName' => $params['auditName'],
  908. 'skuId' => $value['inventorySkuId'],
  909. 'unitName' => $value['unitName'],
  910. 'skuName' => $value['skuName'],
  911. 'inventoryNum' => $outNum,
  912. 'otherNum' => $value['otherNum'],
  913. 'inventoryChangeNum' => isset($selectMaterielData[$md5Key]) ? bcsub($selectMaterielData[$md5Key]['inventoryNum'], $outNum) : bcsub(0, $outNum),
  914. 'batch' => $batch,
  915. 'averageCost' => isset($selectMaterielData[$md5Key]) ? $selectMaterielData[$md5Key]['costPrice'] : 0, // 出库批次成本价 = 当前库存成本价(最后批次成本价)
  916. 'areaId' => $value['areaId'],
  917. 'areaName' => $value['areaName'],
  918. 'areaCode' => $value['areaCode'],
  919. 'storageLocationId' => $value['storageLocationId'],
  920. 'storageLocationName' => $value['storageLocationName'],
  921. 'storageLocationCode' => $value['storageLocationCode'],
  922. 'actionType' => StatusCode::$delete,
  923. 'createTime' => time(),
  924. 'updateTime' => time(),
  925. 'costType' => $costType,
  926. ];
  927. }
  928. return ResultWrapper::success([
  929. 'updateInventoryData' => $updateInventoryMaster,
  930. 'updateWarehouseInventoryData' => $updateWarehouseInventory,
  931. 'updateShopLock' => $updateShopLock,
  932. 'addInventoryDetails' => $addInventoryDetails,
  933. 'updateBatchData' => $updateBatchData,
  934. 'downMaterielData' => $downMaterielData,
  935. 'updateLockDetailsData' => $updateLockDetailsData
  936. ]);
  937. }
  938. /**
  939. * 直接减仓库库存的出库
  940. * @param $params array 单据数据
  941. * @param $inventoryMaster array 主库存数据
  942. * @param $selectMaterielData array 仓库库存
  943. * @param $source int 单据来源
  944. * @param $costType
  945. * @param $outBatchStrategy
  946. * @return ResultWrapper
  947. * @throws Exception
  948. * @throws \Exception
  949. */
  950. public function outByWarehouse($params, $inventoryMaster, $selectMaterielData, $source = 0, $costType, $outBatchStrategy)
  951. {
  952. $updateInventoryMaster = []; // 更新的主库存数据
  953. $updateWarehouseInventory = [];//更新的仓库库存数据
  954. $addInventoryDetails = []; // 新增得库存流水数据
  955. $downMaterielData = [];//下架商品数据
  956. foreach ($params['Details'] as $key => $value) {
  957. $md5Key = md5($params['warehouseId'] .'+'.$value['inventorySkuId']);
  958. //判断数量
  959. if($value['num'] > $selectMaterielData[$md5Key]['inventoryNum']){
  960. return ResultWrapper::fail($value['materielName'].'仓库库存不足', ErrorCode::$paramError);
  961. }
  962. //主库存修改数据
  963. $updateInventoryMaster[] = [
  964. 'id' => $inventoryMaster[$value['inventorySkuId']]['id'],
  965. 'merchantId' => $inventoryMaster[$value['inventorySkuId']]['merchantId'],
  966. 'materielId' => $inventoryMaster[$value['inventorySkuId']]['materielId'],
  967. 'materielCode' => $inventoryMaster[$value['inventorySkuId']]['materielCode'],
  968. 'inventoryNum' => bcsub($inventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num'], 8),
  969. 'otherNum' => bcsub($inventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum'], 8),
  970. 'lockInventory' => $inventoryMaster[$value['inventorySkuId']]['lockInventory'],
  971. 'costPrice' => bcsub($inventoryMaster[$value['inventorySkuId']]['costPrice'],bcmul($selectMaterielData[$md5Key]['costPrice'], $value['num']),4), // 仓库总成本 = 当前成本 - 调拨出库总成本
  972. 'skuId' => $value['inventorySkuId'],
  973. 'updateTime' => time(),
  974. 'createTime' => $inventoryMaster[$value['inventorySkuId']]['createTime'],
  975. ];
  976. //仓库库存修改数据
  977. $updateWarehouseInventory[] = [
  978. 'id' => $selectMaterielData[$md5Key]['id'],
  979. 'merchantId' => $selectMaterielData[$md5Key]['merchantId'],
  980. 'materielId' => $value['materielId'],
  981. 'warehouseId' => $params['warehouseId'],
  982. 'materielCode' => $value['materielCode'],
  983. 'inventoryNum' => bcsub($selectMaterielData[$md5Key]['inventoryNum'], $value['num']), //仓库库存=当前仓库库存-出库数量
  984. 'otherNum' => bcsub($selectMaterielData[$md5Key]['otherNum'], $value['otherNum']), //仓库库存=当前仓库库存-出库数量
  985. 'costPrice' => $selectMaterielData[$md5Key]['costPrice'], //移动加权平均单价
  986. 'skuId' => $value['inventorySkuId'],
  987. 'sort' => $selectMaterielData[$md5Key]['sort'],
  988. 'updateTime' => time(),
  989. 'createTime' => $selectMaterielData[$md5Key]['createTime'],
  990. ];
  991. //库存为空 下架商品
  992. if ($inventoryMaster[$value['inventorySkuId']]['inventoryNum'] <= 0) {
  993. $downMaterielData[] = [
  994. 'shopId' => $params['shopId'],
  995. 'materielId' => $value['materielId']
  996. ];
  997. }
  998. // 出库策略
  999. $order = 'createTime asc';
  1000. if ($outBatchStrategy == 2) {
  1001. $order = 'createTime desc';
  1002. }
  1003. // 查询当前物料该属性的可用批次记录
  1004. $sql = ' warehouseId = ' . $params['warehouseId'] . ' and skuId = ' . $value['inventorySkuId'] . ' and num > 0';
  1005. $inventoryBatchData = $this->objDInventoryBatch->select($sql, 'id,batchNo,num,otherNum,skuId,batchCost', $order);
  1006. if ($inventoryBatchData === false) {
  1007. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  1008. }
  1009. $outNum = $value['num'];// 出库数量
  1010. $batch = []; // 当前出库用到的所有批次数据
  1011. $updateBatchData = []; // 要修改的批次数据
  1012. //判断是否有可用批次数据
  1013. if(!empty($inventoryBatchData)){
  1014. //有可用批次
  1015. // 从多个批次中扣除批次可用库存
  1016. foreach ($inventoryBatchData as $k => $v) {
  1017. // 出库数量 = 当前批次数量
  1018. if (bccomp($value['num'], $v['num'], 8) == 0) {
  1019. $batch[] = ['batch' => $v['batchNo'], 'num' => $value['num'], 'batchCost' => $v['batchCost']];
  1020. $updateBatchData[] = [
  1021. 'id' => $v['id'],
  1022. 'num' => 0,
  1023. 'otherNum' => 0,
  1024. 'updateTime' => time(),
  1025. ];
  1026. break;
  1027. }
  1028. // 出库数量 < 当前批次数量
  1029. if (bccomp($value['num'], $v['num'], 8) == -1) {
  1030. $batch[] = ['batch' => $v['batchNo'], 'num' => $value['num'], 'batchCost' => $v['batchCost']];
  1031. $updateBatchData[] = [
  1032. 'id' => $v['id'],
  1033. 'num' => bcsub($v['num'], $value['num'], 8),
  1034. 'otherNum' => bcsub($v['otherNum'], $value['otherNum'], 8),
  1035. 'updateTime' => time(),
  1036. ];
  1037. break;
  1038. }
  1039. // 出库数量 > 当前批次数量
  1040. if (bccomp($value['num'], $v['num'], 8) == 1) {
  1041. $batch[] = ['batch' => $v['batchNo'], 'num' => $v['num'], 'batchCost' => $v['batchCost']];
  1042. $updateBatchData[] = [
  1043. 'id' => $v['id'],
  1044. 'num' => '0.00000000',
  1045. 'otherNum' => '0.00000000',
  1046. 'updateTime' => time(),
  1047. ];
  1048. $value['num'] = bcsub($value['num'], $v['num'], 8);
  1049. $value['otherNum'] = bcsub($value['otherNum'], $v['otherNum'], 8);
  1050. }
  1051. }
  1052. }
  1053. $batch = json_encode($batch);
  1054. $addInventoryDetails[] = [
  1055. 'merchantId' => $inventoryMaster[$value['inventorySkuId']]['merchantId'],
  1056. 'warehouseId' => $params['warehouseId'],
  1057. 'materielId' => $value['materielId'],
  1058. 'materielCode' => $value['materielCode'],
  1059. 'materielName' => $value['materielName'],
  1060. 'sourceNo' => $params['no'],
  1061. 'source' => $params['type'],
  1062. 'originId' => $params['originId'],
  1063. 'originNo' => $params['originNo'],
  1064. 'operatorId' => $params['auditId'],
  1065. 'operatorName' => $params['auditName'],
  1066. 'skuId' => $value['inventorySkuId'],
  1067. 'unitName' => $value['unitName'],
  1068. 'skuName' => $value['skuName'],
  1069. 'inventoryNum' => $outNum,
  1070. 'otherNum' => $value['otherNum'],
  1071. 'areaId' => $value['areaId'], //库区id
  1072. 'areaName' => $value['areaName'], //库区名称
  1073. 'areaCode' => $value['areaCode'], //库区编码
  1074. 'storageLocationId' => $value['storageLocationId'],//库位id
  1075. 'storageLocationName' => $value['storageLocationName'],//库位名称
  1076. 'storageLocationCode' => $value['storageLocationCode'],//库位编码
  1077. 'batch' => $batch,
  1078. 'averageCost' => $selectMaterielData[$md5Key]['costPrice'], // 出库批次成本价 = 当前库存成本价(最后批次成本价)
  1079. 'actionType' => StatusCode::$delete,
  1080. 'createTime' => time(),
  1081. 'updateTime' => time(),
  1082. 'costType' => $costType,
  1083. 'inventoryChangeNum' => bcsub($selectMaterielData[$md5Key]['inventoryNum'], $outNum),
  1084. ];
  1085. }
  1086. return ResultWrapper::success([
  1087. 'updateInventoryData' => $updateInventoryMaster,
  1088. 'updateWarehouseInventoryData' => $updateWarehouseInventory,
  1089. 'addInventoryDetails' => $addInventoryDetails,
  1090. 'updateBatchData' => $updateBatchData,
  1091. 'downMaterielData' => $downMaterielData,
  1092. ]);
  1093. }
  1094. /**
  1095. * 按照批次出库方式
  1096. * @param $params array 单据数据
  1097. * @param $selectMaterielData array 单据中物料已有库存数据
  1098. * @param $source int 单据来源
  1099. * @param $costType
  1100. * @param $outBatchStrategy
  1101. * @return ResultWrapper
  1102. */
  1103. public function outByBatch($params, $inventoryMaster, $selectMaterielData, $source, $costType, $outBatchStrategy)
  1104. {
  1105. $updateInventoryMaster = []; // 更新的主库存数据
  1106. $updateWarehouseInventory = []; // 更新的仓库库存数据
  1107. $addInventoryDetails = []; // 新增得库存流水数据
  1108. $downMaterielData = [];//下架商品数据
  1109. // 查询业务源头对应的所有物料批次信息
  1110. $condition = [
  1111. 'originId' => $params['originId'],
  1112. 'warehouseId' => $params['warehouseId'],
  1113. ];
  1114. $dbResult = $this->objDInventoryBatch->select($condition, 'id,materielId,skuId,batchNo,num,averageCost,batchCost');
  1115. if ($dbResult === false) {
  1116. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  1117. }
  1118. if (empty($dbResult)) {
  1119. return ResultWrapper::fail('这批出库数据的采购订单物料批次数据为空', ErrorCode::$notAllowAccess);
  1120. }
  1121. $batchData = [];
  1122. $batchTotal = [];
  1123. foreach ($dbResult as $value) {
  1124. $md5Key = md5($params['warehouseId'] .'+'. $value['skuId']);
  1125. $batchTotal[$md5Key] = isset($batchTotal[$md5Key]) ? bcadd($batchTotal[$md5Key], $value['num']) : $value['num'];
  1126. $batchData[$md5Key][] = $value;
  1127. }
  1128. unset($md5Key);
  1129. foreach ($params['Details'] as $key => $value) {
  1130. $md5Key = md5($params['warehouseId'] .'+'. $value['inventorySkuId']);
  1131. // 比较出库数量小于等于批次可用数量
  1132. if (bccomp($value['num'], $batchTotal[$md5Key], 8) == 1) {
  1133. return ResultWrapper::fail($value['materielCode'] . '物料出库数量大于当前批次可用数量', ErrorCode::$notAllowAccess);
  1134. }
  1135. //主库存修改数据
  1136. $updateInventoryMaster[] = [
  1137. 'id' => $inventoryMaster[$value['inventorySkuId']]['id'],
  1138. 'merchantId' => $inventoryMaster[$value['inventorySkuId']]['merchantId'],
  1139. 'materielId' => $inventoryMaster[$value['inventorySkuId']]['materielId'],
  1140. 'materielCode' => $inventoryMaster[$value['inventorySkuId']]['materielCode'],
  1141. 'inventoryNum' => bcsub($inventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num'], 8),
  1142. 'otherNum' => bcsub($inventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum'], 8),
  1143. 'lockInventory' => $inventoryMaster[$value['inventorySkuId']]['lockInventory'],
  1144. 'costPrice' => bcsub($inventoryMaster[$value['inventorySkuId']]['costPrice'], bcmul($selectMaterielData[$md5Key]['costPrice'],$value['num']), 4), // 仓库总成本 = 当前总成本 - 出库总成本
  1145. 'skuId' => $value['inventorySkuId'],
  1146. 'updateTime' => time(),
  1147. 'createTime' => $inventoryMaster[$value['inventorySkuId']]['createTime'],
  1148. ];
  1149. //仓库修改数据
  1150. $updateWarehouseInventory[] = [
  1151. 'id' => $selectMaterielData[$md5Key]['id'],
  1152. 'merchantId' => $selectMaterielData[$md5Key]['merchantId'],
  1153. 'materielId' => $value['materielId'],
  1154. 'warehouseId' => $params['warehouseId'],
  1155. 'materielCode' => $value['materielCode'],
  1156. 'inventoryNum' => bcsub($selectMaterielData[$md5Key]['inventoryNum'], $value['num'], 8), // 减掉之后库存
  1157. 'otherNum' => bcsub($selectMaterielData[$md5Key]['otherNum'], $value['otherNum'], 8), // 减掉之后库存
  1158. 'costPrice' => $selectMaterielData[$md5Key]['costPrice'], // 移动加权平均单价
  1159. 'skuId' => $value['inventorySkuId'],
  1160. 'sort' => $selectMaterielData[$md5Key]['sort'],
  1161. 'updateTime' => time(),
  1162. 'createTime' => $selectMaterielData[$md5Key]['createTime'],
  1163. ];
  1164. //商品库存为空 商品下架
  1165. if (bcsub($inventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num'], 8) <= 0) {
  1166. $downMaterielData[] = [
  1167. 'shopId' => $params['shopId'],
  1168. 'materielId' => $value['materielId'],
  1169. ];
  1170. }
  1171. $batch = [];
  1172. $outNum = $value['num'];
  1173. $outOtherNum = $value['otherNum'];
  1174. foreach($batchData[$md5Key] as $batchItem){
  1175. if($outNum <= 0){
  1176. break;
  1177. }
  1178. if($outNum > $batchItem['num']){
  1179. //出库数量大于该批次
  1180. $batch[] = [
  1181. 'batch' => $batchItem['batchNo'],
  1182. 'num' => $batchItem['num']
  1183. ];
  1184. $updateBatchData[] = [
  1185. 'id' => $batchItem['id'],
  1186. 'num' => 0,
  1187. 'otherNum' => bcsub($outOtherNum,$batchItem['otherNum']) < 0 ? 0 : bcsub($outOtherNum,$batchItem['otherNum']),//抄码商品会有问题 (目前统一根据正常单位更改)
  1188. 'updateTime' => time(),
  1189. ];
  1190. $outNum = bcsub($outNum,$batchItem['num']);
  1191. $outOtherNum = bcsub($outOtherNum,$batchItem['otherNum']) < 0 ? 0 : bcsub($outOtherNum,$batchItem['otherNum']);
  1192. }else{
  1193. //出库数量 小于等于 该批次
  1194. $batch[] = [
  1195. 'batch' => $batchItem['batchNo'],
  1196. 'num' => $outNum
  1197. ];
  1198. $updateBatchData[] = [
  1199. 'id' => $batchItem['id'],
  1200. 'num' => bcsub($batchItem['num'], $outNum, 8),
  1201. 'otherNum' => bcsub($batchItem['otherNum'], $outOtherNum, 8),//抄码商品会有问题 (目前统一根据正常单位更改)
  1202. 'updateTime' => time(),
  1203. ];
  1204. $outNum = 0;
  1205. }
  1206. }
  1207. $batch = json_encode($batch);
  1208. $addInventoryDetails[] = [
  1209. 'merchantId' => $inventoryMaster[$value['inventorySkuId']]['merchantId'],
  1210. 'warehouseId' => $params['warehouseId'],
  1211. 'materielId' => $value['materielId'],
  1212. 'materielCode' => $value['materielCode'],
  1213. 'materielName' => $value['materielName'],
  1214. 'sourceNo' => $params['no'],
  1215. 'originId' => $params['originId'],
  1216. 'originNo' => $params['originNo'],
  1217. 'source' => $params['type'],
  1218. 'operatorId' => $params['auditId'],
  1219. 'operatorName' => $params['auditName'],
  1220. 'skuId' => $value['inventorySkuId'],
  1221. 'unitName' => $value['inventoryUnitName'],
  1222. 'skuName' => $value['skuName'],
  1223. 'inventoryNum' => $value['num'],
  1224. 'otherNum' => $value['otherNum'],
  1225. 'inventoryChangeNum' => bcsub($selectMaterielData[$md5Key]['inventoryNum'], $value['num'], 8), // 变动后库存数量
  1226. 'batch' => $batch,
  1227. 'averageCost' => $selectMaterielData[$md5Key]['costPrice'], // 出库批次成本价 = 当前库存成本价(最后批次成本价)
  1228. 'actionType' => StatusCode::$delete,
  1229. 'createTime' => time(),
  1230. 'updateTime' => time(),
  1231. 'costType' => $costType,
  1232. ];
  1233. }
  1234. return ResultWrapper::success([
  1235. 'updateInventoryData' => $updateInventoryMaster,
  1236. 'updateWarehouseInventoryData' => $updateWarehouseInventory,
  1237. 'addInventoryDetails' => $addInventoryDetails,
  1238. 'updateBatchData' => $updateBatchData,
  1239. 'downMaterielData' => $downMaterielData,
  1240. ]);
  1241. }
  1242. /**
  1243. * 库存方法
  1244. * @param $params array 单据数据
  1245. * @param $costType int 成本计算方式
  1246. * @param $outBatchStrategy int 出库策略 默认1先进先出 2.后进先出
  1247. * @return ResultWrapper
  1248. * @throws Exception
  1249. */
  1250. public function updateInventory($params, $costType, $outBatchStrategy = 1)
  1251. {
  1252. $objMInventoryArea = new MInventoryArea($this->enterpriseId,$this->onLineUserCenterId);
  1253. // 切换流水详情表
  1254. self::setDetailsTable($this->enterpriseId, $params['warehouseId']);
  1255. // 切换批次表
  1256. self::setBatchTable($this->enterpriseId, $params['warehouseId']);
  1257. // 入库操作单据来源
  1258. $inOrderCode = [
  1259. StatusCode::$orderType['purchaseIn'],// 3 采购入库
  1260. StatusCode::$orderType['saleReturnIn'],// 15 销售退货入库
  1261. StatusCode::$orderType['allocateIn'],// 12 调拨入库
  1262. StatusCode::$orderType['merchantPurchaseIn'],// 30 商户入库
  1263. ];
  1264. // 出库操作单据来源
  1265. $outOrderCode = [
  1266. StatusCode::$orderType['purchaseReturnOut'],// 14 采购退货出库
  1267. StatusCode::$orderType['saleOut'],// 5 销售出库
  1268. StatusCode::$orderType['allocateOut']// 8调拨出库
  1269. ];
  1270. if (!isset($params['Details']) || !isset($params['warehouseId'])) {
  1271. return ResultWrapper::fail('要操作的物料数据或仓库id为空', ErrorCode::$paramError);
  1272. }
  1273. // 提取出来所有的物料id
  1274. $materielIds = array_column($params['Details'],'materielId');
  1275. if (empty($materielIds)) {
  1276. return ResultWrapper::fail('要操作的物料id为空', ErrorCode::$paramError);
  1277. }
  1278. // sku单位换算,统一转换为主单位库存数
  1279. $modelResult = self::conversionSku($params);
  1280. if(!$modelResult->isSuccess()){
  1281. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  1282. }
  1283. $params = $modelResult->getData();
  1284. unset($modelResult);
  1285. $inventorySkuIds = array_column($params['Details'], 'inventorySkuId');
  1286. if(empty($inventorySkuIds)) return ResultWrapper::fail('库存skuId查询失败', ErrorCode::$paramError);
  1287. //查询物料的总库存
  1288. $inventoryResult = $this->objDInventory->select(['skuId' => $inventorySkuIds]);
  1289. if ($inventoryResult === false) {
  1290. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  1291. }
  1292. $inventoryMaster = [];
  1293. foreach ($inventoryResult as $key => $value) {
  1294. $inventoryMaster[$value['skuId']] = $value;
  1295. }
  1296. //查询物料在对应仓库的库存
  1297. $InventoryInfos = $this->objDInventoryWarehouse->select(['skuId' => $inventorySkuIds, 'warehouseId' => $params['warehouseId']]);
  1298. if ($InventoryInfos === false) {
  1299. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  1300. }
  1301. $selectMaterielData = [];
  1302. foreach ($InventoryInfos as $key => $value) {
  1303. //仓库与主单位md5生成Key
  1304. $selectMaterielData[md5($value['warehouseId'] .'+'. $value['skuId'])] = $value;
  1305. }
  1306. // 所有入库操作
  1307. if (in_array($params['type'], $inOrderCode)) {
  1308. if($params['type'] == StatusCode::$orderType['purchaseIn'] || $params['type'] == StatusCode::$orderType['allocateIn']){
  1309. //商品入库设置保质期
  1310. $modelResult = self::setInventoryShelfLife($params,$materielIds);
  1311. if(!$modelResult->isSuccess()){
  1312. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  1313. }
  1314. $params = $modelResult->getData();
  1315. unset($modelResult);
  1316. }
  1317. switch ($params['type']) {
  1318. case StatusCode::$orderType['purchaseIn']:// 采购入库
  1319. $result = self::calculateCostPrice($params, $inventoryMaster, $selectMaterielData, $params['type'], $costType);
  1320. break;
  1321. case StatusCode::$orderType['merchantPurchaseIn']:// 商户入库
  1322. $result = self::calculateCostPrice($params, $inventoryMaster, $selectMaterielData, $params['type'], $costType);
  1323. break;
  1324. case StatusCode::$orderType['allocateIn']: // 调拨入库
  1325. $result = self::allocateIn($params, $inventoryMaster,$selectMaterielData, $params['type'], $costType);
  1326. break;
  1327. default://销售退货入库
  1328. $result = self::goBack($params, $inventoryMaster, $selectMaterielData, $params['type'], $costType);
  1329. }
  1330. //组装库存库位数据
  1331. foreach ($params['Details'] as $DetailsKey =>$DetailsValue){
  1332. if(!empty($DetailsValue['areaId']) && $DetailsValue['storageLocationId'] ){
  1333. $areaDate = [
  1334. 'warehouseId'=> $params['warehouseId'],
  1335. 'materielId' => $DetailsValue['materielId'],
  1336. 'merchantId'=> $params['merchantId'],
  1337. 'areaId'=> $DetailsValue['areaId'],
  1338. 'areaName'=> $DetailsValue['areaName'],
  1339. 'areaCode'=> $DetailsValue['areaCode'],
  1340. 'storageLocationId'=> $DetailsValue['storageLocationId'],
  1341. 'storageLocationName'=> $DetailsValue['storageLocationName'],
  1342. 'storageLocationCode'=> $DetailsValue['storageLocationCode'],
  1343. 'skuId'=> $DetailsValue['inventorySkuId'],
  1344. 'unitName'=> $DetailsValue['inventoryUnitName'],
  1345. 'skuName'=> $DetailsValue['skuName'],
  1346. 'type'=> StatusCode::$standard,
  1347. 'num'=> $DetailsValue['num'],
  1348. ];
  1349. $updateAreaResult = $objMInventoryArea->updateInventoryArea($areaDate);
  1350. if(!$updateAreaResult->isSuccess()){
  1351. return ResultWrapper::fail($updateAreaResult->getData(), $updateAreaResult->getErrorCode());
  1352. }
  1353. }
  1354. }
  1355. }
  1356. // 所有出库操作
  1357. if (in_array($params['type'], $outOrderCode)) {
  1358. switch ($params['type']) {
  1359. case StatusCode::$orderType['saleOut']: // 销售出库
  1360. //查询物料的店铺锁定数据
  1361. $dbResult = $this->objDLockingShop->select(['shopId' => $params['shopId'], 'skuId' => $inventorySkuIds]);
  1362. if($dbResult === false){
  1363. return ResultWrapper::fail($this->objDLockingShop->error(), ErrorCode::$dberror);
  1364. }
  1365. $shopLock = [];
  1366. foreach($dbResult as $value){
  1367. $shopLock[$value['skuId']] = $value;
  1368. }
  1369. unset($dbResult);
  1370. $result = self::outByLocking($params, $inventoryMaster, $selectMaterielData, $shopLock, $params['type'], $costType, $outBatchStrategy);
  1371. break;
  1372. case StatusCode::$orderType['allocateOut']: // 调拨出库
  1373. $result = self::outByWarehouse($params, $inventoryMaster, $selectMaterielData, $params['type'], $costType, $outBatchStrategy);
  1374. break;
  1375. default://采购退货出库
  1376. $result = self::outByBatch($params, $inventoryMaster, $selectMaterielData, $params['type'], $costType, $outBatchStrategy);
  1377. }
  1378. //组装库存库位数据
  1379. foreach ($params['Details'] as $DetailsKey =>$DetailsValue){
  1380. if(!empty($DetailsValue['areaId']) && $DetailsValue['storageLocationId'] ){
  1381. $areaDate = [
  1382. 'warehouseId'=> $params['warehouseId'],
  1383. 'materielId' => $DetailsValue['materielId'],
  1384. 'merchantId'=> $params['merchantId'],
  1385. 'areaId'=> $DetailsValue['areaId'],
  1386. 'areaName'=> $DetailsValue['areaName'],
  1387. 'areaCode'=> $DetailsValue['areaCode'],
  1388. 'storageLocationId'=> $DetailsValue['storageLocationId'],
  1389. 'storageLocationName'=> $DetailsValue['storageLocationName'],
  1390. 'storageLocationCode'=> $DetailsValue['storageLocationCode'],
  1391. 'skuId'=> $DetailsValue['inventorySkuId'],
  1392. 'unitName'=> $DetailsValue['inventoryUnitName'],
  1393. 'skuName'=> $DetailsValue['skuName'],
  1394. 'type'=> StatusCode::$delete,
  1395. 'num'=> $DetailsValue['num'],
  1396. ];
  1397. $updateAreaResult = $objMInventoryArea->updateInventoryArea($areaDate);
  1398. if(!$updateAreaResult->isSuccess()){
  1399. return ResultWrapper::fail($updateAreaResult->getData(), $updateAreaResult->getErrorCode());
  1400. }
  1401. }
  1402. }
  1403. }
  1404. if (!$result->isSuccess()) {
  1405. return ResultWrapper::fail($result->getData(), $result->getErrorCode());
  1406. }
  1407. $result = $result->getData();
  1408. $addInventoryDetails = $result['addInventoryDetails'];
  1409. $addBatchData = isset($result['addBatchData']) ? $result['addBatchData'] : [];
  1410. $updateBatchData = isset($result['updateBatchData']) ? $result['updateBatchData'] : [];
  1411. $updateInventoryData = $result['updateInventoryData'];//主库存
  1412. $updateWarehouseInventoryData = $result['updateWarehouseInventoryData'];//仓库库存
  1413. $updateShopLock = isset($result['updateShopLock']) ? $result['updateShopLock'] : [];
  1414. $downMaterielData = isset($result['downMaterielData']) ? $result['downMaterielData'] : [];
  1415. $updateLockDetailsData = isset($result['updateLockDetailsData']) ? $result['updateLockDetailsData'] : [];
  1416. $beginStatus = $this->objDInventory->beginTransaction();
  1417. //销售出库回写库存成本 / 生成商户结算单
  1418. if($params['type'] == StatusCode::$orderType['saleOut']) self::outInventoryCost($params, $addInventoryDetails, $costType);
  1419. //库存不足自动预警
  1420. self::inventoryNullMessage($addInventoryDetails);
  1421. //清除库存缓存
  1422. self::delCacheInventory($addInventoryDetails);
  1423. // 修改主库存数据
  1424. $dbResult = $this->objDInventory->replace($updateInventoryData, true);
  1425. if ($dbResult === false) {
  1426. $this->objDInventory->rollBack();
  1427. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  1428. }
  1429. //修改仓库库存数据
  1430. $dbResult = $this->objDInventoryWarehouse->replace($updateWarehouseInventoryData, true);
  1431. if ($dbResult === false) {
  1432. $this->objDInventory->rollBack();
  1433. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  1434. }
  1435. //修改商铺锁定数据
  1436. if(!empty($updateShopLock)){
  1437. $dbResult = $this->objDLockingShop->replace($updateShopLock, true);
  1438. if ($dbResult === false) {
  1439. $this->objDInventory->rollBack();
  1440. return ResultWrapper::fail($this->objDLockingShop->error(), ErrorCode::$dberror);
  1441. }
  1442. }
  1443. //修改锁定记录
  1444. if(!empty($updateLockDetailsData)){
  1445. $dbResult = $this->objDInventoryLocking->replace($updateLockDetailsData, true);
  1446. if ($dbResult === false) {
  1447. $this->objDInventory->rollBack();
  1448. return ResultWrapper::fail($this->objDInventoryLocking->error(), ErrorCode::$dberror);
  1449. }
  1450. }
  1451. // 修改库存流水表数据
  1452. unset($dbResult);
  1453. //流水表插入数据需要重置表名
  1454. self::setDetailsTable($this->enterpriseId, $params['warehouseId'], 'qianniao_inventory_details');
  1455. $dbResult = $this->objDInventoryDetails->insert($addInventoryDetails, true);
  1456. if ($dbResult === false) {
  1457. $this->objDInventory->rollBack();
  1458. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  1459. }
  1460. // 增加es数据
  1461. /*
  1462. $modelResult = self::addEsData($addInventoryDetails, $dbResult);
  1463. if (!$modelResult->isSuccess()) {
  1464. $this->objDInventory->rollBack();
  1465. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  1466. }*/
  1467. //下架商品
  1468. /* if (!empty($downMaterielData)) {
  1469. $modelResult = self::inventoryNullSetGoodsDown($downMaterielData);
  1470. if (!$modelResult->isSuccess()) {
  1471. $this->objDInventory->rollBack();
  1472. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  1473. }
  1474. }*/
  1475. // 新增库存批次数据
  1476. unset($dbResult);
  1477. if (isset($addBatchData) && !empty($addBatchData)) {
  1478. $dbResult = $this->objDInventoryBatch->insert($addBatchData, true);
  1479. if ($dbResult === false) {
  1480. $this->objDInventory->rollBack();
  1481. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  1482. }
  1483. //设置批次es数据
  1484. /*
  1485. $modelResult = self::setEsDataByBatch($addBatchData, $dbResult, true);
  1486. if (!$modelResult->isSuccess()) {
  1487. $this->objDInventory->rollBack();
  1488. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  1489. }
  1490. $esData = $modelResult->getData();
  1491. unset($modelResult);
  1492. //添加es
  1493. if(!empty($esData)){
  1494. foreach ($esData as $value) {
  1495. //创建es id
  1496. $esId = parent::setEsId($this->enterpriseId, 'inventoryBatchId', $value['id']);
  1497. $result = $this->objDInventoryBatch->addUpSearchIndexDocument($value, $esId);
  1498. $modelResult = parent::isResult($result);
  1499. if (!$modelResult->isSuccess()) {
  1500. $this->objDInventory->rollBack();
  1501. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  1502. }
  1503. }
  1504. }*/
  1505. }
  1506. // 修改批次数据
  1507. unset($dbResult);
  1508. if (isset($updateBatchData) && !empty($updateBatchData)) {
  1509. foreach ($updateBatchData as $key => $value) {
  1510. // 通过batchNo去修改
  1511. if (isset($value['batchData'])) {
  1512. foreach ($value['batchData'] as $k => $v) {
  1513. $sql = 'update ' . $this->objDInventoryBatch->get_Table() . ' set num = ' . $v['num'] . ' + num,updateTime = ' . time() . ' where batchNo = ' . $v['batch'];
  1514. $dbResult = $this->objDInventoryBatch->query($sql);
  1515. if ($dbResult === false) {
  1516. $this->objDInventory->rollBack();
  1517. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  1518. }
  1519. }
  1520. continue;
  1521. }
  1522. // 通过id去修改
  1523. $id = $value['id'];
  1524. unset($value['id']);
  1525. $dbResult = $this->objDInventoryBatch->update($value, $id);
  1526. if ($dbResult === false) {
  1527. $this->objDInventory->rollBack();
  1528. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  1529. }
  1530. }
  1531. }
  1532. $beginStatus && $this->objDInventory->commit();
  1533. return ResultWrapper::success('操作成功');
  1534. }
  1535. /**
  1536. * 商品入库设置保质期
  1537. * @param $params
  1538. * @param $materielIds
  1539. * @return ResultWrapper
  1540. * @throws Exception
  1541. */
  1542. public function setInventoryShelfLife($params, $materielIds)
  1543. {
  1544. // 查询每个物料id对应的保质期
  1545. $objMGoodsBasic = new MGoodsBasic($this->onLineUserCenterId, $this->enterpriseId);
  1546. $modelResult = $objMGoodsBasic->getGoodsDataByGoodsIds($materielIds);
  1547. if(!$modelResult->isSuccess()){
  1548. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  1549. }
  1550. $goodsData = $modelResult->getData();
  1551. unset($modelResult);
  1552. //商品参数加入保质期
  1553. foreach ($params['Details'] as $key => &$value) {
  1554. $value['shelfLife'] = null;
  1555. $value['specType'] = null;
  1556. if(isset($goodsData[$value['materielId']])){
  1557. $value['shelfLife'] = $goodsData[$value['materielId']]['expireTime'];
  1558. $value['specType'] = $goodsData[$value['materielId']]['specType'];
  1559. }
  1560. }
  1561. unset($value);
  1562. return ResultWrapper::success($params);
  1563. }
  1564. /**
  1565. * 清除库存缓存
  1566. * @param $addInventoryDetails
  1567. */
  1568. public function delCacheInventory($addInventoryDetails)
  1569. {
  1570. foreach($addInventoryDetails as $value){
  1571. //出库删除库存redis重置
  1572. $this->objInventoryCache->delCacheHash($value['skuId'], $value['warehouseId']);
  1573. }
  1574. }
  1575. /**
  1576. * 销售出库回写库存成本
  1577. * @param $params
  1578. * @param $addInventoryDetails
  1579. * @param $costType
  1580. */
  1581. public function outInventoryCost($params,$addInventoryDetails, $costType)
  1582. {
  1583. //拼接
  1584. $outBatchData['costType'] = $costType;//成本计算方式
  1585. $outBatchData['enterpriseId'] = $this->enterpriseId;
  1586. $outBatchData['userCenterId'] = $this->onLineUserCenterId;
  1587. $merchantParams = [];
  1588. foreach($addInventoryDetails as $value){
  1589. !isset($outBatchData['originId']) && $outBatchData['originId'] = $value['originId'];
  1590. $outBatchData['stock'][$value['skuId']]['batch'] = json_decode($value['batch'], true);
  1591. $outBatchData['stock'][$value['skuId']]['averageCost'] = $value['averageCost'];
  1592. $outBatchData['stock'][$value['skuId']]['inventoryNum'] = $value['inventoryNum'];
  1593. if($value['averageCost'] > 0){
  1594. $merchantParams[] = [
  1595. "orderId" => $value['originId'],
  1596. "orderNo" => $value['originNo'],
  1597. "goodsId" => $value['materielId'],
  1598. "goodsName" => $value['materielName'],
  1599. "goodsNum" => $value['inventoryNum'],
  1600. "goodsPrice" => $value['averageCost'],
  1601. "goodsMoney" => bcmul($value['averageCost'], $value['inventoryNum'],4),
  1602. "merchantId" => $value['merchantId'],
  1603. "outStockTime" => $value['createTime']
  1604. ];
  1605. }
  1606. }
  1607. $objMMerchantSettlement = new MMerchantSettlement($this->enterpriseId, $this->onLineUserCenterId);
  1608. $modelResult = $objMMerchantSettlement->addMerchantSettlement($merchantParams);
  1609. file_put_contents('/www/wwwroot/logs/api.junhailan.com/9999999.log', date('Y-m-d H:i:s') . '回调数据' . var_export($modelResult->getData(), true) . PHP_EOL, FILE_APPEND);
  1610. //如果是销售出库 需要把回写成本
  1611. if($params['type'] == StatusCode::$orderType['saleOut']){
  1612. self::backOutCostPrise($outBatchData, 'MOrder');
  1613. }
  1614. }
  1615. /**
  1616. * 设置es数据
  1617. * @param $params
  1618. * @param $ids
  1619. * @param bool $type //true:新增 默认false:修改
  1620. * @return ResultWrapper
  1621. * @throws \Exception
  1622. */
  1623. public function setEsDataByBatch($params, $ids, $type = false)
  1624. {
  1625. if (empty($params) || empty($ids)) return ResultWrapper::success($params);
  1626. $addData = [];
  1627. $formatData = parent::formatOrderMan($this->enterpriseId, $params);
  1628. foreach ($formatData as $key => $value) {
  1629. $batchData = [
  1630. 'id' => isset($ids[$key]) ? $ids[$key] : false,
  1631. 'enterpriseId' => $this->enterpriseId,
  1632. 'warehouseId' => isset($value['warehouseId']) ? $value['warehouseId'] : false,
  1633. 'batchNo' => isset($value['batchNo']) ? $value['batchNo'] : false,
  1634. 'originId' => isset($value['originId']) ? $value['originId'] : false,
  1635. 'originNo' => isset($value['originNo']) ? $value['originNo'] : false,
  1636. 'sourceNo' => isset($value['sourceNo']) ? $value['sourceNo'] : false,
  1637. 'materielId' => isset($value['materielId']) ? $value['materielId'] : false,
  1638. 'materielCode' => isset($value['materielCode']) ? $value['materielCode'] : false,
  1639. 'materielName' => isset($value['materielName']) ? $value['materielName'] : false,
  1640. 'skuId' => isset($value['skuId']) ? $value['skuId'] : false,
  1641. 'num' => isset($value['num']) ? $value['num'] : false,
  1642. 'averageCost' => isset($value['averageCost']) ? $value['averageCost'] : false,
  1643. 'batchCost' => isset($value['batchCost']) ? $value['batchCost'] : false,
  1644. 'productionData' => isset($value['productionData']) ? $value['productionData'] : false,
  1645. 'shelfLife' => isset($value['shelfLife']) ? $value['shelfLife'] : false,
  1646. 'batchStatus' => isset($value['batchStatus']) ? $value['batchStatus'] : false,
  1647. 'createTime' => isset($value['createTime']) ? $value['createTime'] : false,
  1648. 'updateTime' => isset($value['updateTime']) ? $value['updateTime'] : false,
  1649. ];
  1650. foreach ($batchData as $k => $v) {
  1651. if ($v === false) {
  1652. if ($type) {
  1653. return ResultWrapper::fail($k . '---ES字段未设置', ErrorCode::$paramError);
  1654. } else {
  1655. unset($batchData[$k]);
  1656. }
  1657. }
  1658. }
  1659. $addData[] = $batchData;
  1660. }
  1661. //创建es id
  1662. return ResultWrapper::success($addData);
  1663. }
  1664. /**
  1665. * 增加库存数量
  1666. */
  1667. public function updateIncInventoryNum($params, $costType = 1)
  1668. {
  1669. $warehouseId = $params['warehouseId'];
  1670. $skuData = $params['details'];
  1671. $updateInventoryMaster = []; // 更新的主库存数据
  1672. $updateWarehouseInventory = [];//更新的仓库库存数据
  1673. $addInventoryDetails = []; // 新增得库存流水数据
  1674. $addBatchData = []; // 新增批次数据
  1675. $updateStorageLocation =[]; // 更新库区库位库存表数据
  1676. $skuIds = [];
  1677. foreach($skuData as &$value){
  1678. $skuIds[] = $value['skuId'];
  1679. $value['inventorySkuId'] = $value['skuId'];
  1680. }
  1681. unset($value);
  1682. //查询主库存
  1683. $dbResult = $this->objDInventory->select(['skuId' => $skuIds]);
  1684. if($dbResult === false){
  1685. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  1686. }
  1687. $inventoryResult = $dbResult;
  1688. unset($dbResult);
  1689. if(empty($inventoryResult)){
  1690. return ResultWrapper::fail('未查询到库存数据', ErrorCode::$paramError);
  1691. }
  1692. $inventoryMaster = [];
  1693. foreach($inventoryResult as $value){
  1694. $inventoryMaster[$value['skuId']] = $value;
  1695. }
  1696. //查询仓库库存
  1697. $dbResult = $this->objDInventoryWarehouse->select(['warehouseId' => $warehouseId, 'skuId' => $skuIds]);
  1698. if($dbResult === false){
  1699. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  1700. }
  1701. $inventoryWarehouseResult = $dbResult;
  1702. unset($dbResult);
  1703. if(empty($inventoryWarehouseResult)){
  1704. return ResultWrapper::fail('未查询到仓库库存数据', ErrorCode::$paramError);
  1705. }
  1706. $inventoryWarehouse = [];
  1707. foreach($inventoryWarehouseResult as $value){
  1708. $inventoryWarehouse[$value['skuId']] = $value;
  1709. }
  1710. // 查询库区库位仓库表数据
  1711. $objDInventoryArea = new DInventoryArea();
  1712. $objDInventoryArea->set_Table('qianniao_inventory_area_'.$this->enterpriseId);
  1713. $condition = [
  1714. 'warehouseId'=>$params['warehouseId'],
  1715. 'merchantId' => getArrayItem($params, 'merchantId', 0),
  1716. 'skuId'=>$skuIds,
  1717. ];
  1718. $dbResult = $objDInventoryArea->select($condition);
  1719. if($dbResult === false){
  1720. return ResultWrapper::fail($objDInventoryArea->error(), ErrorCode::$dberror);
  1721. }
  1722. if(!empty($dbResult)){
  1723. // skuid维度映射库区库位库存数据
  1724. $inventorystorageLocation = [];
  1725. foreach($dbResult as $value){
  1726. $inventorystorageLocation[$value['skuId']][$value['storageLocationId']] = $value;
  1727. }
  1728. }
  1729. foreach ($skuData as $value) {
  1730. $skuId = $value['inventorySkuId'];
  1731. $num = $value['num'];
  1732. if(!isset($inventoryMaster[$skuId])){
  1733. return ResultWrapper::fail('skuId:'.$skuId.'未查询到库存', ErrorCode::$paramError);
  1734. }
  1735. if(!isset($inventoryWarehouse[$skuId])){
  1736. return ResultWrapper::fail('skuId:'.$skuId.'未查询到仓库库存', ErrorCode::$paramError);
  1737. }
  1738. //主库存修改数据
  1739. $updateInventoryMaster[] = [
  1740. 'id' => $inventoryMaster[$skuId]['id'],
  1741. 'materielId' => $inventoryMaster[$skuId]['materielId'],
  1742. 'materielCode' => $inventoryMaster[$skuId]['materielCode'],
  1743. 'inventoryNum' => bcadd($inventoryMaster[$skuId]['inventoryNum'], $num, 8),
  1744. 'otherNum' => $value['otherNum'],
  1745. 'lockInventory' => $inventoryMaster[$skuId]['lockInventory'],
  1746. 'costPrice' => $inventoryMaster[$skuId]['costPrice'],
  1747. 'skuId' => $skuId,
  1748. 'updateTime' => time(),
  1749. 'createTime' => $inventoryMaster[$skuId]['createTime'],
  1750. ];
  1751. //仓库库存修改数据
  1752. $updateWarehouseInventory[] = [
  1753. 'id' => $inventoryWarehouse[$skuId]['id'],
  1754. 'materielId' => $inventoryWarehouse[$skuId]['materielId'],
  1755. 'warehouseId' => $inventoryWarehouse[$skuId]['warehouseId'],
  1756. 'materielCode' => $inventoryWarehouse[$skuId]['materielCode'],
  1757. 'inventoryNum' => bcadd($inventoryWarehouse[$skuId]['inventoryNum'], $num), //仓库库存=当前仓库库存-出库数量
  1758. 'otherNum' => $value['otherNum'], //仓库库存=当前仓库库存-出库数量
  1759. 'costPrice' => $inventoryWarehouse[$skuId]['costPrice'], //移动加权平均单价
  1760. 'skuId' => $inventoryWarehouse[$skuId]['skuId'],
  1761. 'sort' => $inventoryWarehouse[$skuId]['sort'],
  1762. 'updateTime' => time(),
  1763. 'createTime' => $inventoryWarehouse[$skuId]['createTime'],
  1764. ];
  1765. // 库区库位库存修改数据
  1766. if( isset($value['storageLocationId']) && !empty($value['storageLocationId']) ){
  1767. $updateStorageLocation[] = [
  1768. 'id' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['id'],
  1769. 'materielId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['materielId'],
  1770. 'warehouseId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['warehouseId'],
  1771. 'merchantId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['merchantId'],
  1772. 'areaId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['areaId'],
  1773. 'areaName' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['areaName'],
  1774. 'areaCode' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['areaCode'],
  1775. 'storageLocationId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['storageLocationId'],
  1776. 'storageLocationName' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['storageLocationName'],
  1777. 'storageLocationCode' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['storageLocationCode'],
  1778. 'skuId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['skuId'],
  1779. 'unitName'=> $inventorystorageLocation[$skuId][$value['storageLocationId']]['unitName'],
  1780. 'skuName'=> $inventorystorageLocation[$skuId][$value['storageLocationId']]['skuName'],
  1781. 'num'=> bcadd($inventorystorageLocation[$skuId][$value['storageLocationId']]['num'], $num, 8),
  1782. 'updateTime'=> time(),
  1783. ];
  1784. }
  1785. // 生成入库批次号
  1786. $batchNo = createOrderSn(StatusCode::$source['manage'], StatusCode::$orderType['batch'], $this->enterpriseId);
  1787. //流水入库批次数据
  1788. $batch = json_encode([['batch' => $batchNo, 'num' => $value['num'], 'batchCost' => $inventoryWarehouse[$skuId]['costPrice']]]);
  1789. //流水数据
  1790. $addInventoryDetails[] = [
  1791. 'warehouseId' => $params['warehouseId'],
  1792. 'materielId' => $value['materielId'],
  1793. 'materielCode' => $value['materielCode'],
  1794. 'materielName' => $value['materielName'],
  1795. 'originId' => $params['originId'],
  1796. 'originNo' => $params['originNo'],
  1797. 'sourceNo' => $value['linkNo'],
  1798. 'source' => $params['type'],
  1799. 'operatorId' => isset($params['auditId'])?$params['auditId']:$params['operatorId'],
  1800. 'operatorName' => isset($params['auditName'])?$params['auditName']:$params['operatorName'],
  1801. 'skuId' => $value['inventorySkuId'],
  1802. 'unitName' => $value['inventoryUnitName'],
  1803. 'skuName' => $value['skuName'],
  1804. 'inventoryNum' => $value['num'],
  1805. 'otherNum' => $value['otherNum'],
  1806. 'inventoryChangeNum' => bcadd($inventoryWarehouse[$value['skuId']]['inventoryNum'], $value['num'], 8), // 变动后仓库库存数量
  1807. 'batch' => $batch, // 批次数据
  1808. 'averageCost' => $inventoryWarehouse[$value['skuId']]['costPrice'],
  1809. 'actionType' => StatusCode::$standard,
  1810. 'createTime' => time(),
  1811. 'updateTime' => time(),
  1812. 'costType' => $costType,
  1813. ];
  1814. //入库批次数据
  1815. $addBatchData[] = [
  1816. 'originId' => $params['originId'],
  1817. 'originNo' => $params['originNo'],
  1818. 'warehouseId' => $params['warehouseId'],
  1819. 'materielId' => $value['materielId'],
  1820. 'materielCode' => $value['materielCode'],
  1821. 'sourceNo' => $value['linkNo'],
  1822. 'skuId' => $value['inventorySkuId'],
  1823. 'batchNo' => $batchNo,
  1824. 'num' => $value['num'],
  1825. 'otherNum' => $value['otherNum'],
  1826. 'averageCost' => $inventoryWarehouse[$skuId]['costPrice'],
  1827. 'batchCost' => $inventoryWarehouse[$skuId]['costPrice'],
  1828. 'productionData' => 0,//生产日期
  1829. 'shelfLife' => 0,//保质期
  1830. 'batchStatus' => StatusCode::$standard,
  1831. 'createTime' => time(),
  1832. 'updateTime' => time(),
  1833. ];
  1834. }
  1835. $beginStatus = $this->objDInventory->beginTransaction();
  1836. if(!empty($updateInventoryMaster)){
  1837. $dbResult = $this->objDInventory->replace($updateInventoryMaster, true);
  1838. if($dbResult === false){
  1839. $this->objDInventory->rollBack();
  1840. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  1841. }
  1842. }
  1843. if(!empty($updateWarehouseInventory)){
  1844. $dbResult = $this->objDInventoryWarehouse->replace($updateWarehouseInventory, true);
  1845. if($dbResult === false){
  1846. $this->objDInventory->rollBack();
  1847. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  1848. }
  1849. }
  1850. if( !empty($updateStorageLocation) ){
  1851. $dbResult = $objDInventoryArea->replace($updateStorageLocation, true);
  1852. if($dbResult === false){
  1853. $this->objDInventory->rollBack();
  1854. return ResultWrapper::fail($objDInventoryArea->error(), ErrorCode::$dberror);
  1855. }
  1856. }
  1857. //直接修改暂时不考虑增加流水
  1858. if(!empty($addInventoryDetails)){
  1859. self::setDetailsTable($this->enterpriseId, $params['warehouseId'], 'qianniao_inventory_details');
  1860. $dbResult = $this->objDInventoryDetails->insert($addInventoryDetails, true);
  1861. if($dbResult === false){
  1862. $this->objDInventory->rollBack();
  1863. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  1864. }
  1865. }
  1866. //添加批次数据
  1867. if(!empty($addBatchData)){
  1868. $this->objDInventoryBatch->set_Table('qianniao_inventory_batch_'.$this->enterpriseId.'_'.$params['warehouseId']);
  1869. $dbResult = $this->objDInventoryBatch->insert($addBatchData, true);
  1870. if($dbResult === false){
  1871. $this->objDInventory->rollBack();
  1872. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  1873. }
  1874. }
  1875. //删除缓存
  1876. self::delCacheInventory($addInventoryDetails);
  1877. $beginStatus && $this->objDInventory->commit();
  1878. return ResultWrapper::success('操作成功');
  1879. }
  1880. /**
  1881. * 减少库存数量
  1882. */
  1883. public function updateDecInventoryNum($params, $outBatchStrategy = 1, $costType = 1)
  1884. {
  1885. $warehouseId = $params['warehouseId'];
  1886. $skuData = $params['details'];
  1887. $updateInventoryMaster = []; // 更新的主库存数据
  1888. $updateWarehouseInventory = [];//更新的仓库库存数据
  1889. $addInventoryDetails = []; // 新增得库存流水数据
  1890. $updateBatchData = []; // 要修改的批次数据
  1891. $updateStorageLocation = []; // 更新库区库位库存数据
  1892. // 提取所有skuids
  1893. $skuIds = [];
  1894. foreach($skuData as &$value){
  1895. $skuIds[] = $value['skuId'];
  1896. $value['inventorySkuId'] = $value['skuId'];
  1897. }
  1898. unset($value);
  1899. // 查询主库存数据
  1900. $dbResult = $this->objDInventory->select(['skuId' => $skuIds]);
  1901. if($dbResult === false){
  1902. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  1903. }
  1904. $inventoryResult = $dbResult;
  1905. unset($dbResult);
  1906. if(empty($inventoryResult)){
  1907. return ResultWrapper::fail('未查询到库存数据', ErrorCode::$paramError);
  1908. }
  1909. // skuId维度映射主库存数据
  1910. $inventoryMaster = [];
  1911. foreach($inventoryResult as $value){
  1912. $inventoryMaster[$value['skuId']] = $value;
  1913. }
  1914. // 查询仓库库存数据
  1915. $dbResult = $this->objDInventoryWarehouse->select(['warehouseId' => $warehouseId, 'skuId' => $skuIds]);
  1916. if($dbResult === false){
  1917. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  1918. }
  1919. $inventoryWarehouseResult = $dbResult;
  1920. unset($dbResult);
  1921. if(empty($inventoryWarehouseResult)){
  1922. return ResultWrapper::fail('未查询到仓库库存数据', ErrorCode::$paramError);
  1923. }
  1924. // skuid维度映射仓库库存数据
  1925. $inventoryWarehouse = [];
  1926. foreach($inventoryWarehouseResult as $value){
  1927. $inventoryWarehouse[$value['skuId']] = $value;
  1928. }
  1929. // 查询库区库位仓库表数据
  1930. $objDInventoryArea = new DInventoryArea();
  1931. $objDInventoryArea->set_Table('qianniao_inventory_area_'.$this->enterpriseId);
  1932. $condition = [
  1933. 'warehouseId'=>$params['warehouseId'],
  1934. 'merchantId' => getArrayItem($params, 'merchantId', 0),
  1935. 'skuId'=>$skuIds,
  1936. ];
  1937. $dbResult = $objDInventoryArea->select($condition);
  1938. if($dbResult === false){
  1939. return ResultWrapper::fail($objDInventoryArea->error(), ErrorCode::$dberror);
  1940. }
  1941. if(!empty($dbResult)){
  1942. // skuid维度映射库区库位库存数据
  1943. $inventorystorageLocation = [];
  1944. foreach($dbResult as $value){
  1945. $inventorystorageLocation[$value['skuId']][$value['storageLocationId']] = $value;
  1946. }
  1947. }
  1948. // 循环处理盘点单明细数据
  1949. foreach ($skuData as $value) {
  1950. $skuId = $value['inventorySkuId'];
  1951. $num = $value['num'];
  1952. if(!isset($inventoryMaster[$skuId])){
  1953. return ResultWrapper::fail('skuId:'.$skuId.'未查询到总库存', ErrorCode::$paramError);
  1954. }
  1955. if(!isset($inventoryWarehouse[$skuId])){
  1956. return ResultWrapper::fail('skuId:'.$skuId.'未查询到仓库库存', ErrorCode::$paramError);
  1957. }
  1958. //判断数量
  1959. if($num > $inventoryWarehouse[$skuId]['inventoryNum'] || $inventoryWarehouse[$skuId]['inventoryNum'] <= 0 ){
  1960. return ResultWrapper::fail( $inventoryWarehouse[$skuId]['materielName'].'仓库库存不足', ErrorCode::$paramError);
  1961. }
  1962. //主库存修改数据
  1963. $updateInventoryMaster[] = [
  1964. 'id' => $inventoryMaster[$skuId]['id'],
  1965. 'materielId' => $inventoryMaster[$skuId]['materielId'],
  1966. 'materielCode' => $inventoryMaster[$skuId]['materielCode'],
  1967. 'inventoryNum' => bcsub($inventoryMaster[$skuId]['inventoryNum'], $num, 8),
  1968. 'otherNum' => ( $params['type'] == StatusCode::$orderType['stocktaking'] ) ? $value['otherNum'] : bcsub($inventoryMaster[$skuId]['otherNum'], $value['otherNum'], 8),
  1969. 'lockInventory' => $inventoryMaster[$skuId]['lockInventory'],
  1970. 'costPrice' => $inventoryMaster[$skuId]['costPrice'],
  1971. 'skuId' => $skuId,
  1972. 'updateTime' => time(),
  1973. 'createTime' => $inventoryMaster[$skuId]['createTime'],
  1974. ];
  1975. //仓库库存修改数据
  1976. $updateWarehouseInventory[] = [
  1977. 'id' => $inventoryWarehouse[$skuId]['id'],
  1978. 'materielId' => $inventoryWarehouse[$skuId]['materielId'],
  1979. 'warehouseId' => $inventoryWarehouse[$skuId]['warehouseId'],
  1980. 'materielCode' => $inventoryWarehouse[$skuId]['materielCode'],
  1981. 'inventoryNum' => bcsub($inventoryWarehouse[$skuId]['inventoryNum'], $num), //仓库库存=当前仓库库存-出库数量
  1982. 'otherNum' => ( $params['type'] == StatusCode::$orderType['stocktaking'] ) ? $value['otherNum'] : bcsub($inventoryWarehouse[$skuId]['otherNum'], $value['otherNum'], 8),
  1983. 'costPrice' => $inventoryWarehouse[$skuId]['costPrice'], //移动加权平均单价
  1984. 'skuId' => $inventoryWarehouse[$skuId]['skuId'],
  1985. 'sort' => $inventoryWarehouse[$skuId]['sort'],
  1986. 'updateTime' => time(),
  1987. 'createTime' => $inventoryWarehouse[$skuId]['createTime'],
  1988. ];
  1989. // 库区库位库存修改数据
  1990. if( isset($value['storageLocationId']) && !empty($value['storageLocationId']) ){
  1991. $updateStorageLocation[] = [
  1992. 'id' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['id'],
  1993. 'materielId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['materielId'],
  1994. 'warehouseId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['warehouseId'],
  1995. 'merchantId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['merchantId'],
  1996. 'areaId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['areaId'],
  1997. 'areaName' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['areaName'],
  1998. 'areaCode' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['areaCode'],
  1999. 'storageLocationId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['storageLocationId'],
  2000. 'storageLocationName' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['storageLocationName'],
  2001. 'storageLocationCode' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['storageLocationCode'],
  2002. 'skuId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['skuId'],
  2003. 'unitName'=> $inventorystorageLocation[$skuId][$value['storageLocationId']]['unitName'],
  2004. 'skuName'=> $inventorystorageLocation[$skuId][$value['storageLocationId']]['skuName'],
  2005. 'num'=> bcsub($inventorystorageLocation[$skuId][$value['storageLocationId']]['num'], $num, 8),
  2006. 'updateTime'=> time(),
  2007. ];
  2008. }
  2009. // 出库策略
  2010. $order = 'createTime asc';
  2011. if ($outBatchStrategy == 2) {
  2012. $order = 'createTime desc';
  2013. }
  2014. // 查询当前物料该属性的可用批次记录
  2015. $this->objDInventoryBatch->set_Table('qianniao_inventory_batch_'.$this->enterpriseId.'_'.$warehouseId);
  2016. $sql = ' warehouseId = ' . $warehouseId . ' and skuId = ' . $skuId . ' and num > 0';
  2017. $inventoryBatchData = $this->objDInventoryBatch->select($sql, 'id,batchNo,num,skuId,batchCost', $order);
  2018. if ($inventoryBatchData === false) {
  2019. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  2020. }
  2021. $outNum = $num;// 出库数量
  2022. $batch = []; // 当前出库用到的所有批次数据
  2023. //判断是否有可用批次数据
  2024. if(!empty($inventoryBatchData)){
  2025. //有可用批次
  2026. // 从多个批次中扣除批次可用库存
  2027. foreach ($inventoryBatchData as $k => $v) {
  2028. // 出库数量 = 当前批次数量
  2029. if (bccomp($num, $v['num'], 8) == 0) {
  2030. $batch[] = ['batch' => $v['batchNo'], 'num' => $num, 'batchCost' => $v['batchCost']];
  2031. $updateBatchData[] = [
  2032. 'id' => $v['id'],
  2033. 'num' => 0,
  2034. 'otherNum' => 0,
  2035. 'updateTime' => time(),
  2036. ];
  2037. break;
  2038. }
  2039. // 出库数量 < 当前批次数量
  2040. if (bccomp($num, $v['num'], 8) == -1) {
  2041. $batch[] = ['batch' => $v['batchNo'], 'num' => $num, 'batchCost' => $v['batchCost']];
  2042. $updateBatchData[] = [
  2043. 'id' => $v['id'],
  2044. 'num' => bcsub($v['num'], $num, 8),
  2045. 'otherNum' => bcsub($v['otherNum'], $value['otherNum'], 8),
  2046. 'updateTime' => time(),
  2047. ];
  2048. break;
  2049. }
  2050. // 出库数量 > 当前批次数量
  2051. if (bccomp($num, $v['num'], 8) == 1) {
  2052. $batch[] = ['batch' => $v['batchNo'], 'num' => $v['num'], 'batchCost' => $v['batchCost']];
  2053. $updateBatchData[] = [
  2054. 'id' => $v['id'],
  2055. 'num' => '0.00000000',
  2056. 'otherNum' => '0.00000000',
  2057. 'updateTime' => time(),
  2058. ];
  2059. $num = bcsub($num, $v['num'], 8);
  2060. }
  2061. }
  2062. }
  2063. $batch = json_encode($batch);
  2064. $addInventoryDetails[] = [
  2065. 'warehouseId' => $warehouseId,
  2066. 'materielId' => $inventoryWarehouse[$skuId]['materielId'],
  2067. 'materielCode' => $inventoryWarehouse[$skuId]['materielCode'],
  2068. 'materielName' => $value['materielName'],
  2069. 'sourceNo' => $params['sourceNo'],
  2070. 'source' => $params['type'],
  2071. 'originId' => $params['originId'],
  2072. 'originNo' => $params['originNo'],
  2073. 'operatorId' => isset($params['auditId'])?$params['auditId']:$params['operatorId'],
  2074. 'operatorName' => isset($params['auditName'])?$params['auditName']:$params['operatorName'],
  2075. 'skuId' => $value['inventorySkuId'],
  2076. 'unitName' => $value['unitName'],
  2077. 'skuName' => $value['skuName'],
  2078. 'inventoryNum' => $outNum,
  2079. 'otherNum' => $value['otherNum'],
  2080. 'inventoryChangeNum' => bcsub($inventoryWarehouse[$skuId]['inventoryNum'], $outNum),
  2081. 'batch' => $batch,
  2082. 'averageCost' => $inventoryWarehouse[$skuId]['costPrice'], // 出库批次成本价 = 当前库存成本价(最后批次成本价)
  2083. 'actionType' => StatusCode::$delete,
  2084. 'createTime' => time(),
  2085. 'updateTime' => time(),
  2086. 'costType' => $costType
  2087. ];
  2088. }
  2089. $beginStatus = $this->objDInventory->beginTransaction();
  2090. if(!empty($updateInventoryMaster)){
  2091. $dbResult = $this->objDInventory->replace($updateInventoryMaster, true);
  2092. if($dbResult === false){
  2093. $this->objDInventory->rollBack();
  2094. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  2095. }
  2096. }
  2097. if(!empty($updateWarehouseInventory)){
  2098. $dbResult = $this->objDInventoryWarehouse->replace($updateWarehouseInventory, true);
  2099. if($dbResult === false){
  2100. $this->objDInventory->rollBack();
  2101. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  2102. }
  2103. }
  2104. if( !empty($updateStorageLocation) ){
  2105. $dbResult = $objDInventoryArea->replace($updateStorageLocation, true);
  2106. if($dbResult === false){
  2107. $this->objDInventory->rollBack();
  2108. return ResultWrapper::fail($objDInventoryArea->error(), ErrorCode::$dberror);
  2109. }
  2110. }
  2111. //直接修改暂时不考虑增加流水
  2112. if(!empty($addInventoryDetails)){
  2113. //流水表插入数据需要重置表名
  2114. self::setDetailsTable($this->enterpriseId, $params['warehouseId'], 'qianniao_inventory_details');
  2115. $dbResult = $this->objDInventoryDetails->insert($addInventoryDetails, true);
  2116. if($dbResult === false){
  2117. $this->objDInventory->rollBack();
  2118. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  2119. }
  2120. }
  2121. if(!empty($updateBatchData)){
  2122. foreach ($updateBatchData as $key => $value) {
  2123. // 通过batchNo去修改
  2124. if (isset($value['batchData'])) {
  2125. foreach ($value['batchData'] as $k => $v) {
  2126. $sql = 'update ' . $this->objDInventoryBatch->get_Table() . ' set num = ' . $v['num'] . ' + num,updateTime = ' . time() . ' where batchNo = ' . $v['batch'];
  2127. $dbResult = $this->objDInventoryBatch->query($sql);
  2128. if ($dbResult === false) {
  2129. $this->objDInventory->rollBack();
  2130. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  2131. }
  2132. }
  2133. continue;
  2134. }
  2135. // 通过id去修改
  2136. $id = $value['id'];
  2137. unset($value['id']);
  2138. $dbResult = $this->objDInventoryBatch->update($value, $id);
  2139. if ($dbResult === false) {
  2140. $this->objDInventory->rollBack();
  2141. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  2142. }
  2143. }
  2144. }
  2145. //删除缓存
  2146. self::delCacheInventory($addInventoryDetails);
  2147. $beginStatus && $this->objDInventory->commit();
  2148. return ResultWrapper::success('操作成功');
  2149. }
  2150. /**
  2151. * 仓库期初添加库存
  2152. * @param $params
  2153. * @param $originIds
  2154. * @return ResultWrapper
  2155. * @throws Exception
  2156. */
  2157. public function addInventoryByWarehouseBeginning($params, $originIds)
  2158. {
  2159. if(empty($params)) return ResultWrapper::fail('库存参数为空', ErrorCode::$paramError);
  2160. if(empty($originIds)) return ResultWrapper::fail('originIds参数为空', ErrorCode::$paramError);
  2161. //换算单位
  2162. $mobileResult = self::conversionSku(['Details' => $params]);
  2163. if(!$mobileResult->isSuccess()){
  2164. return ResultWrapper::fail($mobileResult->getData(), $mobileResult->getErrorCode());
  2165. }
  2166. $paramsResult = $mobileResult->getData();
  2167. unset($mobileResult);
  2168. $paramsData = $paramsResult['Details'];
  2169. //查询仓库库存
  2170. $skuIds = [];
  2171. $warehouseId = 0;
  2172. $materielData = [];
  2173. foreach($paramsData as $value){
  2174. $warehouseId = $value['warehouseId'];
  2175. $skuIds[] = $value['inventorySkuId'];
  2176. $materielData[$value['inventorySkuId']] = $value['materielName'];
  2177. }
  2178. unset($value);
  2179. $dbResult = $this->objDInventoryWarehouse->select(['warehouseId' => $warehouseId, 'skuId' => $skuIds]);
  2180. if($dbResult === false){
  2181. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  2182. }
  2183. $warehouseInventory = $dbResult;
  2184. unset($dbResult);
  2185. if(!empty($warehouseInventory)){
  2186. $return = '';
  2187. foreach($warehouseInventory as $value){
  2188. $return .= $materielData[$value['skuId']].',';
  2189. }
  2190. return ResultWrapper::fail($return.'在仓库中已有库存', ErrorCode::$paramError);
  2191. }
  2192. //查询主库库存
  2193. $dbResult = $this->objDInventory->select(['skuId' => $skuIds]);
  2194. if($dbResult === false){
  2195. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  2196. }
  2197. $inventoryResult = $dbResult;
  2198. unset($dbResult);
  2199. $inventoryData = [];
  2200. foreach($inventoryResult as $value){
  2201. $inventoryData[$value['skuId']] = $value;
  2202. }
  2203. //执行保存
  2204. $batchData = [];
  2205. $inventoryInsert = [];
  2206. $inventoryWarehouseInsert = [];
  2207. foreach($paramsData as $key => $value){
  2208. $inventoryInsert[] = [
  2209. 'id' => isset($inventoryData[$value['inventorySkuId']]) ? $inventoryData[$value['inventorySkuId']]['id'] : null,
  2210. 'materielId' => $value['materielId'],
  2211. 'materielCode' => $value['materielCode'],
  2212. 'inventoryNum' => isset($inventoryData[$value['inventorySkuId']]) ? bcadd($inventoryData[$value['inventorySkuId']]['inventoryNum'], $value['num']) : $value['num'],
  2213. 'lockInventory' => isset($inventoryData[$value['inventorySkuId']]) ? $inventoryData[$value['inventorySkuId']]['lockInventory'] : 0,
  2214. 'costPrice' => isset($inventoryData[$value['inventorySkuId']]) ? $inventoryData[$value['inventorySkuId']]['costPrice'] : 0,
  2215. 'skuId' => $value['inventorySkuId'],
  2216. 'updateTime' => time(),
  2217. 'createTime' => isset($inventoryData[$value['inventorySkuId']]) ? $inventoryData[$value['inventorySkuId']]['createTime'] : time(),
  2218. ];
  2219. $inventoryWarehouseInsert[] = [
  2220. 'warehouseId' => $value['warehouseId'],
  2221. 'materielId' => $value['materielId'],
  2222. 'materielCode' => $value['materielCode'],
  2223. 'inventoryNum' => $value['num'],
  2224. 'costPrice' => $value['costPrice'],
  2225. 'skuId' => $value['inventorySkuId'],
  2226. 'updateTime' => time(),
  2227. 'createTime' => time(),
  2228. ];
  2229. $batchData[] = [
  2230. 'originId' => $originIds[$key],
  2231. 'originNo' => $value['no'],
  2232. 'warehouseId' => $value['warehouseId'],
  2233. 'materielId' => $value['materielId'],
  2234. 'materielCode' => $value['materielCode'],
  2235. 'sourceNo' => $value['no'],
  2236. 'skuId' => $value['inventorySkuId'],
  2237. 'batchNo' => createOrderSn(StatusCode::$source['manage'], StatusCode::$orderType['batch'], $this->enterpriseId),
  2238. 'num' => $value['num'],
  2239. 'averageCost' => $value['costPrice'],
  2240. 'batchCost' => $value['costPrice'],
  2241. //TODO 期初添加的商品需不需要保质期
  2242. 'productionData' => 0,
  2243. 'shelfLife' => 0,
  2244. 'batchStatus' => StatusCode::$standard,
  2245. 'createTime' => time(),
  2246. 'updateTime' => time(),
  2247. ];
  2248. }
  2249. //修改主库库存
  2250. $dbResult = $this->objDInventory->replace($inventoryInsert, true);
  2251. if($dbResult === false){
  2252. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  2253. }
  2254. unset($dbResult);
  2255. //新增仓库库存
  2256. $dbResult = $this->objDInventoryWarehouse->insert($inventoryWarehouseInsert, true);
  2257. if($dbResult === false){
  2258. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  2259. }
  2260. unset($dbResult);
  2261. //增加批次
  2262. self::setBatchTable($this->enterpriseId, $warehouseId);
  2263. $dbResult = $this->objDInventoryBatch->insert($batchData, true);
  2264. if($dbResult === false){
  2265. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  2266. }
  2267. return ResultWrapper::success($dbResult);
  2268. }
  2269. /**
  2270. * sku转换
  2271. * @param $data
  2272. * @return ResultWrapper
  2273. * @throws Exception
  2274. */
  2275. public function updateNumBySkuId($data)
  2276. {
  2277. //传参是单据详情
  2278. //循环单据详情
  2279. $skuIds = [];
  2280. foreach ($data as $value) {
  2281. //查询每条数据的skuId是否是主单位
  2282. $skuIds[] = $value['skuId'];
  2283. }
  2284. $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId);
  2285. $modelResult = $objMSku->getNameByIds($skuIds, true);
  2286. if (!$modelResult->isSuccess()) {
  2287. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  2288. }
  2289. $skuData = $modelResult->getData();
  2290. unset($modelResult);
  2291. foreach ($data as &$value) {
  2292. if (isset($skuData[$value['skuId']])) {
  2293. if ($skuData[$value['skuId']]['isMaster'] == StatusCode::$delete) {
  2294. // $value['num'] = bcmul($value['num'], $skuData[$value['skuId']]['conversion']);//乘以进率
  2295. $value['num'] = bcdiv($value['num'], $skuData[$value['skuId']]['conversion'], 8);//除以进率
  2296. }
  2297. }else{
  2298. return ResultWrapper::fail('sku查询错误', ErrorCode::$paramError);
  2299. }
  2300. }
  2301. unset($value);
  2302. return ResultWrapper::success($data);
  2303. }
  2304. /**
  2305. * 计算sku 转换成主单位
  2306. * @param $params //多维数组 商品数据Details 包含参数:materielId, skuId, num
  2307. * @param array $skuData //多维数组 $skuData[基础资料id] => [skuId => sku表查询的数据]
  2308. * @return ResultWrapper
  2309. * @throws Exception
  2310. */
  2311. public function conversionSku($params, $skuData = [])
  2312. {
  2313. if(empty($skuData)){
  2314. $materielIds = array_column($params['Details'], 'materielId');
  2315. $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId);
  2316. $modelResult = $objMSku->getSkuDataByGoodsIds($materielIds);
  2317. if (!$modelResult->isSuccess()) {
  2318. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  2319. }
  2320. $selectSkuData = $modelResult->getData();
  2321. unset($modelResult);
  2322. }else{
  2323. $selectSkuData = $skuData;
  2324. }
  2325. //$inventorySkuIds = [];//主单位信息数组
  2326. foreach ($params['Details'] as $key => &$value) {
  2327. if(!isset($selectSkuData[$value['materielId']][$value['skuId']])){
  2328. return ResultWrapper::fail('商品:'.$value['materielName'].',单位:'.$value['unitName'].(isset($value['skuName']) ? $value['skuName'] : '').',skuId:'.$value['skuId'].'查询失败', ErrorCode::$paramError);
  2329. }
  2330. $skuArray = $selectSkuData[$value['materielId']][$value['skuId']];
  2331. $value['inventorySkuId'] = $value['skuId'];//库存单位(主单位) 默认当前传来的单位
  2332. $value['inventoryUnitName'] = isset($value['unitName']) ? $value['unitName'] : '';
  2333. //判断传过来的sku是否是主单位 如果不是 查询同属性主单位skuId的换算比例
  2334. if($skuArray['isMaster'] == StatusCode::$delete){
  2335. //判断是否有属性
  2336. //如果没有属性 对比isMaster = 5 主单位换算比例
  2337. $where = [
  2338. 'isMaster' => StatusCode::$standard,
  2339. 'specGroupHash' => '',
  2340. ];
  2341. //如果有属性 对比isMaster = 5 and 哈希 = 此属性的哈希 查出对应属性的主单位换算比例
  2342. if($skuArray['specType'] == StatusCode::$specType['multiple']){
  2343. $where['specGroupHash'] = $skuArray['specGroupHash'];
  2344. }
  2345. $masterSkuData = [];//主单位数据
  2346. foreach($selectSkuData[$value['materielId']] as $v){
  2347. if(!empty($where['specGroupHash'])){
  2348. //有属性
  2349. if($v['isMaster'] == $where['isMaster'] && $v['specGroupHash'] == $where['specGroupHash']){
  2350. $masterSkuData = $v;
  2351. }
  2352. }else{
  2353. //没属性
  2354. if($v['isMaster'] == $where['isMaster']) {
  2355. $masterSkuData = $v;
  2356. }
  2357. }
  2358. }
  2359. if(empty($masterSkuData)){
  2360. return ResultWrapper::fail($value['materielName'].'主单位查询失败', ErrorCode::$paramError);
  2361. }
  2362. //换算数量
  2363. if(isset($skuArray['isNew']) && $skuArray['isNew'] == StatusCode::$standard){
  2364. $value['num'] = bcmul($value['num'], $skuArray['conversion'], 8);//乘以进率
  2365. }else{
  2366. $value['num'] = bcdiv($value['num'], $skuArray['conversion'], 8);//除以进率
  2367. }
  2368. $value['inventorySkuId'] = $masterSkuData['id'];//赋值主单位id
  2369. $value['inventoryUnitName'] = $masterSkuData['unitName'];
  2370. }
  2371. //过滤相同主单位信息
  2372. /*if(array_key_exists($value['inventorySkuId'], $inventorySkuIds)){
  2373. $params['Details'][$inventorySkuIds[$value['inventorySkuId']]]['num'] = bcadd($params['Details'][$inventorySkuIds[$value['inventorySkuId']]]['num'],$value['num'], 8);
  2374. unset($params['Details'][$key]);
  2375. }else{
  2376. $inventorySkuIds[$value['inventorySkuId']] = $key;
  2377. }*/
  2378. }
  2379. unset($value);
  2380. $params['Details'] = array_values($params['Details']);
  2381. return ResultWrapper::success($params);
  2382. }
  2383. /**
  2384. * 计算sku 转换成辅单位(把传参里的主单位数量转为辅单位sku的换算后数量(如果传来的sku是主单位则不转))
  2385. * @param $params
  2386. * @return ResultWrapper
  2387. * @throws Exception
  2388. */
  2389. public function conversionMinorSku($params)
  2390. {
  2391. if(empty($params)) return ResultWrapper::success($params);
  2392. $skuIds = [];
  2393. foreach($params as $value){
  2394. $skuIds[] = $value['skuId'];
  2395. }
  2396. $objMSku = new MSku($this->onLineUserCenterId,$this->enterpriseId);
  2397. $modelResult = $objMSku->getSkuDataBySkuIds($skuIds);
  2398. if(!$modelResult->isSuccess()){
  2399. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  2400. }
  2401. $skuData = $modelResult->getData();
  2402. unset($modelResult);
  2403. foreach($params as &$value){
  2404. if(isset($skuData[$value['skuId']]) && isset($skuData[$value['skuId']]['conversion']) && !empty($skuData[$value['skuId']]['conversion']) && $skuData[$value['skuId']]['conversion'] > 0){
  2405. if(isset($skuData[$value['skuId']]['isNew']) && $skuData[$value['skuId']]['isNew'] == StatusCode::$standard) {
  2406. $value['num'] = bcmul($value['num'], $skuData[$value['skuId']]['conversion'], 8);//乘以进率
  2407. }else{
  2408. $value['num'] = bcdiv($value['num'], $skuData[$value['skuId']]['conversion'], 8);//除以进率
  2409. }
  2410. }
  2411. }
  2412. return ResultWrapper::success($params);
  2413. }
  2414. /**
  2415. * 锁定库存锁定
  2416. * @param $materielData
  2417. * @return ResultWrapper
  2418. * @throws Exception
  2419. */
  2420. public function updateLockInventory($shopId, $materielData)
  2421. {
  2422. //换算sku
  2423. foreach($materielData as &$value){
  2424. $value['num'] = $value['lockingNum'];//锁定数量
  2425. }
  2426. unset($value);
  2427. $params['Details'] = $materielData;
  2428. $modelResult = self::conversionSku($params);
  2429. if(!$modelResult->isSuccess()){
  2430. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  2431. }
  2432. $formatInventoryNum = $modelResult->getData();
  2433. unset($modelResult);
  2434. $materielData = $formatInventoryNum['Details'];
  2435. //循环拼接数据
  2436. $inventoryLocking = [];
  2437. $skuIds = [];
  2438. $materielIds = [];
  2439. foreach ($materielData as $key => $value) {
  2440. if (!in_array($value['inventorySkuId'], $skuIds)) {
  2441. $skuIds[] = $value['inventorySkuId'];
  2442. }
  2443. if (!in_array($value['materielId'], $materielIds)) {
  2444. $materielIds[] = $value['materielId'];
  2445. }
  2446. $inventoryLockingData['shopId'] = $shopId;
  2447. $inventoryLockingData['materielId'] = $value['materielId'];
  2448. $inventoryLockingData['materielCode'] = createCode(StatusCode::$code['goodsBasic']['prefix'], $value['materielId'], StatusCode::$code['goodsBasic']['length']);
  2449. $inventoryLockingData['originId'] = $value['originId'];
  2450. $inventoryLockingData['originNo'] = $value['originNo'];
  2451. $inventoryLockingData['source'] = $value['source'];
  2452. $inventoryLockingData['sourceNo'] = $value['sourceNo'];
  2453. $inventoryLockingData['totalNum'] = $value['num'];
  2454. $inventoryLockingData['lockingNum'] = $value['num'];
  2455. $inventoryLockingData['unlockNum'] = 0;
  2456. $inventoryLockingData['operatorId'] = $value['operatorId'];
  2457. $inventoryLockingData['operatorName'] = $value['operatorName'];
  2458. $inventoryLockingData['skuId'] = $value['inventorySkuId'];
  2459. $inventoryLockingData['createTime'] = time();
  2460. $inventoryLockingData['updateTime'] = time();
  2461. $inventoryLocking[] = $inventoryLockingData;
  2462. }
  2463. //获取负库存设置
  2464. $objMGoods = new MGoods($this->enterpriseId, false, $this->onLineUserCenterId);
  2465. $modelResult = $objMGoods->getDistributionByShopIdRelMaterielIds($shopId, $materielIds);
  2466. if(!$modelResult->isSuccess()){
  2467. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  2468. }
  2469. $preSale = $modelResult->getData();
  2470. unset($modelResult);
  2471. //查询可用库存
  2472. $dbResult = $this->objDInventory->select(['skuId' => $skuIds]);
  2473. if($dbResult === false){
  2474. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  2475. }
  2476. $inventoryResult = $dbResult;
  2477. unset($dbResult);
  2478. $inventory = [];
  2479. foreach($inventoryResult as $value){
  2480. $inventory[$value['skuId']] = $value;
  2481. }
  2482. //查询商铺锁定数据
  2483. $dbResult = $this->objDLockingShop->select(['shopId' => $shopId, 'skuId' => $skuIds]);
  2484. if($dbResult === false){
  2485. return ResultWrapper::fail($this->objDLockingShop->error(), ErrorCode::$dberror);
  2486. }
  2487. $shopLockResult = $dbResult;
  2488. unset($dbResult);
  2489. $shopLock = [];
  2490. foreach($shopLockResult as $value){
  2491. $shopLock[$value['skuId']] = $value['lockInventory'];
  2492. }
  2493. $beginStatus = $this->objDInventory->beginTransaction();
  2494. foreach ($materielData as $key => $value) {
  2495. //5.修改主库存数据
  2496. if(isset($inventory[$value['inventorySkuId']])){
  2497. $update = [
  2498. 'inventoryNum' => bcsub($inventory[$value['inventorySkuId']]['inventoryNum'] , $value['num'], 8),
  2499. 'lockInventory' => bcadd($inventory[$value['inventorySkuId']]['lockInventory'] , $value['num'], 8),
  2500. 'updateTime' => time(),
  2501. ];
  2502. //判断是否支持预售(负库存销售)
  2503. if(!isset($preSale[$value['materielId']]) || empty($preSale[$value['materielId']]) || $preSale[$value['materielId']] == StatusCode::$delete){
  2504. if($update['inventoryNum'] < 0){
  2505. $this->objDInventory->rollBack();
  2506. if(isset($value['materielName'])){
  2507. return ResultWrapper::fail($value['materielName'].'库存不足', ErrorCode::$paramError);
  2508. }else{
  2509. if(isset($value['goodsName'])){
  2510. return ResultWrapper::fail($value['goodsName'].'库存不足', ErrorCode::$paramError);
  2511. }else{
  2512. return ResultWrapper::fail('materielId:' . $value['materielId'] . 'skuId: '.$value['inventorySkuId'].'库存不足', ErrorCode::$paramError);
  2513. }
  2514. }
  2515. }
  2516. }
  2517. $dbResult = $this->objDInventory->update($update, ['skuId' => $value['inventorySkuId']]);
  2518. }else{
  2519. //创建库存数据
  2520. $insertInventory = [
  2521. 'merchantId' => getArrayItem($value, 'merchantId', 0),
  2522. 'materielId' => $value['materielId'],
  2523. 'materielCode' => $value['materielCode'],
  2524. 'inventoryNum' => bcsub(0 , $value['num'], 8),
  2525. 'lockInventory' => $value['num'],
  2526. 'costPrice' => 0,
  2527. 'skuId' => $value['inventorySkuId'],
  2528. 'updateTime' => time(),
  2529. 'createTime' => time()
  2530. ];
  2531. //判断是否支持预售(负库存销售)
  2532. if(!isset($preSale[$value['materielId']]) || empty($preSale[$value['materielId']]) || $preSale[$value['materielId']] == StatusCode::$delete){
  2533. if($insertInventory['inventoryNum'] < 0){
  2534. $this->objDInventory->rollBack();
  2535. if(isset($value['materielName'])){
  2536. return ResultWrapper::fail($value['materielName'].'库存不足', ErrorCode::$paramError);
  2537. }else{
  2538. if(isset($value['goodsName'])){
  2539. return ResultWrapper::fail($value['goodsName'].'库存不足', ErrorCode::$paramError);
  2540. }else{
  2541. return ResultWrapper::fail('materielId:' . $value['materielId'] . 'skuId: '.$value['inventorySkuId'].'库存不足', ErrorCode::$paramError);
  2542. }
  2543. }
  2544. }
  2545. }
  2546. $dbResult = $this->objDInventory->insert($insertInventory);
  2547. }
  2548. if($dbResult === false){
  2549. $this->objDInventory->rollBack();
  2550. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  2551. }
  2552. unset($dbResult);
  2553. //修改商铺锁定数据
  2554. if(isset($shopLock[$value['inventorySkuId']])){
  2555. $update = [
  2556. 'lockInventory' => bcadd($shopLock[$value['inventorySkuId']], $value['num'], 8),
  2557. 'updateTime' => time(),
  2558. ];
  2559. $dbResult = $this->objDLockingShop->update($update, ['shopId' => $shopId, 'skuId' => $value['inventorySkuId']]);
  2560. }else{
  2561. $insertShopLock = [
  2562. 'shopId' => $shopId,
  2563. 'materielId' => $value['materielId'],
  2564. 'materielCode' => $value['materielCode'],
  2565. 'lockInventory' => $value['num'],
  2566. 'skuId' => $value['inventorySkuId'],
  2567. 'updateTime' => time(),
  2568. 'createTime' => time(),
  2569. ];
  2570. $dbResult = $this->objDLockingShop->insert($insertShopLock);
  2571. }
  2572. if($dbResult === false){
  2573. $this->objDInventory->rollBack();
  2574. return ResultWrapper::fail($this->objDLockingShop->error(), ErrorCode::$dberror);
  2575. }
  2576. unset($dbResult);
  2577. //删除redis
  2578. $this->objInventoryCache->delShopLock($value['inventorySkuId'], $shopId);
  2579. }
  2580. //10.记录锁定流水
  2581. self::setLockingTable();
  2582. $dbResult = $this->objDInventoryLocking->insert($inventoryLocking, true);
  2583. if ($dbResult === false) {
  2584. $this->objDInventory->rollBack();
  2585. return ResultWrapper::fail($this->objDInventoryLocking->error(), ErrorCode::$dberror);
  2586. }
  2587. $beginStatus && $this->objDInventory->commit();
  2588. return ResultWrapper::success($dbResult);
  2589. }
  2590. /**
  2591. * 解锁物料库存
  2592. * @param array $originIds //源头id 订单id
  2593. * @param int $source //来源
  2594. * @param $orderCreateTime 订单创建时间
  2595. * @return ResultWrapper
  2596. * @throws Exception
  2597. */
  2598. public function unlockInventory(array $originIds, $source, $orderCreateTime)
  2599. {
  2600. if( empty($originIds) || empty($orderCreateTime) ){
  2601. return ResultWrapper::fail('解锁库存参数为空', ErrorCode::$paramError);
  2602. }
  2603. // 查询锁定记录 锁定表根据季度分表
  2604. self::setLockingTable($this->enterpriseId, false, $orderCreateTime);
  2605. $dbResult = $this->objDInventoryLocking->select(['originId' => $originIds, 'source' => $source,'lockStatus' => StatusCode::$delete]);
  2606. if($dbResult === false) {
  2607. return ResultWrapper::fail($this->objDInventoryLocking->error(), ErrorCode::$dberror);
  2608. }
  2609. if(empty($dbResult)) {
  2610. return ResultWrapper::fail('锁定数据为空01', ErrorCode::$paramError);
  2611. }
  2612. $lockData = $dbResult;
  2613. unset($dbResult);
  2614. $beginStatus = $this->objDInventory->beginTransaction();
  2615. $ids = [];
  2616. foreach ($lockData as $value) {
  2617. if($value['lockStatus'] == StatusCode::$standard){
  2618. return ResultWrapper::fail('库存已解锁', ErrorCode::$paramError);
  2619. }
  2620. $ids[] = $value['id'];
  2621. $where = [
  2622. 'materielId' => $value['materielId'],
  2623. 'skuId' => $value['skuId'],
  2624. ];
  2625. // 查询总库存表锁定数据
  2626. $dbResult = $this->objDInventory->get($where,'lockInventory');
  2627. if($dbResult === false){
  2628. $this->objDInventory->rollBack();
  2629. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  2630. }
  2631. if(empty($dbResult)){
  2632. $this->objDInventory->rollBack();
  2633. return ResultWrapper::fail('物料'.$value['materielId'].'skuId:'.$value['skuId'].'库存不存在', ErrorCode::$paramError);
  2634. }
  2635. // 如果未解锁过,锁定还未0,则报错
  2636. if($dbResult['lockInventory'] <= 0 && $value['unlockNum'] == 0){
  2637. $this->objDInventory->rollBack();
  2638. return ResultWrapper::fail('物料'.$value['materielId'].'skuId:'.$value['skuId'].'锁定库存不足', ErrorCode::$paramError);
  2639. }
  2640. //减去总锁定
  2641. $dbResult = $this->objDInventory->set_dec('lockInventory', $where, $value['lockingNum']);
  2642. if ($dbResult === false) {
  2643. $this->objDInventory->rollBack();
  2644. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  2645. }
  2646. unset($dbResult);
  2647. //总库存增加
  2648. $dbResult = $this->objDInventory->set_inc('inventoryNum', $where, $value['lockingNum']);
  2649. if ($dbResult === false) {
  2650. $this->objDInventory->rollBack();
  2651. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  2652. }
  2653. unset($dbResult);
  2654. //商铺锁定减少
  2655. $dbResult = $this->objDLockingShop->set_dec('lockInventory', ['shopId' => $value['shopId'], 'skuId' => $value['skuId']], $value['lockingNum']);
  2656. if ($dbResult === false) {
  2657. $this->objDInventory->rollBack();
  2658. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  2659. }
  2660. unset($dbResult);
  2661. //删除redis
  2662. $this->objInventoryCache->delShopLock($value['skuId'], $value['shopId']);
  2663. }
  2664. $updateLockData = [
  2665. 'lockStatus' => StatusCode::$standard,
  2666. 'unlockTime' => time(),
  2667. ];
  2668. $dbResult = $this->objDInventoryLocking->update($updateLockData, ['id' => $ids]);
  2669. if ($dbResult === false) {
  2670. $this->objDInventory->rollBack();
  2671. return ResultWrapper::fail($this->objDInventoryLocking->error(), ErrorCode::$dberror);
  2672. }
  2673. $beginStatus && $this->objDInventory->commit();
  2674. return ResultWrapper::success('修改成功');
  2675. }
  2676. /**
  2677. * 根据skuId和shopId获取物料库存数据
  2678. * @param array $shopId //$shopId
  2679. * @param array $skuIds //$skuIds
  2680. * @return ResultWrapper
  2681. * @throws \Exception
  2682. */
  2683. public function getInventoryByShopIdAndSkuIds(int $shopId,array $skuIds)
  2684. {
  2685. if(empty($shopId)) return ResultWrapper::fail('查询库存shopId参数为空', ErrorCode::$paramError);
  2686. if(empty($skuIds)) return ResultWrapper::fail('查询库存skuIds参数为空', ErrorCode::$paramError);
  2687. $inventoryData = [];
  2688. // 将传过来的skuid统一转换为主单位skuid
  2689. $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId);
  2690. $modelResult = $objMSku->getConversion($skuIds);
  2691. if(!$modelResult->isSuccess()){
  2692. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  2693. }
  2694. $skuData = $modelResult->getData();
  2695. unset($modelResult);
  2696. // 查询店铺绑定仓库
  2697. $objMShop = new MShop($this->enterpriseId, $this->onLineUserCenterId);
  2698. $modelResult = $objMShop->getWarehouseIdsByShopId($shopId);
  2699. if(!$modelResult->isSuccess()){
  2700. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  2701. }
  2702. $warehouseIds = $modelResult->getData();
  2703. $warehouseIds = array_unique($warehouseIds);
  2704. unset($modelResult);
  2705. if( empty($warehouseIds) ){
  2706. $return = [];
  2707. foreach($skuData as $key => $value){
  2708. $return[$key]['num'] = 0;
  2709. $return[$key]['warehouseInventory'] = [];
  2710. }
  2711. return ResultWrapper::success($return);
  2712. }
  2713. foreach($skuData as $key => $value){
  2714. $skuId = $value['masterSkuId'];
  2715. //查询库存数据
  2716. $warehouseInventoryTotal = 0;
  2717. $warehouseInventoryotherTotal = 0;
  2718. //查询仓库库存
  2719. foreach($warehouseIds as $warehouseId){
  2720. $warehouseInventoryNum = 0;
  2721. $warehouseInventoryOtherNum = 0;
  2722. $cacheData = $this->objInventoryCache->getCacheHash($skuId, $warehouseId);
  2723. if(empty($cacheData)){
  2724. $dbResult = $this->objDInventoryWarehouse->get(['warehouseId' => $warehouseId, 'skuId' => $skuId]);
  2725. if($dbResult === false){
  2726. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  2727. }
  2728. $warehouseInventory = $dbResult;
  2729. unset($dbResult);
  2730. if(!empty($warehouseInventory)){
  2731. $addCache = [
  2732. 'materielId' => $warehouseInventory['materielId'],
  2733. 'warehouseId' => $warehouseId,
  2734. 'materielCode' => $warehouseInventory['materielCode'],
  2735. 'inventoryNum' => $warehouseInventory['inventoryNum'],
  2736. 'otherNum' => $warehouseInventory['otherNum'],
  2737. 'costPrice' => $warehouseInventory['costPrice'],
  2738. 'skuId' => $skuId,
  2739. ];
  2740. //保存redis
  2741. $this->objInventoryCache->addCacheHash($skuId, $addCache);
  2742. $warehouseInventoryTotal = bcadd($warehouseInventory['inventoryNum'],$warehouseInventoryTotal,8);
  2743. $warehouseInventoryotherTotal = bcadd($warehouseInventory['otherNum'],$warehouseInventoryotherTotal, 8);
  2744. $warehouseInventoryNum = $warehouseInventory['inventoryNum'];
  2745. $warehouseInventoryOtherNum = $warehouseInventory['otherNum'];
  2746. }else{
  2747. $addCache = [
  2748. 'warehouseId' => $warehouseId,
  2749. 'inventoryNum' => 0,
  2750. 'otherNum' => 0,
  2751. 'costPrice' => 9,
  2752. 'skuId' => $skuId,
  2753. ];
  2754. //保存redis
  2755. $this->objInventoryCache->addCacheHash($skuId, $addCache);
  2756. }
  2757. }else{
  2758. $warehouseInventoryTotal = bcadd($cacheData['inventoryNum'],$warehouseInventoryTotal, 8);
  2759. $warehouseInventoryotherTotal = bcadd(getArrayItem($cacheData,'otherNum',0),$warehouseInventoryotherTotal, 8);
  2760. $warehouseInventoryNum = $cacheData['inventoryNum'];
  2761. $warehouseInventoryOtherNum = getArrayItem($cacheData,'otherNum',0);
  2762. }
  2763. if($warehouseInventoryNum > 0){
  2764. if($value['isMaster'] == StatusCode::$standard){
  2765. $inventoryData[$key]['warehouseInventory'][$warehouseId]['num'] = $warehouseInventoryNum;
  2766. $inventoryData[$key]['warehouseInventory'][$warehouseId]['otherNum'] = $warehouseInventoryOtherNum;
  2767. }else{
  2768. if($value['isNew'] == StatusCode::$standard){
  2769. $inventoryData[$key]['warehouseInventory'][$warehouseId]['num'] = bcdiv($warehouseInventoryNum, $value['conversion'], 8);
  2770. $inventoryData[$key]['warehouseInventory'][$warehouseId]['otherNum'] = $warehouseInventoryOtherNum;
  2771. }else{
  2772. $inventoryData[$key]['warehouseInventory'][$warehouseId]['num'] = bcmul($warehouseInventoryNum, $value['conversion'], 8);
  2773. $inventoryData[$key]['warehouseInventory'][$warehouseId]['otherNum'] = $warehouseInventoryOtherNum;
  2774. }
  2775. }
  2776. }else{
  2777. $inventoryData[$key]['warehouseInventory'][$warehouseId]['num'] = 0;
  2778. $inventoryData[$key]['warehouseInventory'][$warehouseId]['otherNum'] = 0;
  2779. }
  2780. }
  2781. //查询商铺锁定数据
  2782. $skuLockNum = 0;
  2783. $cache = $this->objInventoryCache->getShopLock($shopId, $skuId);
  2784. if($cache === false){
  2785. $dbResult = $this->objDLockingShop->get(['shopId' => $shopId, 'skuId' => $skuId]);
  2786. if($dbResult === false){
  2787. return ResultWrapper::fail($this->objDLockingShop->error(), ErrorCode::$dberror);
  2788. }
  2789. if(!empty($dbResult)){
  2790. $skuLockNum = $dbResult['lockInventory'];
  2791. $this->objInventoryCache->addShopLock($shopId, $skuId, $dbResult['lockInventory']);
  2792. }else{
  2793. $this->objInventoryCache->addShopLock($shopId, $skuId, 0);
  2794. }
  2795. unset($dbResult);
  2796. }else{
  2797. $skuLockNum = $cache;
  2798. }
  2799. $inventoryOtherNum = 0;
  2800. $inventoryNum = bcsub($warehouseInventoryTotal, $skuLockNum);
  2801. if($inventoryNum > 0){
  2802. if($value['isMaster'] == StatusCode::$standard){
  2803. $inventoryData[$key]['num'] = $inventoryNum;
  2804. }else{
  2805. $inventoryOtherNum = bcsub($warehouseInventoryotherTotal, bcdiv($skuLockNum, $value['conversion'], 8));
  2806. if($value['isNew'] == StatusCode::$standard){
  2807. $inventoryData[$key]['num'] = bcdiv($inventoryNum, $value['conversion'], 8);
  2808. $inventoryData[$key]['otherNum'] = $inventoryOtherNum;
  2809. }else{
  2810. $inventoryData[$key]['num'] = bcmul($inventoryNum, $value['conversion'], 8);
  2811. $inventoryData[$key]['otherNum'] = $inventoryOtherNum;
  2812. }
  2813. }
  2814. }else{
  2815. $inventoryData[$key]['num'] = 0;
  2816. $inventoryData[$key]['otherNum'] = 0;
  2817. }
  2818. }
  2819. // 主单位的其他单位 = 辅单位的其他单位
  2820. foreach($inventoryData as $key => $value){
  2821. if(!isset($value['otherNum'])){
  2822. $inventoryData[$key]['otherNum'] = $inventoryOtherNum;
  2823. }
  2824. }
  2825. return ResultWrapper::success($inventoryData);
  2826. }
  2827. /**
  2828. * 根据商铺id和物料ids获取库存信息
  2829. * @param $params
  2830. * @return ResultWrapper
  2831. */
  2832. public function getInventoryByShopIdAndMaterielIds($shopId, $materielIds)
  2833. {
  2834. if(empty($shopId)) return ResultWrapper::fail('查询库存shopId参数为空', ErrorCode::$paramError);
  2835. if(empty($materielIds)) return ResultWrapper::fail('查询库存materielIds参数为空', ErrorCode::$paramError);
  2836. //查询主单位
  2837. $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId);
  2838. // 根据ids数组获取name
  2839. $modelResult = $objMSku->getSkuDataByGoodsIds($materielIds, true);
  2840. if (!$modelResult->isSuccess()) {
  2841. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  2842. }
  2843. $selectSkuData = $modelResult->getData();
  2844. if( empty($selectSkuData) ){
  2845. return ResultWrapper::fail('商品主单位异常', ErrorCode::$contentNotExists);
  2846. }
  2847. unset($modelResult);
  2848. $skuIds = [];
  2849. foreach($selectSkuData as $materielId => $value){
  2850. $skuIds = array_merge($skuIds, array_keys($value));
  2851. }
  2852. // 根据skuId和shopId获取物料库存数据
  2853. $modelResult = self::getInventoryByShopIdAndSkuIds($shopId, $skuIds);
  2854. if(!$modelResult->isSuccess()){
  2855. return ResultWrapper::fail($modelResult->getData(),$modelResult->getErrorCode());
  2856. }
  2857. $inventoryData = $modelResult->getData();
  2858. $return = [];
  2859. foreach($selectSkuData as $materielId => $value){
  2860. foreach($value as $skuId => $v){
  2861. $return[$materielId] = [
  2862. 'num' => $inventoryData[$skuId]['num'],
  2863. 'warehouseInventory' => $inventoryData[$skuId]['warehouseInventory'],
  2864. 'skuId' => $skuId,
  2865. 'materielId' => $materielId,
  2866. 'isMaster' => $v['isMaster'],
  2867. 'isNew' => $v['isNew']
  2868. ];
  2869. }
  2870. }
  2871. return ResultWrapper::success($return);
  2872. }
  2873. /**
  2874. * 获取库存数据
  2875. */
  2876. public function getInventoryData($where)
  2877. {
  2878. $dbResult = $this->objDInventory->select($where);
  2879. if($dbResult === false){
  2880. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  2881. }
  2882. return ResultWrapper::success($dbResult);
  2883. }
  2884. /**
  2885. * 查询仓库库存
  2886. */
  2887. public function getWarehouseInventoryData($warehouseId, $skuIds)
  2888. {
  2889. if(!isset($warehouseId)) return ResultWrapper::fail('查询仓库库存warehouseId为空', ErrorCode::$paramError);
  2890. if(!isset($skuIds)) return ResultWrapper::fail('查询仓库库存skuId为空', ErrorCode::$paramError);
  2891. //转换单位
  2892. $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId);
  2893. $modelResult = $objMSku->getConversion($skuIds);
  2894. if(!$modelResult->isSuccess()){
  2895. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  2896. }
  2897. $skuData = $modelResult->getData();
  2898. unset($modelResult);
  2899. $masterSkuIds = array_column($skuData, 'masterSkuId');
  2900. $where = [
  2901. 'warehouseId' => $warehouseId,
  2902. 'skuId' => $masterSkuIds
  2903. ];
  2904. //查询仓库库存
  2905. $dbResult = $this->objDInventoryWarehouse->select($where);
  2906. if($dbResult === false){
  2907. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  2908. }
  2909. $warehouseInventoryResult = $dbResult;
  2910. unset($dbResult);
  2911. if(empty($warehouseInventoryResult)){
  2912. return ResultWrapper::fail('仓库库存为空', ErrorCode::$paramError);
  2913. }
  2914. $warehouseInventory = [];
  2915. foreach($warehouseInventoryResult as $value){
  2916. $warehouseInventory[$value['skuId']] = $value;
  2917. }
  2918. //转换数量
  2919. $inventoryData = [];
  2920. foreach($skuData as $key => $value){
  2921. $inventoryNum = $warehouseInventory[$value['masterSkuId']]['inventoryNum'];
  2922. if($inventoryNum > 0){
  2923. if($value['isMaster'] == StatusCode::$standard){
  2924. $inventoryData[$key]['num'] = $inventoryNum;
  2925. }else{
  2926. if($value['isNew'] == StatusCode::$standard){
  2927. $inventoryData[$key]['num'] = bcdiv($inventoryNum, $value['conversion'], 8);
  2928. }else{
  2929. $inventoryData[$key]['num'] = bcmul($inventoryNum, $value['conversion'], 8);
  2930. }
  2931. }
  2932. }else{
  2933. $inventoryData[$key]['num'] = 0;
  2934. }
  2935. }
  2936. return ResultWrapper::success($inventoryData);
  2937. }
  2938. /**
  2939. * 根据goodsIds和仓库ids查询库存
  2940. * @param $data
  2941. * @return ResultWrapper
  2942. * @deprecated
  2943. */
  2944. public function getInventoryByGoodsIds($data)
  2945. {
  2946. if (empty($data)) return ResultWrapper::success($data);
  2947. $materielIds = array_column($data, 'goodsId');
  2948. $warehouseIds = [];
  2949. foreach($data as $value){
  2950. $warehouseIds = array_merge($warehouseIds, $value['warehouseId']);
  2951. }
  2952. if(!$materielIds || !$warehouseIds){
  2953. return ResultWrapper::fail('查询库存传参错误', ErrorCode::$paramError);
  2954. }
  2955. $inventoryData = $this->objDInventory->select(['materielId' => $materielIds, 'warehouseId' => $warehouseIds], 'materielId,warehouseId,inventoryNum,skuId,costPrice');
  2956. if ($inventoryData === false) {
  2957. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  2958. }
  2959. $formatInventoryData = [];
  2960. $skuInventoryData = [];
  2961. foreach ($inventoryData as $value) {
  2962. $md5Key = md5($value['warehouseId'] .'+'. $value['materielId']);
  2963. $md5SkuKey = md5($value['warehouseId'] .'+'. $value['skuId']);
  2964. $formatInventoryData[$md5Key]['inventoryNum'] = isset($formatInventoryData[$md5Key]) ? bcadd($formatInventoryData[$md5Key]['inventoryNum'], $value['inventoryNum'], 8) : $value['inventoryNum'];
  2965. $formatInventoryData[$md5Key]['skuData'][] = $value['skuId'];
  2966. $skuInventoryData[$md5SkuKey]['inventoryNum'] = $value['inventoryNum'];
  2967. $skuInventoryData[$md5SkuKey]['materielId'] = $value['materielId'];
  2968. $skuInventoryData[$md5SkuKey]['skuId'] = $value['skuId'];
  2969. $skuInventoryData[$md5SkuKey]['inventoryNum'] = $value['inventoryNum'];
  2970. $skuInventoryData[$md5SkuKey]['warehouseId'] = $value['warehouseId'];
  2971. $skuInventoryData[$md5SkuKey]['costPrice'] = $value['costPrice'];
  2972. }
  2973. foreach ($data as $key => &$value) {
  2974. $value['num'] = 0;
  2975. $value['skuData'] = [];
  2976. foreach($value['warehouseId'] as $v){
  2977. $md5Key = md5($v .'+'. $value['goodsId']);
  2978. if(isset($formatInventoryData[$md5Key])){
  2979. $value['num'] = bcadd($value['num'],$formatInventoryData[$md5Key]['inventoryNum']);
  2980. $skuData = $formatInventoryData[$md5Key]['skuData'];
  2981. foreach($skuData as $skuId){
  2982. $md5SkuKey = md5($v .'+'. $skuId);
  2983. if(isset($skuInventoryData[$md5SkuKey])){
  2984. $value['skuData'][$skuId]['inventoryNum'] = isset($value['skuData'][$skuId]['inventoryNum']) ? bcadd($value['skuData'][$skuId]['inventoryNum'],$skuInventoryData[$md5SkuKey]['inventoryNum']) : $skuInventoryData[$md5SkuKey]['inventoryNum'];
  2985. $value['skuData'][$skuId]['warehouseInventory'][$v] = $skuInventoryData[$md5SkuKey];
  2986. }
  2987. }
  2988. }
  2989. }
  2990. }
  2991. return ResultWrapper::success($data);
  2992. }
  2993. /**
  2994. * 根据skuIds查询所有库存
  2995. * @param array $skuIds
  2996. * @return ResultWrapper
  2997. */
  2998. public function getInventoryBySkuIds(array $skuIds)
  2999. {
  3000. if(empty($skuIds)) return ResultWrapper::fail('参数为空', ErrorCode::$paramError);
  3001. $dbResult = $this->objDInventory->select(['skuId'=> $skuIds]);
  3002. if($dbResult === false){
  3003. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  3004. }
  3005. $formatData = [];
  3006. foreach($dbResult as $value) {
  3007. $inventoryAllNum = bcadd($value['inventoryNum'], $value['lockInventory'], 8);
  3008. if(isset($formatData[$value['skuId']])){
  3009. $formatData[$value['skuId']] = bcadd($formatData[$value['skuId']],$inventoryAllNum, 8);
  3010. }else{
  3011. $formatData[$value['skuId']] = $inventoryAllNum;
  3012. }
  3013. }
  3014. return ResultWrapper::success($formatData);
  3015. }
  3016. /**
  3017. * 根据materielIds查询所有库存
  3018. * @param array $materielIds
  3019. * @return ResultWrapper
  3020. */
  3021. public function getInventoryByMaterielIds(array $materielIds)
  3022. {
  3023. if(empty($materielIds)) return ResultWrapper::fail('参数为空', ErrorCode::$paramError);
  3024. $dbResult = $this->objDInventory->select(['materielId'=> $materielIds]);
  3025. if($dbResult === false){
  3026. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  3027. }
  3028. $formatData = [];
  3029. foreach($dbResult as $value) {
  3030. $inventoryAllNum = bcadd($value['inventoryNum'], $value['lockInventory'], 8);
  3031. if(isset($formatData[$value['materielId']])){
  3032. $formatData[$value['materielId']] = bcadd($formatData[$value['materielId']],$inventoryAllNum, 8);
  3033. }else{
  3034. $formatData[$value['materielId']] = $inventoryAllNum;
  3035. }
  3036. }
  3037. return ResultWrapper::success($formatData);
  3038. }
  3039. /**
  3040. * 根据物料ids查询库存物料剩余数量
  3041. * @param $materielData
  3042. * @return ResultWrapper
  3043. */
  3044. public function getNumByMaterielIds($materielData)
  3045. {
  3046. $where = [
  3047. 'warehouseId' => [],
  3048. 'materielId' => [],
  3049. ];
  3050. foreach ($materielData as $key => $value) {
  3051. if (!in_array($value['warehouseId'], $where['warehouseId'])) {
  3052. $where['warehouseId'][] = $value['warehouseId'];
  3053. }
  3054. $where['materielId'][] = $value['materielId'];
  3055. }
  3056. $dbResult = $this->objDInventory->select($where, 'materielId,warehouseId,inventoryNum,lockInventory');
  3057. if ($dbResult === false) {
  3058. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  3059. }
  3060. $formatData = [];
  3061. foreach ($dbResult as $key => $value) {
  3062. $formatData[$value['warehouseId']][$value['materielId']]['inventoryNum'] = $value['inventoryNum'];
  3063. $formatData[$value['warehouseId']][$value['materielId']]['lockInventory'] = $value['lockInventory'];
  3064. }
  3065. return ResultWrapper::success($formatData);
  3066. }
  3067. /**
  3068. * 库存详情
  3069. * @param $params
  3070. * @return ResultWrapper
  3071. */
  3072. public function getInventoryInfo($params)
  3073. {
  3074. //注意!!!! 获取详情需要按照创建日期重新获取表名
  3075. $params['deleteStatus'] = StatusCode::$standard;
  3076. $dbResult = $this->objDInventory->get($params);
  3077. if ($dbResult === false) {
  3078. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  3079. }
  3080. $dbResult['orderGoodsData'] = $this->objDInventoryDetails->select(['InventoryId' => $dbResult['id']]);
  3081. if ($dbResult['orderGoodsData'] === false) {
  3082. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  3083. }
  3084. return ResultWrapper::success($dbResult);
  3085. }
  3086. /**
  3087. * 库存查询列表
  3088. * @param $selectParams
  3089. * @param $export
  3090. * @return ResultWrapper
  3091. * @throws Exception
  3092. */
  3093. public function getInventoryAll($selectParams, $export = 0)
  3094. {
  3095. $limit = $selectParams['limit'];
  3096. unset($selectParams['limit']);
  3097. $offset = $selectParams['offset'];
  3098. unset($selectParams['offset']);
  3099. if($export){
  3100. $limit = 99999;
  3101. $offset = 0;
  3102. }
  3103. if ((isset($selectParams['materielName']) && !empty($selectParams['materielName'])) || (isset($selectParams['categoryId']) && !empty($selectParams['categoryId']))) {
  3104. $objDGoodsBasic = new DGoodsBasic('default');
  3105. $objDGoodsBasic->setTable( 'qianniao_goods_basic_' . $this->enterpriseId);
  3106. $sql = 'select id from '.$objDGoodsBasic->get_Table().' where ';
  3107. $whereSql = '';
  3108. if( isset($selectParams['materielName']) && !empty($selectParams['materielName']) ){
  3109. $whereSql .= (!empty($whereSql) ? ' and ' : '').' title like "%' . $selectParams['materielName'] . '%" ';
  3110. }
  3111. if( isset($selectParams['categoryId']) && !empty($selectParams['categoryId']) ){
  3112. $whereSql .= (!empty($whereSql) ? ' and ' : '')." FIND_IN_SET('".$selectParams['categoryId']."',categoryPath) ";
  3113. }
  3114. if( isset($selectParams['merchantId']) && $selectParams['merchantId'] != 0 ){
  3115. $whereSql .= (!empty($whereSql) ? ' and ' : '').' merchantId = ' . $selectParams['merchantId'];
  3116. }
  3117. $sql = $sql.$whereSql;
  3118. $dbResult = $objDGoodsBasic->query($sql);
  3119. if ($dbResult === false) {
  3120. return ResultWrapper::fail($objDGoodsBasic->error(), ErrorCode::$dberror);
  3121. }
  3122. $selectParams['materielId'] = [];
  3123. foreach ($dbResult as $value) {
  3124. $selectParams['materielId'][] = $value['id'];
  3125. }
  3126. unset($selectParams['materielName']);
  3127. unset($selectParams['categoryId']);
  3128. if (empty($selectParams['materielId'])) {
  3129. $return['amount'] = 0;
  3130. $return['count'] = 0;
  3131. $return['data'] = [];
  3132. $return['total'] = 0;
  3133. return ResultWrapper::success($return);
  3134. }
  3135. }
  3136. //拼接sql
  3137. $sql = 'select * from qianniao_inventory_'.$this->enterpriseId;
  3138. $whereSql = '';
  3139. if( isset($selectParams['materielId']) && !empty($selectParams['materielId']) ){
  3140. $whereSql .= (empty($whereSql) ? '' : ' and ').' materielId in('.implode(',', $selectParams['materielId']).')';
  3141. }
  3142. if( isset($selectParams['materielId']) && !empty($selectParams['materielId']) ){
  3143. $whereSql .= (empty($whereSql) ? '' : ' and ').' materielId in('.implode(',', $selectParams['materielId']).')';
  3144. }
  3145. if( isset($selectParams['merchantId']) && $selectParams['merchantId'] != 0 ){
  3146. $whereSql .= (empty($whereSql) ? '' : ' and ').' merchantId = '.$selectParams['merchantId'];
  3147. }
  3148. if( isset($selectParams['haveInventoryNum']) && !empty($selectParams['haveInventoryNum']) ){
  3149. switch ($selectParams['haveInventoryNum']) {
  3150. case StatusCode::$standard; // 只查询有库存数量和锁定数量的数据
  3151. $whereSql .= (empty($whereSql) ? '' : ' and ').'( inventoryNum >= 0 )';
  3152. break;
  3153. case StatusCode::$delete;// 只查询没有库存数量和锁定数量的数据
  3154. $whereSql .= (empty($whereSql) ? '' : ' and ').' inventoryNum = 0 and lockInventory = 0 ';
  3155. break;
  3156. case StatusCode::$partion;//只查询库存为负数的数据
  3157. $whereSql .= (empty($whereSql) ? '' : ' and ').' inventoryNum < 0 ';
  3158. break;
  3159. }
  3160. }
  3161. if( isset($selectParams['materielCode']) && !empty($selectParams['materielCode']) ){
  3162. $whereSql .= (empty($whereSql) ? '' : ' and ').' materielCode = "'.$selectParams['materielCode'].'"';
  3163. }
  3164. !empty($whereSql) && $whereSql = ' where '.$whereSql;
  3165. $orderSql = ' order by createTime desc';
  3166. if( isset($selectParams['sortType']) ){
  3167. switch (true){
  3168. case $selectParams['sortType'] ==0;
  3169. $orderSql = ' order by createTime desc';
  3170. break;
  3171. case $selectParams['sortType'] ==1;
  3172. $orderSql = ' order by inventoryNum desc';
  3173. break;
  3174. case $selectParams['sortType'] ==2;
  3175. $orderSql = ' order by inventoryNum asc';
  3176. break;
  3177. case $selectParams['sortType'] ==3;
  3178. $orderSql = ' order by lockInventory desc';
  3179. break;
  3180. case $selectParams['sortType'] ==4;
  3181. $orderSql = ' order by lockInventory asc';
  3182. break;
  3183. }
  3184. }
  3185. $limitSql = ' limit '.$offset.','.$limit;
  3186. $sql = $sql.$whereSql.$orderSql.$limitSql;
  3187. $dbResult = $this->objDInventory->query($sql);
  3188. if ($dbResult === false) {
  3189. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  3190. }
  3191. $sql = "select count(materielId) as count,sum(costPrice) as totalCostPrice from " . $this->objDInventory->get_Table();
  3192. if(isset($selectParams['merchantId'])){
  3193. $sql .= ' where merchantId = '.$selectParams['merchantId'];
  3194. }
  3195. $totalData = $this->objDInventory->query($sql);
  3196. if ($totalData === false) {
  3197. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  3198. }
  3199. $amount = 0;
  3200. $count = 0;
  3201. if (!empty($totalData)) {
  3202. $shiftData = array_shift($totalData);
  3203. $count = $shiftData['count'];
  3204. $amount = $shiftData['totalCostPrice'];
  3205. }
  3206. $sql = 'select count(*) as count from qianniao_inventory_'.$this->enterpriseId.$whereSql;
  3207. $totalResult = $this->objDInventory->query($sql);
  3208. if ($totalResult === false) {
  3209. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  3210. }
  3211. $total = isset($totalResult[0]) ? $totalResult[0]['count'] : 0;
  3212. $formatData = parent::formatOrderMan($this->enterpriseId, $dbResult);
  3213. $modelResult = self::formatSkuNum($formatData);
  3214. if(!$modelResult->isSuccess()){
  3215. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  3216. }
  3217. $return['data'] = $modelResult->getData();
  3218. $return['amount'] = $amount;
  3219. $return['count'] = $count;
  3220. $return['total'] = $total;
  3221. if ($export) {
  3222. // $dbResult = $this->objDInventory->select($selectParams, '*', 'id desc');
  3223. // if ($dbResult === false) {
  3224. // return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  3225. // }
  3226. // $modelResult = self::formatSkuNum($dbResult);
  3227. // if(!$modelResult->isSuccess()){
  3228. // return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  3229. // }
  3230. self::exportInventory($return['data']);
  3231. exit;
  3232. }
  3233. if ($return === false) {
  3234. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  3235. }
  3236. $this->updateCache = true;
  3237. return ResultWrapper::success($return);
  3238. }
  3239. /**
  3240. * 仓库库存
  3241. */
  3242. public function getWarehouseInventory($params)
  3243. {
  3244. $sql = 'select i.materielId,i.materielCode,i.skuId,i.inventoryNum,i.inventoryNum * i.costPrice as total,i.costPrice,i.warehouseId,i.createTime,i.updateTime,w.warehouseName,w.id as warehouseId from qianniao_inventory_warehouse_'.$this->enterpriseId.' i left join qianniao_warehouse_'.$this->enterpriseId.' w on i.warehouseId = w.id where i.skuId = '.$params['skuId'].' order by i.sort,i.createTime desc';
  3245. $dbResult = $this->objDInventory->query($sql);
  3246. if($dbResult === false){
  3247. return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror);
  3248. }
  3249. $formatData = parent::formatOrderMan($this->enterpriseId, $dbResult);
  3250. $modelResult = self::formatSkuNum($formatData);
  3251. if(!$modelResult->isSuccess()){
  3252. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  3253. }
  3254. $return = $modelResult->getData();
  3255. return ResultWrapper::success($return);
  3256. }
  3257. /**
  3258. * 格式化skuNum
  3259. * @param $params //二维数组
  3260. * @param string $materielIdKey //商品基础资料id的key
  3261. * @param string $inventoryNumKey //商品数量的key
  3262. * @param string $skuIdKey //商品skuId的key
  3263. * @return ResultWrapper
  3264. * @throws \Exception
  3265. */
  3266. public function formatSkuNum($params, $materielIdKey = 'materielId', $inventoryNumKey = 'inventoryNum', $skuIdKey = 'skuId')
  3267. {
  3268. if(empty($params)) return ResultWrapper::success($params);
  3269. //获取所有基础资料id
  3270. $materielIds = array_column(array_values($params), $materielIdKey);
  3271. $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId);
  3272. //获取所有skuIds
  3273. $modelResult = $objMSku->getSkuDataByGoodsIds($materielIds);
  3274. if (!$modelResult->isSuccess()) {
  3275. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  3276. }
  3277. $skuData = $modelResult->getData();
  3278. unset($modelResult);
  3279. foreach($params as &$value){
  3280. $value['skuValue'] = '';
  3281. $value['skuNum'] = '0';
  3282. //取出sku数据
  3283. if(isset($skuData[$value[$materielIdKey]]) && isset($skuData[$value[$materielIdKey]][$value[$skuIdKey]])){
  3284. //获取当前单位sku
  3285. $selectSkuData = $skuData[$value[$materielIdKey]][$value[$skuIdKey]];
  3286. $skuParam = [];
  3287. $masterSku = [];//主单位
  3288. //获取所有sku
  3289. foreach($skuData[$value[$materielIdKey]] as $v){
  3290. if($v['isMaster'] == StatusCode::$delete){
  3291. if($selectSkuData['specType'] == 2){
  3292. //有属性 比对哈希 找出同类型单位
  3293. if($v['specGroupHash'] == $selectSkuData['specGroupHash']){
  3294. $skuParam[] = $v;
  3295. }
  3296. }else{
  3297. //无属性 都是同类型单位
  3298. $skuParam[] = $v;
  3299. }
  3300. }else{
  3301. $v['conversion'] = 1;
  3302. $skuParam[] = $v;
  3303. $masterSku = $v;
  3304. }
  3305. }
  3306. if(!empty($skuParam)){
  3307. //重新排序sku
  3308. $conversions = array_column($skuParam,'conversion');
  3309. if($masterSku['isNew'] == StatusCode::$standard){
  3310. $order = SORT_DESC;
  3311. }else{
  3312. $order = SORT_ASC;
  3313. }
  3314. array_multisort($conversions,$order,$skuParam);
  3315. //最小单位
  3316. $smallSku = array_pop($skuParam);
  3317. $skuParam[] = $smallSku;
  3318. //主单位换算比例修改
  3319. if($selectSkuData['isMaster'] == StatusCode::$standard){
  3320. $selectSkuData['conversion'] = 1;
  3321. }
  3322. //主单位数量
  3323. if($masterSku['isNew'] == StatusCode::$standard){
  3324. //新
  3325. //辅换主 乘
  3326. $masterNum = bcmul($value[$inventoryNumKey], $selectSkuData['conversion']);//主单位数量
  3327. //主换辅 除
  3328. $smallNum = bcdiv($masterNum, $smallSku['conversion']);//最小单位数量
  3329. }else{
  3330. //旧
  3331. //辅换主 除
  3332. $masterNum = bcdiv($value[$inventoryNumKey], $selectSkuData['conversion']);//主单位数量
  3333. //主换辅 乘
  3334. $smallNum = bcmul($masterNum, $smallSku['conversion']);//最小单位数量
  3335. }
  3336. foreach($skuParam as $sku){
  3337. //拼接比例
  3338. if($sku['isMaster'] == StatusCode::$delete){
  3339. if($masterSku['isNew'] == StatusCode::$standard) {
  3340. $skuValues = '1'.$sku['unitName'].'='.floatval($sku['conversion']).$masterSku['unitName'];
  3341. }else{
  3342. $skuValues = '1'.$masterSku['unitName'].'='.floatval($sku['conversion']).$sku['unitName'];
  3343. }
  3344. $value['skuValue'] .= (empty($value['skuValue']) ? '':'/').$skuValues;
  3345. }
  3346. if($masterSku['isNew'] == StatusCode::$standard){
  3347. //新
  3348. $conversion = bcdiv($sku['conversion'], $smallSku['conversion']);
  3349. }else{
  3350. //旧
  3351. $conversion = bcdiv($smallSku['conversion'], $sku['conversion']);
  3352. }
  3353. $skuNum = intval(bcdiv($smallNum , $conversion));
  3354. //计算数量
  3355. if($skuNum > 0){
  3356. $smallNum = $smallNum % $conversion;
  3357. $value['skuNum'] == '0' && $value['skuNum'] = '';
  3358. $value['skuNum'] .= floatval($skuNum).$sku['unitName'];
  3359. }
  3360. }
  3361. }
  3362. }
  3363. }
  3364. return ResultWrapper::success($params);
  3365. }
  3366. /**
  3367. * 换算sku数量
  3368. * @param $params
  3369. * @return ResultWrapper
  3370. * @throws \Exception
  3371. */
  3372. public function getSkuNum($params)
  3373. {
  3374. $modelResult = self::formatSkuNum($params,'goodsBasicId','num','skuId');
  3375. if(!$modelResult->isSuccess()){
  3376. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  3377. }
  3378. $data = $modelResult->getData();
  3379. unset($modelResult);
  3380. $return = [];
  3381. foreach($data as $value){
  3382. $return[$value['skuId']] = $value;
  3383. }
  3384. return ResultWrapper::success($return);
  3385. }
  3386. /**
  3387. * 换算主单位sku数量
  3388. * @param $params
  3389. * @return ResultWrapper
  3390. * @throws \Exception
  3391. */
  3392. public function getMasterSkuNum($params)
  3393. {
  3394. $modelResult = self::formatMasterSkuNum($params,'goodsBasicId','num','skuId');
  3395. if(!$modelResult->isSuccess()){
  3396. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  3397. }
  3398. $data = $modelResult->getData();
  3399. unset($modelResult);
  3400. $return = [];
  3401. foreach($data as $value){
  3402. $return[$value['skuId']] = $value;
  3403. }
  3404. return ResultWrapper::success($return);
  3405. }
  3406. /**
  3407. * 换算主单位sku数量
  3408. * @param $params
  3409. * @param string $materielIdKey
  3410. * @param string $inventoryNumKey
  3411. * @param string $skuIdKey
  3412. * @return ResultWrapper
  3413. * @throws \Exception
  3414. */
  3415. public function formatMasterSkuNum($params, $materielIdKey = 'materielId', $inventoryNumKey = 'inventoryNum', $skuIdKey = 'skuId')
  3416. {
  3417. //获取所有基础资料id
  3418. $materielIds = array_column(array_values($params), $materielIdKey);
  3419. $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId);
  3420. //获取所有skuIds
  3421. $modelResult = $objMSku->getSkuDataByGoodsIds($materielIds);
  3422. if (!$modelResult->isSuccess()) {
  3423. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  3424. }
  3425. $skuData = $modelResult->getData();
  3426. unset($modelResult);
  3427. foreach($params as &$value){
  3428. $value['masterNum'] = 0;
  3429. $value['masterName'] = '';
  3430. $value['skuNum'] = 0;
  3431. $value['skuValue'] = '';
  3432. $value['skuName'] = '';
  3433. $value['title'] = '';
  3434. if(isset($skuData[$value[$materielIdKey]])){
  3435. $skuParam = $skuData[$value[$materielIdKey]][$value[$skuIdKey]];
  3436. $value['masterName'] = $skuParam['unitName'];
  3437. $value['masterNum'] = floatval($value[$inventoryNumKey]);
  3438. $value['skuNum'] = $value[$inventoryNumKey];
  3439. $value['skuName'] = $skuParam['unitName'];
  3440. if($skuParam['isMaster'] == StatusCode::$delete){
  3441. if($skuParam['isNew'] == StatusCode::$standard){
  3442. //新 乘
  3443. $value['masterNum'] = floatval(bcmul($value[$inventoryNumKey], $skuParam['conversion'], 2));
  3444. $value['skuNum'] = bcdiv($value['masterNum'], $skuParam['conversion'], 2);
  3445. }else{
  3446. //旧 除
  3447. $value['masterNum'] = floatval(bcdiv($value[$inventoryNumKey], $skuParam['conversion'], 2));
  3448. $value['skuNum'] = bcmul($value['masterNum'], $skuParam['conversion'], 2);
  3449. }
  3450. $skuArray = $skuData[$value[$materielIdKey]];
  3451. $masterSku = [];
  3452. foreach($skuArray as $v){
  3453. if($v['isMaster'] == StatusCode::$standard){
  3454. $masterSku = $v;
  3455. }
  3456. }
  3457. $value['masterName'] = $masterSku['unitName'];
  3458. if($skuParam['isNew'] == StatusCode::$standard) {
  3459. $value['skuValue'] = '1'.$skuParam['unitName'].'='.floatval($skuParam['conversion']).$masterSku['unitName'];
  3460. }else{
  3461. $value['skuValue'] = '1'.$masterSku['unitName'].'='.floatval($skuParam['conversion']).$skuParam['unitName'];
  3462. }
  3463. }
  3464. }
  3465. if($value[$inventoryNumKey] != $value['skuNum']){
  3466. $value['title'] = $value['skuValue'].','.$value[$inventoryNumKey].$value['skuName'].'无法换算为'.$value['masterName'].',请输入正确的数量(换算比例的倍数)';
  3467. $value[$inventoryNumKey] = 0;
  3468. }
  3469. }
  3470. return ResultWrapper::success($params);
  3471. }
  3472. /**
  3473. * 库存导出方法
  3474. * @param $result
  3475. * @return void
  3476. * @throws Exception
  3477. */
  3478. public function exportInventory($result)
  3479. {
  3480. //导出到本地
  3481. header("Content-type:application/vnd.ms-excel");
  3482. header("Content-Disposition:filename=库存记录表.csv");
  3483. header('Cache-Control: max-age=0');
  3484. $fp = fopen('php://output', 'a');
  3485. $head = ['商品编码','商品名称', '商品规格', '可售库存', '占用库存', '换算比例', '换算库存','其他单位']; //定义标题
  3486. foreach ($head as $i => $v) {
  3487. $head[$i] = mb_convert_encoding($v, 'GBK', 'utf-8'); //将中文标题转换编码,否则乱码
  3488. }
  3489. fputcsv($fp, $head);
  3490. $limit = 10000;
  3491. $num = 0; //计数器
  3492. foreach ($result as $v) { //循环数据
  3493. $num++;
  3494. if ($num == $limit) {
  3495. ob_flush(); //释放内存
  3496. flush();
  3497. }
  3498. $v = parent::formatOrderMan($this->enterpriseId, $v);
  3499. $rows['materielCode'] = isset($v['materielCode']) ? $v['materielCode'] : ''; //商品编码
  3500. $rows['materielName'] = isset($v['materielName']) ? $v['materielName'] : ''; //商品名称
  3501. $rows['unitName'] = isset($v['unitName']) ? $v['unitName'] : ''; //商品规格
  3502. $rows['inventoryNum'] = isset($v['inventoryNum']) ? $v['inventoryNum'] : ''; //可售库存
  3503. $rows['lockInventory'] = isset($v['lockInventory']) ? $v['lockInventory'] : ''; //占用库存
  3504. $rows['skuValue'] = $v['isEq'] == 4 ? $v['skuValue'] : ''; //换算比例
  3505. $rows['skuNum'] = isset($v['skuNum']) ? $v['skuNum'] : ''; //换算库存
  3506. $rows['otherNum'] = isset($v['otherNum']) ? $v['otherNum'] : ''; //其他单位
  3507. // $rows['materielName'] = isset($v['materielName']) ? $v['materielName'] : '';
  3508. //// $rows['warehouseName'] = isset($v['warehouseName']) ? $v['warehouseName'] : '';
  3509. // $rows['unitName'] = isset($v['unitName']) ? $v['unitName'] : '';
  3510. //// $rows['skuName'] = isset($v['skuName']) ? $v['skuName'] : '';
  3511. // $rows['inventoryNum'] = isset($v['inventoryNum']) ? $v['inventoryNum'] : '';
  3512. // $rows['lockInventory'] = isset($v['lockInventory']) ? $v['lockInventory'] : '';
  3513. //// $rows['skuValues'] = isset($v['skuValues']) ? $v['skuValues'] : '';
  3514. // $rows['skuNums'] = isset($v['skuNums']) ? $v['skuNums'] : '';
  3515. // $rows['skuNum'] = isset($v['skuNum']) ? $v['skuNum'] : '';
  3516. // $rows['otherNum'] = isset($v['otherNum']) ? $v['otherNum'] : '';
  3517. //// $rows['costPrice'] = isset($v['costPrice']) ? $v['costPrice'] : '';
  3518. //// $rows['total'] = bcmul($v['inventoryNum'], $v['costPrice'], 4);
  3519. foreach ($rows as $kk => $vv) {
  3520. $rs[$kk] = mb_convert_encoding($vv, 'GBK', 'utf-8'); //转译编码
  3521. }
  3522. fputcsv($fp, $rs);
  3523. $rows = [];
  3524. }
  3525. }
  3526. /**
  3527. * 库存流水列表
  3528. * @param $selectParams
  3529. * @param $export
  3530. * @return ResultWrapper
  3531. * @throws Exception
  3532. */
  3533. public function getInventoryDetailsAll($selectParams, $export)
  3534. {
  3535. $limit = $selectParams['limit'];
  3536. unset($selectParams['limit']);
  3537. $offset = $selectParams['offset'];
  3538. unset($selectParams['offset']);
  3539. self::setDetailsTable($this->enterpriseId, $selectParams['warehouseId']);
  3540. unset($selectParams['warehouseId']);
  3541. $dbResult = $this->objDInventoryDetails->select($selectParams, '*', 'id desc', $limit, $offset);
  3542. if ($dbResult === false) {
  3543. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  3544. }
  3545. foreach($dbResult as &$value){
  3546. !empty($value['batch']) && $value['batch'] = json_decode($value['batch'], true);
  3547. $value = $this->formatInventoryDetails($value);
  3548. }
  3549. unset($value);
  3550. $total = $this->objDInventoryDetails->count($selectParams);
  3551. $formatData = parent::formatOrderMan($this->enterpriseId, $dbResult);
  3552. $return['data'] = $formatData;
  3553. $return['total'] = ($total) ? intval($total) : 0;
  3554. if ($export) {
  3555. self::exportInventoryDetails($return['data']);
  3556. exit;
  3557. }
  3558. if ($return === false) {
  3559. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  3560. } else {
  3561. return ResultWrapper::success($return);
  3562. }
  3563. }
  3564. /**
  3565. * 格式化流水数据
  3566. * @param $value
  3567. * @return mixed
  3568. */
  3569. public function formatInventoryDetails($value)
  3570. {
  3571. //移动加权
  3572. $value['costPrice'] = $value['averageCost'];
  3573. //个别计价
  3574. if($value['actionType'] == StatusCode::$standard){
  3575. //入库
  3576. if($value['costType'] == StatusCode::$costType['sp']){
  3577. $batch = json_decode($value['batch'], true);
  3578. $batchData = array_shift($batch);
  3579. $value['costPrice'] = isset($batchData['batchCost']) ? $batchData['batchCost'] : 0;
  3580. }
  3581. }else{
  3582. //出库
  3583. if($value['costType'] == StatusCode::$costType['sp']){
  3584. $batch = json_decode($value['batch'], true);
  3585. $total = 0;//出库总价
  3586. foreach($batch as $v){
  3587. $total = $total + ($v['batchCost'] * $v['num']);
  3588. }
  3589. $value['costPrice'] = $total / $value['inventoryNum'];
  3590. }
  3591. }
  3592. return $value;
  3593. }
  3594. /**
  3595. * 流水列表搜索
  3596. * @param $params
  3597. * @param $export
  3598. * @return ResultWrapper
  3599. * @throws \Exception
  3600. */
  3601. public function searchAllInventoryDetails($params, $export)
  3602. {
  3603. $defaultDSL = ['from' => $params['offset'], 'size' => $params['limit'], 'sort' => ['createTime' => ['order' => 'desc']]];
  3604. $selectParams = [];
  3605. $selectParams[] = ['term' => ['enterpriseId' => $this->enterpriseId]];
  3606. !empty($params['warehouseId']) && $selectParams[] = ['term' => ['warehouseId' => $params['warehouseId']]];
  3607. !empty($params['operatorId']) && $selectParams[] = ['term' => ['operatorId' => $params['operatorId']]];
  3608. !empty($params['skuId']) && $selectParams[] = ['term' => ['skuId' => $params['skuId']]];
  3609. (!empty($params['start']) && !empty($params['end'])) && $selectParams[] = ['range' => ['createTime' => ['gte' => $params['start'], 'lte' => $params['end']]]];
  3610. !empty($params['search']) && $selectParams[] = ['multi_match' => ['fields' => ['sourceNo', 'materielName', 'batch.batch'], 'query' => $params['search'], "type" => "best_fields", "tie_breaker" => 0.3, "minimum_should_match" => "100%"]];
  3611. $dsl = [];
  3612. !empty($selectParams) && $dsl['query']['bool']['must'][] = $selectParams;
  3613. $dsl = array_merge($defaultDSL, $dsl);
  3614. // V(json_encode($dsl,true));
  3615. if ($export) {
  3616. $dbResult = $this->objDInventoryDetails->getScrollSearchQueryDsl($dsl);
  3617. if (isset($dbResult['error'])) {
  3618. return ResultWrapper::fail($dbResult, ErrorCode::$dberror);
  3619. }
  3620. $returnData = parent::formatEsSelectData($dbResult);
  3621. self::exportInventoryDetails($returnData['data']);
  3622. exit;
  3623. }
  3624. $dbResult = $this->objDInventoryDetails->getSearchQueryDsl($dsl);
  3625. if (isset($dbResult['error'])) {
  3626. return ResultWrapper::fail($dbResult, ErrorCode::$dberror);
  3627. }
  3628. $returnData = parent::formatEsSelectData($dbResult, $this->enterpriseId);
  3629. $objMCommon = new MCommon();
  3630. foreach($returnData['data'] as &$value){
  3631. $value = $this->formatInventoryDetails($value);
  3632. $value['sourceName'] = $objMCommon->formatOrderSource($value['source']);
  3633. }
  3634. return ResultWrapper::success($returnData);
  3635. }
  3636. /**
  3637. * 库存流水导出方法
  3638. * @param $result
  3639. * @return void
  3640. * @throws Exception
  3641. */
  3642. public function exportInventoryDetails($result)
  3643. {
  3644. //导出到本地
  3645. header("Content-type:application/vnd.ms-excel");
  3646. header("Content-Disposition:filename=库存流水记录表.csv");
  3647. header('Cache-Control: max-age=0');
  3648. $fp = fopen('php://output', 'a');
  3649. $head = ['单据编号', '制单时间', '单据类型', '商品名称', '出库','入库', '剩余量','其他单位','平均成本', '操作人']; //定义标题
  3650. foreach ($head as $i => $v) {
  3651. $head[$i] = mb_convert_encoding($v, 'GBK', 'utf-8'); //将中文标题转换编码,否则乱码
  3652. }
  3653. fputcsv($fp, $head);
  3654. $limit = 10000;
  3655. $num = 0; //计数器
  3656. foreach ($result as $value) { //循环数据
  3657. $num++;
  3658. if ($num == $limit) {
  3659. ob_flush(); //释放内存
  3660. flush();
  3661. }
  3662. $v = $this->formatInventoryDetails($value);
  3663. $v = parent::formatOrderMan($this->enterpriseId, $v);
  3664. $rows['sourceNo'] = isset($v['sourceNo']) ? $v['sourceNo'] : null;
  3665. $rows['createTime'] = date('Y-m-d H:i:s', $v['createTime']);
  3666. $rows['sourceName'] = isset($v['sourceName']) ? $v['sourceName'] : null;
  3667. $rows['materielName'] = isset($v['materielName']) ? $v['materielName'] : null;
  3668. $rows['Delivery'] = $v['actionType'] == StatusCode::$standard ? '' : '-' . $v['inventoryNum'];//出库
  3669. $rows['Warehousing'] = $v['actionType'] == StatusCode::$standard ? '+' . $v['inventoryNum'] : '';//入库
  3670. $rows['inventoryChangeNum'] = isset($v['inventoryChangeNum']) ? $v['inventoryChangeNum'] : null;
  3671. $rows['otherNum'] = isset($v['otherNum']) ? $v['otherNum'] : null;
  3672. $rows['costPrice'] = isset($v['costPrice']) ? $v['costPrice'] : null;
  3673. $rows['operatorName'] = isset($v['operatorName']) ? $v['operatorName'] : null;
  3674. foreach ($rows as $kk => $vv) {
  3675. $rs[$kk] = mb_convert_encoding($vv, 'GBK', 'utf-8'); //转译编码
  3676. }
  3677. fputcsv($fp, $rs);
  3678. $rows = [];
  3679. }
  3680. }
  3681. /**
  3682. * 库存汇总导出方法
  3683. * @param $result
  3684. * @param $hideAmount
  3685. * @param $reconciliation
  3686. * @return void
  3687. */
  3688. public function exportInventoryDetailsStatistics($result, $hideAmount,$reconciliation)
  3689. {
  3690. //导出到本地
  3691. header("Content-type:application/vnd.ms-excel");
  3692. header("Content-Disposition:filename=库存流水记录表.csv");
  3693. header('Cache-Control: max-age=0');
  3694. $fp = fopen('php://output', 'a');
  3695. if($reconciliation){
  3696. $head = ['商品名称','商品规格','其他单位','昨日结存总数量','今日入库数量','今日出库总数量','采购入库','采购退货出库','销售出库','销售退货入库','调拨入库','调拨出库','今日结存总数量']; //定义标题
  3697. } else {
  3698. if($hideAmount){
  3699. $head = ['商品编码', '商品名称','商品规格','其他单位', '上期结存数量', '本期入库数量', '本期出库数量', '本期结存数量']; //定义标题
  3700. } else {
  3701. $head = ['商品编码', '商品名称','商品规格','其他单位', '上期结存数量', '上期结存金额', '本期入库数量', '本期入库金额', '本期出库数量', '本期出库金额', '本期结存数量', '本期结存金额']; //定义标题
  3702. }
  3703. }
  3704. foreach ($head as $i => $v) {
  3705. $head[$i] = mb_convert_encoding($v, 'GBK', 'utf-8'); //将中文标题转换编码,否则乱码
  3706. }
  3707. fputcsv($fp, $head);
  3708. $limit = 10000;
  3709. $num = 0;//计数器
  3710. foreach ($result as $value) {//循环数据
  3711. foreach($value['Details']as $v){
  3712. $num++;
  3713. if ($num == $limit) {
  3714. ob_flush();//释放内存
  3715. flush();
  3716. }
  3717. if($reconciliation){
  3718. $rows['materielName'] = isset($value['materielName']) ? $value['materielName'] : null;//商品名称
  3719. $rows['skuName'] = isset($v['skuName']) ? $v['skuName'].(!empty($v['skuName']) ? '_' : '').$v['unitName'] : null;//商品规格
  3720. $rows['otherNum'] = isset($value['otherNum']) ? $value['otherNum'] : 0;//其他单位
  3721. $rows['topEndNum'] = isset($v['topEndNum']) ? $v['topEndNum'] : null;//昨日结存总数量
  3722. $rows['selfInNum'] = isset($v['selfInNum']) ? $v['selfInNum'] : null;//今日入库数量
  3723. $rows['selfOutNum'] = isset($v['selfOutNum']) ? $v['selfOutNum'] : null;//今日出库总数量
  3724. $rows['selfPurchaseInNum'] = isset($v['selfPurchaseInNum']) ? $v['selfPurchaseInNum'] : null;//采购入库
  3725. $rows['selfPurchaseReturnOutNum'] = isset($value['selfPurchaseReturnOutNum']) ? $value['selfPurchaseReturnOutNum'] : null;//采购退货出库
  3726. $rows['selfSaleOutNum'] = isset($value['selfSaleOutNum']) ? $value['selfSaleOutNum'] : null;//销售出库
  3727. $rows['selfSaleReturnInNum'] = isset($v['selfSaleReturnInNum']) ? $v['selfSaleReturnInNum'] : null;//销售退货入库
  3728. $rows['selfAllocateInNum'] = isset($v['selfAllocateInNum']) ? $v['selfAllocateInNum'] : null;//调拨入库
  3729. $rows['selfAllocateOutNum'] = isset($v['selfAllocateOutNum']) ? $v['selfAllocateOutNum'] : null;//调拨出库
  3730. $rows['selfEndNum'] = isset($v['selfEndNum']) ? $v['selfEndNum'] : null;//今日结存总数量
  3731. }else{
  3732. if($hideAmount){
  3733. $rows['materielCode'] = isset($value['materielCode']) ? $value['materielCode'] : null;
  3734. $rows['materielName'] = isset($value['materielName']) ? $value['materielName'] : null;
  3735. $rows['skuName'] = isset($v['skuName']) ? $v['skuName'].(!empty($v['skuName']) ? '_' : '').$v['unitName'] : null;
  3736. $rows['otherNum'] = isset($value['otherNum']) ? $value['otherNum'] : 0;//其他单位
  3737. $rows['topEndNum'] = isset($v['topEndNum']) ? $v['topEndNum'] : null;
  3738. $rows['selfInNum'] = isset($v['selfInNum']) ? $v['selfInNum'] : null;
  3739. $rows['selfOutNum'] = isset($v['selfOutNum']) ? $v['selfOutNum'] : null;
  3740. $rows['selfEndNum'] = isset($v['selfEndNum']) ? $v['selfEndNum'] : null;
  3741. }else{
  3742. $rows['materielCode'] = isset($value['materielCode']) ? $value['materielCode'] : null;
  3743. $rows['materielName'] = isset($value['materielName']) ? $value['materielName'] : null;
  3744. $rows['skuName'] = isset($v['skuName']) ? $v['skuName'].(!empty($v['skuName']) ? '_' : '').$v['unitName'] : null;
  3745. $rows['otherNum'] = isset($value['otherNum']) ? $value['otherNum'] : 0;//其他单位
  3746. $rows['topEndNum'] = isset($v['topEndNum']) ? $v['topEndNum'] : null;
  3747. $rows['topEndAmount'] = isset($v['topEndAmount']) ? $v['topEndAmount'] : null;
  3748. $rows['selfInNum'] = isset($v['selfInNum']) ? $v['selfInNum'] : null;
  3749. $rows['selfInAmount'] = isset($v['selfInAmount']) ? $v['selfInAmount'] : null;
  3750. $rows['selfOutNum'] = isset($v['selfOutNum']) ? $v['selfOutNum'] : null;
  3751. $rows['selfOutAmount'] = isset($v['selfOutAmount']) ? $v['selfOutAmount'] : null;
  3752. $rows['selfEndNum'] = isset($v['selfEndNum']) ? $v['selfEndNum'] : null;
  3753. $rows['selfEndAmount'] = isset($v['selfEndAmount']) ? $v['selfEndAmount'] : null;
  3754. }
  3755. }
  3756. foreach ($rows as $kk => $vv) {
  3757. $rs[$kk] = mb_convert_encoding($vv, 'GBK', 'utf-8'); //转译编码
  3758. }
  3759. fputcsv($fp, $rs);
  3760. $rows = [];
  3761. }
  3762. }
  3763. }
  3764. /**
  3765. * 计算表名
  3766. * @param $params
  3767. * @param string $table
  3768. * @return ResultWrapper
  3769. * @throws Exception
  3770. */
  3771. public function setInventoryDetailsTableName($params,$table = 'qianniao_inventory_details')
  3772. {
  3773. if(empty($params['warehouseId'])) return ResultWrapper::fail('仓库参数错误', ErrorCode::$paramError);
  3774. if(empty($params['start'])) return ResultWrapper::fail('开始时间参数错误', ErrorCode::$paramError);
  3775. if(empty($params['end'])) return ResultWrapper::fail('结束时间参数错误', ErrorCode::$paramError);
  3776. $table && $table = $table.'_'.$this->enterpriseId.'_'.$params['warehouseId'].'_';
  3777. $startTableTerm = self::setDetailsTableTerm($params['start']);
  3778. $endTableTerm = self::setDetailsTableTerm($params['end']);
  3779. $startYear = substr(date('Y', $params['start']), -2);
  3780. $endYear = substr(date('Y', $params['end']), -2);
  3781. if($startTableTerm == $endTableTerm){//同一个表
  3782. $dbResult = $this->objDInventoryDetails->existsTable($table.$startTableTerm);
  3783. if($dbResult){
  3784. return ResultWrapper::success([$table.$startTableTerm]);
  3785. }
  3786. return ResultWrapper::success([]);
  3787. }
  3788. //不同表
  3789. $tableNameArray = [];
  3790. for($ii = $startYear; $ii <= $endYear; $ii++){
  3791. for($i = 1; $i <= 4; $i++){
  3792. $term = $ii.$i;
  3793. if($startTableTerm <= $term && $term <= $endTableTerm){
  3794. $tableName = $table.$term;
  3795. $dbResult = $this->objDInventoryDetails->existsTable($tableName);
  3796. if($dbResult){//存在
  3797. $tableNameArray[] = $tableName;
  3798. }else{//不存在
  3799. continue;
  3800. }
  3801. }
  3802. }
  3803. }
  3804. return ResultWrapper::success($tableNameArray);
  3805. }
  3806. /**
  3807. * 库存流水详情列表
  3808. * @param $selectParams
  3809. * @param $export
  3810. * @param $hideAmount
  3811. * @return ResultWrapper
  3812. * @throws \Exception
  3813. */
  3814. public function getAllInventoryDetailsList($selectParams, $export, $hideAmount)
  3815. {
  3816. $limit = $selectParams['limit'];
  3817. unset($selectParams['limit']);
  3818. $offset = $selectParams['offset'];
  3819. unset($selectParams['offset']);
  3820. if(empty($selectParams['start']) && empty($selectParams['end'])){
  3821. $selectParams['start'] = 1546272000;//2 019-01-01 00:00:00
  3822. $selectParams['end'] = time();
  3823. }
  3824. $start = $selectParams['start'];
  3825. if($selectParams['start'] > $selectParams['end']){
  3826. $selectParams['start'] = $selectParams['end'];
  3827. $selectParams['end'] = $start;
  3828. }
  3829. // 计算分表
  3830. $modelResult = self::setInventoryDetailsTableName($selectParams);
  3831. if(!$modelResult->isSuccess()){
  3832. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  3833. }
  3834. $tableNameArray = $modelResult->getData();
  3835. if(empty($tableNameArray)){
  3836. $return['data'] = [];
  3837. $return['total'] = 0;
  3838. return ResultWrapper::success($return);
  3839. }
  3840. if ( strstr($selectParams["search"],'RK') or strstr($selectParams["search"],'CK')){
  3841. $status = strstr($selectParams["search"],'K',true).'K';
  3842. foreach (StatusCode::$noPrefix as $v){
  3843. if ($status ==$v){
  3844. $selectParams["search"] = substr($selectParams["search"],strlen($status));
  3845. break;
  3846. }
  3847. }
  3848. }
  3849. // 组装查询sql
  3850. $whereSql = '';
  3851. !empty($selectParams['search']) && $whereSql .= ' and materielName like "%'.$selectParams["search"].'%" or sourceNo like "%'.$selectParams["search"].'%"';
  3852. !empty($selectParams['skuId']) && $whereSql .= ' and skuId = '.$selectParams["skuId"];
  3853. !empty($selectParams['operatorId']) && $whereSql .= ' and operatorId = '.$selectParams["operatorId"];
  3854. !empty($selectParams['warehouseId']) && $whereSql .= ' and warehouseId = '.$selectParams["warehouseId"];
  3855. !empty($selectParams['merchantId']) && $whereSql .= ' and merchantId = '.$selectParams["merchantId"];
  3856. !empty($selectParams['source']) && $whereSql .= ' and source = '.$selectParams["source"];
  3857. $sql = '';
  3858. // $field = 'materielId,warehouseId,materielCode,materielName,createTime';
  3859. $field = '*';
  3860. foreach($tableNameArray as $tableName){
  3861. !empty($sql) && $sql = $sql.' union all ';
  3862. $sql = $sql . '(select '.$field.' from '.$tableName.' where createTime between '.$selectParams['start'].' and '.$selectParams['end'].' '.$whereSql.' )';
  3863. }
  3864. // $sql = 'select materielId,warehouseId,materielCode,materielName,createTime from ('.$sql.') as details group by materielId ';
  3865. $sql = 'select * from ('.$sql.') as details ';
  3866. $selectSql = $sql.'order by createTime desc limit '.$offset.','.$limit;
  3867. $dbResult = $this->objDInventoryDetails->query($selectSql);
  3868. if ($dbResult === false) {
  3869. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  3870. }
  3871. if(empty($dbResult)){
  3872. $return['data'] = [];
  3873. $return['total'] = 0;
  3874. return ResultWrapper::success($return);
  3875. }
  3876. // 计算总条数
  3877. $countSql = 'select count(materielId) as count from ( '.$sql.' ) as selectDetails';
  3878. $totalDbResult = $this->objDInventoryDetails->query($countSql);
  3879. if($totalDbResult === false){
  3880. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  3881. }
  3882. $total = array_shift($totalDbResult)['count'];
  3883. // 提取所有物料id
  3884. $materielIds = array_column($dbResult, 'materielId');
  3885. if(empty($materielIds)) return ResultWrapper::fail('物料id获取失败', ErrorCode::$paramError);
  3886. $sqlDetails = '';
  3887. foreach($tableNameArray as $tableName){
  3888. !empty($sqlDetails) && $sqlDetails = $sqlDetails.' union all ';
  3889. $sqlDetails = $sqlDetails . '(select * from '.$tableName.' where createTime between '.$selectParams['start'].' and '.$selectParams['end'].' and materielId in('.implode(',',$materielIds).') order by createTime desc )';
  3890. }
  3891. if ($export) {
  3892. $dbResult = $this->objDInventoryDetails->exportQuery($sqlDetails);
  3893. if ($dbResult === false) {
  3894. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  3895. }
  3896. $dbResult = self::formatInventoryStatistics($dbResult, true);
  3897. self::exportInventoryDetailsStatistics($dbResult, $hideAmount);
  3898. exit;
  3899. }
  3900. $return['data'] = self::formatOrderMan($this->enterpriseId, $dbResult);
  3901. $return['total'] = ($total) ? intval($total) : 0;
  3902. return ResultWrapper::success($return);
  3903. }
  3904. /**
  3905. * 库存汇总列表
  3906. * @param $selectParams
  3907. * @param $export
  3908. * @param $hideAmount
  3909. * @param $reconciliation
  3910. * @return ResultWrapper
  3911. * @throws \Exception
  3912. */
  3913. public function inventoryStatistics($selectParams, $export, $hideAmount,$reconciliation)
  3914. {
  3915. $limit = $selectParams['limit'];
  3916. unset($selectParams['limit']);
  3917. $offset = $selectParams['offset'];
  3918. unset($selectParams['offset']);
  3919. if(empty($selectParams['start']) && empty($selectParams['end'])){
  3920. $selectParams['start'] = 1546272000;//2019-01-01 00:00:00
  3921. $selectParams['end'] = time();
  3922. }
  3923. $start = $selectParams['start'];
  3924. if($selectParams['start'] > $selectParams['end']){
  3925. $selectParams['start'] = $selectParams['end'];
  3926. $selectParams['end'] = $start;
  3927. }
  3928. //计算分表
  3929. $modelResult = self::setInventoryDetailsTableName($selectParams);
  3930. if(!$modelResult->isSuccess()){
  3931. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  3932. }
  3933. $tableNameArray = $modelResult->getData();
  3934. if(empty($tableNameArray)){
  3935. $return['data'] = [];
  3936. $return['total'] = 0;
  3937. return ResultWrapper::success($return);
  3938. }
  3939. $whereSql = '';
  3940. !empty($selectParams['search']) && $whereSql = ' and materielName like "%'.$selectParams["search"].'%"';
  3941. !empty($selectParams['merchantId']) && $whereSql = ' and merchantId = '.$selectParams["merchantId"];
  3942. !empty($selectParams['materielCode']) && $whereSql = ' and materielCode = "'.$selectParams["materielCode"].'"';
  3943. $sql = '';
  3944. $field = 'materielId,warehouseId,materielCode,materielName,createTime,merchantId,otherNum';
  3945. foreach($tableNameArray as $tableName){
  3946. !empty($sql) && $sql = $sql.' union all ';
  3947. $sql = $sql . '(select '.$field.' from '.$tableName.' where createTime between '.$selectParams['start'].' and '.$selectParams['end'].$whereSql.' )';
  3948. }
  3949. $sql = 'select materielId,warehouseId,materielCode,materielName,createTime,otherNum from ('.$sql.') as details group by materielId ';
  3950. $selectSql = $sql.'order by createTime desc limit '.$offset.','.$limit;
  3951. $dbResult = $this->objDInventoryDetails->query($selectSql);
  3952. if ($dbResult === false) {
  3953. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  3954. }
  3955. if(empty($dbResult)){
  3956. $return['data'] = [];
  3957. $return['total'] = 0;
  3958. return ResultWrapper::success($return);
  3959. }
  3960. $countSql = 'select count(materielId) as count from ( '.$sql.' ) as selectDetails';
  3961. $totalDbResult = $this->objDInventoryDetails->query($countSql);
  3962. if($totalDbResult === false){
  3963. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  3964. }
  3965. $total = array_shift($totalDbResult)['count'];
  3966. $materielIds = array_column($dbResult, 'materielId');
  3967. if(empty($materielIds)) return ResultWrapper::fail('物料id获取失败', ErrorCode::$paramError);
  3968. $sqlDetails = '';
  3969. foreach($tableNameArray as $tableName){
  3970. !empty($sqlDetails) && $sqlDetails = $sqlDetails.' union all ';
  3971. $sqlDetails = $sqlDetails . '(select * from '.$tableName.' where createTime between '.$selectParams['start'].' and '.$selectParams['end'].' and materielId in('.implode(',',$materielIds).') order by createTime desc )';
  3972. }
  3973. if ($export) {
  3974. $dbResult = $this->objDInventoryDetails->exportQuery($sqlDetails);
  3975. if ($dbResult === false) {
  3976. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  3977. }
  3978. $dbResult = self::formatInventoryStatistics($dbResult, true);
  3979. self::exportInventoryDetailsStatistics($dbResult, $hideAmount,$reconciliation);
  3980. exit;
  3981. }
  3982. $midDbResult = $this->objDInventoryDetails->query($sqlDetails);
  3983. if($midDbResult === false){
  3984. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$paramError);
  3985. }
  3986. $formatData = self::formatInventoryStatistics($midDbResult, true);
  3987. $return['data'] = parent::formatOrderMan($this->enterpriseId,$formatData);
  3988. $return['total'] = ($total) ? intval($total) : 0;
  3989. return ResultWrapper::success($return);
  3990. }
  3991. /**
  3992. * 库存汇总搜索
  3993. * @param $params
  3994. * @param $export
  3995. * @param $hideAmount
  3996. * @return ResultWrapper
  3997. * @throws \Exception
  3998. */
  3999. public function searchInventoryStatistics($params, $export, $hideAmount)
  4000. {
  4001. $defaultDSL = ['from' => $params['offset'], 'size' => $params['limit'], 'sort' => ['id' => ['order' => 'desc']]];
  4002. $selectParams = [];
  4003. $selectParams[] = ['term' => ['enterpriseId' => $this->enterpriseId]];
  4004. !empty($params['warehouseId']) && $selectParams[] = ['term' => ['warehouseId' => $params['warehouseId']]];
  4005. (!empty($params['start']) && !empty($params['end'])) && $selectParams[] = ['range' => ['createTime' => ['gte' => $params['start'], 'lte' => $params['end']]]];
  4006. !empty($params['search']) && $selectParams[] = ['multi_match' => ['fields' => ['materielName', 'materielCode'], 'query' => $params['search'], "type" => "best_fields", "tie_breaker" => 0.3, "minimum_should_match" => "50%"]];
  4007. $dsl = [];
  4008. !empty($selectParams) && $dsl['query']['bool']['must'][] = $selectParams;
  4009. $dsl = array_merge($defaultDSL, $dsl);
  4010. if ($export) {
  4011. $dbResult = $this->objDInventoryDetails->getScrollSearchQueryDsl($dsl);
  4012. if (isset($dbResult['error'])) {
  4013. return ResultWrapper::fail($dbResult, ErrorCode::$dberror);
  4014. }
  4015. $returnData = parent::formatEsSelectData($dbResult);
  4016. $returnData['data'] = self::formatInventoryStatistics($returnData['data'], true);
  4017. self::exportInventoryDetailsStatistics($returnData['data'], $hideAmount);
  4018. exit;
  4019. }
  4020. $dbResult = $this->objDInventoryDetails->getSearchQueryDsl($dsl);
  4021. if (isset($dbResult['error'])) {
  4022. return ResultWrapper::fail($dbResult, ErrorCode::$dberror);
  4023. }
  4024. $returnData = parent::formatEsSelectData($dbResult, $this->enterpriseId);
  4025. $returnData['data'] = self::formatInventoryStatistics($returnData['data'], true);
  4026. return ResultWrapper::success($returnData);
  4027. }
  4028. /**
  4029. * 处理库存汇总数据
  4030. * @param $params
  4031. * @param bool $merge
  4032. * @return array
  4033. * @throws \Exception
  4034. */
  4035. public function formatInventoryStatistics($params, $merge = false)
  4036. {
  4037. if(empty($params)) return [];
  4038. $skuIds = array_column(array_values($params), 'skuId');
  4039. $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId);
  4040. $modelResult = $objMSku->getConversion($skuIds);
  4041. $skuData = [];
  4042. if ($modelResult->isSuccess()) {
  4043. $skuData = $modelResult->getData();
  4044. }
  4045. unset($modelResult);
  4046. //循环流水数据
  4047. $returnData = [];
  4048. foreach($params as $value){
  4049. //分组流水数据
  4050. if(isset($returnData[$value['materielId']]) && isset($returnData[$value['materielId']]['Details']) && isset($returnData[$value['materielId']]['Details'][$value['skuId']])){
  4051. $data = $returnData[$value['materielId']]['Details'][$value['skuId']];
  4052. //上期结存
  4053. if($data['smallCreateTime'] > $value['createTime']){
  4054. if($value['actionType'] == StatusCode::$standard){
  4055. //入库
  4056. $data['topEndNum'] = floatval((bcsub($value['inventoryChangeNum'], $value['inventoryNum'], 8)));
  4057. }else{
  4058. //出库
  4059. $data['topEndNum'] = floatval(bcadd($value['inventoryNum'], $value['inventoryChangeNum'], 8));
  4060. }
  4061. $data['topEndAmount'] = floatval(bcmul($data['topEndNum'], $value['averageCost'], 4));
  4062. $data['smallCreateTime'] = $value['createTime'];
  4063. }
  4064. //本期入库
  4065. if($value['actionType'] == StatusCode::$standard){
  4066. $data['selfInNum'] = floatval(bcadd($data['selfInNum'], $value['inventoryNum'], 8));
  4067. $data['selfInAmount'] = floatval(bcadd($data['selfInAmount'], bcmul($value['inventoryNum'], $value['averageCost'], 4), 4));
  4068. switch ($value['source']){
  4069. case StatusCode::$orderType['purchaseIn']:
  4070. //采购入库
  4071. $data['selfPurchaseInNum'] = floatval(bcadd($data['selfPurchaseInNum'], $value['inventoryNum'], 8));
  4072. break;
  4073. case StatusCode::$orderType['allocateIn']:
  4074. //调拨入库
  4075. $data['selfAllocateInNum'] = floatval(bcadd($data['selfPurchaseInNum'], $value['inventoryNum'], 8));
  4076. break;
  4077. case StatusCode::$orderType['saleReturnIn']:
  4078. //销售退货入库
  4079. $data['selfSaleReturnInNum'] = floatval(bcadd($data['selfSaleReturnInNum'], $value['inventoryNum'], 8));
  4080. break;
  4081. default:
  4082. break;
  4083. }
  4084. }else{
  4085. $data['selfOutNum'] = floatval(bcadd($data['selfOutNum'], $value['inventoryNum'], 8));
  4086. $data['selfOutAmount'] = floatval(bcadd($data['selfOutAmount'], bcmul($value['inventoryNum'], $value['averageCost'], 4), 4));
  4087. switch ($value['source']){
  4088. case StatusCode::$orderType['saleOut']:
  4089. //销售出库
  4090. $data['selfSaleOutNum'] = floatval(bcadd($data['selfSaleOutNum'], $value['inventoryNum'], 8));
  4091. break;
  4092. case StatusCode::$orderType['allocateOut']:
  4093. //调拨出库
  4094. $data['selfAllocateOutNum'] = floatval(bcadd($data['selfAllocateOutNum'], $value['inventoryNum'], 8));
  4095. break;
  4096. case StatusCode::$orderType['purchaseReturnOut']:
  4097. //采购退货出库
  4098. $data['selfPurchaseReturnOutNum'] = floatval(bcadd($data['selfPurchaseReturnOutNum'], $value['inventoryNum'], 8));
  4099. break;
  4100. default:
  4101. break;
  4102. }
  4103. }
  4104. //本期结存
  4105. if($data['bigCreateTime'] < $value['createTime']){
  4106. $data['selfEndNum'] = floatval($value['inventoryChangeNum']);
  4107. $data['selfEndAmount'] = floatval(bcmul($value['inventoryChangeNum'], $value['averageCost'], 4));
  4108. $data['bigCreateTime'] = $value['createTime'];
  4109. }
  4110. $returnData[$value['materielId']]['Details'][$value['skuId']] = $data;
  4111. }else{
  4112. $data = [
  4113. 'bigCreateTime' => $value['createTime'],
  4114. 'smallCreateTime' => $value['createTime'],
  4115. 'warehouseId' => $value['warehouseId'],
  4116. 'materielId' => $value['materielId'],
  4117. 'skuId' => isset($skuData[$value['skuId']]['masterSkuId']) ? $skuData[$value['skuId']]['masterSkuId'] : $value['skuId'],
  4118. 'materielCode' => isset($value['materielCode']) ? $value['materielCode'] : createCode(StatusCode::$code['goodsBasic']['prefix'], $value['materielId'], StatusCode::$code['goodsBasic']['length']),
  4119. 'materielName' => $value['materielName'],
  4120. ];
  4121. //上期结存 本期第一个出/入数量 +/- 变动后数量 = 上期结存数量
  4122. if($value['actionType'] == StatusCode::$standard){
  4123. //入库
  4124. $data['topEndNum'] = floatval(bcsub($value['inventoryChangeNum'], $value['inventoryNum'], 8));
  4125. }else{
  4126. //出库
  4127. $data['topEndNum'] = floatval(bcadd($value['inventoryNum'], $value['inventoryChangeNum'], 8));
  4128. }
  4129. $data['topEndAmount'] = floatval(bcmul($data['topEndNum'], $value['averageCost'], 4));
  4130. //本期入库
  4131. $data['selfInNum'] = 0;
  4132. $data['selfInAmount'] = 0;
  4133. //本期出库
  4134. $data['selfOutNum'] = 0;
  4135. $data['selfOutAmount'] = 0;
  4136. $data['selfPurchaseInNum'] = 0;
  4137. $data['selfAllocateInNum'] = 0;
  4138. $data['selfSaleReturnInNum'] = 0;
  4139. $data['selfSaleOutNum'] = 0;
  4140. $data['selfAllocateOutNum'] = 0;
  4141. $data['selfPurchaseReturnOutNum'] = 0;
  4142. if($value['actionType'] == StatusCode::$standard){
  4143. $data['selfInNum'] = floatval($value['inventoryNum']);
  4144. $data['selfInAmount'] = floatval(bcmul($value['inventoryNum'], $value['averageCost'], 4));
  4145. switch ($value['source']){
  4146. case StatusCode::$orderType['purchaseIn']:
  4147. //采购入库
  4148. $data['selfPurchaseInNum'] = floatval($value['inventoryNum']);
  4149. break;
  4150. case StatusCode::$orderType['allocateIn']:
  4151. //调拨入库
  4152. $data['selfAllocateInNum'] = floatval($value['inventoryNum']);
  4153. break;
  4154. case StatusCode::$orderType['saleReturnIn']:
  4155. //销售退货入库
  4156. $data['selfSaleReturnInNum'] = floatval($value['inventoryNum']);
  4157. break;
  4158. default:
  4159. break;
  4160. }
  4161. }else{
  4162. $data['selfOutNum'] = floatval($value['inventoryNum']);
  4163. $data['selfOutAmount'] = floatval(bcmul($value['inventoryNum'], $value['averageCost'], 4));
  4164. switch ($value['source']){
  4165. case StatusCode::$orderType['saleOut']:
  4166. //销售出库
  4167. $data['selfSaleOutNum'] = floatval($value['inventoryNum']);
  4168. break;
  4169. case StatusCode::$orderType['allocateOut']:
  4170. //调拨出库
  4171. $data['selfAllocateOutNum'] = floatval($value['inventoryNum']);
  4172. break;
  4173. case StatusCode::$orderType['purchaseReturnOut']:
  4174. //采购退货出库
  4175. $data['selfPurchaseReturnOutNum'] = floatval($value['inventoryNum']);
  4176. break;
  4177. default:
  4178. break;
  4179. }
  4180. }
  4181. //本期结存
  4182. $data['selfEndNum'] = floatval($value['inventoryChangeNum']);
  4183. $data['selfEndAmount'] = floatval(bcmul($value['inventoryChangeNum'], $value['averageCost'], 4));
  4184. if(!isset($returnData[$value['materielId']])){
  4185. $returnData[$value['materielId']]['warehouseId'] = $value['warehouseId'];
  4186. $returnData[$value['materielId']]['materielId'] = $value['materielId'];
  4187. $returnData[$value['materielId']]['materielCode'] = $value['materielCode'];
  4188. $returnData[$value['materielId']]['materielName'] = $value['materielName'];
  4189. }
  4190. $returnData[$value['materielId']]['Details'][$value['skuId']] = parent::formatSkuId($this->enterpriseId,$data);
  4191. }
  4192. }
  4193. foreach($returnData as &$value){
  4194. $value['Details'] = array_merge($value['Details']);
  4195. }
  4196. if($merge) return array_merge($returnData);
  4197. return $returnData;
  4198. }
  4199. /**
  4200. * 批次列表
  4201. * @param $selectParams
  4202. * @return ResultWrapper
  4203. * @throws Exception
  4204. */
  4205. public function getAllBatch($selectParams)
  4206. {
  4207. $limit = $selectParams['limit'];
  4208. unset($selectParams['limit']);
  4209. $offset = $selectParams['offset'];
  4210. unset($selectParams['offset']);
  4211. self::setBatchTable($this->enterpriseId, $selectParams['warehouseId']);
  4212. $where = ' warehouseId ='.$selectParams['warehouseId'];
  4213. // 关键字筛选
  4214. if( isset($selectParams['keyword']) && !empty($selectParams['keyword']) ){
  4215. // 根据输入的商品名称关键字查询对应的商品ids
  4216. $objMGoodsBasic = new MGoodsBasic($this->onLineUserCenterId, $this->enterpriseId);
  4217. $materielIdS = $objMGoodsBasic->getBasicGoodsIdsByGoodsTitleKeyword($selectParams['keyword']);
  4218. if(!$materielIdS->isSuccess()){
  4219. return ResultWrapper::fail($materielIdS->getData(), $materielIdS->getErrorCode());
  4220. }
  4221. $materielIdS = $materielIdS->getData();
  4222. unset($selectParams['keyword']);
  4223. if( empty($materielIdS) ){
  4224. return ResultWrapper::success(['data'=>[],'total'=>0]);
  4225. }
  4226. if (empty($selectParams['batchNo'])){
  4227. $where .=' and materielId in ('.implode(',', $materielIdS).')';
  4228. }
  4229. }
  4230. //批次号
  4231. if( isset($selectParams['batchNo']) && !empty($selectParams['batchNo']) ){
  4232. $where .= ' and batchNo ='.$selectParams['batchNo'];
  4233. }
  4234. // 时间筛选
  4235. if( isset($selectParams['startTime']) && !empty($selectParams['startTime']) && isset($selectParams['endTime']) && !empty($selectParams['endTime'])){
  4236. $where .=' and createTime >= '.$selectParams['startTime'].' and createTime <= '.$selectParams['endTime'];
  4237. }
  4238. // materielId过滤
  4239. if( isset($selectParams['materielId']) && !empty($selectParams['materielId']) ){
  4240. $where .= ' and materielId ='.$selectParams['materielId'];
  4241. }
  4242. // skuId过滤
  4243. if( isset($selectParams['skuId']) && !empty($selectParams['skuId']) ){
  4244. $where .= ' and skuId ='.$selectParams['skuId'];
  4245. }
  4246. $dbResult = $this->objDInventoryBatch->select($where, '*', 'id asc', $limit, $offset);
  4247. if ($dbResult === false) {
  4248. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  4249. }
  4250. $total = $this->objDInventoryBatch->count($where);
  4251. $formatData = parent::formatOrderMan($this->enterpriseId, $dbResult);
  4252. $return['data'] = $formatData;
  4253. $return['total'] = ($total) ? intval($total) : 0;
  4254. if ($return === false) {
  4255. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  4256. } else {
  4257. return ResultWrapper::success($return);
  4258. }
  4259. }
  4260. /**
  4261. * 批次搜索
  4262. * @param $params
  4263. * @return ResultWrapper
  4264. * @throws Exception
  4265. */
  4266. public function searchAllInventoryBatch($params)
  4267. {
  4268. $defaultDSL = ['from' => $params['offset'], 'size' => $params['limit'], 'sort' => ['createTime' => ['order' => 'desc']]];
  4269. $selectParams = [];
  4270. $selectParams[] = ['term' => ['enterpriseId' => $this->enterpriseId]];
  4271. !empty($params['warehouseId']) && $selectParams[] = ['term' => ['warehouseId' => $params['warehouseId']]];
  4272. (!empty($params['start']) && !empty($params['end'])) && $selectParams[] = ['range' => ['createTime' => ['gte' => $params['start'], 'lte' => $params['end']]]];
  4273. !empty($params['search']) && $selectParams[] = ['multi_match' => ['fields' => ['batchNo', 'originNo', 'materielName'], 'query' => $params['search'], 'fuzziness' => 'AUTO']];
  4274. $dsl = [];
  4275. !empty($selectParams) && $dsl['query']['bool']['must'][] = $selectParams;
  4276. $dsl = array_merge($defaultDSL, $dsl);
  4277. $dbResult = $this->objDInventoryBatch->getSearchQueryDsl($dsl);
  4278. if (isset($dbResult['error'])) {
  4279. return ResultWrapper::fail($dbResult, ErrorCode::$dberror);
  4280. }
  4281. $returnData = parent::formatEsSelectData($dbResult, $this->enterpriseId);
  4282. return ResultWrapper::success($returnData);
  4283. }
  4284. /**
  4285. * 批次详情
  4286. * @param $selectParams
  4287. * @return ResultWrapper
  4288. * @throws Exception
  4289. */
  4290. public function getBatchInfo($selectParams)
  4291. {
  4292. $skuIds = [
  4293. 871,870,868,865,872,869
  4294. ];
  4295. self::getInventoryBySkuIds($skuIds);
  4296. $this->objDInventoryBatch->setTable('qianniao_inventory_batch_'.$this->enterpriseId.'_'.$selectParams['warehouseId']);
  4297. $dbResult = $this->objDInventoryBatch->get($selectParams);
  4298. if($dbResult === false){
  4299. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  4300. }
  4301. $returnData = parent::formatOrderMan($this->enterpriseId, $dbResult);
  4302. return ResultWrapper::success($returnData);
  4303. }
  4304. /**
  4305. * 库存不足自动预警
  4306. * @param $data
  4307. * @return ResultWrapper
  4308. */
  4309. public function inventoryNullMessage($data)
  4310. {
  4311. //获取当前设置的预警数量
  4312. $objMBasicSetup = new MBasicSetup($this->enterpriseId);
  4313. $modelResult = $objMBasicSetup->getBasicSetup();
  4314. if(!$modelResult->isSuccess()){
  4315. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  4316. }
  4317. $system = $modelResult->getData();
  4318. if(!isset($system['basicData']) || !isset($system['basicData']['goodsNum']) || empty((int)$system['basicData']['goodsNum'])){
  4319. return ResultWrapper::success(true);
  4320. }
  4321. $settingNum = $system['basicData']['goodsNum'];
  4322. unset($modelResult);
  4323. $insertMessage = [];
  4324. foreach($data as $value){
  4325. //判断剩余数量是否低于预警数量
  4326. if(bccomp($settingNum, $value['inventoryChangeNum'])){
  4327. //如果低于等于预警数量
  4328. //创建一条预警消息发送给当前企业管理员
  4329. $insertMessage[] = $value['materielName'];
  4330. }
  4331. }
  4332. $params = [
  4333. 'enterpriseId' => $this->enterpriseId,
  4334. 'data' => $insertMessage,
  4335. ];
  4336. if($insertMessage){
  4337. self::inventoryNumWarning($params, 'MMessage');
  4338. }
  4339. }
  4340. /**
  4341. * 库存为空自动下架
  4342. * 根据商铺id和物料id
  4343. * @param $params
  4344. * @param array $updateData
  4345. * @return ResultWrapper
  4346. * @throws Exception
  4347. */
  4348. public function inventoryNullSetGoodsDown($params, $updateData = [])
  4349. {
  4350. if (empty($params)) return ResultWrapper::fail('参数为空', ErrorCode::$paramError);
  4351. //查询系统设置
  4352. $objMBasicSetup = new MBasicSetup($this->enterpriseId);
  4353. $modelResult = $objMBasicSetup->getBasicSetup();
  4354. if(!$modelResult->isSuccess()){
  4355. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  4356. }
  4357. $system = $modelResult->getData();
  4358. //判断是否开启 库存为空 下架商品功能
  4359. if(isset($system['basicData']) || isset($system['basicData']['autoRemoveGoods']) || $system['basicData']['autoRemoveGoods'] == StatusCode::$standard){
  4360. return ResultWrapper::success(true);
  4361. }
  4362. //判断是否是全部库存为0 TODO
  4363. $whereParams = [];
  4364. foreach ($params as $value) {
  4365. $whereParams[$value['shopId']][] = $value['materielId'];
  4366. }
  4367. $objMGoods = new MGoods($this->enterpriseId, false, $this->onLineUserCenterId);
  4368. foreach ($whereParams as $shopId => $materielIds) {
  4369. if (empty($updateData)) {
  4370. $updateData = [
  4371. 'enableStatus' => StatusCode::$delete,
  4372. ];
  4373. }
  4374. $updateData['updateTime'] = time();
  4375. $where = ['shopId' => $shopId, 'basicGoodsId' => $materielIds];
  4376. $modelResult = $objMGoods->updateGoodsData($updateData, $where);
  4377. if (!$modelResult->isSuccess()) {
  4378. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  4379. }
  4380. }
  4381. return ResultWrapper::success(true);
  4382. }
  4383. /**
  4384. * 根据仓库id查询所有物料库存信息
  4385. * @param $selectParams
  4386. * @return ResultWrapper
  4387. * @throws Exception
  4388. * $export 导出
  4389. */
  4390. public function getInventoryByWarehouseId($selectParams,$export = 0)
  4391. {
  4392. $limit = $selectParams['limit'];
  4393. unset($selectParams['limit']);
  4394. $offset = $selectParams['offset'];
  4395. unset($selectParams['offset']);
  4396. if($export){
  4397. $limit = null;
  4398. $offset = null;
  4399. }
  4400. $categoryId = isset($selectParams['categoryId']) ? $selectParams['categoryId'] : '';
  4401. unset($selectParams['categoryId']);
  4402. if(isset($selectParams['search']) || !empty($categoryId)){
  4403. $objDGoodsBasic = new DGoodsBasic('default');
  4404. $objDGoodsBasic->setTable( 'qianniao_goods_basic_' . $this->enterpriseId);
  4405. $sql = 'select id from '.$objDGoodsBasic->get_Table().' WHERE deleteStatus = '.StatusCode::$standard;
  4406. if (isset($selectParams['search']) && !empty($selectParams['search'])){
  4407. $search = '"%'.$selectParams['search'].'%"';
  4408. $sql .= ' AND ( title LIKE '.$search.' OR code LIKE '.$search.') ';
  4409. }
  4410. if (!empty($categoryId)){
  4411. $sql .= ' AND find_in_set('.$categoryId.',categoryPath) ';
  4412. }
  4413. $dbResult = $objDGoodsBasic->query($sql);
  4414. if ($dbResult === false) {
  4415. return ResultWrapper::fail($objDGoodsBasic->error(), ErrorCode::$dberror);
  4416. }
  4417. $selectParams['materielId'] = [];
  4418. foreach ($dbResult as $value) {
  4419. $selectParams['materielId'][] = $value['id'];
  4420. }
  4421. unset($selectParams['search']);
  4422. if (empty($selectParams['materielId'])) {
  4423. $return['data'] = [];
  4424. $return['total'] = 0;
  4425. return ResultWrapper::success($return);
  4426. }
  4427. }
  4428. $dbResult = $this->objDInventoryWarehouse->select($selectParams, '*,inventoryNum as allNum, inventoryNum * costPrice as total', 'createTime desc', $limit, $offset);
  4429. if ($dbResult === false) {
  4430. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  4431. }
  4432. if (empty($dbResult)) {
  4433. $return['data'] = [];
  4434. $return['total'] = 0;
  4435. return ResultWrapper::success($return);
  4436. }
  4437. $total = $this->objDInventoryWarehouse->count($selectParams);
  4438. if ($total === false) {
  4439. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  4440. }
  4441. $formatData = parent::formatOrderMan($this->enterpriseId, $dbResult);
  4442. $return['data'] = $formatData;
  4443. $return['total'] = ($total) ? intval($total) : 0;
  4444. //仓库库存导出
  4445. if($export){
  4446. self::exportInventoryWarehouse($formatData);
  4447. exit;
  4448. }
  4449. return ResultWrapper::success($return);
  4450. }
  4451. /**
  4452. * 根据仓库id和物料ids查询物料批次信息和剩余可用库存
  4453. * @param $params
  4454. * @param bool $fields
  4455. * @return ResultWrapper
  4456. * @throws Exception
  4457. */
  4458. public function getBatchByIds($params, $fields = false)
  4459. {
  4460. $materielIds = [];
  4461. foreach ($params as $value) {
  4462. $materielIds[$value['warehouseId']][] = $value['materielId'];
  4463. }
  4464. $formatBatch = [];
  4465. foreach ($materielIds as $warehouseId => $materielId) {
  4466. self::setBatchTable($this->enterpriseId, $warehouseId, 'qianniao_inventory_batch');
  4467. $where = ' materielId in(' . implode(',', $materielId) . ') and warehouseId = ' . $warehouseId . ' and num > 0 ';
  4468. $order = ' createTime asc';
  4469. if ($fields) {
  4470. $fields .= ',warehouseId,materielId';
  4471. } else {
  4472. $fields = '*';
  4473. }
  4474. $dbResult = $this->objDInventoryBatch->select($where, $fields, $order);
  4475. if ($dbResult === false) {
  4476. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  4477. }
  4478. foreach ($dbResult as $value) {
  4479. $mdKey = md5($value['warehouseId'] . $value['materielId']);
  4480. if ($fields) {
  4481. unset($value['warehouseId']);
  4482. unset($value['materielId']);
  4483. }
  4484. $formatBatch[$mdKey][] = $value;
  4485. }
  4486. }
  4487. foreach ($params as &$value) {
  4488. $value['batch'] = $formatBatch[md5($value['warehouseId'] . $value['materielId'])];
  4489. }
  4490. unset($value);
  4491. return ResultWrapper::success($params);
  4492. }
  4493. /**
  4494. * 计算物料出那些批次
  4495. * @param $params
  4496. * @param bool $type
  4497. * @return ResultWrapper
  4498. * @throws Exception
  4499. */
  4500. public function getBatchByInventoryOut($params, $type = false)
  4501. {
  4502. $modelResult = self::getBatchByIds($params, 'batchNo, num');
  4503. if (!$modelResult->isSuccess()) {
  4504. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  4505. }
  4506. $batchData = $modelResult->getData();
  4507. unset($modelResult);
  4508. $returnData = [];
  4509. foreach ($batchData as &$value) {
  4510. $num = $value['num'];//要出的物料数量
  4511. foreach ($value['batch'] as $batch) {
  4512. if ($num <= $batch['num']) {//批次剩余库存数量够
  4513. $value['batchData'][] = [
  4514. 'batchNo' => $batch['batchNo'],
  4515. 'lessNum' => $num,
  4516. ];
  4517. break;
  4518. }
  4519. $num = bcsub($num,$batch['num']);
  4520. $value['batchData'][] = [
  4521. 'batchNo' => $batch['batchNo'],
  4522. 'lessNum' => $num,
  4523. ];
  4524. }
  4525. $returnData[md5($value['warehouseId'] . $value['materielId'])] = $value['batchData'];
  4526. }
  4527. if ($type) {
  4528. return ResultWrapper::success($returnData);
  4529. }
  4530. return ResultWrapper::success($batchData);
  4531. }
  4532. /**
  4533. * 统计商品的种类
  4534. * @return int|ResultWrapper
  4535. */
  4536. public function statistics()
  4537. {
  4538. //库存商品总
  4539. $numberOfProductsInStock = $this->objOverviewCache->getAggregateStatistics($this->enterpriseId, 'numberOfProductsInStock');
  4540. if (!$numberOfProductsInStock) {
  4541. $sql = 'SELECT COUNT(id) FROM ' . $this->objDInventory->get_Table() . ' WHERE inventoryNum > 0 GROUP BY materielId,skuId';
  4542. $dbResult = $this->objDInventory->query($sql);
  4543. if ($dbResult === false) {
  4544. return ResultWrapper::fail('操作数据库失败', ErrorCode::$dberror);
  4545. }
  4546. $num = count($dbResult);
  4547. $this->objOverviewCache->setAggregateStatistics($this->enterpriseId, 'numberOfProductsInStock', $num);
  4548. unset($sql);
  4549. unset($dbResult);
  4550. $return['numberOfProductsInStock'] = $num;
  4551. } else {
  4552. $return['numberOfProductsInStock'] = $numberOfProductsInStock;
  4553. }
  4554. //库存总金额
  4555. $totalMoneyOfInventory = $this->objOverviewCache->getAggregateStatistics($this->enterpriseId, 'totalMoneyOfInventory');
  4556. if (!$totalMoneyOfInventory) {
  4557. $sql = "select sum(costPrice) as amount from " . $this->objDInventory->get_Table();
  4558. $dbResult = $this->objDInventory->query($sql);
  4559. if ($dbResult === false) {
  4560. return ResultWrapper::fail('操作数据库失败', ErrorCode::$dberror);
  4561. }
  4562. $amount = isset($dbResult[0]['amount']) ? $dbResult[0]['amount'] : 0;
  4563. $this->objOverviewCache->setAggregateStatistics($this->enterpriseId, 'totalMoneyOfInventory', $amount);
  4564. $return['totalMoneyOfInventory'] = $amount;
  4565. }else{
  4566. $return['totalMoneyOfInventory'] = $totalMoneyOfInventory;
  4567. }
  4568. return $return;
  4569. }
  4570. /**
  4571. * 根据源头id获取批次信息和库存剩余数量
  4572. * @param $params
  4573. * @return ResultWrapper
  4574. */
  4575. public function getBatchDataByOriginId($warehouseId, $originId, $skuIds)
  4576. {
  4577. if(empty($warehouseId)) return ResultWrapper::fail('查询批次warehouseId参数错误', ErrorCode::$paramError);
  4578. if(empty($originId)) return ResultWrapper::fail('查询批次originId参数错误', ErrorCode::$paramError);
  4579. if(empty($skuIds)) return ResultWrapper::fail('查询批次skuIds参数错误', ErrorCode::$paramError);
  4580. //转换单位
  4581. $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId);
  4582. $modelResult = $objMSku->getConversion($skuIds);
  4583. if(!$modelResult->isSuccess()){
  4584. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  4585. }
  4586. $skuData = $modelResult->getData();
  4587. unset($modelResult);
  4588. $masterSkuIds = array_column($skuData, 'masterSkuId');
  4589. //查询批次
  4590. self::setBatchTable($this->enterpriseId,$warehouseId, 'qianniao_inventory_batch');
  4591. $dbResult = $this->objDInventoryBatch->select(['originId' => $originId, 'skuId' => $masterSkuIds]);
  4592. if ($dbResult === false) {
  4593. return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror);
  4594. }
  4595. $batchResult = $dbResult;
  4596. unset($dbResult);
  4597. if(empty($batchResult)){
  4598. return ResultWrapper::fail('批次数据为空', ErrorCode::$paramError);
  4599. }
  4600. $batchData = [];
  4601. foreach($batchResult as $value){
  4602. if(isset($batchData[$value['skuId']])){
  4603. $batchData[$value['skuId']]['num'] = bcadd($batchData[$value['skuId']]['num'], $value['num'], 8);
  4604. }else{
  4605. $batchData[$value['skuId']] = $value;
  4606. }
  4607. }
  4608. //转换数量
  4609. $inventoryData = [];
  4610. foreach($skuData as $key => $value){
  4611. $inventoryNum = $batchData[$value['masterSkuId']]['num'];
  4612. if($inventoryNum > 0){
  4613. if($value['isMaster'] == StatusCode::$standard){
  4614. $inventoryData[$key]['num'] = $inventoryNum;
  4615. }else{
  4616. if($value['isNew'] == StatusCode::$standard){
  4617. $inventoryData[$key]['num'] = bcdiv($inventoryNum, $value['conversion'], 8);
  4618. }else{
  4619. $inventoryData[$key]['num'] = bcmul($inventoryNum, $value['conversion'], 8);
  4620. }
  4621. }
  4622. }else{
  4623. $inventoryData[$key]['num'] = 0;
  4624. }
  4625. }
  4626. return ResultWrapper::success($inventoryData);
  4627. }
  4628. /**
  4629. * 增加详情es数据
  4630. * @param $data
  4631. * @param $ids
  4632. * @return ResultWrapper
  4633. */
  4634. /*
  4635. public function addEsData($data, $ids)
  4636. {
  4637. foreach ($data as $key => $value) {
  4638. $modelResult = self::updateEsData($value, $ids[$key]);
  4639. if (!$modelResult->isSuccess()) {
  4640. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  4641. }
  4642. }
  4643. return ResultWrapper::success(true);
  4644. }*/
  4645. /**
  4646. * 添加详情es
  4647. * @param $id
  4648. * @param $data
  4649. * @return ResultWrapper
  4650. */
  4651. /*public function updateEsData($data, $id)
  4652. {
  4653. $addEsData = [
  4654. 'id' => $id,
  4655. 'enterpriseId' => $this->enterpriseId,
  4656. 'sourceNo' => StatusCode::$noPrefix[$data['source']].$data['sourceNo'],
  4657. 'warehouseId' => $data['warehouseId'],
  4658. 'materielId' => $data['materielId'],
  4659. 'materielName' => $data['materielName'],
  4660. 'operatorId' => $data['operatorId'],
  4661. 'operatorName' => $data['operatorName'],
  4662. 'inventoryNum' => $data['inventoryNum'],
  4663. 'inventoryChangeNum' => $data['inventoryChangeNum'],
  4664. 'skuId' => $data['skuId'],
  4665. 'unitName' => $data['unitName'],
  4666. 'skuName' => $data['skuName'],
  4667. 'source' => $data['source'],
  4668. 'batch' => json_decode($data['batch'], true),
  4669. 'costType' => $data['costType'],
  4670. 'averageCost' => $data['averageCost'],
  4671. 'actionType' => $data['actionType'],
  4672. 'createTime' => $data['createTime'],
  4673. 'updateTime' => $data['updateTime'],
  4674. ];
  4675. //创建es id
  4676. $esId = self::esId($id);
  4677. $result = $this->objDInventoryDetails->addUpSearchIndexDocument($addEsData, $esId);
  4678. // var_dump($result);
  4679. if (isset($result['_shards']) && isset($result['_shards']['successful']) && $result['_shards']['successful'] == 1) {
  4680. return ResultWrapper::success(isset($result['_id']) ? $result['_id'] : false);
  4681. }
  4682. return ResultWrapper::fail($result['error']['reason'], ErrorCode::$paramError);
  4683. // return ResultWrapper::fail('ES添加失败', ErrorCode::$paramError);
  4684. }*/
  4685. /**
  4686. * 拼接详情es id
  4687. * @param $id
  4688. * @return string
  4689. */
  4690. /*public function esId($id)
  4691. {
  4692. return 'EnterpriseId_' . $this->enterpriseId . '_inventoryDetailsId_' . $id;
  4693. }*/
  4694. /**
  4695. * 格式化入库es
  4696. */
  4697. public function formatInventoryDetailsEsData()
  4698. {
  4699. //查询列表数据
  4700. $dbResult = $this->objDInventoryDetails->select([],'*');
  4701. if($dbResult === false){
  4702. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  4703. }
  4704. if(empty($dbResult)){
  4705. return ResultWrapper::fail('格式化数据为空', ErrorCode::$dberror);
  4706. }
  4707. //增加es搜索
  4708. foreach($dbResult as $value){
  4709. //增加es搜索
  4710. $modelResult = self::updateEsData($value, $value['id']);
  4711. if(!$modelResult->isSuccess()){
  4712. return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
  4713. }
  4714. }
  4715. return ResultWrapper::success('格式化成功');
  4716. }
  4717. public function __destruct()
  4718. {
  4719. // TODO: Implement __destruct() method.
  4720. if ($this->updateCache === false) return true;
  4721. //统计库存商品数
  4722. $sql = 'SELECT COUNT(id) FROM ' . $this->objDInventory->get_Table() . ' WHERE inventoryNum > 0 GROUP BY materielId,skuId';
  4723. $dbResult = $this->objDInventory->query($sql);
  4724. if ($dbResult === false) {
  4725. return false;
  4726. }
  4727. $num = count((array)$dbResult);
  4728. $this->objOverviewCache->setAggregateStatistics($this->enterpriseId, 'numberOfProductsInStock', $num);
  4729. //库存总金额
  4730. $sql = "select sum((inventoryNum + lockInventory)*costPrice) as amount from " . $this->objDInventory->get_Table();
  4731. $dbResult = $this->objDInventory->query($sql);
  4732. if ($dbResult === false) {
  4733. return false;
  4734. }
  4735. $amount = isset($dbResult[0]['amount']) ? $dbResult[0]['amount'] : 0;
  4736. $this->objOverviewCache->setAggregateStatistics($this->enterpriseId, 'totalMoneyOfInventory', $amount);
  4737. return true;
  4738. }
  4739. /**
  4740. * 修改负库存出库流水成本
  4741. */
  4742. public function updateSaleOrderOutCostPrise($warehouseId, $skuIds, $skuCostParse)
  4743. {
  4744. //计算表名
  4745. self::setDetailsTable($this->enterpriseId, $warehouseId);
  4746. $where = [
  4747. 'skuId' => $skuIds,
  4748. 'actionType' => 4,
  4749. 'source' => StatusCode::$orderType['saleOut']
  4750. ];
  4751. //查询所有包含skuId的订单出库库存流水
  4752. $dbResult = $this->objDInventoryDetails->select($where);
  4753. if($dbResult === false){
  4754. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  4755. }
  4756. $return = [];
  4757. if(empty($dbResult)){
  4758. return ResultWrapper::success($return);
  4759. }
  4760. //拿到所有订单id
  4761. $orderId = [];
  4762. $updateOrder = [];
  4763. $beginStatus = $this->objDInventoryDetails->beginTransaction();
  4764. foreach($dbResult as $value){
  4765. !in_array($value['originId'],$orderId) && $orderId[] = $value['originId'];
  4766. if(isset($skuCostParse[$value['skuId']])){
  4767. $updateOrder[] = [
  4768. 'where' => [
  4769. 'orderId' => $value['originId'],
  4770. 'skuId' => $value['skuId'],
  4771. ],
  4772. 'update' => [
  4773. 'outCostPrice' => $skuCostParse[$value['skuId']]
  4774. ]
  4775. ];
  4776. //修改流水记录的出库成本
  4777. $result = $this->objDInventoryDetails->update(['averageCost' => $skuCostParse[$value['skuId']]], ['id' => $value['id']]);
  4778. if($result === false){
  4779. $this->objDInventoryDetails->rollBack();
  4780. return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror);
  4781. }
  4782. }
  4783. }
  4784. $beginStatus && $this->objDInventoryDetails->commit();
  4785. $return['orderId'] = $orderId;
  4786. $return['updateOrder'] = $updateOrder;
  4787. return ResultWrapper::success($return);
  4788. }
  4789. /**
  4790. * 修改库存成本
  4791. * @param $params
  4792. * @return ResultWrapper
  4793. */
  4794. public function updateInventoryCost($params)
  4795. {
  4796. $where = [
  4797. 'skuId' => $params['skuId'],
  4798. ];
  4799. $sql = ' skuId = '.$params['skuId'].' and merchantId <> 0';
  4800. $dbResult = $this->objDInventoryWarehouse->get($sql);
  4801. if($dbResult === false){
  4802. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  4803. }
  4804. if(empty($dbResult)){
  4805. return ResultWrapper::success(false);
  4806. }
  4807. //修改库存成本
  4808. $update = [
  4809. 'skuId' => $params['skuId'],
  4810. 'costPrice' => $params['costPrice'],
  4811. 'updateTime' => time()
  4812. ];
  4813. $beginStatus = $this->objDInventoryWarehouse->beginTransaction();
  4814. $dbResult = $this->objDInventoryWarehouse->update($update,$where);
  4815. if($dbResult === false){
  4816. $this->objDInventoryWarehouse->rollBack();
  4817. return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror);
  4818. }
  4819. $beginStatus && $this->objDInventoryWarehouse->commit();
  4820. return ResultWrapper::success($dbResult);
  4821. }
  4822. /**
  4823. * 仓库库存导出方法
  4824. * @param $result
  4825. * @return void
  4826. * @throws Exception
  4827. */
  4828. public function exportInventoryWarehouse($result)
  4829. {
  4830. //导出到本地
  4831. header("Content-type:application/vnd.ms-excel");
  4832. header("Content-Disposition:filename=仓库库存记录表.csv");
  4833. header('Cache-Control: max-age=0');
  4834. $fp = fopen('php://output', 'a');
  4835. $head = ['物料编码', '商品', '规格', '仓库库存', '换算比例','换算库存']; //定义标题
  4836. foreach ($head as $i => $v) {
  4837. $head[$i] = mb_convert_encoding($v, 'GBK', 'utf-8'); //将中文标题转换编码,否则乱码
  4838. }
  4839. fputcsv($fp, $head);
  4840. $limit = 10000;
  4841. $num = 0; //计数器
  4842. foreach ($result as $v) { //循环数据
  4843. $num++;
  4844. if ($num == $limit) {
  4845. ob_flush(); //释放内存
  4846. flush();
  4847. }
  4848. $rows['materielCode'] = isset($v['materielCode']) ? $v['materielCode'] : '';//物料编码
  4849. $rows['warehouseName'] = isset($v['materielName']) ? $v['materielName'] : '';//商品
  4850. $rows['unitName'] = isset($v['unitName']) ? $v['unitName'] : '';//规格
  4851. $rows['inventoryNum'] = isset($v['inventoryNum']) ? $v['inventoryNum'] : '';//仓库库存
  4852. $rows['skuValue'] = isset($v['skuValue']) ? $v['skuValue'] : '';//换算比例
  4853. $rows['otherNum'] = isset($v['otherNum']) ? $v['otherNum'] : '';//换算库存
  4854. foreach ($rows as $kk => $vv) {
  4855. $rs[$kk] = mb_convert_encoding($vv, 'GBK', 'utf-8'); //转译编码
  4856. }
  4857. fputcsv($fp, $rs);
  4858. $rows = [];
  4859. }
  4860. }
  4861. }