first version
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Exceptions\RepositoryException;
|
||||
use App\Models\StatementItemModel;
|
||||
use App\Models\StatementModel;
|
||||
use App\Models\StoreModel;
|
||||
use App\Models\StoreOrderItemModel;
|
||||
use App\Models\StoreOrderModel;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* 门店对账单生成(小程序端自助生成)
|
||||
*
|
||||
* 流程(事务内):
|
||||
* 1. 拉取门店周期内的订单明细(排除已取消订单,按 order_item 去重防止重复入账)
|
||||
* 2. 快照当前 payment_cycle_days,settlement_date = period_end + cycle 天
|
||||
* 3. 明细快照商品名/单价/数量/重量/金额,statement_no = ST…
|
||||
*/
|
||||
class StatementGenerateService
|
||||
{
|
||||
public function __construct(private readonly BillNumberService $billNumberService)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StoreModel $store 门店(回款周期从此快照)
|
||||
* @param string $periodStart 周期开始(Y-m-d)
|
||||
* @param string $periodEnd 周期结束(Y-m-d)
|
||||
*/
|
||||
public function generate(StoreModel $store, string $periodStart, string $periodEnd): StatementModel
|
||||
{
|
||||
return DB::transaction(function () use ($store, $periodStart, $periodEnd) {
|
||||
$orderItems = StoreOrderItemModel::query()
|
||||
->join('store_order', 'store_order.id', '=', 'store_order_item.order_id')
|
||||
->where('store_order_item.store_id', $store->id)
|
||||
->whereDate('store_order.order_date', '>=', $periodStart)
|
||||
->whereDate('store_order.order_date', '<=', $periodEnd)
|
||||
->where('store_order.status', '<>', StoreOrderModel::STATUS_CANCELLED)
|
||||
->select('store_order_item.*')
|
||||
->get();
|
||||
|
||||
if ($orderItems->isEmpty()) {
|
||||
throw new RepositoryException('周期内本店无订单数据,无法生成对账单');
|
||||
}
|
||||
|
||||
// 防重复入账:剔除已计入过对账单的订单明细
|
||||
$usedItemIds = StatementItemModel::query()
|
||||
->whereIn('statement_id', StatementModel::where('store_id', $store->id)->pluck('id'))
|
||||
->pluck('order_item_id');
|
||||
$orderItems = $orderItems->reject(fn ($item) => $usedItemIds->contains($item->id));
|
||||
if ($orderItems->isEmpty()) {
|
||||
throw new RepositoryException('周期内的订单明细均已生成过对账单');
|
||||
}
|
||||
|
||||
// 快照回款周期 → 应结算日期
|
||||
$cycleDays = (int) $store->payment_cycle_days;
|
||||
$totalAmount = $orderItems->reduce(
|
||||
static fn (string $carry, $item): string => bcadd($carry, (string) $item->amount, 2),
|
||||
'0'
|
||||
);
|
||||
|
||||
$statement = StatementModel::create([
|
||||
'statement_no' => $this->billNumberService->make('ST'),
|
||||
'store_id' => $store->id,
|
||||
'period_start' => $periodStart,
|
||||
'period_end' => $periodEnd,
|
||||
'total_amount' => $totalAmount,
|
||||
'payment_cycle_days' => $cycleDays,
|
||||
'settlement_date' => Carbon::parse($periodEnd)->addDays($cycleDays)->toDateString(),
|
||||
'status' => StatementModel::STATUS_PENDING,
|
||||
]);
|
||||
|
||||
$rows = [];
|
||||
$now = now();
|
||||
foreach ($orderItems as $item) {
|
||||
$rows[] = [
|
||||
'statement_id' => $statement->id,
|
||||
'order_id' => $item->order_id,
|
||||
'order_item_id' => $item->id,
|
||||
'product_id' => $item->product_id,
|
||||
'product_name' => $item->product_name,
|
||||
'price' => $item->price,
|
||||
'quantity' => $item->quantity,
|
||||
'weight' => $item->weight,
|
||||
'amount' => $item->amount,
|
||||
'is_reconciled' => StatementItemModel::NOT_RECONCILED,
|
||||
'store_remark' => '',
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
}
|
||||
StatementItemModel::insert($rows);
|
||||
|
||||
return $statement;
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user