238 lines
8.4 KiB
PHP
238 lines
8.4 KiB
PHP
<?php
|
||
|
||
namespace App\Service\business;
|
||
|
||
use App\BaseApp\BaseService;
|
||
use App\Models\business\ListItemModel;
|
||
use App\Models\business\ListModel;
|
||
use App\Models\business\OrderModel;
|
||
use App\Models\business\PriceSheetModel;
|
||
use App\Models\business\WxUserModel;
|
||
|
||
/**
|
||
* 清单管理(后台)
|
||
*
|
||
* 后台看清单是为了帮客户报价与下单,所以详情里带的是「按该用户倍率算过的价格」,
|
||
* 与用户在小程序里看到的一致,否则电话里报的价和客户手机上的价对不上。
|
||
*/
|
||
class ListService extends BaseService
|
||
{
|
||
public function __construct()
|
||
{
|
||
parent::__construct();
|
||
$this->model = ListModel::class;
|
||
$this->selectField = [
|
||
'id', 'list_no', 'name', 'user_id', 'enterprise_id', 'remark',
|
||
'status', 'package_id', 'package_amount', 'original_amount',
|
||
'created_at', 'updated_at',
|
||
];
|
||
$this->queryField = [
|
||
'list_no' => 'like',
|
||
'name' => 'like',
|
||
'user_id' => '=',
|
||
'enterprise_id' => '=',
|
||
'status' => '=',
|
||
];
|
||
$this->with = ['user', 'enterprise'];
|
||
}
|
||
|
||
public function list(): array
|
||
{
|
||
$keyword = trim((string) request()->get('user_keyword', ''));
|
||
if ($keyword !== '') {
|
||
// 前端只给一个「客户」输入框,昵称与手机号都要能搜到
|
||
$userIds = WxUserModel::where('deleted_at', 0)
|
||
->where(function ($query) use ($keyword) {
|
||
$query->where('nick_name', 'like', '%' . $keyword . '%')
|
||
->orWhere('phone', 'like', '%' . $keyword . '%');
|
||
})->pluck('id')->all();
|
||
$this->whereIn = ['user_id', empty($userIds) ? [0] : $userIds];
|
||
}
|
||
|
||
$result = $this->getPageList();
|
||
$listIds = array_column($result['items'], 'id');
|
||
$counts = ListItemModel::whereIn('list_id', $listIds)
|
||
->where('deleted_at', 0)
|
||
->selectRaw('list_id, count(*) as total, sum(quantity) as quantity')
|
||
->groupBy('list_id')
|
||
->get()
|
||
->keyBy('list_id');
|
||
$orderCounts = OrderModel::whereIn('list_id', $listIds)
|
||
->where('deleted_at', 0)
|
||
->selectRaw('list_id, count(*) as total')
|
||
->groupBy('list_id')
|
||
->get()
|
||
->keyBy('list_id');
|
||
foreach ($result['items'] as &$item) {
|
||
$item['item_count'] = (int) ($counts[$item['id']]['total'] ?? 0);
|
||
$item['quantity'] = (int) ($counts[$item['id']]['quantity'] ?? 0);
|
||
$item['order_count'] = (int) ($orderCounts[$item['id']]['total'] ?? 0);
|
||
$item['user_name'] = $item['user']['nick_name'] ?? '';
|
||
$item['user_phone'] = $item['user']['phone'] ?? '';
|
||
$item['enterprise_name'] = $item['enterprise']['name'] ?? '';
|
||
}
|
||
unset($item);
|
||
return $result;
|
||
}
|
||
|
||
public function option(): mixed
|
||
{
|
||
$this->optionField = ['id', 'name'];
|
||
return $this->getOption();
|
||
}
|
||
|
||
/**
|
||
* 详情:带明细与算过倍率的价格
|
||
*/
|
||
public function detail($id): mixed
|
||
{
|
||
$info = ListModel::with([
|
||
'user',
|
||
'enterprise',
|
||
'items' => fn ($query) => $query->where('deleted_at', 0),
|
||
'items.catalogue',
|
||
'items.priceSheet',
|
||
])->where('id', $id)->where('deleted_at', 0)->first();
|
||
if (empty($info)) {
|
||
return $this->utils->notFound('清单不存在');
|
||
}
|
||
$info = $info->toArray();
|
||
$price = PriceService::getInstance();
|
||
$multiplier = $info['user']['price_number'] ?? 1;
|
||
$total = 0;
|
||
foreach ($info['items'] as &$item) {
|
||
$routine = $item['price_sheet']['routine'] ?? '';
|
||
$unit = (int) $item['unit_price'];
|
||
if ($unit <= 0) {
|
||
$unit = $price->resolveUnitPrice($routine, (string) $item['material_key'], $multiplier);
|
||
}
|
||
$item['unit_price'] = $unit;
|
||
$item['unit_price_text'] = $price->centsToYuan($unit);
|
||
$item['total_price'] = $unit * max(1, (int) $item['quantity']);
|
||
$item['routine_list'] = $price->formatRoutine($routine, true, $multiplier);
|
||
$total += $item['total_price'];
|
||
}
|
||
unset($item);
|
||
$info['total_amount'] = $total;
|
||
$info['total_amount_text'] = $price->centsToYuan($total);
|
||
$payable = PackageQuoteService::getInstance()->listPayable(
|
||
(int) ($info['package_id'] ?? 0),
|
||
(int) ($info['package_amount'] ?? 0),
|
||
(int) ($info['original_amount'] ?? 0),
|
||
$info['items']
|
||
);
|
||
$info = array_merge($info, PackageQuoteService::getInstance()->withText($payable));
|
||
return $info;
|
||
}
|
||
|
||
public function create($params): mixed
|
||
{
|
||
$params['list_no'] = SerialNoService::getInstance()->generate(SerialNoService::PREFIX_LIST, 'list', 'list_no');
|
||
return $this->insert($params);
|
||
}
|
||
|
||
public function update($id, $params): mixed
|
||
{
|
||
unset($params['list_no'], $params['user_id']);
|
||
return $this->save($id, $params);
|
||
}
|
||
|
||
public function delete($ids): mixed
|
||
{
|
||
return $this->del($ids);
|
||
}
|
||
|
||
/**
|
||
* 某个用户的全部清单,用户详情模态框里用
|
||
*/
|
||
public function byUser(int $userId): array
|
||
{
|
||
$rows = ListModel::where('user_id', $userId)->where('deleted_at', 0)->orderBy('id', 'desc')->get([
|
||
'id', 'list_no', 'name', 'status', 'created_at',
|
||
])->toArray();
|
||
$counts = ListItemModel::whereIn('list_id', array_column($rows, 'id'))
|
||
->where('deleted_at', 0)
|
||
->selectRaw('list_id, count(*) as total')
|
||
->groupBy('list_id')
|
||
->get()
|
||
->keyBy('list_id');
|
||
foreach ($rows as &$row) {
|
||
$row['item_count'] = (int) ($counts[$row['id']]['total'] ?? 0);
|
||
}
|
||
unset($row);
|
||
return $rows;
|
||
}
|
||
|
||
/**
|
||
* 后台代客下单
|
||
*/
|
||
public function toOrder(int $listId, array $params): array
|
||
{
|
||
return OrderCoreService::getInstance()->createFromList($listId, 0, $params);
|
||
}
|
||
|
||
/**
|
||
* 改明细(后台帮客户补规格与数量)
|
||
*/
|
||
public function saveItem(array $params): mixed
|
||
{
|
||
$itemId = (int) ($params['id'] ?? 0);
|
||
if ($itemId <= 0) {
|
||
$this->utils->errorThrow('参数错误');
|
||
}
|
||
$item = ListItemModel::with('list.user')->where('id', $itemId)->where('deleted_at', 0)->first();
|
||
if (empty($item)) {
|
||
$this->utils->errorThrow('明细不存在');
|
||
}
|
||
$update = ['updated_at' => time()];
|
||
foreach (['price_sheet_id', 'quantity'] as $field) {
|
||
if (array_key_exists($field, $params)) {
|
||
$update[$field] = (int) $params[$field];
|
||
}
|
||
}
|
||
foreach (['material_key', 'remark'] as $field) {
|
||
if (array_key_exists($field, $params)) {
|
||
$update[$field] = (string) $params[$field];
|
||
}
|
||
}
|
||
// 改规格后按该客户倍率重算当前单价,套餐清单才能按差额补差价
|
||
$sheetId = (int) ($update['price_sheet_id'] ?? $item['price_sheet_id']);
|
||
$material = (string) ($update['material_key'] ?? $item['material_key'] ?? 'routine');
|
||
if ($sheetId > 0) {
|
||
$sheet = PriceSheetModel::where('id', $sheetId)->where('deleted_at', 0)->first();
|
||
if (!empty($sheet)) {
|
||
$multiplier = $item['list']['user']['price_number'] ?? 1;
|
||
$update['unit_price'] = PriceService::getInstance()->resolveUnitPrice(
|
||
(string) ($sheet['routine'] ?? ''),
|
||
$material,
|
||
$multiplier
|
||
);
|
||
}
|
||
}
|
||
return ListItemModel::where('id', $itemId)->update($update);
|
||
}
|
||
|
||
/**
|
||
* 删明细
|
||
*/
|
||
public function deleteItem(array|int $ids): mixed
|
||
{
|
||
return ListItemModel::whereIn('id', (array) $ids)->update([
|
||
'deleted_at' => time(),
|
||
'updated_at' => time(),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 导出清单报价:后台画 xlsx,小程序用 text 分享
|
||
*/
|
||
public function exportQuote(int $id): array
|
||
{
|
||
$info = $this->detail($id);
|
||
if (!is_array($info)) {
|
||
$this->utils->errorThrow('清单不存在');
|
||
}
|
||
return \App\Service\common\ExcelCsvService::getInstance()->quoteFromList($info);
|
||
}
|
||
}
|