Files
coolcoth.com/app/Controllers/PSI/PurchaseOrdersController.php
T
2026-08-08 15:53:53 +08:00

177 lines
8.1 KiB
PHP

<?php
namespace App\Controllers\PSI;
use App\Controllers\Controller;
use App\Models\PSI\PurchaseOrder;
use App\Models\PSI\PurchaseOrderItem;
use App\Models\PSI\Material;
use App\Models\PSI\Product;
use App\Models\PSI\Purchase;
use App\Controllers\PSI\StockHelper;
/**
* 采购订单:录入(可打印)、收货入库(写 psi_purchases 并增加成品库存)。
* 供应商从 psi_suppliers 选择;明细可为物料或成品。
*/
class PurchaseOrdersController extends Controller
{
public function index()
{
$orders = array_reverse((new PurchaseOrder())->all());
$itemM = new PurchaseOrderItem();
foreach ($orders as &$o) { $o['_items'] = $itemM->whereAll('po_id', $o['id']); }
return $this->renderSubsys('psi', 'psi/purchase_orders', ['orders' => $orders], \psi_nav(), 'purchase_orders');
}
public function create()
{
return $this->renderSubsys('psi', 'psi/purchase_order_form', [
'o' => null, 'items' => [], 'materials' => (new Material())->all(), 'products' => (new Product())->all(),
], \psi_nav(), 'purchase_orders');
}
public function store()
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !csrf_check()) return $this->redirect('PSI/purchase_orders/create');
$items = $this->parseItems();
if (empty($items)) { $this->flash('请至少添加一条采购明细', 'err'); return $this->redirect('PSI/purchase_orders/create'); }
$id = (new PurchaseOrder())->insert([
'order_no' => $oNo = \psi_gen_no('PO'),
'supplier_id' => (int)$this->post('supplier_id'),
'supplier_name' => $supp = trim($this->post('supplier_name')),
'salesman' => $buyer = trim($this->post('salesman')) ?: ($_SESSION['admin_name'] ?? ''),
'status' => 'pending',
'expected_at' => $this->post('expected_at') ?: null,
'remark' => trim($this->post('remark')),
'created_at' => date('Y-m-d H:i:s'),
]);
$itemM = new PurchaseOrderItem();
foreach ($items as $it) { $it['po_id'] = $id; $itemM->insert($it); }
\Core\Notify::newPurchaseOrder($oNo, $supp, $buyer, $id);
$this->flash('采购订单已创建', 'ok');
if ($this->post('auto_print', '1') !== '0') {
return $this->redirect('PSI/purchase_orders/print/' . $id);
}
return $this->redirect('PSI/purchase_orders/show/' . $id);
}
public function show($id)
{
$o = (new PurchaseOrder())->find($id);
if (!$o) { \Core\App::notFound(); return; }
$items = (new PurchaseOrderItem())->whereAll('po_id', $id);
return $this->renderSubsys('psi', 'psi/purchase_order_show', ['o' => $o, 'items' => $items], \psi_nav(), 'purchase_orders');
}
public function edit($id)
{
$o = (new PurchaseOrder())->find($id);
if (!$o) { \Core\App::notFound(); return; }
if (in_array($o['status'], ['received'], true)) { $this->flash('已收货的采购订单不可编辑', 'err'); return $this->redirect('PSI/purchase_orders/show/' . $id); }
$items = (new PurchaseOrderItem())->whereAll('po_id', $id);
return $this->renderSubsys('psi', 'psi/purchase_order_form', [
'o' => $o, 'items' => $items, 'materials' => (new Material())->all(), 'products' => (new Product())->all(),
], \psi_nav(), 'purchase_orders');
}
public function update($id)
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !csrf_check()) return $this->redirect('PSI/purchase_orders/edit/' . $id);
$o = (new PurchaseOrder())->find($id);
if (!$o) { \Core\App::notFound(); return; }
$items = $this->parseItems();
if (empty($items)) { $this->flash('请至少添加一条采购明细', 'err'); return $this->redirect('PSI/purchase_orders/edit/' . $id); }
(new PurchaseOrder())->update($id, [
'supplier_id' => (int)$this->post('supplier_id'),
'supplier_name' => trim($this->post('supplier_name')),
'salesman' => trim($this->post('salesman')) ?: ($_SESSION['admin_name'] ?? ''),
'expected_at' => $this->post('expected_at') ?: null,
'remark' => trim($this->post('remark')),
]);
$old = (new PurchaseOrderItem())->whereAll('po_id', $id);
$recv = [];
foreach ($old as $oi) { $recv[($oi['item_type'] ?? '') . '|' . ($oi['item_id'] ?? 0) . '|' . $oi['name']] = (int)($oi['received_qty'] ?? 0); }
(new PurchaseOrderItem())->deleteRaw('po_id', $id);
foreach ($items as $it) {
$key = ($it['item_type'] ?? '') . '|' . ($it['item_id'] ?? 0) . '|' . $it['name'];
$it['received_qty'] = $recv[$key] ?? 0;
$it['po_id'] = $id;
(new PurchaseOrderItem())->insert($it);
}
$this->flash('采购订单已更新', 'ok');
return $this->redirect('PSI/purchase_orders/show/' . $id);
}
/** 收货入库:成品增加库存 + 写入采购入库流水;更新已收数量与状态 */
public function receive($id)
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !csrf_check()) return $this->redirect('PSI/purchase_orders/show/' . $id);
$o = (new PurchaseOrder())->find($id);
if (!$o) { \Core\App::notFound(); return; }
if ($o['status'] === 'received') { $this->flash('该采购订单已收货,不可重复操作', 'err'); return $this->redirect('PSI/purchase_orders/show/' . $id); }
$items = (new PurchaseOrderItem())->whereAll('po_id', $id);
$purchaseM = new Purchase();
foreach ($items as $it) {
if ((int)$it['qty'] <= 0) continue;
if ($it['item_type'] === 'product' && (int)$it['item_id'] > 0) {
StockHelper::adjustStock((int)$it['item_id'], (int)$it['qty'], 'in', '采购入库', $o['order_no']);
$purchaseM->insert([
'product_id' => (int)$it['item_id'], 'qty' => (int)$it['qty'],
'price' => (float)$it['price'], 'amount' => (float)$it['amount'],
'supplier' => $o['supplier_name'], 'order_no' => $o['order_no'],
'created_at' => date('Y-m-d H:i:s'),
]);
}
(new PurchaseOrderItem())->update($it['id'], ['received_qty' => (int)$it['qty']]);
}
(new PurchaseOrder())->update($id, ['status' => 'received']);
$this->flash('采购订单已收货入库', 'ok');
return $this->redirect('PSI/purchase_orders/show/' . $id);
}
public function destroy($id)
{
if ($_SERVER['REQUEST_METHOD'] === 'POST' && csrf_check()) {
(new PurchaseOrderItem())->deleteRaw('po_id', $id);
(new PurchaseOrder())->delete($id);
$this->flash('采购订单已删除', 'ok');
}
return $this->redirect('PSI/purchase_orders');
}
public function printDoc($id)
{
$o = (new PurchaseOrder())->find($id);
if (!$o) { \Core\App::notFound(); return; }
$items = (new PurchaseOrderItem())->whereAll('po_id', $id);
$body = \App\Core\View::render('psi/purchase_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[] = [
'item_type' => $row['item_type'] === 'product' ? 'product' : 'material',
'item_id' => (int)($row['item_id'] ?? 0),
'name' => $name,
'spec' => trim((string)($row['spec'] ?? '')),
'unit' => trim((string)($row['unit'] ?? '')),
'qty' => $qty,
'price' => $price,
'amount' => round($qty * $price, 2),
'received_qty' => 0,
];
}
return $out;
}
}