diff --git a/e2e/tests/admin-basicinfo.spec.ts b/e2e/tests/admin-basicinfo.spec.ts index 63b2335cf4b..43fcd545707 100644 --- a/e2e/tests/admin-basicinfo.spec.ts +++ b/e2e/tests/admin-basicinfo.spec.ts @@ -1325,4 +1325,65 @@ test.describe('Admin Basic Info (EA07)', () => { await page.waitForLoadState('load'); await expect(page.locator('#page_admin_setting_shop_calendar .alert-success')).toContainText('保存しました'); }); + + test('basicinfo_納品書PDFの出力項目トグル - EA0701-UC01-T15', async ({ page }) => { + // dev 環境の Symfony デバッグツールバーが送信ボタンを覆うことがあるため非表示にする + // (CI の test 環境ではツールバー自体が存在しないため no-op)。 + const hideDebugToolbar = () => page.addStyleTag({ + content: '.sf-toolbar, .sf-minitoolbar { display: none !important; }', + }).catch(() => { /* ツールバーが無い環境では無視 */ }); + + await page.goto(`/${adminRoute}/setting/shop`); + await page.waitForLoadState('load'); + await ensureAdminLoggedIn(page); + if (!page.url().includes('/setting/shop')) { + await page.goto(`/${adminRoute}/setting/shop`); + await page.waitForLoadState('load'); + } + await hideDebugToolbar(); + + // 納品書PDFの出力項目セクションが表示されていること + const hourCheckbox = page.locator('#shop_master_order_pdf_visible_business_hour'); + const invoiceCheckbox = page.locator('#shop_master_order_pdf_visible_invoice_number'); + await expect(hourCheckbox).toBeAttached(); + await expect(invoiceCheckbox).toBeAttached(); + + // 初期状態を退避(アサーション失敗時も finally で必ず復元する) + const hourInitial = await hourCheckbox.isChecked(); + const invoiceInitial = await invoiceCheckbox.isChecked(); + + try { + // 既定 OFF の「店舗営業時間」と既定 ON の「インボイス登録番号」を反転して保存 + await page.locator('label[for="shop_master_order_pdf_visible_business_hour"]').click(); + await page.locator('label[for="shop_master_order_pdf_visible_invoice_number"]').click(); + await page.waitForTimeout(500); + await page.locator('button.ladda-button[type="submit"]').click(); + await page.waitForLoadState('load'); + await expect(page.locator('.alert-success')).toContainText('保存しました', { timeout: 30_000 }); + + // 再表示して反転後の状態が保持されていること + await page.goto(`/${adminRoute}/setting/shop`); + await page.waitForLoadState('load'); + await hideDebugToolbar(); + await expect(page.locator('#shop_master_order_pdf_visible_business_hour')).toBeChecked({ checked: !hourInitial }); + await expect(page.locator('#shop_master_order_pdf_visible_invoice_number')).toBeChecked({ checked: !invoiceInitial }); + } finally { + // 初期状態へ復元して保存(アサーションが失敗しても設定を元に戻す) + await page.goto(`/${adminRoute}/setting/shop`); + await page.waitForLoadState('load'); + await hideDebugToolbar(); + const hourNow = await page.locator('#shop_master_order_pdf_visible_business_hour').isChecked(); + if (hourNow !== hourInitial) { + await page.locator('label[for="shop_master_order_pdf_visible_business_hour"]').click(); + } + const invoiceNow = await page.locator('#shop_master_order_pdf_visible_invoice_number').isChecked(); + if (invoiceNow !== invoiceInitial) { + await page.locator('label[for="shop_master_order_pdf_visible_invoice_number"]').click(); + } + await page.waitForTimeout(500); + await page.locator('button.ladda-button[type="submit"]').click(); + await page.waitForLoadState('load'); + await expect(page.locator('.alert-success')).toContainText('保存しました', { timeout: 30_000 }); + } + }); }); diff --git a/src/Eccube/Entity/BaseInfo.php b/src/Eccube/Entity/BaseInfo.php index 064dc6d5b1c..f69552751c7 100644 --- a/src/Eccube/Entity/BaseInfo.php +++ b/src/Eccube/Entity/BaseInfo.php @@ -170,6 +170,42 @@ class BaseInfo extends AbstractEntity #[ORM\Column(name: 'ucp_catalog_requires_auth', type: Types::BOOLEAN, options: ['default' => false])] private bool $ucp_catalog_requires_auth = false; + // 納品書PDFの店舗情報の出力項目トグル(#6197)。 + // 既定は「現状出力している項目+インボイス要件の会社名」を ON、新規項目は OFF とし、 + // アップグレード時も既存の納品書の見た目を極力維持する。 + #[ORM\Column(name: 'order_pdf_visible_shop_name', type: Types::BOOLEAN, options: ['default' => true])] + private bool $order_pdf_visible_shop_name = true; + + #[ORM\Column(name: 'order_pdf_visible_shop_kana', type: Types::BOOLEAN, options: ['default' => false])] + private bool $order_pdf_visible_shop_kana = false; + + #[ORM\Column(name: 'order_pdf_visible_shop_name_eng', type: Types::BOOLEAN, options: ['default' => false])] + private bool $order_pdf_visible_shop_name_eng = false; + + #[ORM\Column(name: 'order_pdf_visible_address', type: Types::BOOLEAN, options: ['default' => true])] + private bool $order_pdf_visible_address = true; + + #[ORM\Column(name: 'order_pdf_visible_company_name', type: Types::BOOLEAN, options: ['default' => true])] + private bool $order_pdf_visible_company_name = true; + + #[ORM\Column(name: 'order_pdf_visible_company_kana', type: Types::BOOLEAN, options: ['default' => false])] + private bool $order_pdf_visible_company_kana = false; + + #[ORM\Column(name: 'order_pdf_visible_phone_number', type: Types::BOOLEAN, options: ['default' => true])] + private bool $order_pdf_visible_phone_number = true; + + #[ORM\Column(name: 'order_pdf_visible_business_hour', type: Types::BOOLEAN, options: ['default' => false])] + private bool $order_pdf_visible_business_hour = false; + + #[ORM\Column(name: 'order_pdf_visible_email', type: Types::BOOLEAN, options: ['default' => true])] + private bool $order_pdf_visible_email = true; + + #[ORM\Column(name: 'order_pdf_visible_invoice_number', type: Types::BOOLEAN, options: ['default' => true])] + private bool $order_pdf_visible_invoice_number = true; + + #[ORM\Column(name: 'order_pdf_visible_message', type: Types::BOOLEAN, options: ['default' => false])] + private bool $order_pdf_visible_message = false; + /** * Get id. * @@ -937,4 +973,202 @@ public function isUcpCatalogRequiresAuth(): bool { return $this->ucp_catalog_requires_auth; } + + /** + * Set orderPdfVisibleShopName. + */ + public function setOrderPdfVisibleShopName(bool $orderPdfVisibleShopName): BaseInfo + { + $this->order_pdf_visible_shop_name = $orderPdfVisibleShopName; + + return $this; + } + + /** + * Get orderPdfVisibleShopName. + */ + public function isOrderPdfVisibleShopName(): bool + { + return $this->order_pdf_visible_shop_name; + } + + /** + * Set orderPdfVisibleShopKana. + */ + public function setOrderPdfVisibleShopKana(bool $orderPdfVisibleShopKana): BaseInfo + { + $this->order_pdf_visible_shop_kana = $orderPdfVisibleShopKana; + + return $this; + } + + /** + * Get orderPdfVisibleShopKana. + */ + public function isOrderPdfVisibleShopKana(): bool + { + return $this->order_pdf_visible_shop_kana; + } + + /** + * Set orderPdfVisibleShopNameEng. + */ + public function setOrderPdfVisibleShopNameEng(bool $orderPdfVisibleShopNameEng): BaseInfo + { + $this->order_pdf_visible_shop_name_eng = $orderPdfVisibleShopNameEng; + + return $this; + } + + /** + * Get orderPdfVisibleShopNameEng. + */ + public function isOrderPdfVisibleShopNameEng(): bool + { + return $this->order_pdf_visible_shop_name_eng; + } + + /** + * Set orderPdfVisibleAddress. + */ + public function setOrderPdfVisibleAddress(bool $orderPdfVisibleAddress): BaseInfo + { + $this->order_pdf_visible_address = $orderPdfVisibleAddress; + + return $this; + } + + /** + * Get orderPdfVisibleAddress. + */ + public function isOrderPdfVisibleAddress(): bool + { + return $this->order_pdf_visible_address; + } + + /** + * Set orderPdfVisibleCompanyName. + */ + public function setOrderPdfVisibleCompanyName(bool $orderPdfVisibleCompanyName): BaseInfo + { + $this->order_pdf_visible_company_name = $orderPdfVisibleCompanyName; + + return $this; + } + + /** + * Get orderPdfVisibleCompanyName. + */ + public function isOrderPdfVisibleCompanyName(): bool + { + return $this->order_pdf_visible_company_name; + } + + /** + * Set orderPdfVisibleCompanyKana. + */ + public function setOrderPdfVisibleCompanyKana(bool $orderPdfVisibleCompanyKana): BaseInfo + { + $this->order_pdf_visible_company_kana = $orderPdfVisibleCompanyKana; + + return $this; + } + + /** + * Get orderPdfVisibleCompanyKana. + */ + public function isOrderPdfVisibleCompanyKana(): bool + { + return $this->order_pdf_visible_company_kana; + } + + /** + * Set orderPdfVisiblePhoneNumber. + */ + public function setOrderPdfVisiblePhoneNumber(bool $orderPdfVisiblePhoneNumber): BaseInfo + { + $this->order_pdf_visible_phone_number = $orderPdfVisiblePhoneNumber; + + return $this; + } + + /** + * Get orderPdfVisiblePhoneNumber. + */ + public function isOrderPdfVisiblePhoneNumber(): bool + { + return $this->order_pdf_visible_phone_number; + } + + /** + * Set orderPdfVisibleBusinessHour. + */ + public function setOrderPdfVisibleBusinessHour(bool $orderPdfVisibleBusinessHour): BaseInfo + { + $this->order_pdf_visible_business_hour = $orderPdfVisibleBusinessHour; + + return $this; + } + + /** + * Get orderPdfVisibleBusinessHour. + */ + public function isOrderPdfVisibleBusinessHour(): bool + { + return $this->order_pdf_visible_business_hour; + } + + /** + * Set orderPdfVisibleEmail. + */ + public function setOrderPdfVisibleEmail(bool $orderPdfVisibleEmail): BaseInfo + { + $this->order_pdf_visible_email = $orderPdfVisibleEmail; + + return $this; + } + + /** + * Get orderPdfVisibleEmail. + */ + public function isOrderPdfVisibleEmail(): bool + { + return $this->order_pdf_visible_email; + } + + /** + * Set orderPdfVisibleInvoiceNumber. + */ + public function setOrderPdfVisibleInvoiceNumber(bool $orderPdfVisibleInvoiceNumber): BaseInfo + { + $this->order_pdf_visible_invoice_number = $orderPdfVisibleInvoiceNumber; + + return $this; + } + + /** + * Get orderPdfVisibleInvoiceNumber. + */ + public function isOrderPdfVisibleInvoiceNumber(): bool + { + return $this->order_pdf_visible_invoice_number; + } + + /** + * Set orderPdfVisibleMessage. + */ + public function setOrderPdfVisibleMessage(bool $orderPdfVisibleMessage): BaseInfo + { + $this->order_pdf_visible_message = $orderPdfVisibleMessage; + + return $this; + } + + /** + * Get orderPdfVisibleMessage. + */ + public function isOrderPdfVisibleMessage(): bool + { + return $this->order_pdf_visible_message; + } } diff --git a/src/Eccube/Form/Type/Admin/ShopMasterType.php b/src/Eccube/Form/Type/Admin/ShopMasterType.php index eb5fa362bb7..b4d840981a9 100644 --- a/src/Eccube/Form/Type/Admin/ShopMasterType.php +++ b/src/Eccube/Form/Type/Admin/ShopMasterType.php @@ -225,6 +225,18 @@ public function buildForm(FormBuilderInterface $builder, array $options): void // エージェントコマース checkout の有効化フラグ (discovery / catalog は常時公開、checkout のみ制御) ->add('acp_checkout_enabled', ToggleSwitchType::class) ->add('ucp_checkout_enabled', ToggleSwitchType::class) + // 納品書PDFの店舗情報出力項目トグル(#6197)。並び順は納品書の描画順にそろえる + ->add('order_pdf_visible_shop_name', ToggleSwitchType::class) + ->add('order_pdf_visible_shop_kana', ToggleSwitchType::class) + ->add('order_pdf_visible_shop_name_eng', ToggleSwitchType::class) + ->add('order_pdf_visible_address', ToggleSwitchType::class) + ->add('order_pdf_visible_company_name', ToggleSwitchType::class) + ->add('order_pdf_visible_company_kana', ToggleSwitchType::class) + ->add('order_pdf_visible_phone_number', ToggleSwitchType::class) + ->add('order_pdf_visible_business_hour', ToggleSwitchType::class) + ->add('order_pdf_visible_email', ToggleSwitchType::class) + ->add('order_pdf_visible_invoice_number', ToggleSwitchType::class) + ->add('order_pdf_visible_message', ToggleSwitchType::class) ; $builder->add( diff --git a/src/Eccube/Resource/locale/messages.en.yaml b/src/Eccube/Resource/locale/messages.en.yaml index a3f34448b1b..e50abc1fb2c 100644 --- a/src/Eccube/Resource/locale/messages.en.yaml +++ b/src/Eccube/Resource/locale/messages.en.yaml @@ -1231,6 +1231,19 @@ admin.setting.shop.shop.agent_commerce: "Agent Commerce" admin.setting.shop.shop.agent_commerce.description: "Enable checkout via AI agents (ChatGPT / Gemini, etc.). Discovery and catalog are always public; only checkout is controlled here. Checkout is not yet available in Japan, so normally leave these disabled." admin.setting.shop.shop.agent_commerce.acp_checkout_enabled: "Enable ACP checkout" admin.setting.shop.shop.agent_commerce.ucp_checkout_enabled: "Enable UCP checkout" +admin.setting.shop.shop.order_pdf: "Delivery slip PDF items" +admin.setting.shop.shop.order_pdf.description: "Choose the items to print in the shop information area of the delivery slip PDF. Only the items turned ON are printed, using the values entered in the basic settings (items with an empty value are not printed)." +admin.setting.shop.shop.order_pdf.shop_name: "Shop name" +admin.setting.shop.shop.order_pdf.shop_kana: "Shop name (kana)" +admin.setting.shop.shop.order_pdf.shop_name_eng: "Shop name (English)" +admin.setting.shop.shop.order_pdf.address: "Postal code / address" +admin.setting.shop.shop.order_pdf.company_name: "Company name" +admin.setting.shop.shop.order_pdf.company_kana: "Company name (kana)" +admin.setting.shop.shop.order_pdf.phone_number: "Phone number" +admin.setting.shop.shop.order_pdf.business_hour: "Business hours" +admin.setting.shop.shop.order_pdf.email: "Email address" +admin.setting.shop.shop.order_pdf.invoice_number: "Invoice registration number" +admin.setting.shop.shop.order_pdf.message: "Message from shop" #------------------------------------------------------------------------------------ # Settings:Store Settings:Trade Law Settings diff --git a/src/Eccube/Resource/locale/messages.ja.yaml b/src/Eccube/Resource/locale/messages.ja.yaml index 9e16c989b3c..f34ecf99721 100644 --- a/src/Eccube/Resource/locale/messages.ja.yaml +++ b/src/Eccube/Resource/locale/messages.ja.yaml @@ -1230,6 +1230,19 @@ admin.setting.shop.shop.agent_commerce: "エージェントコマース" admin.setting.shop.shop.agent_commerce.description: "AIエージェント (ChatGPT / Gemini 等) 経由のチェックアウトを有効化します。Discovery / カタログは常時公開され、ここでは checkout のみを制御します。checkout は日本未提供のため、通常は無効のままにしてください。" admin.setting.shop.shop.agent_commerce.acp_checkout_enabled: "ACP チェックアウトを有効にする" admin.setting.shop.shop.agent_commerce.ucp_checkout_enabled: "UCP チェックアウトを有効にする" +admin.setting.shop.shop.order_pdf: "納品書PDFの出力項目" +admin.setting.shop.shop.order_pdf.description: "納品書PDFの店舗情報欄に出力する項目を選びます。基本設定で入力済みの値のうち、ONにした項目だけが出力されます(値が空の項目は出力されません)。" +admin.setting.shop.shop.order_pdf.shop_name: "店名" +admin.setting.shop.shop.order_pdf.shop_kana: "店名(カナ)" +admin.setting.shop.shop.order_pdf.shop_name_eng: "店名(英語表記)" +admin.setting.shop.shop.order_pdf.address: "郵便番号・住所" +admin.setting.shop.shop.order_pdf.company_name: "会社名" +admin.setting.shop.shop.order_pdf.company_kana: "会社名(カナ)" +admin.setting.shop.shop.order_pdf.phone_number: "電話番号" +admin.setting.shop.shop.order_pdf.business_hour: "店舗営業時間" +admin.setting.shop.shop.order_pdf.email: "メールアドレス" +admin.setting.shop.shop.order_pdf.invoice_number: "インボイス登録番号" +admin.setting.shop.shop.order_pdf.message: "店舗からのメッセージ" #------------------------------------------------------------------------------------ # 設定:店舗設定:特定商取引法設定 diff --git a/src/Eccube/Resource/template/admin/Setting/Shop/shop_master.twig b/src/Eccube/Resource/template/admin/Setting/Shop/shop_master.twig index 0e37636b8d0..54103beb43a 100644 --- a/src/Eccube/Resource/template/admin/Setting/Shop/shop_master.twig +++ b/src/Eccube/Resource/template/admin/Setting/Shop/shop_master.twig @@ -425,6 +425,22 @@ file that was distributed with this source code. +
{{ 'admin.setting.shop.shop.order_pdf.description'|trans }}
+ {% for field in ['shop_name', 'shop_kana', 'shop_name_eng', 'address', 'company_name', 'company_kana', 'phone_number', 'business_hour', 'email', 'invoice_number', 'message'] %} + {% set widget = attribute(form, 'order_pdf_visible_' ~ field) %} +