user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail(), ); } private function pageUrl(): string { return route('business.financial-ledger.account-basic', [ 'company_id' => $this->company->id, 'view' => 'non_store', ]); } private function importUrl(): string { return route('business.financial-ledger.accounts.alipay.import', [ 'company_id' => $this->company->id, ]); } public function test_alipay_page_exposes_basic_import_and_columns(): void { DB::connection('business_mirror')->table('fin_accounts')->insert([ 'company_name' => '页面展示支付宝公司', 'account_short' => '展示支付宝', 'alipay_merchant_no' => '208800000001', 'alipay_account_kind' => '企业', 'alipay_store_name' => '非店铺', 'account_type' => '支付宝', 'account_no' => 'display@example.com', 'bank_name' => '/', 'account_should_keep' => '否', ]); $response = $this->loginAs()->get($this->pageUrl()) ->assertOk() ->assertSee('导入支付宝基本信息') ->assertSee('data-alipay-import-form', false) ->assertSee('商户号') ->assertSee('账户类型') ->assertSee('店铺') ->assertSee('208800000001') ->assertSee('display@example.com'); $html = $response->getContent(); $this->assertSame( 1, preg_match('/(.*?)<\/table>/s', $html, $table), ); preg_match_all('/data-ledger-header-field="([^"]+)"/', $table[1], $columns); $this->assertSame([ 'company_name', 'account_short', 'legal_representative', 'alipay_account_kind', 'alipay_merchant_no', 'account_no', 'account_status', 'account_should_keep', 'alipay_store_name', 'remark', ], $columns[1]); $this->assertSame( 1, preg_match('/]*>(.*?)<\/tr>/s', $html, $row), ); $this->assertSame(10, substr_count($row[1], 'assertStringNotContainsString('data-ledger-header-field="bank_affiliation"', $table[1]); $this->assertStringNotContainsString('data-ledger-header-field="current_balance"', $table[1]); } public function test_import_updates_existing_adds_new_and_preserves_other_accounts(): void { $connection = DB::connection('business_mirror'); $accounts = [ [ 'company_name' => '支付宝导入甲公司', 'account_short' => '导入甲支付宝', 'account_type' => '支付宝', 'account_no' => 'alpha@example.com', 'bank_name' => '/', 'current_balance' => 100, 'remark' => '原备注保留', 'account_should_keep' => '是', 'company_plan' => '保留', ], [ 'company_name' => '支付宝导入乙公司', 'account_short' => '导入乙支付宝', 'account_type' => '支付宝', 'account_no' => 'old-beta@example.com', 'bank_name' => '/', 'current_balance' => 50, 'account_should_keep' => '是', 'company_plan' => '保留', ], [ 'company_name' => '表格外支付宝公司', 'account_short' => '表格外支付宝', 'account_type' => '支付宝', 'account_no' => 'outside@example.com', 'bank_name' => '/', 'current_balance' => 25, 'account_should_keep' => '是', 'company_plan' => '保留', ], [ 'company_name' => '银行账户公司', 'account_short' => '测试银行账户', 'account_type' => '公户', 'account_no' => '888800001', 'bank_name' => '测试银行', ], ]; foreach ($accounts as $account) { $connection->table('fin_accounts')->insert($account); } $this->loginAs()->post($this->importUrl(), [ 'file' => $this->workbook(), ])->assertRedirect()->assertSessionHas('success'); $this->assertDatabaseHas('fin_accounts', [ 'account_short' => '导入甲支付宝', 'company_name' => '支付宝导入甲公司', 'legal_representative' => '法人甲', 'alipay_merchant_no' => '208800000101', 'alipay_account_kind' => '企业', 'alipay_store_name' => '非店铺', 'account_no' => 'alpha@example.com', 'company_plan' => '待注销', 'account_should_keep' => '否', 'current_balance' => 100, 'remark' => '原备注保留', ], 'business_mirror'); $this->assertDatabaseHas('fin_accounts', [ 'account_short' => '导入乙支付宝', 'company_name' => '支付宝导入乙公司', 'legal_representative' => '法人乙', 'alipay_merchant_no' => '208800000102', 'alipay_account_kind' => '个人', 'alipay_store_name' => '天猫-测试店', 'account_no' => 'beta@example.com', 'company_plan' => '保留', 'account_should_keep' => '是', 'current_balance' => 50, 'remark' => '新备注', ], 'business_mirror'); $this->assertDatabaseHas('fin_accounts', [ 'company_name' => '支付宝新增丙公司', 'account_short' => '新增丙支付宝', 'legal_representative' => '法人丙', 'alipay_merchant_no' => '208800000103', 'alipay_account_kind' => '企业', 'alipay_store_name' => '非店铺', 'account_no' => 'gamma@example.com', 'account_type' => '支付宝', 'bank_name' => '/', 'company_plan' => '待注销', 'account_should_keep' => '否', ], 'business_mirror'); $this->assertDatabaseHas('fin_accounts', [ 'account_short' => '表格外支付宝', 'current_balance' => 25, ], 'business_mirror'); $this->assertDatabaseHas('fin_accounts', [ 'account_short' => '测试银行账户', 'account_type' => '公户', ], 'business_mirror'); $this->assertDatabaseMissing('fin_accounts', [ 'account_no' => 'old-beta@example.com', 'account_short' => '导入乙支付宝', ], 'business_mirror'); $this->assertDatabaseHas('fin_companies', [ 'name' => '支付宝新增丙公司', ], 'business_mirror'); $this->loginAs()->post($this->importUrl(), [ 'file' => $this->workbook(), ])->assertRedirect()->assertSessionHas( 'success', '支付宝基本信息导入完成:共 3 条,新增 0 条,更新 0 条,未变化 3 条,保留表格外现有账户 1 条。', ); $this->assertDatabaseCount('fin_accounts', 5, 'business_mirror'); } public function test_import_rejects_duplicate_accounts_and_requires_editor_role(): void { $this->withExceptionHandling()->loginAs()->post($this->importUrl(), [ 'file' => $this->workbook(true), ])->assertRedirect()->assertSessionHasErrors('file'); $viewer = user_model_class()::create([ 'name' => '支付宝只读用户', 'email' => 'alipay-viewer-' . uniqid() . '@example.com', 'password' => 'local-test-password', 'locale' => 'zh-CN', 'enabled' => 1, 'landing_page' => 'dashboard', 'created_from' => 'core::test', ]); $viewer->companies()->attach($this->company->id); $viewer->roles()->attach(Role::where('name', 'user')->firstOrFail()->id); $viewer->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail()); $this->withExceptionHandling()->loginAs($viewer)->post($this->importUrl(), [ 'file' => $this->workbook(), ])->assertForbidden(); } private function workbook(bool $duplicate = false): UploadedFile { $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $rows = [ ['公司名称', '账户简称', '法人', '账户类型', '商户号', '支付宝账号', '账户状态', '是否保留', '店铺', '备注'], ['支付宝导入甲公司', null, '法人甲', '企业', '208800000101', 'alpha@example.com', null, '不保留', '非店铺', null], ['支付宝导入乙公司', null, '法人乙', '个人', '208800000102', 'beta@example.com', null, '保留', '天猫-测试店', '新备注'], ['支付宝新增丙公司', null, '法人丙', '企业', '208800000103', 'gamma@example.com', null, '不保留', '非店铺', null], ]; if ($duplicate) { $rows[2][5] = 'alpha@example.com'; } $sheet->fromArray($rows, null, 'A1'); $path = tempnam(sys_get_temp_dir(), 'alipay-basic-'); (new Xlsx($spreadsheet))->save($path); $spreadsheet->disconnectWorksheets(); return new UploadedFile( $path, '支付宝基本信息.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', null, true, ); } }