Files
xin-procurement/app/Services/BillDetailService.php
T
2026-09-25 00:30:02 +08:00

98 lines
3.9 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\BillModel;
use App\Models\ProductModel;
use App\Models\StoreOrderItemModel;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Contracts\Container\CircularDependencyException;
use Illuminate\Support\Collection;
/**
* 账单详情数据组装(后台门店账单页与小程序账单详情共用)
*/
class BillDetailService
{
/**
* 合并后的商品明细:按商品聚合账单关联的全部订单明细
* 单价为加权平均口径(Σ金额÷Σ数量),保证 单价×数量=金额;附商品首图
*
* @param BillModel $bill
* @return array<int, array{product_id: int, product_name: string, product_spec: string, unit: string, price: string, quantity: int, weight: string, amount: string, spec: string, price_unit: string, image: string}>
* @throws BindingResolutionException
* @throws CircularDependencyException
*/
public function mergedItems(BillModel $bill): array
{
$items = StoreOrderItemModel::query()
->where('bill_id', $bill->id)
->where('quantity', '>', 0)
->orderBy('id')
->get();
return $this->aggregateItems($items);
}
/**
* 按商品聚合订单明细:数量累加、重量/金额 bc 累加、单价加权平均,
* 首图取明细快照 image_ids 批量解析,按「分类sort → 商品sort」排序
*
* @param Collection<int, StoreOrderItemModel> $items
* @return array<int, array{product_id: int, product_name: string, product_spec: string, unit: string, price: string, quantity: int, weight: string, amount: string, spec: string, price_unit: string, image: string}>
* @throws BindingResolutionException
* @throws CircularDependencyException
*/
private function aggregateItems(Collection $items): array
{
// 排序键:分类 sort → 商品 sort(与采购单明细矩阵同序)
$products = ProductModel::withTrashed()
->with('category:id,sort')
->whereIn('id', $items->pluck('product_id')->unique())
->get()
->keyBy('id');
$rows = [];
foreach ($items->groupBy('product_id') as $productId => $group) {
$product = $products->get((int) $productId);
$first = $group->first();
$quantity = 0;
$weight = '0';
$amount = '0';
foreach ($group as $item) {
$quantity += (int) $item->quantity;
$weight = bcadd($weight, (string) $item->weight, 3);
$amount = bcadd($amount, (string) $item->amount, 2);
}
$price = bcdiv($amount, (string) $quantity, 2);
$rows[] = [
'product_id' => (int) $productId,
'product_name' => $first->product_name,
'product_spec' => $first->product_spec,
'unit' => $first->unit,
'price' => $price,
'quantity' => $quantity,
'weight' => $weight,
'amount' => $amount,
'spec' => $product->spec,
'price_unit' => $product->price_unit,
'image_ids' => (array) $first->image_ids,
'category_sort' => (int) ($product->category->sort ?? 9999),
'product_sort' => (int) ($product->sort ?? 9999),
];
}
usort($rows, static fn (array $a, array $b): int =>
[$a['category_sort'], $a['product_sort'], $a['product_id']]
<=> [$b['category_sort'], $b['product_sort'], $b['product_id']]);
// 首图批量解析(写入 image、移除 image_ids)
app(ItemImageResolver::class)->resolve($rows);
return array_map(static function (array $row): array {
unset($row['category_sort'], $row['product_sort']);
return $row;
}, $rows);
}
}