157 lines
6.4 KiB
PHP
157 lines
6.4 KiB
PHP
<?php
|
|
namespace App\Controllers\PSI;
|
|
|
|
use App\Controllers\Controller;
|
|
use App\Models\PSI\SalesOrder;
|
|
use App\Models\PSI\SalesOrderItem;
|
|
use App\Models\PSI\Product;
|
|
|
|
/**
|
|
* 销售订单:录入(可打印)、关联出库。
|
|
* 业务员默认取当前登录人;商品可关联 psi_products(用于后续出库扣减库存)。
|
|
*/
|
|
class SalesOrdersController extends Controller
|
|
{
|
|
public function index()
|
|
{
|
|
$orders = (new SalesOrder())->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;
|
|
}
|
|
}
|