1, 'version' => 1, 'company_id' => 0, 'alias_name' => 'import_test_' . uniqid(), 'name' => 'Test Menu', 'url' => '/test', 'sort' => 1, 'pid' => 0, 'apis' => '', 'icon' => '', 'is_show' => true, 'is_menu' => true, 'disabled' => false, 'menu_type' => ['all'], ]; return array_merge($defaults, $overrides); } /** * 导入后按 version+company_id 取第一条菜单的 shopmenu_id(用于单条断言) */ private function getFirstInsertedShopmenuId(ShopMenuService $service, int $version, int $companyId): ?int { $res = $service->shopMenuRepository->lists( ['version' => $version, 'company_id' => $companyId], 'shopmenu_id', 1, 1, ['shopmenu_id' => 'ASC'] ); $list = $res['list'] ?? []; return isset($list[0]['shopmenu_id']) ? (int) $list[0]['shopmenu_id'] : null; } /** * 按 alias_name 查找导入后的 shopmenu_id */ private function getShopmenuIdByAlias(ShopMenuService $service, int $version, int $companyId, string $aliasName): ?int { $res = $service->shopMenuRepository->getInfo([ 'version' => $version, 'company_id' => $companyId, 'alias_name' => $aliasName, ]); return isset($res['shopmenu_id']) ? (int) $res['shopmenu_id'] : null; } /** * TC-I1:新格式文件,含 3 语种 name_lang。 * #given 新格式 list 含 name 与 name_lang(zh-CN, en-CN, ar-SA) * #when 调用 uploadMenus 导入 * #then 主表 name 正确;3 个多语言表均有对应 data_id 的 attribute_value(当前 RED:未实现 saveLang) */ public function testImportNewFormatWithThreeLanguagesWritesMainTableAndMultilangTcI1(): void { $companyId = 0; $version = 91; // SMALLINT 范围内,避免与业务 version 1-7 冲突 $row = $this->buildUploadMenuRow([ 'version' => $version, 'company_id'=> $companyId, 'name' => '首页', 'name_lang' => [ 'zh-CN' => '首页', 'en-CN' => 'Home', 'ar-SA' => 'الرئيسية', ], ]); $service = new ShopMenuService(); $service->uploadMenus([$row], $companyId); $sid = $this->getFirstInsertedShopmenuId($service, $version, $companyId); $this->assertNotNull($sid, '导入后应能查到菜单 (TC-I1)'); $mainMenu = $service->shopMenuRepository->getInfo(['shopmenu_id' => $sid]); $this->assertSame('首页', $mainMenu['name'] ?? null, '主表 name 应为 list[].name (TC-I1)'); $commonLang = new CommonLangModService(); foreach (self::CONFIG_LANGS as $lang) { $value = $commonLang->getFieldByLangue($companyId, $lang, 'name', $sid, 'shop_menu', 'shop_menu'); $this->assertSame($row['name_lang'][$lang], $value, "多语言表 {$lang} 应有对应 data_id 的 attribute_value (TC-I1)"); } } /** * TC-I2:旧格式文件(无 name_lang)。 * #given 旧格式 list 仅有 name,无 name_lang * #when 调用 uploadMenus 导入 * #then 导入成功,主表 name 正确,多语言表不写入该批(当前可实现:未写多语言即满足) */ public function testImportOldFormatWithoutNameLangWritesOnlyMainTableTcI2(): void { $companyId = 0; $version = 92; // SMALLINT 范围内 $row = $this->buildUploadMenuRow([ 'version' => $version, 'company_id'=> $companyId, 'name' => '旧格式菜单', ]); unset($row['name_lang']); $service = new ShopMenuService(); $service->uploadMenus([$row], $companyId); $sid = $this->getFirstInsertedShopmenuId($service, $version, $companyId); $this->assertNotNull($sid, '导入后应能查到菜单 (TC-I2)'); $mainMenu = $service->shopMenuRepository->getInfo(['shopmenu_id' => $sid]); $this->assertSame('旧格式菜单', $mainMenu['name'] ?? null, '主表 name 应与文件中 name 一致 (TC-I2)'); $commonLang = new CommonLangModService(); foreach (self::CONFIG_LANGS as $lang) { $value = $commonLang->getFieldByLangue($companyId, $lang, 'name', $sid, 'shop_menu', 'shop_menu'); $this->assertSame('', $value, '旧格式导入时多语言表不写入该批 (TC-I2)'); } } /** * TC-I3:先导入新格式,再导入同 version+company 的另一新格式。 * #given 第一次导入含 name_lang,第二次导入同 version+company 不同 name_lang * #when 第二次导入完成 * #then 无第一次的多语言残留,以第二次文件为准(当前 RED:未先 deleteLang 再写) */ public function testImportSameVersionCompanyTwiceHasNoResidualMultilangTcI3(): void { $companyId = 0; $version = 93; // SMALLINT 范围内 $alias = 'import_tc3_' . uniqid(); $firstRow = $this->buildUploadMenuRow([ 'version' => $version, 'company_id' => $companyId, 'alias_name' => $alias, 'name' => '第一版', 'name_lang' => ['zh-CN' => '第一版', 'en-CN' => 'First', 'ar-SA' => ''], ]); $secondRow = $this->buildUploadMenuRow([ 'version' => $version, 'company_id' => $companyId, 'alias_name' => $alias, 'name' => '第二版', 'name_lang' => ['zh-CN' => '第二版', 'en-CN' => 'Second', 'ar-SA' => ''], ]); $service = new ShopMenuService(); $service->uploadMenus([$firstRow], $companyId); $sid = $this->getShopmenuIdByAlias($service, $version, $companyId, $alias); $this->assertNotNull($sid); $service->uploadMenus([$secondRow], $companyId); $sid2 = $this->getShopmenuIdByAlias($service, $version, $companyId, $alias); $this->assertNotNull($sid2, '第二次导入后应有一条菜单 (TC-I3)'); $mainMenu = $service->shopMenuRepository->getInfo(['shopmenu_id' => $sid2]); $this->assertSame('第二版', $mainMenu['name'] ?? null, '主表以第二次为准 (TC-I3)'); $commonLang = new CommonLangModService(); $zhValue = $commonLang->getFieldByLangue($companyId, 'zh-CN', 'name', $sid2, 'shop_menu', 'shop_menu'); $this->assertSame('第二版', $zhValue, '第二次导入后无第一次多语言残留,zh-CN 应以第二次文件为准 (TC-I3)'); } /** * TC-I4:新格式但某条 name_lang 仅含 zh-CN。 * #given list 一项 name_lang 仅含 zh-CN * #when 调用 uploadMenus 导入 * #then 主表 name 取自 list[].name;仅 zh-CN 多语言表有该条;en-CN/ar-SA 无该 data_id(当前 RED:未实现 saveLang) */ public function testImportNewFormatWithOnlyZhCnInNameLangWritesOnlyZhCnTcI4(): void { $companyId = 0; $version = 94; // SMALLINT 范围内 $row = $this->buildUploadMenuRow([ 'version' => $version, 'company_id'=> $companyId, 'name' => '概况', 'name_lang' => ['zh-CN' => '概况'], ]); $service = new ShopMenuService(); $service->uploadMenus([$row], $companyId); $sid = $this->getFirstInsertedShopmenuId($service, $version, $companyId); $this->assertNotNull($sid, '导入后应能查到菜单 (TC-I4)'); $mainMenu = $service->shopMenuRepository->getInfo(['shopmenu_id' => $sid]); $this->assertSame('概况', $mainMenu['name'] ?? null, '主表 name 取自 list[].name (TC-I4)'); $commonLang = new CommonLangModService(); $zh = $commonLang->getFieldByLangue($companyId, 'zh-CN', 'name', $sid, 'shop_menu', 'shop_menu'); $this->assertSame('概况', $zh, '仅 zh-CN 多语言表应有该条 (TC-I4)'); $en = $commonLang->getFieldByLangue($companyId, 'en-CN', 'name', $sid, 'shop_menu', 'shop_menu'); $this->assertSame('', $en, 'en-CN 无该 data_id (TC-I4)'); $ar = $commonLang->getFieldByLangue($companyId, 'ar-SA', 'name', $sid, 'shop_menu', 'shop_menu'); $this->assertSame('', $ar, 'ar-SA 无该 data_id (TC-I4)'); } /** * TC-I5:新格式但 name_lang 为空对象 {}。 * #given list 一项 name_lang 为 {} * #when 调用 uploadMenus 导入 * #then 主表 name 用 list[].name;多语言表不写入该条(当前可实现:未写即满足) */ public function testImportNewFormatWithEmptyNameLangObjectWritesOnlyMainTableTcI5(): void { $companyId = 0; $version = 95; // SMALLINT 范围内 $row = $this->buildUploadMenuRow([ 'version' => $version, 'company_id'=> $companyId, 'name' => '仅主表名称', 'name_lang' => [], ]); $service = new ShopMenuService(); $service->uploadMenus([$row], $companyId); $sid = $this->getFirstInsertedShopmenuId($service, $version, $companyId); $this->assertNotNull($sid, '导入后应能查到菜单 (TC-I5)'); $mainMenu = $service->shopMenuRepository->getInfo(['shopmenu_id' => $sid]); $this->assertSame('仅主表名称', $mainMenu['name'] ?? null, '主表 name 用 list[].name (TC-I5)'); $commonLang = new CommonLangModService(); foreach (self::CONFIG_LANGS as $lang) { $value = $commonLang->getFieldByLangue($companyId, $lang, 'name', $sid, 'shop_menu', 'shop_menu'); $this->assertSame('', $value, 'name_lang 为空对象时多语言表不写入该条 (TC-I5)'); } } /** * TC-I6:单条菜单、name_lang 含部分语种。 * #given 单条 list,name_lang 仅含 zh-CN 与 en-CN * #when 调用 uploadMenus 导入 * #then 仅存在的语种写入多语言表(当前 RED:未实现 saveLang) */ public function testImportSingleMenuWithPartialNameLangWritesOnlyPresentLangsTcI6(): void { $companyId = 0; $version = 96; // SMALLINT 范围内 $row = $this->buildUploadMenuRow([ 'version' => $version, 'company_id'=> $companyId, 'name' => '边界单条', 'name_lang' => ['zh-CN' => '边界单条', 'en-CN' => 'Single Partial'], ]); $service = new ShopMenuService(); $service->uploadMenus([$row], $companyId); $sid = $this->getFirstInsertedShopmenuId($service, $version, $companyId); $this->assertNotNull($sid, '导入后应能查到菜单 (TC-I6)'); $mainMenu = $service->shopMenuRepository->getInfo(['shopmenu_id' => $sid]); $this->assertSame('边界单条', $mainMenu['name'] ?? null, '主表 name 用 list[].name (TC-I6)'); $commonLang = new CommonLangModService(); $this->assertSame('边界单条', $commonLang->getFieldByLangue($companyId, 'zh-CN', 'name', $sid, 'shop_menu', 'shop_menu'), 'zh-CN 应写入 (TC-I6)'); $this->assertSame('Single Partial', $commonLang->getFieldByLangue($companyId, 'en-CN', 'name', $sid, 'shop_menu', 'shop_menu'), 'en-CN 应写入 (TC-I6)'); $this->assertSame('', $commonLang->getFieldByLangue($companyId, 'ar-SA', 'name', $sid, 'shop_menu', 'shop_menu'), 'ar-SA 未提供则不写入 (TC-I6)'); } }