From bfc119608fc2f8a8743ad9ed00d470ee0657da14 Mon Sep 17 00:00:00 2001 From: WuYongJie <549727955@qq.com> Date: Mon, 5 Oct 2026 11:17:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=A8=8E=E9=87=91?= =?UTF-8?q?=E9=A2=84=E6=B5=8B=E8=A1=A8=E9=80=BB=E8=BE=91=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/Business/Pages.php | 51 +++++ config/business_navigation.php | 4 + .../Services/TaxForecastLogic.php | 201 +++++++++++++++++ .../tax-forecast-data-logic-edit.blade.php | 211 ++++++++++++++++++ .../tax-forecast-data-logic.blade.php | 183 +++++++++++++++ .../components/layouts/admin/menu.blade.php | 1 + routes/admin.php | 8 + tests/Feature/Business/ManagementCrudTest.php | 50 ++++- 8 files changed, 708 insertions(+), 1 deletion(-) create mode 100644 modules/EcommerceFinance/Services/TaxForecastLogic.php create mode 100644 resources/views/business/pages/company-management/tax-forecast-data-logic-edit.blade.php create mode 100644 resources/views/business/pages/company-management/tax-forecast-data-logic.blade.php diff --git a/app/Http/Controllers/Business/Pages.php b/app/Http/Controllers/Business/Pages.php index d7f858d3..d8eed3ea 100644 --- a/app/Http/Controllers/Business/Pages.php +++ b/app/Http/Controllers/Business/Pages.php @@ -69,6 +69,7 @@ use Modules\EcommerceFinance\Repositories\TmallTaobaoSpreadBillRepository; use Modules\EcommerceFinance\Services\AccountMappingStore; use Modules\EcommerceFinance\Services\AccountMappingValidator; use Modules\EcommerceFinance\Services\StoreReportInitialPeriods; +use Modules\EcommerceFinance\Services\TaxForecastLogic; use Modules\EcommerceFinance\Services\UpstreamQueryCacheFactory; use Modules\EcommerceFinance\Services\SupplierPayableMaintenanceRegistry; use Modules\EcommerceFinance\Services\PayablesFinalRegistry; @@ -1673,10 +1674,60 @@ class Pages extends Controller 'planting-details' => $this->contentForPlantingDetails(), 'jst-order-labels' => $this->contentForJstOrderLabels(), 'store-report-data-logic' => $this->prepareStoreReportLogic(), + 'tax-forecast-data-logic' => $this->contentForTaxForecastLogic(), default => null, }; } + /** + * 税金预测表逻辑配置:规则清单、数据源状态和运行参数。 + */ + protected function contentForTaxForecastLogic(): array + { + return [ + 'view' => 'business.pages.company-management.tax-forecast-data-logic', + 'taxRules' => TaxForecastLogic::rules(), + 'taxSettings' => TaxForecastLogic::current(), + 'taxHealth' => TaxForecastLogic::health(), + ]; + } + + public function editTaxForecastLogic() + { + return view('business.pages.company-management.tax-forecast-data-logic-edit', [ + 'section' => ['slug' => 'trademark-management', 'title' => '商标管理'], + 'page' => ['slug' => 'tax-forecast-data-logic', 'title' => '税金预测表逻辑配置'], + 'settings' => TaxForecastLogic::current(), + 'incomeForecastSources' => TaxForecastLogic::INCOME_FORECAST_SOURCES, + ]); + } + + public function updateTaxForecastLogic(Request $request) + { + $data = $request->validate([ + 'vat_small_rate' => ['required', 'numeric', 'min:0', 'max:100'], + 'vat_free_threshold' => ['required', 'numeric', 'min:0'], + 'vat_general_enabled' => ['required', 'in:0,1'], + 'surtax_city_rate' => ['required', 'numeric', 'min:0', 'max:100'], + 'surtax_education_rate' => ['required', 'numeric', 'min:0', 'max:100'], + 'surtax_local_education_rate' => ['required', 'numeric', 'min:0', 'max:100'], + 'surtax_halved' => ['required', 'in:0,1'], + 'stamp_duty_rate' => ['required', 'numeric', 'min:0', 'max:100'], + 'stamp_duty_halved' => ['required', 'in:0,1'], + 'cit_effective_rate' => ['required', 'numeric', 'min:0', 'max:100'], + 'cit_threshold' => ['required', 'numeric', 'min:0'], + 'individual_halved_threshold' => ['required', 'numeric', 'min:0'], + 'assessed_income_rate' => ['required', 'numeric', 'min:0', 'max:100'], + 'income_forecast_source' => ['required', 'in:' . implode(',', array_keys(TaxForecastLogic::INCOME_FORECAST_SOURCES))], + ]); + + TaxForecastLogic::save($data); + + return redirect() + ->route('business.pages.show', ['section' => 'trademark-management', 'page' => 'tax-forecast-data-logic']) + ->with('success', '税金预测表逻辑配置已保存,下次预测按新参数计算。'); + } + /** 首次打开店铺维度报表逻辑页时把代码里的期初数据固化成可编辑设置。 */ protected function prepareStoreReportLogic(): ?array { diff --git a/config/business_navigation.php b/config/business_navigation.php index e8dd36fd..272d5294 100644 --- a/config/business_navigation.php +++ b/config/business_navigation.php @@ -233,6 +233,10 @@ $navigation = [ 'slug' => 'store-report-data-logic', 'title' => '店铺维度报表逻辑配置', ], + [ + 'slug' => 'tax-forecast-data-logic', + 'title' => '税金预测表逻辑配置', + ], ], ], ], diff --git a/modules/EcommerceFinance/Services/TaxForecastLogic.php b/modules/EcommerceFinance/Services/TaxForecastLogic.php new file mode 100644 index 00000000..6c78e15e --- /dev/null +++ b/modules/EcommerceFinance/Services/TaxForecastLogic.php @@ -0,0 +1,201 @@ + self::PREFIX . '.vat_small_rate', + 'vat_free_threshold' => self::PREFIX . '.vat_free_threshold', + 'vat_general_enabled' => self::PREFIX . '.vat_general_enabled', + 'surtax_city_rate' => self::PREFIX . '.surtax_city_rate', + 'surtax_education_rate' => self::PREFIX . '.surtax_education_rate', + 'surtax_local_education_rate' => self::PREFIX . '.surtax_local_education_rate', + 'surtax_halved' => self::PREFIX . '.surtax_halved', + 'stamp_duty_rate' => self::PREFIX . '.stamp_duty_rate', + 'stamp_duty_halved' => self::PREFIX . '.stamp_duty_halved', + 'cit_effective_rate' => self::PREFIX . '.cit_effective_rate', + 'cit_threshold' => self::PREFIX . '.cit_threshold', + 'individual_halved_threshold' => self::PREFIX . '.individual_halved_threshold', + 'assessed_income_rate' => self::PREFIX . '.assessed_income_rate', + 'income_forecast_source' => self::PREFIX . '.income_forecast_source', + ]; + + public const INCOME_FORECAST_SOURCES = [ + 'last_month_actual' => '上月实际收入(bills.income)', + 'cost_arrangement' => '公司成本安排的当月收入预测', + 'manual' => '手工录入', + ]; + + /** @return array */ + public static function defaults(): array + { + return [ + 'vat_small_rate' => '1', + 'vat_free_threshold' => '300000', + 'vat_general_enabled' => '1', + 'surtax_city_rate' => '7', + 'surtax_education_rate' => '3', + 'surtax_local_education_rate' => '2', + 'surtax_halved' => '1', + 'stamp_duty_rate' => '0.03', + 'stamp_duty_halved' => '1', + 'cit_effective_rate' => '5', + 'cit_threshold' => '3000000', + 'individual_halved_threshold' => '2000000', + 'assessed_income_rate' => '10', + 'income_forecast_source' => 'last_month_actual', + ]; + } + + /** @return array */ + public static function current(): array + { + $values = []; + foreach (self::KEYS as $key => $settingKey) { + $value = setting($settingKey, null); + $values[$key] = is_array($value) ? implode('', $value) : (string) ($value ?? ''); + } + + return array_merge(self::defaults(), array_filter($values, static fn (string $value): bool => $value !== '')); + } + + public static function value(string $key, mixed $default = null): mixed + { + $current = self::current(); + + return $current[$key] ?? ($default ?? (self::defaults()[$key] ?? null)); + } + + public static function rate(string $key): float + { + return max((float) self::value($key, 0), 0); + } + + public static function amount(string $key): float + { + return max((float) self::value($key, 0), 0); + } + + public static function toggled(string $key): bool + { + return (string) self::value($key, '1') === '1'; + } + + /** @param array $values */ + public static function save(array $values): void + { + $payload = []; + foreach (self::defaults() as $key => $default) { + if (! array_key_exists($key, $values) || ! isset(self::KEYS[$key])) { + continue; + } + $payload[self::KEYS[$key]] = mb_substr(trim((string) $values[$key]), 0, 191); + } + + if ($payload !== []) { + setting($payload)->save(); + } + } + + /** + * 规则目录:页面上的规则清单以这里为准,和取数公式文档 + * docs/税金预测表需求说明.md 保持一致。 + * + * @return array> + */ + public static function rules(): array + { + return [ + '主体识别' => [ + ['code' => 'R1', 'object' => '公司名称、公司税务类型', 'logic' => '读取公司基础信息镜像的营业执照名称和纳税类别及类型,作为增值税口径判断依据。', 'source' => 'rpt.fys_companyInfo(只读镜像)', 'priority' => '税务类型空值时按“无税务登记”处理并提示补充。'], + ['code' => 'R2', 'object' => '工商类型', 'logic' => '区分有限责任公司、个人独资企业、合伙企业、个体工商户,决定所得税种。', 'source' => '待接入:工商登记信息或人工维护', 'priority' => '缺失时所得税列留空,不按企业所得税估算。'], + ['code' => 'R3', 'object' => '征收方式、核定应税所得率', 'logic' => '查账征收按利润计算;核定征收按 收入 × 核定应税所得率 计算;定期定额按核定定额折算。', 'source' => '待接入:电子税务局数据或人工维护', 'priority' => '缺失时按查账征收展示,并在备注列标记待确认。'], + ], + '增值税' => [ + ['code' => 'R4', 'object' => '小规模纳税人免税判断', 'logic' => '季度不含税销售额不超过免税额度时,预计增值税为 0。', 'source' => 'bills.income 按主体期间归集', 'priority' => '免税额度按配置参数执行,默认 30 万元/季。'], + ['code' => 'R5', 'object' => '小规模纳税人征收率', 'logic' => '超过免税额度时,预计增值税 = 不含税销售额 × 征收率。', 'source' => '配置参数', 'priority' => '默认 1%(3% 减按 1%)。'], + ['code' => 'R6', 'object' => '一般纳税人计税', 'logic' => '预计增值税 = 销项税额 − 进项税额;进项缺失时按销项全额提示。', 'source' => 'bills.income 与进项数据', 'priority' => '默认开启,可在配置中关闭改为简易口径。'], + ['code' => 'R7', 'object' => '个体工商户、个人独资企业、合伙企业', 'logic' => '增值税按小规模纳税人口径计算。', 'source' => '同上', 'priority' => '不因工商类型改为一般纳税人口径。'], + ], + '附加税费' => [ + ['code' => 'R8', 'object' => '城建税', 'logic' => '城建税 = 预计增值税 × 城建税税率。', 'source' => '配置参数', 'priority' => '默认市区 7%,县城/镇 5%,其他 1%。'], + ['code' => 'R9', 'object' => '教育费附加、地方教育附加', 'logic' => '教育费附加 = 增值税 × 3%;地方教育附加 = 增值税 × 2%。', 'source' => '配置参数', 'priority' => '税率可调。'], + ['code' => 'R10', 'object' => '六税两费减半', 'logic' => '小规模纳税人、小型微利企业、个体工商户的附加税费减半征收。', 'source' => '配置开关', 'priority' => '默认开启;关闭后按全额计算。'], + ], + '印花税' => [ + ['code' => 'R11', 'object' => '购销合同印花税', 'logic' => '印花税 = 购销合同金额 × 印花税税率(减半开关生效时再乘 50%)。', 'source' => '配置参数与成本安排金额', 'priority' => '默认 0.03% 并减半。'], + ], + '所得税' => [ + ['code' => 'R12', 'object' => '小型微利企业所得税', 'logic' => '应纳税所得额 × 25% × 20%,年不超过上限部分实际税负 5%。', 'source' => '配置参数 + 预计利润', 'priority' => '默认上限 300 万元,超过部分提示分段计算。'], + ['code' => 'R13', 'object' => '经营所得个人所得税', 'logic' => '个人独资企业、合伙企业、个体工商户按经营所得五级超额累进计算;核定征收按 收入 × 核定应税所得率 计算。', 'source' => '配置参数 + 核定通知书', 'priority' => '核定应税所得率默认 10%。'], + ['code' => 'R14', 'object' => '个体工商户减半', 'logic' => '年应纳税所得额不超过上限部分,经营所得个人所得税减半征收。', 'source' => '配置参数', 'priority' => '默认上限 200 万元。'], + ], + '数据来源' => [ + ['code' => 'R15', 'object' => '收入预测', 'logic' => '按主体生效/失效期间把 bills.income 归集到预测月份;未出账时按配置的收入预测口径取值。', 'source' => 'runtime/bills.sqlite', 'priority' => '口径可在配置中切换。'], + ['code' => 'R16', 'object' => '成本费用预测', 'logic' => '供应商成本安排 + 快递成本安排 + 人工成本预测 + 其他费用预测。', 'source' => '公司成本安排页', 'priority' => '成本安排未接入时所得税列留空。'], + ], + ]; + } + + /** + * 数据源现状:只读共享业务镜像,不访问上游。 + * + * @return array + */ + public static function health(): array + { + $health = [ + [ + 'name' => '公司基础信息(含税务类型)', + 'object' => 'ops_fys_company_info', + 'status' => '尚未同步', + 'detail' => '', + ], + [ + 'name' => '工商类型', + 'object' => '待接入', + 'status' => '未接入', + 'detail' => '现有镜像无法区分个人独资企业、合伙企业;确认数据来源后接入。', + ], + [ + 'name' => '征收方式与核定率', + 'object' => '待接入', + 'status' => '未接入', + 'detail' => '查账/核定、核定应税所得率需电子税务局数据或人工维护。', + ], + ]; + + try { + $connection = DB::connection((string) config('upstream_mirrors.connection', 'business_mirror')); + if ($connection->getSchemaBuilder()->hasTable('ops_fys_company_info')) { + $row = $connection->table('ops_fys_company_info') + ->selectRaw("COUNT(*) AS total, SUM(CASE WHEN taxCategoryAndType = '小规模纳税人' THEN 1 ELSE 0 END) AS small, SUM(CASE WHEN taxCategoryAndType = '一般纳税人' THEN 1 ELSE 0 END) AS general") + ->first(); + $health[0]['status'] = '已同步'; + $health[0]['detail'] = sprintf( + '主体 %d 家:小规模 %d 家、一般纳税人 %d 家', + (int) ($row->total ?? 0), + (int) ($row->small ?? 0), + (int) ($row->general ?? 0), + ); + } + } catch (Throwable) { + $health[0]['detail'] = '读取共享镜像失败,请检查连接与同步状态。'; + } + + return $health; + } +} diff --git a/resources/views/business/pages/company-management/tax-forecast-data-logic-edit.blade.php b/resources/views/business/pages/company-management/tax-forecast-data-logic-edit.blade.php new file mode 100644 index 00000000..4a159854 --- /dev/null +++ b/resources/views/business/pages/company-management/tax-forecast-data-logic-edit.blade.php @@ -0,0 +1,211 @@ +@php + use Modules\EcommerceFinance\Services\TaxForecastLogic; + + $rules = TaxForecastLogic::rules(); +@endphp + + + +
+
+ @csrf + +
+

