feat: 新增税金预测表页面与取数口径说明

This commit is contained in:
WuYongJie 2026-10-05 11:01:34 +08:00
parent 8419d4097c
commit 35fe10bc69
6 changed files with 139 additions and 9 deletions

View File

@ -119,7 +119,7 @@ class SidebarPermissions
return null; return null;
}, $navigation))); }, $navigation)));
// 新增的公司成本安排与主体经营报表共用公司经营报表权限。 // 新增的公司成本安排、税金预测表与主体经营报表共用公司经营报表权限。
// 对已经保存过精确权限的账号兼容旧配置,避免新增页面被旧权限集合隐藏。 // 对已经保存过精确权限的账号兼容旧配置,避免新增页面被旧权限集合隐藏。
foreach ($navigation as &$section) { foreach ($navigation as &$section) {
if (($section['slug'] ?? null) !== 'company-management') { if (($section['slug'] ?? null) !== 'company-management') {
@ -127,14 +127,23 @@ class SidebarPermissions
} }
$hasSubjectReport = collect($section['pages'] ?? [])->contains('slug', 'subject-operating-report'); $hasSubjectReport = collect($section['pages'] ?? [])->contains('slug', 'subject-operating-report');
$hasCostArrangement = collect($section['pages'] ?? [])->contains('slug', 'company-cost-arrangement');
if ($hasSubjectReport && ! $hasCostArrangement) { if ($hasSubjectReport) {
$costPage = collect(BusinessNavigation::all()) $configuredPages = collect(BusinessNavigation::all())
->firstWhere('slug', 'company-management')['pages'] ?? []; ->firstWhere('slug', 'company-management')['pages'] ?? [];
$costPage = collect($costPage)->firstWhere('slug', 'company-cost-arrangement');
if ($costPage) { foreach (['company-cost-arrangement', 'tax-forecast'] as $sharedReportSlug) {
$section['pages'][] = $costPage; $alreadyVisible = collect($section['pages'] ?? [])->contains('slug', $sharedReportSlug);
if ($alreadyVisible) {
continue;
}
$sharedReportPage = collect($configuredPages)->firstWhere('slug', $sharedReportSlug);
if ($sharedReportPage) {
$section['pages'][] = $sharedReportPage;
}
} }
} }
} }

View File

