ProductInventoryService.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <?php
  2. namespace App\Service;
  3. use App\Model\BasicType;
  4. use App\Model\Construction;
  5. use App\Model\ConstructionProductInfo;
  6. use App\Model\InOutRecord;
  7. use App\Model\InvoiceOrder;
  8. use App\Model\InvoiceOrderInfo;
  9. use App\Model\Product;
  10. use App\Model\ProductCategory;
  11. use App\Model\ProductInventory;
  12. use App\Model\PurchaseOrder;
  13. use App\Model\ReturnExchangeOrder;
  14. use App\Model\SalesOrder;
  15. use App\Model\Setting;
  16. use Illuminate\Support\Facades\DB;
  17. class ProductInventoryService extends Service
  18. {
  19. //获取产品真实库存
  20. public static function getRealStock($product_id = [],$data=[]){
  21. if(empty($product_id)) return [];
  22. $array = ProductInventory::whereIn('product_id',$product_id)
  23. ->where('number','>',0)
  24. ->select('id','product_id','number','crt_time','lock_number')
  25. ->get()->toArray();
  26. $map = [];
  27. if(! empty($data['order_number'])){
  28. if(strpos($data['order_number'],InvoiceOrder::prefix) !== false){
  29. $id = InvoiceOrder::where('order_number',$data['order_number'])
  30. ->where('del_time',0)
  31. ->value('id');
  32. $model = new InvoiceOrderInfo();
  33. }else{
  34. foreach (Construction::$prefix as $value){
  35. if(strpos($data['order_number'],$value) !== false){
  36. $model = new ConstructionProductInfo();
  37. }
  38. }
  39. $id = Construction::where('order_number',$data['order_number'])
  40. ->where('del_time',0)
  41. ->value('id');
  42. }
  43. if(! empty($model) && ! empty($id)){
  44. $save = $model->where('del_time',0)
  45. ->where('id',$id)
  46. ->select('product_id','number')
  47. ->get()->toArray();
  48. foreach ($save as $value){
  49. $key = $value['product_id'];
  50. if(isset($map[$key])){
  51. $map[$key] += $value['number'];
  52. }else{
  53. $map[$key] = $value['number'];
  54. }
  55. }
  56. }
  57. }
  58. $return = [];
  59. if(! empty($array)){
  60. $setting_map = Setting::where('setting_name','lock_number')
  61. ->pluck('setting_value','setting_name')
  62. ->toArray();
  63. foreach ($array as $value){
  64. if(! empty($setting_map['lock_number'])){//真实库存
  65. $tmp = $map[$value['product_id']] ?? 0;//已保存数量
  66. $tmp_lock = ($value['lock_number'] > 0 ? $value['lock_number'] : 0) - $tmp;
  67. if($value['number'] > $tmp_lock) {
  68. $return[] = [
  69. 'id' => $value['id'],
  70. 'product_id' => $value['product_id'],
  71. 'number' => $value['number'] - ($tmp_lock > 0 ? $tmp_lock : 0),
  72. ];
  73. }
  74. }else{
  75. $return[] = [
  76. 'id' => $value['id'],
  77. 'product_id' => $value['product_id'],
  78. 'number' => $value['number'],
  79. ];
  80. }
  81. }
  82. }
  83. return $return;
  84. }
  85. //更新锁定库存
  86. //第一个数组 (提交的数据) 第二个数组(保存过的数据)
  87. public static function changeLockNumber($submit_total = [], $save_total = []){
  88. if(empty($submit_total) && empty($save_total)) return;
  89. $setting_map = Setting::where('setting_name','lock_number')
  90. ->pluck('setting_value','setting_name')
  91. ->toArray();
  92. if(empty($setting_map['lock_number'])) return; //是否使用锁定库存
  93. //产品数扣减
  94. if(! empty($save_total)){
  95. foreach ($save_total as $key => $value){
  96. if(! isset($submit_total[$key])){
  97. $submit_total[$key] = - $value;
  98. }else{
  99. $submit_total[$key] = $submit_total[$key] - $value;
  100. }
  101. }
  102. }
  103. //更新锁定库存
  104. foreach ($submit_total as $key => $value){
  105. $product_id = $key;
  106. ProductInventory::where('product_id',$product_id)
  107. ->update(['lock_number' => DB::raw('lock_number + ('. $value . ')')]);
  108. }
  109. }
  110. //比较库存
  111. public static function compareStock($product_id = [],$product_submit = [], $product_save = []){
  112. if(empty($product_id) || empty($product_submit)) return [false,'比较参数不能为空'];
  113. //库存
  114. $array = ProductInventory::whereIn('product_id',$product_id)
  115. ->where('number','>',0)
  116. ->select('id','product_id','number','crt_time','lock_number')
  117. ->get()->toArray();
  118. if(empty($array)) return [false,'未找到产品库存数据'];
  119. $pro = Product::whereIn('id',$product_id)
  120. ->pluck('title','id')
  121. ->toArray();
  122. $setting_map = Setting::where('setting_name','lock_number')
  123. ->pluck('setting_value','setting_name')
  124. ->toArray();
  125. //比较
  126. foreach ($array as $value){
  127. $pro_tmp = $pro[$value['product_id']] ?? '';
  128. if(! $pro_tmp) return [false,'异常产品数据'];
  129. if(! isset($product_submit[$value['product_id']])) return [false,'产品:' . $pro_tmp.'库存不足'];
  130. if(! empty($setting_map['lock_number'])){//真实库存
  131. $tmp = $product_save[$value['product_id']] ?? 0;//已保存数量
  132. $tmp_lock = ($value['lock_number'] > 0 ? $value['lock_number'] : 0) - $tmp;
  133. $number = $value['number'] - ($tmp_lock > 0 ? $tmp_lock : 0);
  134. }else{
  135. $number = $value['number'];
  136. }
  137. if($product_submit[$value['product_id']] > $number) return [false,$pro_tmp . '数量不足,当前数量:'. $number];
  138. }
  139. return [true,''];
  140. }
  141. //现存量
  142. public function productInventoryList($data,$user){
  143. $model = ProductInventory::from('product_inventory as a')
  144. ->join('product as b','b.id','a.product_id')
  145. ->select('a.product_id','a.id','a.number','b.title','b.code','b.product_category_id','b.unit','b.bar_code','a.crt_time')
  146. ->orderby('a.crt_time', 'desc');
  147. if(! empty($data['product_name'])){
  148. $product_name = $data['product_name'];
  149. $id = Product::where('del_time',0)
  150. ->when(! empty($product_name), function ($query) use ($product_name) {
  151. return $query->where('title', 'LIKE', '%'.$product_name.'%');
  152. })
  153. ->select('id')
  154. ->get()->toArray();
  155. $model->whereIn('a.product_id',array_unique(array_column($id,'id')));
  156. }
  157. if(! empty($data['product_category_name'])){
  158. $product_category_name = $data['product_category_name'];
  159. $c = ProductCategory::where('del_time',0)
  160. ->where('title', 'LIKE', '%'.$product_category_name.'%')
  161. ->select('id')
  162. ->get()->toArray();
  163. $model->whereIn('b.product_category_id',array_unique(array_column($c,'id')));
  164. }
  165. if(!empty($data['code'])) $model->where('b.code', 'LIKE', '%'.$data['code'].'%');
  166. if(! empty($data['crt_time'][0]) && ! empty($data['crt_time'][1])) {
  167. $return = $this->changeDateToTimeStampAboutRange($data['crt_time']);
  168. $model->whereBetween('a.crt_time',[$return[0],$return[1]]);
  169. }
  170. $list = $this->limit($model,'',$data);
  171. $list = $this->fillListData($list);
  172. return [true, $list];
  173. }
  174. public function fillListData($data){
  175. if(empty($data['data'])) return $data;
  176. $category = ProductCategory::whereIn('id',array_column($data['data'],'product_category_id'))
  177. ->pluck('title','id')
  178. ->toArray();
  179. $basic_map = BasicType::whereIn('id',array_unique(array_column($data['data'],'unit')))
  180. ->pluck('title','id')
  181. ->toArray();
  182. foreach ($data['data'] as $key => $value){
  183. $data['data'][$key]['unit_title'] = $basic_map[$value['unit']] ?? '';
  184. $data['data'][$key]['product_category_title'] = $category[$value['product_category_id']] ?? '';
  185. $data['data'][$key]['crt_time'] = $value['crt_time'] ? date("Y-m-d H:i:s",$value['crt_time']):'';
  186. }
  187. return $data;
  188. }
  189. //库存台账
  190. public function productInventoryStockList($data,$user){
  191. $model = InOutRecord::from('in_out_record as a')
  192. ->where('a.del_time',0)
  193. ->join('product as b','b.id','a.product_id')
  194. ->select('a.id','a.product_id','a.number','a.order_type','a.crt_time','b.title','b.code','b.product_category_id','b.unit',DB::raw('SUM(CASE WHEN number < 0 THEN number ELSE 0 END) as out_number'),DB::raw('SUM(CASE WHEN number >= 0 THEN number ELSE 0 END) as in_number'),'a.order_number','a.crt_time')
  195. ->groupby('a.product_id','a.order_number')
  196. ->orderBy('a.crt_time','asc');
  197. if(empty($data['crt_time'][0]) || empty($data['crt_time'][1])) return [false,'时间必须选择'];
  198. $return = $this->changeDateToTimeStampAboutRange($data['crt_time']);
  199. $model->whereBetween('a.crt_time',[$return[0],$return[1]]);
  200. if(! empty($data['product_category_id'])) $model->whereIn("b.product_category_id", $data['product_category_id']);
  201. if(! empty($data['code'])) $model->where('b.code', 'LIKE', '%'.$data['code'].'%');
  202. if(! empty($data['product_id'])) $model->where('a.product_id', $data['product_id']);
  203. $list = $model->get()->toArray();
  204. $list = $this->fillData($list, $return);
  205. return [true, $list];
  206. }
  207. public function fillData($data,$time_arr){
  208. if (empty($data)) return $data;
  209. $start_data = InOutRecord::whereIn('product_id',array_column($data,'product_id'))
  210. ->where('crt_time','<',$time_arr[0])
  211. ->where('del_time',0)
  212. ->select('product_id','number',DB::raw('sum(number) as number'))
  213. ->groupby('product_id')
  214. ->get()->toArray();
  215. $start_map = [];
  216. foreach ($start_data as $value){
  217. $start_map[$value['product_id']] = $value['number'];
  218. }
  219. $category = ProductCategory::whereIn('id',array_unique(array_column($data,'b_r_f_id')))
  220. ->pluck('title','id')
  221. ->toArray();
  222. $roll_tmp = [];
  223. $order_type = $this->getOrderType();
  224. foreach ($data as $key => $value){
  225. $keys = $value['product_id'];
  226. if(! isset($roll_tmp[$keys])){
  227. if(isset($start_map[$keys])){
  228. $data[$key]['start_number'] = $start_map[$keys];
  229. }else{
  230. $data[$key]['start_number'] = 0;
  231. }
  232. $tmp = $data[$key]['start_number'] + $value['in_number'] + $value['out_number'];
  233. $data[$key]['end_number'] = round($tmp,2);
  234. $roll_tmp[$keys] = $data[$key]['end_number'];
  235. }else{
  236. $data[$key]['start_number'] = $roll_tmp[$keys];
  237. $tmp = $data[$key]['start_number'] + $value['in_number'] + $value['out_number'];
  238. $data[$key]['end_number'] = round($tmp,2);
  239. $roll_tmp[$keys] = $data[$key]['end_number'];
  240. }
  241. $data[$key]['out_number'] = abs($value['out_number']);
  242. $data[$key]['product_category_title'] = $category[$value['product_category_id']] ?? '';
  243. $data[$key]['order_name'] = $order_type[$value['order_type']] ?? '';
  244. $data[$key]['crt_time'] = $value['crt_time'] ? date("Y-m-d",$value['crt_time']):'';
  245. }
  246. return $data;
  247. }
  248. public function getOrderType(){
  249. $array = [];
  250. foreach (Construction::$prefix as $value){
  251. $array[$value] = '施工单';
  252. }
  253. foreach (ReturnExchangeOrder::$prefix as $key => $value){
  254. $array[$value] = ReturnExchangeOrder::$model_type_name[$key] ?? '';
  255. }
  256. foreach (SalesOrder::$prefix as $value){
  257. $array[$value] = '合同';
  258. }
  259. $array[InvoiceOrder::prefix] = '发货单';
  260. $array[PurchaseOrder::prefix] = '采购单';
  261. return $array;
  262. }
  263. }