CaiWuXiTong/tests/Feature/Business/SupplierBookkeepingConfigTest.php
limeng 09b4ffcb8a 供应商应付-厂家记账:新增厂家记账配置并按配置判定厂家扣款
- 新增配置表 business_supplier_bookkeeping_configs(+ 操作日志表),迁移时导入财务提供的 209 家存量配置
- 记账方式:正常记账 / 仅代发仓发错货记账 / 不记账,支持生效期;配置页支持新增、编辑、删除恢复、Excel 导入导出
- 扣款判定:厂家记账按供应商配置,仅正常记账扣款;仓库记账仅订单发货仓库为代发仓且二级原因含“仓库发错货”时作为厂家扣款项,其余不扣
- 未配置/生效期外显示待配置,多供应商判定不一致显示待确认,均不计入扣款金额
- 明细页新增厂家扣款判定筛选、扣款工单数与扣款金额指标、导出列

涉及:数据库迁移(新建配置表并写入存量配置)、金额汇总展示;不涉及上游写入和权限模型。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JouFR6TJ7vGscRJanYScEo
2026-10-19 10:38:36 +08:00

121 lines
6.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Tests\Feature\Business;
use App\Models\Auth\Permission;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Modules\EcommerceFinance\Repositories\SupplierBookkeepingWorkOrderRepository;
use Modules\EcommerceFinance\Services\SupplierBookkeepingConfigStore as Store;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Tests\Feature\FeatureTestCase;
class SupplierBookkeepingConfigTest extends FeatureTestCase
{
protected function setUp(): void
{
parent::setUp();
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$repository = \Mockery::mock(SupplierBookkeepingWorkOrderRepository::class);
$repository->shouldReceive('syncStatus')->andReturn(['code' => 'ready', 'last_succeeded_at' => null]);
$repository->shouldReceive('rows')->andReturn([]);
$this->app->instance(SupplierBookkeepingWorkOrderRepository::class, $repository);
}
private function url(string $name, array $params = []): string
{
return route($name, ['company_id' => $this->company->id] + $params);
}
private function configPage(array $query = []): string
{
return route('business.pages.show', ['company_id' => $this->company->id, 'section' => 'supplier-payables', 'page' => 'manufacturer-bookkeeping', 'bk_view' => 'config'] + $query);
}
private function xlsx(array $rows): UploadedFile
{
$book = new Spreadsheet();
$book->getActiveSheet()->fromArray($rows);
$path = tempnam(sys_get_temp_dir(), 'sbc') . '.xlsx';
(new Xlsx($book))->save($path);
return new UploadedFile($path, '厂家记账配置.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', null, true);
}
public function test_migration_imports_existing_finance_configs(): void
{
$this->assertSame(209, DB::table(Store::TABLE)->count());
$this->assertSame(4, DB::table(Store::TABLE)->where('mode', 'normal')->count());
$this->assertSame(48, DB::table(Store::TABLE)->where('mode', 'dropship_wrong')->count());
$row = DB::table(Store::TABLE)->where('supplier_name', '景瓴十方')->first();
$this->assertSame(['none', '2025-03-01', '2026-02-28'], [$row->mode, $row->effective_from, $row->effective_to]);
$this->loginAs()->get($this->configPage(['supplier_name' => '曹县洪耀']))
->assertOk()
->assertSee('厂家记账配置')
->assertSee('曹县洪耀')
->assertSee('代发仓发货错需记账,其他原因均不记账')
->assertSee('导入存量厂家记账配置:新增209条');
}
public function test_create_update_delete_restore_with_audit_log(): void
{
$this->loginAs()->post($this->url('business.supplier-bookkeeping-configs.store'), ['supplier_name' => ' 新厂家 ', 'mode' => 'normal'])
->assertRedirect();
$id = DB::table(Store::TABLE)->where('supplier_name', '新厂家')->value('id');
$this->assertNotNull($id);
$this->withExceptionHandling()->loginAs()->post($this->url('business.supplier-bookkeeping-configs.store'), ['supplier_name' => '新厂家', 'mode' => 'none'])
->assertSessionHasErrors('supplier_name');
$this->loginAs()->patch($this->url('business.supplier-bookkeeping-configs.update', ['configId' => $id]), [
'supplier_name' => '新厂家', 'mode' => 'none', 'effective_from' => '2026-01-01', 'effective_to' => '2026-12-31',
])->assertRedirect();
$this->assertSame('none', DB::table(Store::TABLE)->where('id', $id)->value('mode'));
$this->withExceptionHandling()->loginAs()->patch($this->url('business.supplier-bookkeeping-configs.update', ['configId' => $id]), [
'supplier_name' => '新厂家', 'mode' => 'none', 'effective_from' => '2026-12-31', 'effective_to' => '2026-01-01',
])->assertSessionHasErrors('effective_to');
$this->loginAs()->delete($this->url('business.supplier-bookkeeping-configs.destroy', ['configId' => $id]))->assertRedirect();
$this->assertNotNull(DB::table(Store::TABLE)->where('id', $id)->value('deleted_at'));
$this->loginAs()->post($this->url('business.supplier-bookkeeping-configs.restore', ['configId' => $id]))->assertRedirect();
$this->assertNull(DB::table(Store::TABLE)->where('id', $id)->value('deleted_at'));
$this->assertSame(['import', 'create', 'update', 'delete', 'restore'], DB::table(Store::EVENTS)->orderBy('id')->pluck('action')->all());
}
public function test_import_finance_sheet_adds_updates_and_skips(): void
{
$file = $this->xlsx([
['供应商', '厂家是否记账'],
['鑫呈', '正常记账'],
['尊享', '代发仓发货错需记账,其他原因均不记账'],
['供应商', '厂家是否记账'],
['全新厂', '不记账(2025.3月-2027.12.30)'],
]);
$this->loginAs()->post($this->url('business.supplier-bookkeeping-configs.import'), ['file' => $file])
->assertRedirect()
->assertSessionHas('bookkeeping_config_message', '导入完成:新增1条,更新1条,未变化1条。');
$this->assertSame('dropship_wrong', DB::table(Store::TABLE)->where('supplier_name', '尊享')->value('mode'));
$this->assertSame('2027-12-30', DB::table(Store::TABLE)->where('supplier_name', '全新厂')->value('effective_to'));
$before = DB::table(Store::TABLE)->count();
$bad = $this->xlsx([['供应商', '厂家是否记账'], ['再一个厂', '正常记账'], ['坏行厂', '看情况']]);
$this->withExceptionHandling()->loginAs()->post($this->url('business.supplier-bookkeeping-configs.import'), ['file' => $bad])
->assertSessionHasErrors('file');
$this->assertSame($before, DB::table(Store::TABLE)->count());
}
public function test_export_round_trips_through_import(): void
{
$response = $this->loginAs()->get($this->url('business.supplier-bookkeeping-configs.export', ['supplier_name' => '景瓴十方']));
$response->assertOk();
$path = tempnam(sys_get_temp_dir(), 'sbe') . '.xlsx';
file_put_contents($path, $response->streamedContent());
$rows = app(\Modules\EcommerceFinance\Services\SupplierBookkeepingConfigImporter::class)->read($path);
$this->assertSame([['supplier_name' => '景瓴十方', 'mode' => 'none', 'effective_from' => '2025-03-01', 'effective_to' => '2026-02-28', 'source_text' => '不记账(2025.3月-2026.2月)']], $rows);
}
}