Files

215 lines
6.4 KiB
PHP
Raw Permalink Normal View History

<?php
namespace App\Service\business;
use App\BaseApp\BaseService;
use App\Models\business\CatalogueModel;
use App\Models\business\PriceSheetModel;
use Exception;
use Illuminate\Support\Facades\DB;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
/**
* 报价单(商品规格 + 常规价)
*
* 老接口靠 specification-1a / dimension-1b / routine-1b 这种动态键接收多行表单,
* 数量还得靠 count($params) 猜,多一个无关字段就会多循环一轮。
* 新接口收 rows 数组,并提供 saveRows 一次性覆盖某商品的全部规格行——抽屉里就是这个语义。
*/
class PriceSheetService extends BaseService
{
public function __construct()
{
parent::__construct();
$this->model = PriceSheetModel::class;
$this->selectField = array_merge(
['id', 'catalogue_id', 'specification', 'dimension'],
PriceSheetModel::MATERIAL_FIELDS,
['status', 'created_at', 'updated_at']
);
$this->queryField = ['catalogue_id' => '=', 'specification' => 'like', 'status' => '='];
$this->orderBy = ['name' => 'id', 'sort' => 'asc'];
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function list(): array
{
return $this->getPageList();
}
public function option(): mixed
{
$this->optionField = ['id', 'specification as name'];
return $this->getOption();
}
/**
* @throws Exception
*/
public function detail($id): mixed
{
return $this->getDetail($id);
}
/**
* 新增单行或多行rows
* @throws Exception
*/
public function create($params): mixed
{
$catalogueId = (int) ($params['catalogue_id'] ?? 0);
$this->assertCatalogue($catalogueId);
$rows = $this->normalizeRows($catalogueId, $params);
if (empty($rows)) {
$this->utils->errorThrow('请至少填写一行规格');
}
if (count($rows) === 1) {
return $this->insert($rows[0]);
}
return PriceSheetModel::insert($rows);
}
/**
* @throws Exception
*/
public function update($id, $params): mixed
{
unset($params['rows']);
return $this->save($id, $params);
}
/**
* @throws Exception
*/
public function delete($id): mixed
{
return $this->del(is_array($id) ? $id : [$id]);
}
/**
* @throws Exception
*/
public function status($id, $status): mixed
{
return $this->save($id, ['status' => (int) $status]);
}
/**
* 覆盖式保存某商品的全部规格行:带 id 的更新,不带的新增,界面上被删掉的软删。
* 一次事务完成,避免中途失败留下半套规格。
* @throws Exception
*/
public function saveRows(int $catalogueId, array $rows): bool
{
$this->assertCatalogue($catalogueId);
$now = time();
$keepIds = [];
DB::connection('business')->beginTransaction();
try {
foreach ($rows as $row) {
$payload = $this->pickRowFields($row);
if (trim((string) ($payload['specification'] ?? '')) === '') {
continue;
}
$payload['catalogue_id'] = $catalogueId;
$id = (int) ($row['id'] ?? 0);
if ($id > 0) {
$payload['updated_at'] = $now;
PriceSheetModel::where('id', $id)->where('catalogue_id', $catalogueId)->update($payload);
$keepIds[] = $id;
} else {
$payload['created_at'] = $now;
$keepIds[] = (int) PriceSheetModel::insertGetId($payload);
}
}
PriceSheetModel::where('catalogue_id', $catalogueId)
->where('deleted_at', 0)
->when(!empty($keepIds), fn ($q) => $q->whereNotIn('id', $keepIds))
->update(['deleted_at' => $now, 'updated_at' => $now]);
DB::connection('business')->commit();
} catch (Exception $e) {
DB::connection('business')->rollBack();
$this->utils->errorThrow($e->getMessage());
}
return true;
}
/**
* 某商品的全部规格行,供报价单抽屉回填
*/
public function rowsOf(int $catalogueId): array
{
return PriceSheetModel::where('catalogue_id', $catalogueId)
->where('deleted_at', 0)
->orderBy('id')
->get($this->selectField)
->toArray();
}
/**
* 兼容单行字段与 rows 数组两种入参
*/
private function normalizeRows(int $catalogueId, array $params): array
{
$now = time();
$source = [];
if (!empty($params['rows']) && is_array($params['rows'])) {
$source = $params['rows'];
} elseif (trim((string) ($params['specification'] ?? '')) !== '') {
$source = [$params];
}
$rows = [];
foreach ($source as $row) {
if (!is_array($row)) {
continue;
}
$payload = $this->pickRowFields($row);
if (trim((string) ($payload['specification'] ?? '')) === '') {
continue;
}
$payload['catalogue_id'] = $catalogueId;
$payload['created_at'] = $now;
$rows[] = $payload;
}
return $rows;
}
/**
* 只取表里真实存在的列,把前端多传的字段挡在外面
*/
private function pickRowFields(array $row): array
{
$allowed = array_merge(['specification', 'dimension'], PriceSheetModel::MATERIAL_FIELDS);
$payload = [];
foreach ($allowed as $field) {
if (array_key_exists($field, $row)) {
$payload[$field] = is_scalar($row[$field]) ? (string) $row[$field] : '';
}
}
return $payload;
}
/**
* @throws Exception
*/
private function assertCatalogue(int $catalogueId): void
{
if ($catalogueId <= 0) {
$this->utils->errorThrow('请选择商品');
}
$exists = CatalogueModel::where('id', $catalogueId)->where('deleted_at', 0)->exists();
if (!$exists) {
$this->utils->errorThrow('商品不存在');
}
}
}