增值税

+

小规模纳税人按季度销售额判断免税;一般纳税人的进销项抵扣可单独关闭。

+
+
+ + +
对应规则 R5,默认 1%(3% 减按 1%)。
+
+
+ + +
对应规则 R4,默认 300000 元/季。
+
+
+ + +
对应规则 R6。
+
+
+
+ +
+

附加税费

+

附加税费以预计增值税为计税依据,六税两费减半开关对附加税费统一生效。

+
+
+ + +
对应规则 R8,市区 7%、县城/镇 5%、其他 1%。
+
+
+ + +
对应规则 R9,默认 3%。
+
+
+ + +
对应规则 R9,默认 2%。
+
+
+ + +
对应规则 R10。
+
+
+
+ +
+

印花税

+

印花税按购销合同金额计算,减半开关单独维护。

+
+
+ + +
对应规则 R11,默认 0.03%。
+
+
+ + +
对应规则 R11。
+
+
+
+ +
+

所得税

+

有限公司按小型微利企业口径,个人独资企业、合伙企业、个体工商户按经营所得口径。

+
+
+ + +
对应规则 R12,默认 5%(25% × 20%)。
+
+
+ + +
超过上限部分提示分段计算。
+
+
+ + +
对应规则 R14,默认 2000000 元。
+
+
+ + +
核定征收主体未单独维护时按此默认值。
+
+
+
+ +
+

