CaiWuXiTong/modules/EcommerceFinance/Services/ShengsuanOrderProfitRowMapper.php
renshen 1b6ff0bb75 feat: 新增成本运费异常监控 (#992)
成本/运费异常页监控商品成本和快递费同时缺失的订单。
2026-11-07 18:04:44 +08:00

130 lines
4.2 KiB
PHP

<?php
namespace Modules\EcommerceFinance\Services;
class ShengsuanOrderProfitRowMapper
{
public const TABLE = 'ops_shengsuan_order_profit_rows';
private const FEE_FIELDS = [
'包材费(自动匹配)' => 'matched_package_fee',
'快递费(自动匹配)' => 'matched_freight_fee',
'账单费用(自动匹配)' => 'matched_bill_fee',
'分类单成本生成费用' => 'generated_classification_fee',
'商品成本生成费用' => 'generated_product_fee',
'人工维护' => 'manual_fee',
'订单费用' => 'order_fee',
'其中:推广费' => 'promotion_fee',
];
private const ROW_FIELDS = [
'店铺名称' => 'shop_name',
'线上单号' => 'online_order_no',
'内部单号' => 'internal_order_no',
'发货时间' => 'ship_time',
'商品成本' => 'product_cost',
];
public function table(): string
{
return self::TABLE;
}
/**
* @param array<string,mixed> $decoded
* @return list<array<string,mixed>>
*/
public function rows(array $decoded): array
{
$data = $decoded['data'] ?? $decoded;
if (! is_array($data)) {
return [];
}
$heads = is_array($data['fldHeads'] ?? null) ? $data['fldHeads'] : [];
$dataList = is_array($data['dataList'] ?? null) ? $data['dataList'] : [];
$fields = [];
foreach (self::ROW_FIELDS + self::FEE_FIELDS as $title => $field) {
$fields[$field] = $this->fieldForTitle($heads, $title);
}
$rows = [];
$now = now();
foreach ($dataList as $record) {
if (! is_array($record)) {
continue;
}
$shopName = trim((string) $this->value($record, $fields['shop_name'] ?? null));
$onlineOrder = trim((string) $this->value($record, $fields['online_order_no'] ?? null));
$internalOrder = trim((string) $this->value($record, $fields['internal_order_no'] ?? null));
$orderNo = $onlineOrder !== '' ? $onlineOrder : $internalOrder;
if ($shopName === '' || $orderNo === '') {
continue;
}
$row = [
'shop_name' => $shopName,
'online_order_no' => $onlineOrder !== '' ? $onlineOrder : null,
'internal_order_no' => $internalOrder !== '' ? $internalOrder : null,
'order_key' => $shopName . '|' . $orderNo,
'ship_time' => $this->dateTime($this->value($record, $fields['ship_time'] ?? null)),
'product_cost' => $this->decimal($this->value($record, $fields['product_cost'] ?? null)),
'source_payload' => json_encode($record, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
'synced_at' => $now,
'created_at' => $now,
'updated_at' => $now,
];
foreach (self::FEE_FIELDS as $title => $column) {
$row[$column] = $this->decimal($this->value($record, $fields[$column] ?? null));
}
$rows[] = $row;
}
return $rows;
}
/**
* @param list<array<string,mixed>> $heads
*/
private function fieldForTitle(array $heads, string $title): ?string
{
foreach ($heads as $head) {
if (trim((string) ($head['title'] ?? '')) === $title) {
$field = trim((string) ($head['fld'] ?? ''));
return $field === '' ? null : $field;
}
}
return null;
}
/** @param array<string,mixed> $record */
private function value(array $record, ?string $field): mixed
{
return $field === null ? null : ($record[$field] ?? null);
}
private function decimal(mixed $value): ?float
{
if ($value === null || $value === '') {
return null;
}
return is_numeric($value) ? round((float) $value, 2) : null;
}
private function dateTime(mixed $value): ?string
{
if ($value === null || trim((string) $value) === '') {
return null;
}
$timestamp = strtotime((string) $value);
return $timestamp === false ? null : date('Y-m-d H:i:s', $timestamp);
}
}