# Asteria(Magento 1)→ Bagisto 数据迁移说明 从旧站 Asteria(Magento 1.x)只读导入商品、用户、评论、订单到本店。源库以 **`as`** 为准(不要用 `longyishop`)。命令共用 Laravel 连接名 `asteria`,可分批、可断点续跑、可 `--dry-run`,重复执行不会重复插入。 **推荐顺序:** 需要清空现有数据时先 reset,再迁商品,再迁用户,再迁订单 / 评论。 ```bash php artisan migrate php artisan catalog:reset --dry-run # 先看会清哪些表 php artisan catalog:reset --force # 清空现有商品,便于重新导入 php artisan products:migrate-asteria # Magento 商品 → flexible_variant,SKU 与旧站一致 php artisan customers:reset --dry-run php artisan customers:reset --force # 清空现有用户,便于重新导入 php artisan customers:migrate-asteria php artisan orders:migrate-asteria php artisan reviews:migrate-asteria --sync # 或走队列,见下文 ``` `catalog:reset` 会 TRUNCATE 商品及变体 / 库存 / 评论 / 购物车行 / 收藏,并把历史订单行的 `product_id` 置空(SKU 快照保留)。属性、分类、用户、订单头不删。也可跑 `database/scripts/reset_catalog.sql`。图片目录加 `--purge-files`。 `customers:reset` 会 TRUNCATE 前台用户及地址 / 订阅 / 收藏 / 积分成长值,并把历史订单、评论的 `customer_id` 置空(邮箱快照保留)。客户分组、后台管理员、商品、订单头不删。也可跑 `database/scripts/reset_customers.sql`。 --- ## 1. 前置:Asteria 数据库连接 `.env` 中配置只读 Magento 库(应用层只跑 SELECT): ```env ASTERIA_DB_HOST=127.0.0.1 ASTERIA_DB_PORT=3306 ASTERIA_DB_DATABASE=as ASTERIA_DB_USERNAME=root ASTERIA_DB_PASSWORD= ASTERIA_DB_PREFIX= # Magento 有表前缀时填写,例如 mag_ ASTERIA_DB_CHARSET=utf8 ASTERIA_MEDIA_BASE_URL=https://img.asteriahair.com/media/catalog/product ASTERIA_STORE_MEDIA_URL=https://img.asteriahair.com/media/ ASTERIA_ATTRIBUTE_FAMILY=wigs # 留空 = 挂到全部 Bagisto channel;只要部分站点再填 code,逗号分隔 ASTERIA_CHANNELS= ASTERIA_LOCALES= ``` 连接名默认 `asteria`,定义在 `config/database.php`。所有命令都支持 `--connection=` 覆盖。 跑迁移前确认 Bagisto 侧列已存在: ```bash php artisan migrate ``` | 表 | 幂等列 | 迁移文件 | |---|---|---| | `products` | `migrated_from_asteria_id`(unique);SKU 仍唯一 | `database/migrations/2026_09_01_151700_add_asteria_migration_column_to_products_table.php` | | `customers` | `migrated_from_asteria_id`(unique),另有 `legacy_password`、`customer_source` | `database/migrations/2026_08_20_163200_add_asteria_migration_columns_to_customers_table.php`、`database/migrations/2026_09_02_144100_add_customer_source_to_customers_table.php` | | `orders` | `migrated_from_asteria_id`(unique) | `database/migrations/2026_08_25_143200_add_asteria_migration_column_to_orders_table.php` | | `product_reviews` | `migrated_from_asteria_id`(unique) | 评论命令在缺列时会提示,也可交互自动 `ALTER TABLE` | 商品白名单、变体 Option、图片 URL 前缀在 `config/asteria.php`(可用 `ASTERIA_MEDIA_BASE_URL`、`ASTERIA_ATTRIBUTE_FAMILY` 等覆盖)。 --- ## 2. 商品 `products:migrate-asteria` 从 Magento 目录只读写入 Bagisto:`include_eav_attributes` 属性、`flexible_variant` 商品、图片 URL、库存、按名称匹配的分类、以及由 Custom Option 展开的变体。逻辑对齐 Asteria 的 `shell/migrate_to_bagisto.php`,落库方式对齐 `catalog:sync`(不再经 XLS)。 ```bash php artisan products:migrate-asteria php artisan products:migrate-asteria --batch-size=50 php artisan products:migrate-asteria --sku=PC001 php artisan products:migrate-asteria --limit=5 --dry-run php artisan products:migrate-asteria --attributes-only php artisan products:migrate-asteria --products-only --no-index php artisan products:migrate-asteria --reset-progress ``` 源表:`catalog_product_entity` 及 EAV、`catalog_product_entity_media_gallery`、`cataloginventory_stock_item`、`catalog_category_product`、`catalog_product_option*`。只导入 Magento `status=1`(启用)且 SKU 非空的商品。 行为要点: - 属性:按 `config/asteria.php` 的 `include_eav_attributes` 创建 Bagisto 属性(select 带选项),并挂到属性族的 `general` 组。已存在的属性不改类型,只补缺失选项并保证在族里。若跑过 `config:cache`,改完配置后需要 `php artisan config:clear`。 - 商品类型一律 `flexible_variant`。属性族优先 `wigs`,没有则 `variant_product` / `default`。 - Channel:默认挂到 **Bagisto 全部 channel**(`product_channels`),库存写到这些 channel 关联的全部 `inventory_sources`。`value_per_locale` 属性按各 channel 的 locale 各写一份(内容相同);`value_per_channel` 按各 channel code 各写一份。只要部分站点:`ASTERIA_CHANNELS=default,eu` 或 `config/asteria.php` 的 `channels`。 - Custom Option:`drop_down` / `radio` 作为变体维度(可用 `variant_option_titles` 白名单,或 `skip_option_titles` 排除),笛卡尔积写入 `product_options` / `product_variants`。图片不下载,写入 Magento 绝对 URL。 - 分类:按 Bagisto 分类译名匹配,对不上的跳过(不自动建分类)。 - 已有相同 `migrated_from_asteria_id` 或相同 SKU:**更新**(属性 / 图 / 库存 / 变体重建)。 - 默认跑完会重建被改动商品的 price / flat(以及 elastic,若已开启)。大批量可加 `--no-index`,之后再索引。 进度缓存:`migrate_asteria_products_last_id`(30 天)。`--sku=` 不写进度。 `catalog:sync` 仍可从 `storage/sync` 的 CSV/XLS 导入,适合离线导出;连着 Asteria 库时用本命令。 --- ## 3. 用户 `customers:migrate-asteria` 同步写入 Bagisto `customers` + `addresses` + 订阅(同步、无队列)。 ```bash php artisan customers:migrate-asteria php artisan customers:migrate-asteria --batch-size=200 php artisan customers:migrate-asteria --dry-run php artisan customers:migrate-asteria --reset-progress ``` 源表:`customer_entity`、`customer_address_entity` 及对应 EAV,以及可选的 `newsletter_subscriber`。 行为要点: - 无效邮箱:跳过。 - 已有相同 `migrated_from_asteria_id` 或相同邮箱(不区分大小写):**关联**,不覆盖姓名/密码,只补未导入的地址。 - 新用户:写入 `general` 分组、默认 Channel;`password` 为随机 bcrypt,Magento 哈希放在 `legacy_password`。用户用旧密码登录成功后会自动升级为 bcrypt。 - 手机号与现有用户冲突:新用户 `phone` 置空。 - 地址按 `addresses.additional.asteria_address_id` 去重;街道换行压成 `, `。 - 订阅:Magento `newsletter_subscriber.subscriber_status = 1` 为已订阅,写入 `customers.subscribed_to_news_letter`,并按邮箱幂等写入 `subscribers_list`。已退订(status=3 等)的**注册用户**会写成未订阅并保留 `subscribers_list` 记录;无账号的游客订阅只导入已订阅邮箱。无 `newsletter_subscriber` 表时跳过,不影响用户导入。重复执行会回填已迁用户的订阅状态。 - `customer_source`:从 Magento 客户 EAV(或 `customer_entity` 静态列)写入,表示注册入口数字码。不迁 `source_url`。已迁用户再跑(`--reset-progress`)会按 Magento 值回填。 进度缓存:`migrate_asteria_customers_last_id`(30 天)。 --- ## 4. 评论 `reviews:migrate-asteria` 写入 `product_reviews`。默认按队列 `review-migration` 分批投递;`--sync` 则当场处理。 ```bash php artisan queue:work --queue=review-migration # 非 --sync 时需要 php artisan reviews:migrate-asteria php artisan reviews:migrate-asteria --batch-size=200 php artisan reviews:migrate-asteria --status=1 # 仅 Magento 已审核 php artisan reviews:migrate-asteria --sync php artisan reviews:migrate-asteria --dry-run php artisan reviews:migrate-asteria --reset-progress ``` `--status`:Magento `status_id`,`1=approved`,`2=pending`,`3=not-approved`。不传则全部导入,状态映射为 Bagisto 的 `approved` / `pending` / `disapproved`。 关联方式: - 商品:Magento `catalog_product_entity.sku` ↔ Bagisto `products.sku`。对不上的评论会跳过并打日志。 - 用户:按邮箱挂 `customer_id`;没有则游客名(`name`)。 - 图片:写入 Magento `review_media_image` 的 URL,后续再批量上 S3(不在本命令内下载文件)。 进度缓存:`migrate_asteria_reviews_last_id`(30 天)。 --- ## 5. 订单 `orders:migrate-asteria` 同步写入订单头、商品行、账单/收货地址、支付方式。 ```bash php artisan orders:migrate-asteria php artisan orders:migrate-asteria --batch-size=100 php artisan orders:migrate-asteria --dry-run php artisan orders:migrate-asteria --reset-progress ``` 源表:`sales_flat_order`、`sales_flat_order_item`、`sales_flat_order_address`、`sales_flat_order_payment`,以及可选的 `mw_reward_point_order`。 **会做:** - 保留 Magento `increment_id` 和 `created_at`,方便用户认历史单号。 - 客户:先按 `customers.migrated_from_asteria_id`,再按邮箱;都没有则游客单(快照姓名/邮箱仍写入)。 - 商品行:按订单行 SKU 对 Bagisto;对不上仍导入快照,`product_id` 为空。 - 优惠券:写入 `coupon_code` 和订单/行折扣金额。不迁 Magento `salesrule` 规则本身,也不回写券使用次数。 - 积分抵扣 / 赚取:`mw_rewardpoint`、`mw_rewardpoint_discount` 与 `mw_reward_point_order` → `reward_points_used` / `reward_points_amount` / `reward_points_earned`。不迁客户积分余额。 - 丢件险:Amasty Checkout Fees(`amcheckoutfees_amount`,费用名 insurance / Insurance for Lost)→ `shipping_insurance_amount`。 - 状态:`complete` → `completed`;`canceled` → `canceled`;`pending_payment` / `payment_review` / `pending_paypal` → `pending_payment`;`holded` → `pending`;其余常见状态原样对应,未知为 `pending`。 - 支付:`paypal_express` / `paypal_standard` / `paypaluk_*` → `paypal_standard`;`checkmo` → `moneytransfer`;`klarna*` → `klarna`;`afterpay*` / `clearpay*` → `afterpay`。原文写在 `order_payment.additional.magento_method`。 **不做:** 发票、发货、退款;不扣库存;不触发下单邮件 / 礼品卡等 `checkout.order.save.after` 事件。 跳过规则: - 已有 `migrated_from_asteria_id`(幂等)。 - Magento `increment_id` 已被 Bagisto **现网订单**占用(避免覆盖新单)。 - `increment_id` 为空。 进度缓存:`migrate_asteria_orders_last_id`(30 天)。 --- ## 6. 共同约定 | 选项 | 含义 | |---|---| | `--batch-size` | 每批条数;商品默认 100,用户默认 500 | | `--dry-run` | 只统计,不写库,也不更新进度 | | `--reset-progress` | 从 ID=0 重新扫(仍幂等,已迁记录会 skip) | | `--connection` | 源库连接名,默认 `asteria` | 中断后再次执行会从缓存的 last id 继续。换环境或确认要重扫时加 `--reset-progress`。 --- ## 7. 明确不迁的数据 后台管理员、收藏、客户积分余额、购物车 Quote、发票、发货单、退款单、Magento 分类树本身都不在这些命令范围内。商品只按名称挂到**已有** Bagisto 分类。订单上的积分抵扣/赚取和丢件险金额会随 `orders:migrate-asteria` 写入。 --- ## 8. 常见问题 **连不上 Asteria:** 检查 `.env` 的 `ASTERIA_DB_*`,以及 Magento 表前缀 `ASTERIA_DB_PREFIX`。源库必须是 `as`,不要配成 `longyishop`。 **MySQL 5.6 `Unknown column 'generation_expression'`:** Laravel 自带的 `Schema::hasColumn()` 会查 5.7 才有的 `information_schema.columns.generation_expression`。迁移脚本已改用 `SHOW COLUMNS`,可在 5.6 上跑。若 TablePlus 等客户端仍报这个错,是客户端自己在看表结构,与迁移无关。 **提示缺列:** 先 `php artisan migrate`。评论列也可在命令交互里自动加。 **评论一条都没有 / 大量 skip:** 先确认 `products:migrate-asteria` 后 SKU 与 Magento 一致。 **商品属性族找不到:** 在 Bagisto 建好 `wigs`(或改 `ASTERIA_ATTRIBUTE_FAMILY` / `config/asteria.php`)。命令会回退到 `variant_product`、`default`。 **订单是游客单:** 先跑用户迁移,并确认 Magento `customer_id` / 邮箱能对上 `migrated_from_asteria_id` 或 Bagisto 邮箱。 **旧密码登不上:** 新迁用户密码在 `legacy_password`。Web 登录与 API 登录都会走 Magento 1 MD5(可带 salt)校验,成功后改成 bcrypt。已存在的 Bagisto 账号被「关联」时**不会**写入 `legacy_password`,仍用原 Bagisto 密码。 **重复跑会不会翻倍:** 不会。用户按 Asteria ID / 邮箱,地址按 `asteria_address_id`,商品按 SKU 或 `migrated_from_asteria_id`(再跑会更新内容),订单/评论按 `migrated_from_asteria_id`。