预测口径

+

预测月份尚未出账时,收入取值方式。

+
+
+ + +
对应规则 R15。
+
+
+
+ +
+ + 返回规则页 +
+
+ +
+

规则目录(只读)

+

规则编号和逻辑说明与取数公式文档保持一致,用于核对上面参数的实际含义。

+ + + + + + + + + + + + @foreach ($rules as $category => $categoryRules) + @foreach ($categoryRules as $rule) + + + + + + + + @endforeach + @endforeach + +
规则编号规则类别规则对象规则逻辑优先级说明
{{ $rule['code'] }}{{ $category }}{{ $rule['object'] }}{{ $rule['logic'] }}{{ $rule['priority'] }}
+
+
diff --git a/resources/views/business/pages/company-management/tax-forecast-data-logic.blade.php b/resources/views/business/pages/company-management/tax-forecast-data-logic.blade.php new file mode 100644 index 00000000..82b54759 --- /dev/null +++ b/resources/views/business/pages/company-management/tax-forecast-data-logic.blade.php @@ -0,0 +1,183 @@ +@php + use Modules\EcommerceFinance\Services\TaxForecastLogic; + + $parameterRows = [ + ['label' => '小规模增值税征收率', 'value' => ($taxSettings['vat_small_rate'] ?? '1') . '%', 'hint' => '超过免税额度时按不含税销售额计算'], + ['label' => '小规模季度免税额度', 'value' => number_format((float) ($taxSettings['vat_free_threshold'] ?? 0)) . ' 元/季', 'hint' => '季度不含税销售额不超过该额度时增值税为 0'], + ['label' => '一般纳税人进销项抵扣', 'value' => ($taxSettings['vat_general_enabled'] ?? '1') === '1' ? '开启' : '关闭', 'hint' => '关闭后一般纳税人按销项税额全额提示'], + ['label' => '城建税税率', 'value' => ($taxSettings['surtax_city_rate'] ?? '7') . '%', 'hint' => '市区 7%、县城/镇 5%、其他 1%'], + ['label' => '教育费附加', 'value' => ($taxSettings['surtax_education_rate'] ?? '3') . '%', 'hint' => '以预计增值税为计税依据'], + ['label' => '地方教育附加', 'value' => ($taxSettings['surtax_local_education_rate'] ?? '2') . '%', 'hint' => '以预计增值税为计税依据'], + ['label' => '六税两费减半', 'value' => ($taxSettings['surtax_halved'] ?? '1') === '1' ? '开启' : '关闭', 'hint' => '附加税费减半征收'], + ['label' => '印花税税率(购销合同)', 'value' => ($taxSettings['stamp_duty_rate'] ?? '0.03') . '%', 'hint' => '按购销合同金额计算'], + ['label' => '印花税减半', 'value' => ($taxSettings['stamp_duty_halved'] ?? '1') === '1' ? '开启' : '关闭', 'hint' => '小规模、小微减半征收'], + ['label' => '小型微利企业所得税实际税负', 'value' => ($taxSettings['cit_effective_rate'] ?? '5') . '%', 'hint' => '应纳税所得额 × 25% × 20%'], + ['label' => '年应纳税所得额上限', 'value' => number_format((float) ($taxSettings['cit_threshold'] ?? 0)) . ' 元', 'hint' => '超过上限部分提示分段计算'], + ['label' => '个体工商户减半上限', 'value' => number_format((float) ($taxSettings['individual_halved_threshold'] ?? 0)) . ' 元', 'hint' => '经营所得个人所得税减半'], + ['label' => '核定应税所得率默认值', 'value' => ($taxSettings['assessed_income_rate'] ?? '10') . '%', 'hint' => '核定征收主体未单独维护时按此默认值'], + ['label' => '收入预测口径', 'value' => TaxForecastLogic::INCOME_FORECAST_SOURCES[$taxSettings['income_forecast_source'] ?? ''] ?? '上月实际收入(bills.income)', 'hint' => '预测月份未出账时取值方式'], + ]; +@endphp + + + +
+
+ 规则参数由负责人维护,保存后下次预测按新参数计算。 + 编辑配置 +
+
+ 本页是税金预测表当前实际使用的计算口径,与 docs/税金预测表需求说明.md 保持一致; + 工商类型、征收方式(查账/核定)接入前,涉及所得税的列在预测表中留空,不做推测。 + 返回税金预测表 +
+ +
+

