erp-backend/app/Services/PurchaseService.php
2026-04-01 17:07:04 +08:00

189 lines
5.8 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\Services;
use App\Models\PurchaseOrder;
use App\Models\ReceivingOrder;
use App\Models\ReceivingOrderItem;
use App\Models\ErpSku;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class PurchaseService
{
protected $stockService;
public function __construct(StockService $stockService)
{
$this->stockService = $stockService;
}
/**
* 生成采购单号
*/
public function generatePoNo()
{
$prefix = 'PO';
$date = date('Ymd');
$last = PurchaseOrder::where('po_no', 'like', $prefix . $date . '%')
->orderBy('po_no', 'desc')
->first();
if ($last) {
$num = intval(substr($last->po_no, -4)) + 1;
} else {
$num = 1;
}
return $prefix . $date . str_pad($num, 4, '0', STR_PAD_LEFT);
}
/**
* 生成收货单号
*/
public function generateReceivingNo()
{
$prefix = 'RO';
$date = date('Ymd');
$last = ReceivingOrder::where('receiving_no', 'like', $prefix . $date . '%')
->orderBy('receiving_no', 'desc')
->first();
if ($last) {
$num = intval(substr($last->receiving_no, -4)) + 1;
} else {
$num = 1;
}
return $prefix . $date . str_pad($num, 4, '0', STR_PAD_LEFT);
}
/**
* 审核采购单
*/
public function approve(PurchaseOrder $order)
{
if ($order->status !== 'under_review') {
throw new \Exception('采购单状态错误,无法审核');
}
DB::transaction(function () use ($order) {
$order->status = 'approved';
$order->save();
// 自动生成收货单
$receivingNo = $this->generateReceivingNo();
$totalQty = $order->items->sum('quantity');
$receivingOrder = ReceivingOrder::create([
'receiving_no' => $receivingNo,
'po_id' => $order->id,
'warehouse_id' => $order->warehouse_id,
'total_quantity' => $totalQty,
'received_quantity' => 0,
'status' => 'pending',
'receiver' => null,
'is_cloud_warehouse' => $order->cloud_system ? true : false,
]);
foreach ($order->items as $item) {
ReceivingOrderItem::create([
'receiving_order_id' => $receivingOrder->id,
'sku_code' => $item->sku_code,
'sku_name' => $item->sku_name,
'order_quantity' => $item->quantity,
'received_quantity' => 0,
]);
}
});
return $order;
}
/**
* 驳回采购单
*/
public function reject(PurchaseOrder $order, $comment)
{
if ($order->status !== 'under_review') {
throw new \Exception('采购单状态错误,无法驳回');
}
$order->status = 'rejected';
$order->audit_comment = $comment;
$order->save();
return $order;
}
/**
* 执行收货
*/
public function receive(ReceivingOrder $receivingOrder, array $items, $receiver)
{
if ($receivingOrder->status === 'completed') {
throw new \Exception('收货单已完成,无法再次收货');
}
DB::transaction(function () use ($receivingOrder, $items, $receiver) {
$totalReceived = 0;
$po = $receivingOrder->purchaseOrder;
foreach ($receivingOrder->items as $orderItem) {
$found = collect($items)->firstWhere('sku_code', $orderItem->sku_code);
if ($found) {
$qty = min($found['received_quantity'], $orderItem->order_quantity - $orderItem->received_quantity);
if ($qty > 0) {
$orderItem->received_quantity += $qty;
$orderItem->save();
// 入库到库存
$this->stockService->inbound(
$orderItem->sku_code,
$receivingOrder->warehouse_id,
$qty,
$po->po_no,
'采购入库,采购单号:' . $po->po_no
);
$totalReceived += $qty;
}
}
}
$receivingOrder->received_quantity += $totalReceived;
$receivingOrder->receiver = $receiver;
if ($receivingOrder->received_quantity >= $receivingOrder->total_quantity) {
$receivingOrder->status = 'completed';
$allCompleted = $po->receivingOrders()->where('status', '!=', 'completed')->count() == 0;
if ($allCompleted && $po->status !== 'completed') {
$po->status = 'completed';
$po->save();
}
} else {
$receivingOrder->status = 'partial';
}
$receivingOrder->save();
});
return $receivingOrder->fresh();
}
/**
* 推送云仓(模拟)
*/
public function pushToCloud(PurchaseOrder $order)
{
if ($order->pushed_to_cloud) {
throw new \Exception('采购单已推送过云仓');
}
// 模拟推送逻辑实际应调用对应云仓API
try {
$response = ['success' => true, 'message' => '推送成功', 'cloud_po_no' => 'CLOUD_' . $order->po_no];
$order->pushed_to_cloud = true;
$order->pushed_at = now();
$order->cloud_response = json_encode($response);
$order->save();
return $response;
} catch (\Exception $e) {
throw new \Exception('推送云仓失败:' . $e->getMessage());
}
}
}