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

111 lines
4.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Controllers\PSI;
use App\Controllers\Controller;
use App\Models\PSI\Sales;
use App\Models\PSI\Product;
use App\Models\PSI\Material;
/** 销售出库:内销 + 外贸出口。出库自动扣减库存并校验库存充足 */
class SalesController extends Controller
{
use StockHelper;
public function index()
{
$sales = (new Sales())->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');
}
}