all(); // id 升序 $orders = array_reverse($orders); // 最新在前 $itemM = new SalesOrderItem(); foreach ($orders as &$o) { $o['_items'] = $itemM->whereAll('so_id', $o['id']); } return $this->renderSubsys('psi', 'psi/sales_orders', ['orders' => $orders], \psi_nav(), 'sales_orders'); } public function create() { $products = (new Product())->all(); return $this->renderSubsys('psi', 'psi/sales_order_form', [ 'o' => null, 'items' => [], 'products' => $products, ], \psi_nav(), 'sales_orders'); } public function store() { if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !csrf_check()) return $this->redirect('PSI/sales_orders/create'); $items = $this->parseItems(); if (empty($items)) { $this->flash('请至少添加一条商品明细', 'err'); return $this->redirect('PSI/sales_orders/create'); } $id = (new SalesOrder())->insert([ 'order_no' => $oNo = \psi_gen_no('SO'), 'customer' => $cust = trim($this->post('customer')), 'salesman' => $sales = trim($this->post('salesman')) ?: ($_SESSION['admin_name'] ?? ''), 'channel' => $this->post('channel') === 'export' ? 'export' : 'domestic', 'region' => trim($this->post('region')), 'delivery_date' => $this->post('delivery_date') ?: null, 'remark' => trim($this->post('remark')), 'status' => 'pending', 'created_at' => date('Y-m-d H:i:s'), ]); $itemM = new SalesOrderItem(); foreach ($items as $it) { $it['so_id'] = $id; $itemM->insert($it); } \Core\Notify::newSalesOrder($oNo, $cust, $sales, $id); $this->flash('销售订单已创建', 'ok'); if ($this->post('auto_print', '1') !== '0') { return $this->redirect('PSI/sales_orders/print/' . $id); } return $this->redirect('PSI/sales_orders/show/' . $id); } public function show($id) { $o = (new SalesOrder())->find($id); if (!$o) { \Core\App::notFound(); return; } $items = (new SalesOrderItem())->whereAll('so_id', $id); return $this->renderSubsys('psi', 'psi/sales_order_show', [ 'o' => $o, 'items' => $items, ], \psi_nav(), 'sales_orders'); } public function edit($id) { $o = (new SalesOrder())->find($id); if (!$o) { \Core\App::notFound(); return; } $items = (new SalesOrderItem())->whereAll('so_id', $id); $products = (new Product())->all(); return $this->renderSubsys('psi', 'psi/sales_order_form', [ 'o' => $o, 'items' => $items, 'products' => $products, ], \psi_nav(), 'sales_orders'); } public function update($id) { if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !csrf_check()) return $this->redirect('PSI/sales_orders/edit/' . $id); $o = (new SalesOrder())->find($id); if (!$o) { \Core\App::notFound(); return; } $items = $this->parseItems(); if (empty($items)) { $this->flash('请至少添加一条商品明细', 'err'); return $this->redirect('PSI/sales_orders/edit/' . $id); } (new SalesOrder())->update($id, [ 'customer' => trim($this->post('customer')), 'salesman' => trim($this->post('salesman')) ?: ($_SESSION['admin_name'] ?? ''), 'channel' => $this->post('channel') === 'export' ? 'export' : 'domestic', 'region' => trim($this->post('region')), 'delivery_date' => $this->post('delivery_date') ?: null, 'remark' => trim($this->post('remark')), ]); // 保留已交付数量(delivered_qty)避免覆盖出库记录 $old = (new SalesOrderItem())->whereAll('so_id', $id); $delivered = []; foreach ($old as $oi) { $delivered[($oi['product_id'] ?? 0) . '|' . $oi['name']] = (int)($oi['delivered_qty'] ?? 0); } (new SalesOrderItem())->deleteRaw('so_id', $id); foreach ($items as $it) { $key = ($it['product_id'] ?? 0) . '|' . $it['name']; $it['delivered_qty'] = $delivered[$key] ?? 0; $it['so_id'] = $id; (new SalesOrderItem())->insert($it); } \psi_recompute_so($id); $this->flash('销售订单已更新', 'ok'); return $this->redirect('PSI/sales_orders/show/' . $id); } public function destroy($id) { if ($_SERVER['REQUEST_METHOD'] === 'POST' && csrf_check()) { (new SalesOrderItem())->deleteRaw('so_id', $id); (new SalesOrder())->delete($id); $this->flash('销售订单已删除', 'ok'); } return $this->redirect('PSI/sales_orders'); } public function printDoc($id) { $o = (new SalesOrder())->find($id); if (!$o) { \Core\App::notFound(); return; } $items = (new SalesOrderItem())->whereAll('so_id', $id); $body = \App\Core\View::render('psi/sales_order_print', ['o' => $o, 'items' => $items]); echo \psi_print_shell('销售订单 ' . $o['order_no'], $body); } /** 解析提交的商品明细行 */ private function parseItems(): array { $raw = $_POST['items'] ?? []; $out = []; foreach ($raw as $row) { $name = trim((string)($row['name'] ?? '')); $qty = (int)($row['qty'] ?? 0); $price = (float)($row['price'] ?? 0); if ($name === '' || $qty <= 0) continue; $out[] = [ 'product_id' => (int)($row['product_id'] ?? 0), 'name' => $name, 'spec' => trim((string)($row['spec'] ?? '')), 'unit' => trim((string)($row['unit'] ?? '')), 'qty' => $qty, 'price' => $price, 'amount' => round($qty * $price, 2), 'delivered_qty' => 0, ]; } return $out; } }