业绩明细:新增优惠金额/冲减金额两列(取科目映射表财务备注=优惠收入/冲减收入,支持 --amounts-only 回填)
This commit is contained in:
parent
4bcfde58f7
commit
c8a035a18f
@ -7,6 +7,7 @@ use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use InvalidArgumentException;
|
||||
use Modules\EcommerceFinance\Services\AccountLedgerRemarkMap;
|
||||
use Modules\EcommerceFinance\Services\AccountMappingStore;
|
||||
use Modules\EcommerceFinance\Services\LedgerRemarkFilter;
|
||||
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQueryFactory;
|
||||
use Throwable;
|
||||
@ -31,7 +32,8 @@ class SyncStoreReceiptOrderMatches extends Command
|
||||
{month : 账单月份,格式 YYYY-MM}
|
||||
{--platform=taobao-alipay : 收款账户,目前支持 taobao-alipay}
|
||||
{--chunk=1200 : 单次向上游查询的订单号数量}
|
||||
{--limit=0 : 仅处理前 N 笔账单(调试用,0 表示全量)}';
|
||||
{--limit=0 : 仅处理前 N 笔账单(调试用,0 表示全量)}
|
||||
{--amounts-only : 只回填「优惠金额 / 冲减金额」两列,不重跑订单侧匹配}';
|
||||
|
||||
protected $description = '按店铺收款账户账单匹配订单侧商品金额,生成「业绩明细」核对镜像';
|
||||
|
||||
@ -95,6 +97,21 @@ class SyncStoreReceiptOrderMatches extends Command
|
||||
'订单收入',
|
||||
];
|
||||
|
||||
/**
|
||||
* 「优惠金额」列口径:账单的总账备注命中以下取值。
|
||||
*
|
||||
* 总账备注优先取「财务规则 › 科目映射表」的财务备注(与店铺收款账户账单页一致),
|
||||
* 取不到时回落到 ec_account_ledger_remarks。金额不计入收入金额与差额。
|
||||
*/
|
||||
private const DISCOUNT_REMARKS = [
|
||||
'优惠收入',
|
||||
];
|
||||
|
||||
/** 「冲减金额」列口径:账单的总账备注命中以下取值,不参与收入金额与差额计算。 */
|
||||
private const OFFSET_REMARKS = [
|
||||
'冲减收入',
|
||||
];
|
||||
|
||||
private const TARGET_TABLE = 'store_receipt_order_match_rows';
|
||||
|
||||
private const STATUS_MATCHED = '已匹配';
|
||||
@ -152,13 +169,28 @@ class SyncStoreReceiptOrderMatches extends Command
|
||||
|
||||
// 「总账备注」→ 按平台分组的账单项目集合(淘系页签同页混有淘宝/天猫/阿里巴巴店铺,
|
||||
// 必须连店铺名前缀一起过滤,才能与页面按行取到的总账备注一致)。
|
||||
$groups = $this->ledgerRemarkGroups($platform);
|
||||
if ($groups === []) {
|
||||
// 收入金额只认 LEDGER_REMARKS;优惠/冲减金额各自单独成列,不参与收入与差额。
|
||||
$baseGroups = $this->ledgerRemarkGroups($platform);
|
||||
$discountGroups = $this->ledgerRemarkGroups($platform, self::DISCOUNT_REMARKS);
|
||||
$offsetGroups = $this->ledgerRemarkGroups($platform, self::OFFSET_REMARKS);
|
||||
// 总账备注现在优先取科目映射表的财务备注,因此这两列的候选账单项目
|
||||
// 也要按科目映射表补一遍,否则「优惠收入 / 冲减收入」永远取不到项目。
|
||||
$promoItems = array_values(array_unique(array_merge(
|
||||
$this->accountMappingItems($platform, self::DISCOUNT_REMARKS),
|
||||
$this->accountMappingItems($platform, self::OFFSET_REMARKS),
|
||||
)));
|
||||
// 微信账户页签的账单项目带「wx」前缀(wx限时红包代商家垫付扣回 等),
|
||||
// 科目映射表用的是不带前缀的名字,这里两种写法都带上。
|
||||
$promoItems = $this->withWxVariants($promoItems);
|
||||
if ($baseGroups === []) {
|
||||
$this->error('「总账备注」映射表没有匹配到任何账单项目,请先导入 ec_account_ledger_remarks。');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
$this->info('总账备注命中平台分组:' . count($groups) . ' 组');
|
||||
$this->info('总账备注命中平台分组:' . count($baseGroups) . ' 组');
|
||||
if ($discountGroups === [] && $offsetGroups === [] && $promoItems === []) {
|
||||
$this->warn('「优惠收入」「冲减收入」在科目映射表与总账备注映射里都没有对应账单项目,两列将全部为空。');
|
||||
}
|
||||
|
||||
$select = ['store_name', 'bill_item', $orderColumn, $timeColumn, $amountColumn];
|
||||
if ($realStoreColumn !== '') {
|
||||
@ -193,13 +225,18 @@ class SyncStoreReceiptOrderMatches extends Command
|
||||
$billQuery->whereIn('generation', $generations);
|
||||
$this->info('活动代:' . count($generations) . ' 个');
|
||||
}
|
||||
LedgerRemarkFilter::applyGroups(
|
||||
$billQuery,
|
||||
$groups,
|
||||
'bill_item',
|
||||
static fn ($sub, string $prefix) => $sub->where('store_name', 'like', $prefix . '%'),
|
||||
static fn ($sub, string $prefix) => $sub->where('store_name', 'not like', $prefix . '%'),
|
||||
);
|
||||
$billQuery->where(function ($group) use ($baseGroups, $discountGroups, $offsetGroups, $promoItems): void {
|
||||
LedgerRemarkFilter::applyGroups(
|
||||
$group,
|
||||
array_merge($baseGroups, $discountGroups, $offsetGroups),
|
||||
'bill_item',
|
||||
static fn ($sub, string $prefix) => $sub->where('store_name', 'like', $prefix . '%'),
|
||||
static fn ($sub, string $prefix) => $sub->where('store_name', 'not like', $prefix . '%'),
|
||||
);
|
||||
if ($promoItems !== []) {
|
||||
$group->orWhereIn('bill_item', $promoItems);
|
||||
}
|
||||
});
|
||||
$bills = $billQuery->orderBy($timeColumn)->get();
|
||||
|
||||
if ($limit > 0) {
|
||||
@ -216,7 +253,38 @@ class SyncStoreReceiptOrderMatches extends Command
|
||||
$groups = [];
|
||||
$paymentTotal = 0;
|
||||
$incomeTotal = 0.0;
|
||||
$discountTotal = 0.0;
|
||||
$offsetTotal = 0.0;
|
||||
$remarkMap = app(AccountLedgerRemarkMap::class);
|
||||
$tabPlatform = $remarkMap->defaultPlatform($platform);
|
||||
$ledgerMap = $remarkMap->map();
|
||||
$incomeOverlapRows = 0;
|
||||
$incomeOverlapTotal = 0.0;
|
||||
foreach ($bills as $bill) {
|
||||
$storeName = (string) ($bill->store_name ?? '');
|
||||
$billItem = (string) ($bill->bill_item ?? '');
|
||||
// 收入金额沿用「总账备注映射」白名单口径,保证既有数字不变;
|
||||
// 优惠 / 冲减两列按新口径(科目映射表的财务备注优先)取数。
|
||||
$legacyRemark = $ledgerMap[$remarkMap->platform($storeName, $tabPlatform) ?? ''][$billItem] ?? null;
|
||||
$remark = $remarkMap->remark($storeName, $tabPlatform, $billItem);
|
||||
$isPromoRemark = in_array($remark, self::DISCOUNT_REMARKS, true)
|
||||
|| in_array($remark, self::OFFSET_REMARKS, true);
|
||||
$isIncomeRemark = in_array($legacyRemark, self::LEDGER_REMARKS, true);
|
||||
if ($isIncomeRemark && $isPromoRemark) {
|
||||
// 已经在收入金额里的行:不重复计入优惠/冲减列,单独提示金额。
|
||||
$incomeOverlapRows++;
|
||||
$incomeOverlapTotal += (float) $bill->{$amountColumn};
|
||||
}
|
||||
$bucket = match (true) {
|
||||
$isIncomeRemark => 'income',
|
||||
in_array($remark, self::DISCOUNT_REMARKS, true) => 'discount',
|
||||
in_array($remark, self::OFFSET_REMARKS, true) => 'offset',
|
||||
default => null,
|
||||
};
|
||||
if ($bucket === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rawNo = trim((string) ($bill->{$orderColumn} ?? ''));
|
||||
$core = self::cleanOrderNo($rawNo);
|
||||
$realStore = $realStoreColumn !== '' ? (string) ($bill->{$realStoreColumn} ?? '') : '';
|
||||
@ -233,16 +301,47 @@ class SyncStoreReceiptOrderMatches extends Command
|
||||
'occurred_date' => substr((string) $bill->{$timeColumn}, 0, 10),
|
||||
'payment_count' => 0,
|
||||
'income_amount' => 0.0,
|
||||
'discount_amount' => 0.0,
|
||||
'discount_seen' => false,
|
||||
'offset_amount' => 0.0,
|
||||
'offset_seen' => false,
|
||||
];
|
||||
}
|
||||
|
||||
$groups[$key]['payment_count']++;
|
||||
$groups[$key]['income_amount'] += (float) $bill->{$amountColumn};
|
||||
$paymentTotal++;
|
||||
$incomeTotal += (float) $bill->{$amountColumn};
|
||||
$amount = (float) $bill->{$amountColumn};
|
||||
if ($bucket === 'income') {
|
||||
$groups[$key]['payment_count']++;
|
||||
$groups[$key]['income_amount'] += $amount;
|
||||
$paymentTotal++;
|
||||
$incomeTotal += $amount;
|
||||
} elseif ($bucket === 'discount') {
|
||||
$groups[$key]['discount_seen'] = true;
|
||||
$groups[$key]['discount_amount'] += $amount;
|
||||
$discountTotal += $amount;
|
||||
} else {
|
||||
$groups[$key]['offset_seen'] = true;
|
||||
$groups[$key]['offset_amount'] += $amount;
|
||||
$offsetTotal += $amount;
|
||||
}
|
||||
}
|
||||
|
||||
// 行口径保持不变:仍然是「有收款账单(收入白名单)的店铺 + 订单号」,
|
||||
// 只有优惠/冲减、没有收款的订单号不单独成行。
|
||||
$groups = array_filter($groups, static fn (array $group): bool => (int) $group['payment_count'] > 0);
|
||||
|
||||
$this->info('账单收款笔数:' . $paymentTotal . ',按「店铺 + 订单号」聚合后:' . count($groups) . ' 行');
|
||||
$this->line(' 优惠金额合计:' . number_format($discountTotal, 2) . ',冲减金额合计:' . number_format($offsetTotal, 2));
|
||||
if ($incomeOverlapRows > 0) {
|
||||
$this->line(sprintf(
|
||||
' 提示:%d 笔(%s 元)按旧口径已计入收入金额,未重复计入优惠/冲减列。',
|
||||
$incomeOverlapRows,
|
||||
number_format($incomeOverlapTotal, 2),
|
||||
));
|
||||
}
|
||||
|
||||
if ((bool) $this->option('amounts-only')) {
|
||||
return $this->backfillPromoAmounts($month, $source, $groups, $reportMonth);
|
||||
}
|
||||
|
||||
// 订单侧的单号在不同平台形态不同:淘系/京东是无前缀纯数字,
|
||||
// 拼多多等平台带日期前缀(260630-xxx)。这里同时带上原始号与清洗后的
|
||||
@ -419,6 +518,8 @@ class SyncStoreReceiptOrderMatches extends Command
|
||||
'order_core_no' => $core !== '' ? $core : null,
|
||||
'payment_count' => (int) $group['payment_count'],
|
||||
'income_amount' => $income,
|
||||
'discount_amount' => ! empty($group['discount_seen']) ? round((float) $group['discount_amount'], 2) : null,
|
||||
'offset_amount' => ! empty($group['offset_seen']) ? round((float) $group['offset_amount'], 2) : null,
|
||||
'product_amount' => $productAmount,
|
||||
'difference' => $difference,
|
||||
'match_status' => $status,
|
||||
@ -452,6 +553,105 @@ class SyncStoreReceiptOrderMatches extends Command
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 只回填「优惠金额 / 冲减金额」两列:不重建业绩明细、不查订单侧,
|
||||
* 先清空该账期该平台的两列,再按 row_key 更新镜像里已存在的行。
|
||||
*
|
||||
* @param array<string,mixed> $source
|
||||
* @param array<string,array<string,mixed>> $groups
|
||||
*/
|
||||
private function backfillPromoAmounts(string $month, array $source, array $groups, string $reportMonth): int
|
||||
{
|
||||
$connection = (string) config('upstream_mirrors.connection', 'business_mirror');
|
||||
$platform = (string) $source['label'];
|
||||
$target = static fn () => DB::connection($connection)->table(self::TARGET_TABLE);
|
||||
|
||||
$existing = $target()
|
||||
->where('report_month', $reportMonth)
|
||||
->where('platform', $platform)
|
||||
->pluck('row_key')
|
||||
->flip()
|
||||
->all();
|
||||
|
||||
$target()
|
||||
->where('report_month', $reportMonth)
|
||||
->where('platform', $platform)
|
||||
->update(['discount_amount' => null, 'offset_amount' => null]);
|
||||
|
||||
$discounts = [];
|
||||
$offsets = [];
|
||||
foreach ($groups as $group) {
|
||||
if (empty($group['discount_seen']) && empty($group['offset_seen'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rowKey = md5($reportMonth . '|' . $platform . '|' . $group['shop_key'] . '|' . $group['order_core_no']);
|
||||
if (! isset($existing[$rowKey])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! empty($group['discount_seen'])) {
|
||||
$discounts[$rowKey] = round((float) $group['discount_amount'], 2);
|
||||
}
|
||||
if (! empty($group['offset_seen'])) {
|
||||
$offsets[$rowKey] = round((float) $group['offset_amount'], 2);
|
||||
}
|
||||
}
|
||||
|
||||
$this->updateAmountColumn($connection, $reportMonth, 'discount_amount', $discounts);
|
||||
$this->updateAmountColumn($connection, $reportMonth, 'offset_amount', $offsets);
|
||||
|
||||
$this->info(sprintf(
|
||||
'已回填 %s %s:优惠 %d 行(%s)/ 冲减 %d 行(%s),镜像原有 %d 行,未重建业绩明细。',
|
||||
$month,
|
||||
$platform,
|
||||
count($discounts),
|
||||
number_format(array_sum($discounts), 2),
|
||||
count($offsets),
|
||||
number_format(array_sum($offsets), 2),
|
||||
count($existing),
|
||||
));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 row_key 批量更新一列金额:只更新镜像里已有的行,不做插入。
|
||||
*
|
||||
* @param array<string,float> $values row_key => 金额
|
||||
*/
|
||||
private function updateAmountColumn(string $connection, string $reportMonth, string $column, array $values): void
|
||||
{
|
||||
if ($values === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (array_chunk($values, 500, true) as $chunk) {
|
||||
$cases = '';
|
||||
$bindings = [];
|
||||
foreach ($chunk as $rowKey => $amount) {
|
||||
$cases .= ' WHEN ? THEN ?';
|
||||
$bindings[] = (string) $rowKey;
|
||||
$bindings[] = $amount;
|
||||
}
|
||||
|
||||
$bindings[] = $reportMonth;
|
||||
$bindings = array_merge($bindings, array_map('strval', array_keys($chunk)));
|
||||
$placeholders = implode(',', array_fill(0, count($chunk), '?'));
|
||||
|
||||
DB::connection($connection)->update(
|
||||
sprintf(
|
||||
'update %s set %s = case row_key%s end where report_month = ? and row_key in (%s)',
|
||||
self::TARGET_TABLE,
|
||||
$column,
|
||||
$cases,
|
||||
$placeholders,
|
||||
),
|
||||
$bindings,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** 单号清洗:去掉日期前缀(如 260630-)、空格、横杠,得到核心号。 */
|
||||
public static function cleanOrderNo(string $value): string
|
||||
{
|
||||
@ -471,18 +671,85 @@ class SyncStoreReceiptOrderMatches extends Command
|
||||
return strtoupper($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 科目映射表里「财务备注命中给定备注」的账单项目(限本页签涉及的平台)。
|
||||
*
|
||||
* @param list<string> $remarks
|
||||
* @return list<string>
|
||||
*/
|
||||
private function accountMappingItems(string $tab, array $remarks): array
|
||||
{
|
||||
$map = app(AccountLedgerRemarkMap::class);
|
||||
$platforms = $map->platformsForTab($tab);
|
||||
$items = [];
|
||||
|
||||
foreach (app(AccountMappingStore::class)->all() as $rule) {
|
||||
if (! is_array($rule)) {
|
||||
continue;
|
||||
}
|
||||
$platform = trim((string) ($rule['platform'] ?? ''));
|
||||
$item = trim((string) ($rule['item'] ?? ''));
|
||||
$memo = trim((string) ($rule['memo'] ?? ''));
|
||||
if ($platform === '' || $item === '' || ! in_array($platform, $platforms, true)) {
|
||||
continue;
|
||||
}
|
||||
if (! in_array($memo, $remarks, true)) {
|
||||
continue;
|
||||
}
|
||||
$items[$item] = true;
|
||||
}
|
||||
|
||||
$list = array_keys($items);
|
||||
sort($list);
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 账单项目名的「wx」前缀变体:科目映射表用不带前缀的名字,
|
||||
* 微信账户页签的账单带前缀(反之亦然),两种写法都纳入候选。
|
||||
*
|
||||
* @param list<string> $items
|
||||
* @return list<string>
|
||||
*/
|
||||
private function withWxVariants(array $items): array
|
||||
{
|
||||
$candidates = [];
|
||||
foreach ($items as $item) {
|
||||
$item = trim((string) $item);
|
||||
if ($item === '') {
|
||||
continue;
|
||||
}
|
||||
$candidates[$item] = true;
|
||||
if (stripos($item, 'wx') === 0) {
|
||||
$stripped = ltrim(mb_substr($item, 2));
|
||||
if ($stripped !== '') {
|
||||
$candidates[$stripped] = true;
|
||||
}
|
||||
} else {
|
||||
$candidates['wx' . $item] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$list = array_keys($candidates);
|
||||
sort($list);
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 「总账备注」集合 → 平台分组条件(复用账单页同一份映射与翻译)。
|
||||
*
|
||||
* @param list<string>|null $remarks 为空时取收入白名单(LEDGER_REMARKS)
|
||||
* @return list<array<string,mixed>>
|
||||
*/
|
||||
private function ledgerRemarkGroups(string $tab): array
|
||||
private function ledgerRemarkGroups(string $tab, ?array $remarks = null): array
|
||||
{
|
||||
$map = app(AccountLedgerRemarkMap::class);
|
||||
$groups = [];
|
||||
$seen = [];
|
||||
|
||||
foreach (self::LEDGER_REMARKS as $remark) {
|
||||
foreach ($remarks ?? self::LEDGER_REMARKS as $remark) {
|
||||
foreach ($map->billItemGroupsForTab($tab, $remark) as $group) {
|
||||
$key = (string) ($group['platform'] ?? '') . '|' . implode(',', (array) ($group['items'] ?? []));
|
||||
if (isset($seen[$key])) {
|
||||
|
||||
@ -634,6 +634,8 @@ class Pages extends Controller
|
||||
$agg = $aggQuery->selectRaw("
|
||||
SUM(payment_count) as payments,
|
||||
SUM(income_amount) as income_total,
|
||||
SUM(discount_amount) as discount_total,
|
||||
SUM(offset_amount) as offset_total,
|
||||
SUM(product_amount) as goods_total,
|
||||
SUM(difference) as difference_total,
|
||||
SUM(CASE WHEN payment_count > 1 THEN 1 ELSE 0 END) as multi_pay,
|
||||
@ -653,6 +655,8 @@ class Pages extends Controller
|
||||
'orders_multi_pay' => (int) ($agg->multi_pay ?? 0),
|
||||
'orders_zero_income' => (int) ($agg->zero_income ?? 0),
|
||||
'income_total' => round((float) ($agg->income_total ?? 0), 2),
|
||||
'discount_total' => round((float) ($agg->discount_total ?? 0), 2),
|
||||
'offset_total' => round((float) ($agg->offset_total ?? 0), 2),
|
||||
'goods_total' => round((float) ($agg->goods_total ?? 0), 2),
|
||||
'difference_total' => round((float) ($agg->difference_total ?? 0), 2),
|
||||
];
|
||||
@ -689,6 +693,8 @@ class Pages extends Controller
|
||||
'store_name' => ['store_name', '店铺名称', 'text'],
|
||||
'online_order_no' => ['online_order_no', '线上单号', 'text'],
|
||||
'income_amount' => ['income_amount', '收入金额', 'money'],
|
||||
'discount_amount' => ['discount_amount', '优惠金额', 'money'],
|
||||
'offset_amount' => ['offset_amount', '冲减金额', 'money'],
|
||||
'product_amount' => ['product_amount', '商品金额', 'money'],
|
||||
'difference' => ['difference', '差额', 'money'],
|
||||
'match_status' => ['match_status', '匹配状态', 'text'],
|
||||
|
||||
@ -787,7 +787,7 @@ $navigation = [
|
||||
'directory' => [
|
||||
'icon' => 'receipt_long',
|
||||
'status' => '共享镜像',
|
||||
'description' => '覆盖店铺收款账户账单各平台页签(总账备注=订单收入),按「店铺 + 订单号」匹配订单侧商品金额;一行 = 一个店铺的一个订单,商品金额只挂一次,差额保留供后续分类。',
|
||||
'description' => '覆盖店铺收款账户账单各平台页签(总账备注=订单收入),按「店铺 + 订单号」匹配订单侧商品金额;一行 = 一个店铺的一个订单,商品金额只挂一次,差额保留供后续分类。「优惠金额」「冲减金额」另取总账备注=优惠收入 / 冲减收入的账单金额,不计入收入金额与差额。',
|
||||
'empty' => '店铺收款匹配订单明细尚未同步,请先执行 store-receipt:order-match:sync。',
|
||||
'fields' => [
|
||||
['name' => 'platform', 'label' => '平台'],
|
||||
@ -795,6 +795,8 @@ $navigation = [
|
||||
['name' => 'store_name', 'label' => '店铺名称'],
|
||||
['name' => 'online_order_no', 'label' => '线上单号'],
|
||||
['name' => 'income_amount', 'label' => '收入金额', 'kind' => 'number'],
|
||||
['name' => 'discount_amount', 'label' => '优惠金额', 'kind' => 'number'],
|
||||
['name' => 'offset_amount', 'label' => '冲减金额', 'kind' => 'number'],
|
||||
['name' => 'product_amount', 'label' => '商品金额', 'kind' => 'number'],
|
||||
['name' => 'difference', 'label' => '差额', 'kind' => 'number'],
|
||||
['name' => 'match_status', 'label' => '匹配状态'],
|
||||
|
||||
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* 业绩明细新增「优惠金额 / 冲减金额」两列:
|
||||
* 取店铺收款账户账单里总账备注为「优惠收入」「冲减收入」的金额,
|
||||
* 与「收入金额」(订单收入类口径)并列展示,不参与差额计算。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
private function connection(): string
|
||||
{
|
||||
return (string) config('upstream_mirrors.connection', 'business_mirror');
|
||||
}
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$schema = Schema::connection($this->connection());
|
||||
if (! $schema->hasTable('store_receipt_order_match_rows')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$schema->table('store_receipt_order_match_rows', function (Blueprint $table): void {
|
||||
if (! Schema::connection($this->connection())->hasColumn('store_receipt_order_match_rows', 'discount_amount')) {
|
||||
$table->decimal('discount_amount', 20, 4)->nullable()->after('income_amount');
|
||||
}
|
||||
if (! Schema::connection($this->connection())->hasColumn('store_receipt_order_match_rows', 'offset_amount')) {
|
||||
$table->decimal('offset_amount', 20, 4)->nullable()->after('discount_amount');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$schema = Schema::connection($this->connection());
|
||||
if (! $schema->hasTable('store_receipt_order_match_rows')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$columns = array_values(array_filter(
|
||||
['discount_amount', 'offset_amount'],
|
||||
static fn (string $column): bool => Schema::connection($this->connection())
|
||||
->hasColumn('store_receipt_order_match_rows', $column),
|
||||
));
|
||||
|
||||
if ($columns !== []) {
|
||||
$schema->table('store_receipt_order_match_rows', function (Blueprint $table) use ($columns): void {
|
||||
$table->dropColumn($columns);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1039,6 +1039,8 @@
|
||||
<span class="receipt-match-summary__item is-warn"><em>一单多笔</em><strong>{{ number_format($receiptStats['orders_multi_pay']) }}</strong></span>
|
||||
<span class="receipt-match-summary__item"><em>收入为 0 的账单行</em><strong>{{ number_format($receiptStats['orders_zero_income']) }}</strong></span>
|
||||
<span class="receipt-match-summary__item"><em>账单收入合计</em><strong>{{ number_format((float) $receiptStats['income_total'], 2) }}</strong></span>
|
||||
<span class="receipt-match-summary__item"><em>优惠金额合计</em><strong>{{ number_format((float) ($receiptStats['discount_total'] ?? 0), 2) }}</strong></span>
|
||||
<span class="receipt-match-summary__item"><em>冲减金额合计</em><strong>{{ number_format((float) ($receiptStats['offset_total'] ?? 0), 2) }}</strong></span>
|
||||
<span class="receipt-match-summary__item"><em>订单商品金额合计</em><strong>{{ number_format((float) $receiptStats['goods_total'], 2) }}</strong></span>
|
||||
<span class="receipt-match-summary__item"><em>差额合计(已匹配)</em><strong>{{ number_format((float) $receiptStats['difference_total'], 2) }}</strong></span>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user