在京东账单右侧新增京喜账单页签,复用京东日账单的取数、列定义、筛选、排序、分页与导出,只增加平台维度过滤:京东账单排除京喜店铺,京喜账单只取京喜店铺。平台口径集中在 config/jd_bill_platform.php 与 JdBillPlatform(含口径切换起始日期参数,默认全量历史),仓库通过 forPlatform() 收窄,两个口径互补、总额守恒,底层镜像数据不修改不删除。真实镜像实测:京喜 488,464 笔 + 京东 210,983 笔 = 拆分前 699,447 笔,收入/支出/差额逐项误差为 0。
85 lines
3.1 KiB
PHP
85 lines
3.1 KiB
PHP
<?php
|
||
|
||
namespace Modules\EcommerceFinance;
|
||
|
||
/**
|
||
* 京东账单的平台口径(单一数据源)。
|
||
*
|
||
* 京东日账单导出里没有平台字段:单据类型(订单/取消退款单/售后服务单/非销售单)两边都有,
|
||
* 费用项与账户代码、京东门店编码、品牌门店编号、门店名称均为空,账单项目只有「直营服务费」
|
||
* 单独属于京喜。全量 699,447 笔实测里只有店铺维度能可靠区分:
|
||
* 京喜 213 个店铺(488,464 笔)与京东 46 个店铺(210,983 笔)互不重叠,店铺号也不跨两边。
|
||
*
|
||
* 因此「京东账单」与「京喜账单」共用同一份取数逻辑,只用店铺名关键字拆数据:
|
||
* - 京东账单 = 排除京喜店铺
|
||
* - 京喜账单 = 只取京喜店铺
|
||
* 两个口径落点互补,笔数与金额之和恒等于拆分前,且不修改任何底层数据。
|
||
*/
|
||
final class JdBillPlatform
|
||
{
|
||
/** 店铺收款账户账单 › 京东账单。 */
|
||
public const BILL_TYPE_JD = 'jd-transactions';
|
||
|
||
/** 店铺收款账户账单 › 京喜账单。 */
|
||
public const BILL_TYPE_JINGXI = 'jingxi';
|
||
|
||
/** 口径配置(关键字、起始日期)统一在 config/jd_bill_platform.php,这里只读不定义。 */
|
||
private const CONFIG_KEY = 'jd_bill_platform';
|
||
|
||
/** @return list<string> 与京东日账单共用取数与渲染逻辑的页签。 */
|
||
public static function tabs(): array
|
||
{
|
||
return [self::BILL_TYPE_JD, self::BILL_TYPE_JINGXI];
|
||
}
|
||
|
||
public static function isJdBillTab(string $billType): bool
|
||
{
|
||
return in_array($billType, self::tabs(), true);
|
||
}
|
||
|
||
/** 页签对应的平台口径:'jingxi'、'jd',非京东系列页签返回 null。 */
|
||
public static function platformForBillType(string $billType): ?string
|
||
{
|
||
return match ($billType) {
|
||
self::BILL_TYPE_JINGXI => 'jingxi',
|
||
self::BILL_TYPE_JD => 'jd',
|
||
default => null,
|
||
};
|
||
}
|
||
|
||
/** 京喜店铺名关键字。 */
|
||
public static function storeNameKeyword(): string
|
||
{
|
||
$keyword = trim((string) config(self::CONFIG_KEY . '.jingxi_store_name_keyword', '京喜'));
|
||
|
||
return $keyword === '' ? '京喜' : $keyword;
|
||
}
|
||
|
||
/** 口径切换起始日期;null = 全量历史。 */
|
||
public static function scopeStartDate(): ?string
|
||
{
|
||
$start = config(self::CONFIG_KEY . '.scope_start_date');
|
||
|
||
return is_string($start) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $start) === 1 ? $start : null;
|
||
}
|
||
|
||
/**
|
||
* 店铺维度的过滤条件。
|
||
*
|
||
* @param 'jingxi'|'jd'|null $platform
|
||
* @return array{mode:string,keyword:string,start_date:?string}|null mode: only=只取该平台,exclude=排除该平台
|
||
*/
|
||
public static function storeNameScope(?string $platform): ?array
|
||
{
|
||
if (! in_array($platform, ['jingxi', 'jd'], true)) {
|
||
return null;
|
||
}
|
||
|
||
return [
|
||
'mode' => $platform === 'jingxi' ? 'only' : 'exclude',
|
||
'keyword' => self::storeNameKeyword(),
|
||
'start_date' => self::scopeStartDate(),
|
||
];
|
||
}
|
||
}
|