当前运行参数

+ + + + + + + + + + @foreach ($parameterRows as $row) + + + + + + @endforeach + +
参数当前值说明
{{ $row['label'] }}{{ $row['value'] }}{{ $row['hint'] }}
+
+ +
+

数据来源

+ + + + + + + + + + + @foreach ($taxHealth as $source) + + + + + + + @endforeach + +
来源对象状态说明
{{ $source['name'] }}{{ $source['object'] }} + {{ $source['status'] }} + + {{ $source['detail'] !== '' ? $source['detail'] : '—' }} +
收入口径:主体维度经营报表同源(bills.income);成本口径:公司成本安排页。
+
+
+ +
+

规则清单

+ + + + + + + + + + + + + + @foreach ($taxRules as $category => $categoryRules) + @foreach ($categoryRules as $rule) + + + + + + + + + + @endforeach + @endforeach + +
规则编号规则类别规则对象规则逻辑数据来源优先级说明状态
{{ $rule['code'] }}{{ $category }}{{ $rule['object'] }}{{ $rule['logic'] }}{{ $rule['source'] }}{{ $rule['priority'] }}已生效
+
+
diff --git a/resources/views/components/layouts/admin/menu.blade.php b/resources/views/components/layouts/admin/menu.blade.php index e971b24c..75ff220f 100644 --- a/resources/views/components/layouts/admin/menu.blade.php +++ b/resources/views/components/layouts/admin/menu.blade.php @@ -165,6 +165,7 @@ ['trademark-management', 'subject-trademark-rules', '主体商标规则', 'rule'], ['trademark-management', 'store-change-rules', '店铺变更规则', 'rule'], ['trademark-management', 'store-report-data-logic', '店铺维度报表逻辑配置', 'table_chart'], + ['trademark-management', 'tax-forecast-data-logic', '税金预测表逻辑配置', 'calculate'], ]], ['title' => '业务进度', 'items' => [ ['company-management', 'company-progress', '公司进度表', 'timeline'], diff --git a/routes/admin.php b/routes/admin.php index 616cbf46..cb49d6d3 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -353,6 +353,14 @@ Route::get('workspace/trademark-management/store-report-data-logic/edit', 'Busin ->middleware('business.page:trademark-management,store-report-data-logic') ->name('business.store-report-logic.edit'); +Route::get('workspace/trademark-management/tax-forecast-data-logic/edit', 'Business\Pages@editTaxForecastLogic') + ->middleware('business.page:trademark-management,tax-forecast-data-logic') + ->name('business.tax-forecast-logic.edit'); + +Route::post('workspace/trademark-management/tax-forecast-data-logic/edit', 'Business\Pages@updateTaxForecastLogic') + ->middleware('business.page:trademark-management,tax-forecast-data-logic') + ->name('business.tax-forecast-logic.update'); + Route::get('workspace/financial-operations/billing-details/export', 'Business\Pages@exportBillingDetails') ->middleware('business.page:financial-operations,billing-details') ->name('business.financial-operations.billing-details.export'); diff --git a/tests/Feature/Business/ManagementCrudTest.php b/tests/Feature/Business/ManagementCrudTest.php index 7895871b..009edbf1 100644 --- a/tests/Feature/Business/ManagementCrudTest.php +++ b/tests/Feature/Business/ManagementCrudTest.php @@ -455,6 +455,54 @@ class ManagementCrudTest extends FeatureTestCase ->assertSeeText('编辑期初数据'); } + public function testTaxForecastLogicConfigurationCanBeEditedFromThePage(): void + { + $this->loginAs() + ->get(route('business.tax-forecast-logic.edit')) + ->assertOk() + ->assertSeeText('小规模增值税征收率') + ->assertSeeText('小规模季度免税额度') + ->assertSeeText('核定应税所得率默认值') + ->assertSeeText('规则目录(只读)'); + + $this->post(route('business.tax-forecast-logic.update'), [ + 'vat_small_rate' => '1', + 'vat_free_threshold' => '300000', + 'vat_general_enabled' => '1', + 'surtax_city_rate' => '7', + 'surtax_education_rate' => '3', + 'surtax_local_education_rate' => '2', + 'surtax_halved' => '1', + 'stamp_duty_rate' => '0.03', + 'stamp_duty_halved' => '1', + 'cit_effective_rate' => '5', + 'cit_threshold' => '3000000', + 'individual_halved_threshold' => '2000000', + 'assessed_income_rate' => '12', + 'income_forecast_source' => 'cost_arrangement', + ])->assertRedirect(route('business.pages.show', [ + 'section' => 'trademark-management', + 'page' => 'tax-forecast-data-logic', + ])); + + $this->assertSame('12', (string) setting('business_tax_forecast.assessed_income_rate')); + $this->assertSame('cost_arrangement', setting('business_tax_forecast.income_forecast_source')); + + $this->loginAs() + ->get(route('business.pages.show', ['section' => 'trademark-management', 'page' => 'tax-forecast-data-logic'])) + ->assertOk() + ->assertSeeText('当前运行参数') + ->assertSeeText('规则清单') + ->assertSeeText('R12') + ->assertSeeText('小型微利企业所得税') + ->assertSeeText('12%'); + + setting([ + 'business_tax_forecast.assessed_income_rate' => '10', + 'business_tax_forecast.income_forecast_source' => 'last_month_actual', + ])->save(); + } + public function testWorkbookDirectoryReplacesManagementSubmenus(): void { $navigation = BusinessNavigation::all(); @@ -471,7 +519,7 @@ class ManagementCrudTest extends FeatureTestCase $rulesPage = collect($sections['trademark-management']['pages'])->firstWhere('slug', 'rules-information'); $this->assertNotNull($rulesPage); $this->assertSame( - ['subject-trademark-rules', 'store-change-rules', 'store-report-data-logic'], + ['subject-trademark-rules', 'store-change-rules', 'store-report-data-logic', 'tax-forecast-data-logic'], array_column($rulesPage['children'], 'slug') ); $this->assertSame(