all(); return $this->renderSubsys('psi', 'psi/sales', ['sales' => $sales], \psi_nav(), 'sales'); } public function create() { subsys_admin('psi') or \Core\App::forbidden('需要 PSI 管理员权限'); $materials = (new \App\Models\PSI\Material())->all(); $products = (new \App\Models\PSI\Product())->all(); return $this->renderSubsys('psi', 'psi/sale_form', [ 'sale' => null, 'materials' => $materials, 'products' => $products, ], \psi_nav(), 'sales'); } public function store() { subsys_admin('psi') or \Core\App::forbidden('需要 PSI 管理员权限'); if (!csrf_check()) return $this->redirect('PSI/sales'); $itemType = $this->post('item_type') === 'material' ? 'material' : 'product'; $itemId = (int)$this->post('item_id'); $qty = (float)$this->post('qty'); $price = (float)$this->post('price'); if ($itemId <= 0 || $qty <= 0) { $this->flash('请选择有效的成品/物料并填写数量'); return $this->redirect('PSI/sales'); } $model = $itemType === 'product' ? new Product() : new Material(); $item = $model->find($itemId); if (!$item || (float)($item['stock'] ?? 0) < $qty) { $this->flash('库存不足,无法出库(当前库存:' . (isset($item) ? (float)$item['stock'] : 0) . ')'); return $this->redirect('PSI/sales'); } $no = 'SO' . date('Ymd') . '-' . substr(uniqid(), -4); $saleId = (new Sales())->insert([ 'order_no' => $no, 'customer' => trim($this->post('customer')), 'channel' => $this->post('channel') === 'export' ? 'export' : 'domestic', 'region' => trim($this->post('region')), 'item_id' => $itemId, 'item_type' => $itemType, 'qty' => $qty, 'price' => $price, 'amount' => $qty * $price, 'status' => 'shipped', 'batch_no' => trim($this->post('batch_no')), 'remark' => trim($this->post('remark')), 'created_at' => date('Y-m-d'), ]); $this->adjustStock($itemType, $itemId, $qty, 'out', $no, trim($this->post('batch_no'))); $this->flash('销售出库成功,库存已扣减', 'ok'); if ($this->post('auto_print', '1') !== '0') { return $this->redirect('PSI/sales/print/' . $saleId); } return $this->redirect('PSI/sales'); } public function show($id) { $sale = (new Sales())->find($id); if (!$sale) { \Core\App::notFound('销售记录不存在'); return; } $itemInfo = $this->lookupItem($sale['item_id'] ?? 0, $sale['item_type'] ?? ''); return $this->renderSubsys('psi', 'psi/sales_show', [ 's' => $sale, 'item' => $itemInfo, ], \psi_nav(), 'sales'); } public function printDoc($id) { $sale = (new Sales())->find($id); if (!$sale) { \Core\App::notFound('销售记录不存在'); return; } $itemInfo = $this->lookupItem($sale['item_id'] ?? 0, $sale['item_type'] ?? ''); $body = \Core\View::buffer('psi/sales_print', ['s' => $sale, 'item' => $itemInfo]); echo \psi_print_shell('销售出库单 - ' . e($sale['order_no']), $body); } /** 尝试从成品表或物料表查找物品信息 */ private function lookupItem(int $itemId, string $itemType = ''): array { if ($itemId <= 0) return ['name' => '—', 'spec' => '', 'unit' => '']; if ($itemType === 'material') { $row = (new Material())->find($itemId); } else { $row = (new Product())->find($itemId) ?: (new Material())->find($itemId); } if ($row) return ['name' => $row['name'] ?? '—', 'spec' => $row['spec'] ?? '', 'unit' => $row['unit'] ?? '']; return ['name' => '—', 'spec' => '', 'unit' => '']; } public function destroy($id) { subsys_admin('psi') or \Core\App::forbidden('需要 PSI 管理员权限'); (new Sales())->delete($id); return $this->redirect('PSI/sales'); } }