费用明细分类汇总改为弹窗明细 #541

Merged
yueyang merged 1 commits from feature/yueyang-expense-summary-dialog into main 2026-10-25 03:33:39 +08:00
5 changed files with 177 additions and 81 deletions

View File

@ -110,12 +110,12 @@ class BillingDetailsPageData
'remark' => ['备注', 'text'],
];
/** 费用明细精简列:平台、店铺、线上单号、总账备注、收支净额。 */
/** 费用明细精简列:平台、店铺、线上单号、账单费用、收支净额。 */
public const EXPENSE_COLUMNS = [
'platform' => ['平台', 'text'],
'store_name' => ['店铺', 'text'],
'online_order_no' => ['线上单号', 'text'],
'finance_remark' => ['总账备注', 'text'],
'finance_remark' => ['账单费用', 'text'],
'amount' => ['金额(收-支)', 'num'],
];
@ -365,7 +365,7 @@ class BillingDetailsPageData
}
/**
* 费用明细的总账备注分类汇总:只响应汇总请求,避免拖慢主表首屏。
* 费用明细的账单费用分类汇总:只响应汇总请求,避免拖慢主表首屏。
*
* @return array{
* categories:list<array{
@ -377,7 +377,8 @@ class BillingDetailsPageData
* }>,
* category_count:int,
* invoice_net:float,
* non_invoice_net:float
* non_invoice_net:float,
* net:float
* }
*/
public function expenseCategorySummary(?array $input = null, array $forcedFilters = []): array
@ -387,7 +388,7 @@ class BillingDetailsPageData
$signature = md5((string) json_encode($filters, JSON_UNESCAPED_UNICODE));
return cache()->remember(
'billing-details-item-summary-v4:' . $signature,
'billing-details-item-summary-v5:' . $signature,
now()->addMinutes(2),
function () use ($filters): array {
$connection = $this->connection();
@ -431,7 +432,7 @@ class BillingDetailsPageData
foreach ($memoConditions as $memo => $conditions) {
$memoSql .= ' WHEN (' . implode(' OR ', $conditions) . ') THEN ' . $this->literal($memo);
}
$memoSql .= ' ELSE ' . $this->literal('未填写总账备注') . ' END';
$memoSql .= ' ELSE ' . $this->literal('未填写账单费用') . ' END';
$bucketSql = 'CASE';
if ($invoiceConditions !== []) {
@ -485,6 +486,7 @@ class BillingDetailsPageData
'category_count' => count($items),
'invoice_net' => round($invoiceNet, 2),
'non_invoice_net' => round($nonInvoiceNet, 2),
'net' => round($invoiceNet + $nonInvoiceNet, 2),
];
},
);
@ -504,7 +506,7 @@ class BillingDetailsPageData
float $net,
string $invoiceBucket,
): void {
$ledgerMemo = trim($ledgerMemo) ?: '未填写总账备注';
$ledgerMemo = trim($ledgerMemo) ?: '未填写账单费用';
$billItem = $this->normalizeItem($billItem) ?: '未填写账单项目';
$totals[$ledgerMemo] ??= ['invoice_net' => 0.0, 'non_invoice_net' => 0.0, 'items' => []];
$totals[$ledgerMemo]['items'][$billItem] ??= ['invoice_net' => 0.0, 'non_invoice_net' => 0.0];
@ -747,7 +749,7 @@ class BillingDetailsPageData
if ($platform === '' || $item === '' || trim((string) ($rule['category'] ?? '')) !== '费用') {
continue;
}
$memo = trim((string) ($rule['memo'] ?? '')) ?: '未填写总账备注';
$memo = trim((string) ($rule['memo'] ?? '')) ?: '未填写账单费用';
$previous = $groups[$platform][$item] ?? null;
if ($previous !== null && $previous !== $memo) {
throw new \RuntimeException('费用分类无法唯一确定:' . $platform . ' / ' . $item);

View File

@ -37,26 +37,43 @@
.expense-details-page #pdItemSummary { order:2; }
.expense-details-page #pdFilterForm { order:3; }
.expense-details-page .pd-detail-list { order:4; }
.pd-item-summary { margin:0 0 1rem; border:1px solid #d8d2c7; border-radius:.75rem; background:#fff; overflow:hidden; }
.pd-item-summary__head { display:flex; flex-wrap:wrap; align-items:center; gap:.5rem .875rem; padding:.75rem 1rem; border-bottom:1px solid #e8e0d2; background:#faf6ee; }
.pd-item-summary__head strong { color:#2f2a23; }
.pd-item-summary__head span { color:#7c7468; font-size:.75rem; }
.pd-item-summary__wrap { max-height:clamp(24rem, 58vh, 32rem); overflow:auto; }
.pd-item-summary table { width:100%; border-collapse:collapse; font-size:.8125rem; }
.pd-item-summary th { position:sticky; top:0; z-index:1; padding:.55rem .8rem; border-bottom:1px solid #d8d2c7; background:#f3ece0; color:#3d3a35; text-align:left; white-space:nowrap; }
.pd-item-summary { margin:0 0 1.25rem; border:1px solid #d8d2c7; border-radius:1rem; background:#fff; overflow:hidden; }
.pd-item-summary__head { display:flex; flex-wrap:wrap; align-items:center; gap:.75rem 1.25rem; padding:1rem 1.25rem; border-bottom:1px solid #e8e0d2; background:#faf6ee; }
.pd-item-summary__head-main { display:grid; gap:.25rem; min-width:18rem; }
.pd-item-summary__title { display:flex; flex-wrap:wrap; align-items:baseline; gap:.35rem .75rem; }
.pd-item-summary__title strong { color:#2f2a23; font-size:1rem; }
.pd-item-summary__title span, .pd-item-summary__status { color:#7c7468; font-size:.75rem; }
.pd-item-summary__total { display:flex; align-items:baseline; gap:.55rem; margin-left:auto; padding-left:1.25rem; border-left:1px solid #e3dac9; }
.pd-item-summary__total span { color:#7c7468; font-size:.75rem; }
.pd-item-summary__total strong { color:#856632; font-size:1.375rem; font-variant-numeric:tabular-nums; }
.pd-item-summary__wrap { max-height:clamp(30rem, 70vh, 44rem); overflow:auto; }
.pd-item-summary table { width:100%; border-collapse:collapse; font-size:.875rem; }
.pd-item-summary th { position:sticky; top:0; z-index:1; padding:.7rem 1rem; border-bottom:1px solid #d8d2c7; background:#f3ece0; color:#3d3a35; text-align:left; white-space:nowrap; }
.pd-item-summary th.num, .pd-item-summary td.num { text-align:right; }
.pd-item-summary td { padding:.5rem .8rem; border-bottom:1px solid #eee7da; color:#3d3a35; }
.pd-item-summary td { padding:.65rem 1rem; border-bottom:1px solid #eee7da; color:#3d3a35; }
.pd-item-summary td.num { font-variant-numeric:tabular-nums; white-space:nowrap; }
.pd-item-summary tfoot td { position:sticky; bottom:0; z-index:1; border-top:1px solid #d8d2c7; background:#fff8e9; font-weight:700; }
.pd-item-summary__toggle { display:inline-flex; align-items:center; gap:.35rem; padding:0; border:0; background:transparent; color:#2f2a23; font:inherit; font-weight:600; cursor:pointer; }
.pd-item-summary__toggle:hover { color:#856632; }
.pd-item-summary__toggle .material-icons-outlined { font-size:1rem; transition:transform .18s ease; }
.pd-item-summary__toggle[aria-expanded="true"] .material-icons-outlined { transform:rotate(180deg); }
.pd-item-summary__drill td { padding:.65rem .9rem .85rem 2rem; background:#fcfaf5; }
.pd-item-summary__drill-title { margin-bottom:.4rem; color:#6d6458; font-size:.75rem; }
.pd-item-summary__drill table { border:1px solid #e7dfd2; border-radius:.4rem; overflow:hidden; }
.pd-item-summary__drill th { position:static; padding:.4rem .55rem; border-bottom:1px solid #e7dfd2; background:#f4eee4; }
.pd-item-summary__drill td { padding:.4rem .55rem; background:#fff; }
.pd-item-summary tbody tr:hover { background:#fcfaf5; }
.pd-item-summary__open { display:inline-flex; align-items:center; gap:.35rem; padding:0; border:0; background:transparent; color:#2f2a23; font:inherit; font-weight:600; cursor:pointer; }
.pd-item-summary__open:hover { color:#856632; }
.pd-item-summary__open .material-icons-outlined { color:#856632; font-size:1rem; }
.pd-expense-dialog { width:min(76rem, calc(100vw - 2rem)); max-height:min(86vh, 52rem); padding:0; border:1px solid #d8d2c7; border-radius:1rem; background:#fff; color:#171717; overflow:hidden; }
.pd-expense-dialog::backdrop { background:rgba(23, 23, 23, .48); }
.pd-expense-dialog__head { display:flex; flex-wrap:wrap; align-items:center; gap:.75rem 1.25rem; padding:1rem 1.25rem; border-bottom:1px solid #e8e0d2; background:#faf6ee; }
.pd-expense-dialog__head-main { display:grid; gap:.25rem; min-width:18rem; }
.pd-expense-dialog__title { margin:0; color:#2f2a23; font-size:1rem; }
.pd-expense-dialog__subtitle { color:#7c7468; font-size:.75rem; }
.pd-expense-dialog__total { display:flex; align-items:baseline; gap:.55rem; margin-left:auto; }
.pd-expense-dialog__total span { color:#7c7468; font-size:.75rem; }
.pd-expense-dialog__total strong { color:#856632; font-size:1.375rem; font-variant-numeric:tabular-nums; }
.pd-expense-dialog__close { display:inline-flex; align-items:center; justify-content:center; width:2rem; height:2rem; padding:0; border:1px solid #d8d2c7; border-radius:999px; background:#fff; color:#595959; font-size:1.25rem; cursor:pointer; }
.pd-expense-dialog__close:hover { background:#f7f0de; color:#856632; }
.pd-expense-dialog__body { max-height:calc(86vh - 6rem); overflow:auto; padding:0 1.25rem 1.25rem; }
.pd-expense-dialog__table { width:100%; border-collapse:collapse; font-size:.875rem; }
.pd-expense-dialog__table th { position:sticky; top:0; z-index:1; padding:.65rem .85rem; border-bottom:1px solid #d8d2c7; background:#f3ece0; color:#3d3a35; text-align:left; white-space:nowrap; }
.pd-expense-dialog__table td { padding:.6rem .85rem; border-bottom:1px solid #eee7da; color:#3d3a35; }
.pd-expense-dialog__table th.num, .pd-expense-dialog__table td.num { text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }
.pd-expense-dialog__empty { padding:2rem 1rem; color:#7c7468; text-align:center; }
/* 筛选栏:12 列栅格对齐——一行 4 个下拉;账单项目与关键词同一行;发生时间单独一行 */
.pd-filter-grid { display:grid; grid-template-columns:repeat(12, minmax(0, 1fr)); gap:.75rem 1rem; align-items:end; }
.pd-filter-grid .upstream-data-field { min-width:0; }
@ -127,7 +144,7 @@
.pd-export-progress__bar { height:.5rem; border:1px solid #d8d2c7; border-radius:999px; background:#fff; overflow:hidden; }
.pd-export-progress__bar span { display:block; height:100%; width:0; background:#856632; transition:width .3s ease; }
.pd-export-progress__text { margin-top:.35rem; color:#595959; font-size:.75rem; }
@media (max-width:900px) { .pd-stats { grid-template-columns:repeat(2, minmax(0, 1fr)); } .pd-compact-summary { margin-left:0; } }
@media (max-width:900px) { .pd-stats { grid-template-columns:repeat(2, minmax(0, 1fr)); } .pd-compact-summary { margin-left:0; } .pd-item-summary__total { margin-left:0; padding-left:0; border-left:0; } }
@media (max-width:520px) { .pd-stats { grid-template-columns:1fr; } }
</style>
@ -146,7 +163,7 @@
<div class="pd-page-description">
数据源=各平台已导入账单(与「店铺收款账户账单」同源);<b>财务备注</b>、<b>财务类型</b>由科目映射表按「平台+账单项目(wx 自动去前缀)」带出,匹配不到的留空并标红。
@if ($expenseOnly)
本页只展示科目映射表中<b>财务类型=费用</b>的账单;费用按<b>总账备注</b>分类汇总,金额单位为<b>万</b>。
本页只展示科目映射表中<b>财务类型=费用</b>的账单;费用按<b>账单费用</b>分类汇总,金额单位为<b>万</b>。
@else
同一交易单号跨月合并后已与订单实付对平的,差额备注优先显示为<b>差额=跨月收款(合并已对平)</b>;未对平仍显示<b>差额待核实</b>。
@endif
@ -266,17 +283,26 @@
@if ($expenseOnly)
<div class="pd-item-summary" id="pdItemSummary" data-endpoint="{{ $expenseItemSummaryRoute }}">
<div class="pd-item-summary__head">
<strong>费用分类汇总</strong>
<span>单位:万;汇总金额 = 收入 - 支出</span>
<span id="pdItemSummaryStatus">正在汇总…</span>
<div class="pd-item-summary__head-main">
<div class="pd-item-summary__title">
<strong>费用分类汇总</strong>
<span>单位:万元;汇总金额 = 收入 - 支出</span>
</div>
<span class="pd-item-summary__status" id="pdItemSummaryStatus">正在汇总…</span>
</div>
<div class="pd-item-summary__total">
<span>总金额(万元)</span>
<strong id="pdItemSummaryTotalAll">—</strong>
</div>
</div>
<div class="pd-item-summary__wrap" id="pdItemSummaryWrap" hidden>
<table>
<thead>
<tr>
<th>总账备注</th>
<th>账单费用</th>
<th class="num">开票金额(万)</th>
<th class="num">不开票金额(万)</th>
<th class="num">总金额(万)</th>
</tr>
</thead>
<tbody id="pdItemSummaryRows"></tbody>
@ -285,11 +311,40 @@
<td>合计</td>
<td class="num" id="pdItemSummaryTotalInvoice">—</td>
<td class="num" id="pdItemSummaryTotalNonInvoice">—</td>
<td class="num" id="pdItemSummaryTotalNet">—</td>
</tr>
</tfoot>
</table>
</div>
</div>
<dialog class="pd-expense-dialog" id="pdExpenseCategoryDialog" aria-labelledby="pdExpenseCategoryDialogTitle">
<div class="pd-expense-dialog__head">
<div class="pd-expense-dialog__head-main">
<h2 class="pd-expense-dialog__title" id="pdExpenseCategoryDialogTitle">费用分类明细</h2>
<span class="pd-expense-dialog__subtitle">按账单名称汇总;开票与不开票金额均以万元展示</span>
</div>
<div class="pd-expense-dialog__total">
<span>当前分类合计(万元)</span>
<strong id="pdExpenseCategoryDialogTotal">—</strong>
</div>
<button type="button" class="pd-expense-dialog__close" id="pdExpenseCategoryDialogClose" aria-label="关闭费用分类明细">×</button>
</div>
<div class="pd-expense-dialog__body">
<table class="pd-expense-dialog__table">
<thead>
<tr>
<th>账单名称</th>
<th class="num">开票金额(万)</th>
<th class="num">不开票金额(万)</th>
<th class="num">总金额(万)</th>
</tr>
</thead>
<tbody id="pdExpenseCategoryDialogRows"></tbody>
</table>
<div class="pd-expense-dialog__empty" id="pdExpenseCategoryDialogEmpty" hidden>当前分类没有账单名称明细。</div>
</div>
</dialog>
@endif
<div class="pd-detail-list">
@ -326,7 +381,7 @@
<tr>
@if ($expenseOnly)
<th data-col="platform">平台</th><th data-col="store_name">店铺</th>
<th data-col="online_order_no">线上单号</th><th data-col="finance_remark">总账备注</th>
<th data-col="online_order_no">线上单号</th><th data-col="finance_remark">账单费用</th>
<th data-col="amount">金额(收-支)</th>
@else
<th data-col="record_code">记录编码</th><th data-col="store_name">店铺</th><th data-col="finance_remark">财务备注</th>
@ -676,6 +731,13 @@
var summaryRows = document.getElementById('pdItemSummaryRows');
var summaryTotalInvoice = document.getElementById('pdItemSummaryTotalInvoice');
var summaryTotalNonInvoice = document.getElementById('pdItemSummaryTotalNonInvoice');
var summaryTotalNet = document.getElementById('pdItemSummaryTotalNet');
var summaryTotalAll = document.getElementById('pdItemSummaryTotalAll');
var categoryDialog = document.getElementById('pdExpenseCategoryDialog');
var categoryDialogTitle = document.getElementById('pdExpenseCategoryDialogTitle');
var categoryDialogTotal = document.getElementById('pdExpenseCategoryDialogTotal');
var categoryDialogRows = document.getElementById('pdExpenseCategoryDialogRows');
var categoryDialogEmpty = document.getElementById('pdExpenseCategoryDialogEmpty');
var summaryParams = new URLSearchParams(window.location.search);
summaryParams.delete('page');
var summaryUrl = itemSummaryBox.getAttribute('data-endpoint')
@ -687,6 +749,50 @@
});
};
function openCategoryDialog(category) {
categoryDialogTitle.textContent = String(category.memo || '费用分类') + ' · 费用明细';
categoryDialogTotal.textContent = formatWan(
category.net === undefined
? Number(category.invoice_net || 0) + Number(category.non_invoice_net || 0)
: category.net
);
categoryDialogRows.replaceChildren();
(category.items || []).forEach(function (item) {
var tr = document.createElement('tr');
[
item.bill_item,
formatWan(item.invoice_net),
formatWan(item.non_invoice_net),
formatWan(item.net)
].forEach(function (value, index) {
var cell = document.createElement('td');
cell.textContent = value;
if (index > 0) cell.className = 'num';
tr.appendChild(cell);
});
categoryDialogRows.appendChild(tr);
});
categoryDialogEmpty.hidden = Number((category.items || []).length) > 0;
if (typeof categoryDialog.showModal === 'function') {
if (!categoryDialog.open) categoryDialog.showModal();
} else {
categoryDialog.setAttribute('open', '');
}
}
function closeCategoryDialog() {
if (typeof categoryDialog.close === 'function') {
categoryDialog.close();
} else {
categoryDialog.removeAttribute('open');
}
}
document.getElementById('pdExpenseCategoryDialogClose').addEventListener('click', closeCategoryDialog);
categoryDialog.addEventListener('click', function (event) {
if (event.target === categoryDialog) closeCategoryDialog();
});
fetch(summaryUrl, { headers: { Accept: 'application/json' } })
.then(function (response) {
return response.json().then(function (payload) {
@ -699,21 +805,29 @@
(summary.categories || []).forEach(function (category) {
var tr = document.createElement('tr');
var memoCell = document.createElement('td');
var toggle = document.createElement('button');
toggle.type = 'button';
toggle.className = 'pd-item-summary__toggle';
toggle.setAttribute('aria-expanded', 'false');
var openButton = document.createElement('button');
openButton.type = 'button';
openButton.className = 'pd-item-summary__open';
openButton.setAttribute('aria-haspopup', 'dialog');
openButton.setAttribute('aria-label', '查看' + String(category.memo || '费用分类') + '的账单名称明细');
var memoLabel = document.createElement('span');
memoLabel.textContent = String(category.memo || '');
var memoIcon = document.createElement('span');
memoIcon.className = 'material-icons-outlined';
memoIcon.setAttribute('aria-hidden', 'true');
memoIcon.textContent = 'expand_more';
toggle.appendChild(memoLabel);
toggle.appendChild(memoIcon);
memoCell.appendChild(toggle);
memoIcon.textContent = 'chevron_right';
openButton.appendChild(memoLabel);
openButton.appendChild(memoIcon);
openButton.addEventListener('click', function () {
openCategoryDialog(category);
});
memoCell.appendChild(openButton);
tr.appendChild(memoCell);
[formatWan(category.invoice_net), formatWan(category.non_invoice_net)]
[
formatWan(category.invoice_net),
formatWan(category.non_invoice_net),
formatWan(category.net)
]
.forEach(function (value) {
var td = document.createElement('td');
td.className = 'num';
@ -721,42 +835,14 @@
tr.appendChild(td);
});
summaryRows.appendChild(tr);
var drill = document.createElement('tr');
drill.className = 'pd-item-summary__drill';
drill.hidden = true;
var drillCell = document.createElement('td');
drillCell.colSpan = 3;
var title = document.createElement('div');
title.className = 'pd-item-summary__drill-title';
title.textContent = '包含账单名称:' + Number((category.items || []).length).toLocaleString('zh-CN') + ' 个';
var itemTable = document.createElement('table');
itemTable.innerHTML = '<thead><tr><th>账单项目</th><th class="num">开票金额(万)</th><th class="num">不开票金额(万)</th></tr></thead><tbody></tbody>';
var itemBody = itemTable.querySelector('tbody');
(category.items || []).forEach(function (item) {
var itemRow = document.createElement('tr');
[item.bill_item, formatWan(item.invoice_net), formatWan(item.non_invoice_net)]
.forEach(function (value, index) {
var cell = document.createElement('td');
cell.textContent = value;
if (index > 0) cell.className = 'num';
itemRow.appendChild(cell);
});
itemBody.appendChild(itemRow);
});
drillCell.appendChild(title);
drillCell.appendChild(itemTable);
drill.appendChild(drillCell);
summaryRows.appendChild(drill);
toggle.addEventListener('click', function () {
var expanded = toggle.getAttribute('aria-expanded') === 'true';
toggle.setAttribute('aria-expanded', expanded ? 'false' : 'true');
drill.hidden = expanded;
});
});
summaryTotalInvoice.textContent = formatWan(summary.invoice_net);
summaryTotalNonInvoice.textContent = formatWan(summary.non_invoice_net);
var summaryNet = summary.net === undefined
? Number(summary.invoice_net || 0) + Number(summary.non_invoice_net || 0)
: summary.net;
summaryTotalNet.textContent = formatWan(summaryNet);
summaryTotalAll.textContent = formatWan(summaryNet);
summaryStatus.textContent = Number(summary.category_count || 0) > 0
? (Number(summary.category_count).toLocaleString('zh-CN') + ' 个费用分类')
: '当前筛选没有费用项目';

View File

@ -6,7 +6,7 @@ use Tests\Feature\FeatureTestCase;
class ExpenseDetailsDrilldownPageTest extends FeatureTestCase
{
public function testExpenseDetailsPageRendersCategoryDrilldownAndCompactColumns(): void
public function testExpenseDetailsPageRendersCategoryDialogAndCompactColumns(): void
{
$this->loginAs()
->get(route('business.pages.show', [
@ -16,8 +16,11 @@ class ExpenseDetailsDrilldownPageTest extends FeatureTestCase
->assertOk()
->assertSeeText('费用明细')
->assertSeeText('费用分类汇总')
->assertSeeText('账单费用')
->assertSeeText('总金额(万元)')
->assertSee('/workspace/financial-operations/expense-details/item-summary', false)
->assertSee('id="pdItemSummary"', false)
->assertSee('id="pdExpenseCategoryDialog"', false)
->assertDontSee('data-col="record_code"', false)
->assertDontSee('data-col="bill_item"', false);
@ -37,10 +40,13 @@ class ExpenseDetailsDrilldownPageTest extends FeatureTestCase
'finance_remark',
'amount',
], $columns[1]);
$this->assertStringContainsString('pd-item-summary__toggle', $template);
$this->assertStringContainsString('category.items', $template);
$this->assertStringContainsString('pd-item-summary__open', $template);
$this->assertStringContainsString('openCategoryDialog(category)', $template);
$this->assertStringContainsString('pd-expense-dialog__table', $template);
$this->assertStringNotContainsString('pd-item-summary__toggle', $template);
$this->assertStringNotContainsString('pd-item-summary__drill', $template);
$this->assertStringContainsString(
'max-height:clamp(24rem, 58vh, 32rem)',
'max-height:clamp(30rem, 70vh, 44rem)',
$template,
);
}

View File

@ -143,14 +143,15 @@ class NavigationTest extends FeatureTestCase
]))
->assertOk()
->assertSeeText('费用明细')
->assertSeeText('本页只展示科目映射表中财务类型=费用的账单;费用按总账备注分类汇总,金额单位为万。')
->assertSeeText('本页只展示科目映射表中财务类型=费用的账单;费用按账单费用分类汇总,金额单位为万。')
->assertSeeText('费用分类汇总')
->assertSee('/workspace/financial-operations/expense-details/export', false)
->assertSee('/workspace/financial-operations/expense-details/filter-options', false)
->assertSee('/workspace/financial-operations/expense-details/item-summary', false)
->assertSee('id="pdItemSummary"', false)
->assertSee('pd-compact-summary', false)
->assertSeeText('总账备注')
->assertSeeText('账单费用')
->assertSeeText('总金额(万元)')
->assertSeeText('开票金额(万)')
->assertSeeText('不开票金额(万)')
->assertDontSee('<div class="pd-stats">', false)

View File

@ -26,6 +26,7 @@ class BillingDetailsExpenseFilterTest extends TestCase
[],
BillingDetailsPageData::EXPENSE_COLUMNS,
)));
$this->assertSame('账单费用', BillingDetailsPageData::EXPENSE_COLUMNS['finance_remark'][0]);
}
public function test_ledger_memo_totals_split_invoice_buckets(): void
@ -64,7 +65,7 @@ class BillingDetailsExpenseFilterTest extends TestCase
],
],
[
'memo' => '未填写总账备注',
'memo' => '未填写账单费用',
'invoice_net' => 0.0,
'non_invoice_net' => -0.5,
'net' => -0.5,