first version

This commit is contained in:
liu
2026-07-23 20:41:25 +08:00
parent 00a0938a1b
commit 10cff754a4
211 changed files with 11577 additions and 842 deletions
+100
View File
@@ -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_dayssettlement_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;
});
}
}