@ -48,6 +48,40 @@ $navigation = [
], ],
], ],
], ],
[
'slug' => 'tax-forecast',
'title' => '税金预测表',
'directory' => [
'icon' => 'calculate',
'status' => '字段已定义',
'index_label' => '序号',
'description' => '按公司主体预测当月税金:先按公司税务类型、工商类型和征收方式确定口径,再计算增值税及附加、印花税和所得税;取数公式见 docs/税金预测表需求说明.md。',
'empty' => '税金预测表尚未接入取数:工商类型、征收方式(查账征收/核定征收)确认并补齐数据来源后开始计算。',
'fields' => [
['name' => 'company_name', 'label' => '公司名称'],
['name' => 'taxpayer_type', 'label' => '公司税务类型'],
['name' => 'business_registration_type', 'label' => '工商类型'],
['name' => 'collection_method', 'label' => '征收方式'],
['name' => 'assessed_income_rate', 'label' => '核定应税所得率(%)', 'kind' => 'number'],
['name' => 'forecast_month', 'label' => '预测月份'],
['name' => 'revenue_incl_tax', 'label' => '当月含税收入预测', 'kind' => 'number'],
['name' => 'revenue_excl_tax', 'label' => '当月不含税收入', 'kind' => 'number'],
['name' => 'quarter_sales_excl_tax', 'label' => '季度累计销售额(不含税)', 'kind' => 'number'],
['name' => 'cost_forecast', 'label' => '当月成本费用预测', 'kind' => 'number'],
['name' => 'taxable_income', 'label' => '预计应纳税所得额', 'kind' => 'number'],
['name' => 'vat_rate', 'label' => '增值税征收率/税率'],
['name' => 'vat_payable', 'label' => '预计增值税', 'kind' => 'number'],
['name' => 'urban_maintenance_tax', 'label' => '城建税', 'kind' => 'number'],
['name' => 'education_surcharge', 'label' => '教育费附加', 'kind' => 'number'],
['name' => 'local_education_surcharge', 'label' => '地方教育附加', 'kind' => 'number'],
['name' => 'stamp_duty', 'label' => '印花税', 'kind' => 'number'],
['name' => 'income_tax', 'label' => '企业所得税/经营所得个税', 'kind' => 'number'],
['name' => 'total_tax', 'label' => '税金合计', 'kind' => 'number'],
['name' => 'tax_burden_rate', 'label' => '综合税负率(%)', 'kind' => 'number'],
['name' => 'notes', 'label' => '备注'],
],
],
],
[ [
'slug' => 'basic-information', 'slug' => 'basic-information',
'title' => '公司基础信息', 'title' => '公司基础信息',

View File

@ -0,0 +1,62 @@
# 税金预测表需求说明
## 1. 文档状态
- 状态:页面和字段结构已建立;取数公式为初稿,税率口径和两个新增数据源待负责人确认。
- 页面:经营报表 → 税金预测表。
- 路由标识:`company-management/tax-forecast`。
- 适用对象:小微企业主体(小规模纳税人、小型微利企业、个体工商户、个人独资企业、合伙企业等)。
- 本文之外不自行扩展业务规则;正式口径以负责人和主管税务机关确认为准。
## 2. 展示粒度
一行 = 一个公司主体 × 一个预测月份。
先看“公司税务类型 + 工商类型 + 征收方式”三列确定算法口径,再看税种明细列;
不是同一个口径的主体不放在同一组做横向比较。
## 3. 字段顺序与取数公式
序号由目录表自动生成,不占数据字段。
| 顺序 | 字段 | 取数 / 公式 |
| ---: | --- | --- |
| 1 | 公司名称 | 公司基础信息镜像 `rpt.fys_companyInfo.businessLicenseName` |
| 2 | 公司税务类型 | 公司基础信息镜像 `taxCategoryAndType`:一般纳税人 / 小规模纳税人 / 个体工商户 / 无税务登记 |
| 3 | 工商类型 | **新增数据源**:工商登记类型(有限责任公司、有限责任公司(自然人独资)、个人独资企业、合伙企业、个体工商户)。用于区分经营所得个税与企业所得税 |
| 4 | 征收方式 | **新增数据源**:查账征收 / 核定征收 / 定期定额。核定户按核定通知书取数 |
| 5 | 核定应税所得率(%) | 核定征收时按主管税务机关核定通知书维护;定期定额户按核定定额折算 |
| 6 | 预测月份 | 页面参数,默认当月 |
| 7 | 当月含税收入预测 | 主体维度经营报表同口径:`bills.income` 按主体生效/失效期间归集到当月;当月未出账时取上月实际值或公司成本安排页的“当月收入预测” |
| 8 | 当月不含税收入 | 小规模:含税收入 ÷ (1 + 征收率);一般纳税人:按适用税率(6%/9%/13%)分别换算后合计 |
| 9 | 季度累计销售额(不含税) | 本季度 3 个月不含税销售额之和,作为小规模免征增值税的判断基数 |
| 10 | 当月成本费用预测 | 公司成本安排页:供应商成本安排 + 快递成本安排 + 人工成本预测 + 其他费用预测 |
| 11 | 预计应纳税所得额 | 查账征收:不含税收入 − 成本 − 费用 − 税金及附加;核定征收:不含税收入 × 核定应税所得率 |
| 12 | 增值税征收率/税率 | 小规模 1%(3% 减按 1%);一般纳税人按业务适用 6%/9%/13% |
| 13 | 预计增值税 | 小规模:季度销售额 > 30 万元时 = 不含税销售额 × 1%,≤ 30 万元 = 0;一般纳税人:销项税额 − 进项税额;个体工商户、个人独资企业同小规模口径 |
| 14 | 城建税 | 预计增值税 × 7%(市区)/ 5%(县城、镇)/ 1%(其他)× 50%(六税两费减半) |
| 15 | 教育费附加 | 预计增值税 × 3% × 50% |
| 16 | 地方教育附加 | 预计增值税 × 2% × 50% |
| 17 | 印花税 | 购销合同金额 × 0.03% × 50%(小规模、小微减半) |
| 18 | 企业所得税/经营所得个税 | 有限公司(小型微利):应纳税所得额 × 25% × 20%,年 ≤ 300 万元部分实际税负 5%;个人独资/合伙/个体户:经营所得五级超额累进(5%~35%),核定户按 收入 × 核定应税所得率 计算,个体工商户 200 万元以内减半 |
| 19 | 税金合计 | 增值税 + 城建税 + 教育费附加 + 地方教育附加 + 印花税 + 所得税 |
| 20 | 综合税负率(%) | 税金合计 ÷ 当月不含税收入 × 100% |
| 21 | 备注 | 数据来源、核定依据、需人工确认项;工资薪金个税、分红个税按实际发生单独测算,不并入本表 |
## 4. 政策口径(2026 年 10 月初稿,待财务确认)
以下按现行小微企业通用政策整理,执行期限和适用条件以最新公告为准:
- 小规模纳税人月销售额 10 万元以下(季度 30 万元以下)免征增值税;3% 征收率减按 1% 征收。
- 增值税小规模纳税人、小型微利企业和个体工商户“六税两费”减半征收(含城建税、教育费附加、地方教育附加、印花税等)。
- 小型微利企业年应纳税所得额不超过 300 万元部分,减按 25% 计入应纳税所得额,按 20% 税率缴纳企业所得税(实际税负 5%)。
- 个体工商户年应纳税所得额不超过 200 万元部分,经营所得个人所得税减半征收。
## 5. 数据缺口与前置条件
1. **工商类型**:现有共享镜像只有 `businessLicenseType`(内部管理分类,如“店铺-普通公司”“个体户”),无法区分个人独资企业、合伙企业、有限责任公司。需要确认来源:工商公示/企查查爬虫接入,或维护在公司档案中。
2. **征收方式与核定应税所得率**:属于税务登记信息,现有镜像没有。需要确认来源:电子税务局取数,或由财务在系统内维护。
3. **收入预测**:沿用主体维度经营报表的主体收入口径(`bills.income` + 店铺主体生命周期)。
4. **成本费用预测**:等待公司成本安排页接入供应商、快递、人工和其他费用数据。
以上 1、2 两项确认前,页面保持“字段已定义、数据待接入”,不显示推测数据。

View File

@ -44,6 +44,7 @@
'store-management/store-report', 'store-management/store-report',
'company-management/subject-operating-report', 'company-management/subject-operating-report',
'company-management/company-cost-arrangement', 'company-management/company-cost-arrangement',
'company-management/tax-forecast',
'company-management/personnel-inventory', 'company-management/personnel-inventory',
'store-management/internal-flow-report', 'store-management/internal-flow-report',
], true); ], true);
@ -55,6 +56,7 @@
'store-management/store-report' => '按店铺、主体和月份销量查询经营数据并导出', 'store-management/store-report' => '按店铺、主体和月份销量查询经营数据并导出',
'company-management/subject-operating-report' => '按主体和收入月份查询经营汇总并导出', 'company-management/subject-operating-report' => '按主体和收入月份查询经营汇总并导出',
'company-management/company-cost-arrangement' => '按公司类型和发票类型查询成本安排字段', 'company-management/company-cost-arrangement' => '按公司类型和发票类型查询成本安排字段',
'company-management/tax-forecast' => '按税务类型、工商类型和征收方式查询税金预测口径',
'company-management/personnel-inventory' => '按人员、职位和公司类型查询人员盘点字段', 'company-management/personnel-inventory' => '按人员、职位和公司类型查询人员盘点字段',
'product-inventory/monthly-weighted-average-price' => '按月份、商品编码、仓储方和分类查询商品月加权平均单价', 'product-inventory/monthly-weighted-average-price' => '按月份、商品编码、仓储方和分类查询商品月加权平均单价',
'store-management/internal-flow-report' => '按抬头、标签查询内部流转明细并导出', 'store-management/internal-flow-report' => '按抬头、标签查询内部流转明细并导出',
@ -1064,6 +1066,13 @@
['name' => 'company_name', 'label' => '抬头', 'placeholder' => '输入公司名称关键词'], ['name' => 'company_name', 'label' => '抬头', 'placeholder' => '输入公司名称关键词'],
['name' => 'tag', 'label' => '标签'], ['name' => 'tag', 'label' => '标签'],
], ],
'company-management/tax-forecast' => [
['name' => 'company_name', 'label' => '公司名称', 'placeholder' => '输入公司名称关键词'],
['name' => 'taxpayer_type', 'label' => '公司税务类型'],
['name' => 'business_registration_type', 'label' => '工商类型'],
['name' => 'collection_method', 'label' => '征收方式'],
['name' => 'forecast_month', 'label' => '预测月份', 'placeholder' => '例如 2026-10'],
],
default => $directoryFields, default => $directoryFields,
}; };
$directoryExcludedQueryFields = match ($directoryPageKey) { $directoryExcludedQueryFields = match ($directoryPageKey) {
@ -1106,6 +1115,7 @@
'store-management/store-report' => ['status', 'can_change', 'company_type'], 'store-management/store-report' => ['status', 'can_change', 'company_type'],
'company-management/subject-operating-report' => ['company_type', 'can_change_entity'], 'company-management/subject-operating-report' => ['company_type', 'can_change_entity'],
'company-management/company-cost-arrangement' => ['company_type', 'invoice_type'], 'company-management/company-cost-arrangement' => ['company_type', 'invoice_type'],
'company-management/tax-forecast' => ['taxpayer_type', 'business_registration_type', 'collection_method'],
'company-management/personnel-inventory' => ['company_type'], 'company-management/personnel-inventory' => ['company_type'],
'store-management/internal-flow-report' => ['tag'], 'store-management/internal-flow-report' => ['tag'],
default => [], default => [],
@ -1162,6 +1172,8 @@
'taxpayer_type' => ['一般纳税人', '小规模纳税人', '个体工商户', '无税务登记', 'CORP'], 'taxpayer_type' => ['一般纳税人', '小规模纳税人', '个体工商户', '无税务登记', 'CORP'],
'company_status' => ['正常', '已注销'], 'company_status' => ['正常', '已注销'],
'company_type' => ['个体工商户', '个体户', '二级公司', '人力资源公司', '仓储公司', '其他', '合同公司', '品牌公司', '店铺-国标公司', '店铺-国标商标', '店铺-大店公司', '店铺-普通公司', '母公司', '资产型'], 'company_type' => ['个体工商户', '个体户', '二级公司', '人力资源公司', '仓储公司', '其他', '合同公司', '品牌公司', '店铺-国标公司', '店铺-国标商标', '店铺-大店公司', '店铺-普通公司', '母公司', '资产型'],
'business_registration_type' => ['有限责任公司', '有限责任公司(自然人独资)', '个人独资企业', '合伙企业', '个体工商户', '其他'],
'collection_method' => ['查账征收', '核定征收', '定期定额'],
'status' => ['0' => '开店中', '3' => '关店中', '6' => '关店'], 'status' => ['0' => '开店中', '3' => '关店中', '6' => '关店'],
'can_change', 'can_change_entity' => ['是', '否'], 'can_change', 'can_change_entity' => ['是', '否'],
'invoice_type' => ['普票', '专票'], 'invoice_type' => ['普票', '专票'],
@ -1484,7 +1496,7 @@
<thead> <thead>
<tr> <tr>
@unless ($directoryHasGroupedHeader) @unless ($directoryHasGroupedHeader)
<th scope="col" data-directory-fixed="start">序号</th> <th scope="col" data-directory-fixed="start">{{ $directory['index_label'] ?? '序号' }}</th>
@endunless @endunless
@if ($directoryHasGroupedHeader) @if ($directoryHasGroupedHeader)
@php @php

View File

@ -150,6 +150,7 @@
['title' => '经营报表', 'items' => [ ['title' => '经营报表', 'items' => [
['company-management', 'subject-operating-report', '主体维度经营报表', 'domain'], ['company-management', 'subject-operating-report', '主体维度经营报表', 'domain'],
['company-management', 'company-cost-arrangement', '公司成本安排', 'account_balance_wallet'], ['company-management', 'company-cost-arrangement', '公司成本安排', 'account_balance_wallet'],
['company-management', 'tax-forecast', '税金预测表', 'calculate'],
['store-management', 'store-report', '店铺维度报表', 'storefront'], ['store-management', 'store-report', '店铺维度报表', 'storefront'],
['store-management', 'internal-flow-report', '内部流转报表', 'swap_horiz'], ['store-management', 'internal-flow-report', '内部流转报表', 'swap_horiz'],
['company-management', 'personnel-inventory', '人员盘点表', 'groups'], ['company-management', 'personnel-inventory', '人员盘点表', 'groups'],

View File

@ -461,7 +461,7 @@ class ManagementCrudTest extends FeatureTestCase
$sections = collect($navigation)->keyBy('slug'); $sections = collect($navigation)->keyBy('slug');
$this->assertSame( $this->assertSame(
['subject-operating-report', 'company-cost-arrangement', 'basic-information', 'personnel-inventory', 'company-progress'], ['subject-operating-report', 'company-cost-arrangement', 'tax-forecast', 'basic-information', 'personnel-inventory', 'company-progress'],
array_column($sections['company-management']['pages'], 'slug') array_column($sections['company-management']['pages'], 'slug')
); );
$this->assertSame( $this->assertSame(
@ -548,6 +548,7 @@ class ManagementCrudTest extends FeatureTestCase
$expectedHeaders = [ $expectedHeaders = [
['section' => 'company-management', 'page' => 'subject-operating-report', 'headers' => ['市', '主体', '最近12个月累计收入', '1月收入', '12月收入']], ['section' => 'company-management', 'page' => 'subject-operating-report', 'headers' => ['市', '主体', '最近12个月累计收入', '1月收入', '12月收入']],
['section' => 'company-management', 'page' => 'company-cost-arrangement', 'headers' => ['公司', '公司类型', '发票类型', '当月收入预测', '往期成本缺口', '供应商成本安排', '快递成本安排', '当月税金预测', '人工成本预测', '其他费用预测']], ['section' => 'company-management', 'page' => 'company-cost-arrangement', 'headers' => ['公司', '公司类型', '发票类型', '当月收入预测', '往期成本缺口', '供应商成本安排', '快递成本安排', '当月税金预测', '人工成本预测', '其他费用预测']],
['section' => 'company-management', 'page' => 'tax-forecast', 'headers' => ['序号', '公司名称', '公司税务类型', '工商类型', '征收方式', '预计增值税', '企业所得税/经营所得个税', '税金合计']],
['section' => 'company-management', 'page' => 'personnel-inventory', 'headers' => ['人员名称', '税务局密码', '可担任公司数量']], ['section' => 'company-management', 'page' => 'personnel-inventory', 'headers' => ['人员名称', '税务局密码', '可担任公司数量']],
['section' => 'company-management', 'page' => 'company-progress', 'headers' => ['公司进度表字段尚未定义']], ['section' => 'company-management', 'page' => 'company-progress', 'headers' => ['公司进度表字段尚未定义']],
['section' => 'trademark-management', 'page' => 'trademark-progress', 'headers' => ['商标号', '是否完成', '办理人']], ['section' => 'trademark-management', 'page' => 'trademark-progress', 'headers' => ['商标号', '是否完成', '办理人']],
@ -582,6 +583,17 @@ class ManagementCrudTest extends FeatureTestCase
->assertSeeText('导出 Excel') ->assertSeeText('导出 Excel')
->assertSee('position: sticky', false) ->assertSee('position: sticky', false)
->assertSee('overflow: auto', false); ->assertSee('overflow: auto', false);
$this->get(route('business.pages.show', [
'section' => 'company-management',
'page' => 'tax-forecast',
]))
->assertOk()
->assertSeeText('按税务类型、工商类型和征收方式查询税金预测口径')
->assertSeeText('字段已定义')
->assertSeeText('个人独资企业')
->assertSeeText('核定征收')
->assertSeeText('查账征收');
} }
private function mockUpstreamPage(object $row): void private function mockUpstreamPage(object $row): void