189 lines
5.8 KiB
PHP
189 lines
5.8 KiB
PHP
<?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());
|
||
}
|
||
}
|
||
} |