asteria-migration.md 18 KB

Asteria(Magento 1)→ Bagisto 数据迁移说明

从旧站 Asteria(Magento 1.x)只读导入商品、用户、评论、订单到本店。源库以 as 为准(不要用 longyishop)。命令共用 Laravel 连接名 asteria,可分批、可断点续跑、可 --dry-run,重复执行不会重复插入。

空库约定: 目标 products / customers / orders / shipments / product_reviews 无业务行;Magento 目录只有 simple 商品。属性族、分类、渠道、客户组等种子表的 id 不动。

主键: 新建的客户 / 商品 / 订单 / 发货用 Magento entity_id 作为 Bagisto id,评论用 Magento review_idmigrated_from_asteria_id 保留,新建行写入与 id 相同的 Magento ID。已有行(同映射列 / SKU / 邮箱)只关联,不改 Bagisto 主键。目标 id 已被占用则 skip,不覆盖。product_variantsproduct_optionsorder_itemsorder_payment、订单/客户地址仍自增。MySQL/MariaDB 在各命令写完后把对应表的 AUTO_INCREMENT 调到 MAX(id)+1(SQLite 跳过;命令若包在事务里也跳过,避免 DDL 提交测试事务)。

推荐顺序: 需要清空现有数据时先 reset,再迁商品,再迁用户,再迁订单 / 评论。

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:reset --dry-run
php artisan orders:reset --force           # 清空现有订单,便于重新导入
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

orders:reset 会 TRUNCATE 订单及明细 / 支付 / 发票 / 发货 / 退款,并删除订单地址。用户、商品、购物车不删。礼品卡使用记录、积分/成长值流水只把 order_id 置空。也可跑 database/scripts/reset_orders.sql


1. 前置:Asteria 数据库连接

.env 中配置只读 Magento 库(应用层只跑 SELECT):

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 侧列已存在:

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_passwordcustomer_source database/migrations/2026_08_20_163200_add_asteria_migration_columns_to_customers_table.phpdatabase/migrations/2026_09_02_144100_add_customer_source_to_customers_table.phpdatabase/migrations/2026_09_03_101500_change_customer_source_to_string_on_customers_table.php
orders migrated_from_asteria_id(unique);另有 remote_ip、积分/丢件险金额列 database/migrations/2026_08_25_143200_add_asteria_migration_column_to_orders_table.phpdatabase/migrations/2026_09_07_155700_add_remote_ip_to_orders_table.php
shipments migrated_from_asteria_id(unique) database/migrations/2026_09_07_155800_add_asteria_migration_column_to_shipments_table.php
product_reviews migrated_from_asteria_id(unique) 评论命令在缺列时会提示,也可交互自动 ALTER TABLE

商品白名单、变体 Option、图片 URL 前缀在 config/asteria.php(可用 ASTERIA_MEDIA_BASE_URLASTERIA_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)。

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_gallerycataloginventory_stock_itemcatalog_category_productcatalog_product_option*。默认导入全部 SKU 非空商品(含 Magento 禁用商品,写入 Bagisto status=0),不按库存过滤,以便评论等能按 SKU 挂上。若只要启用商品:ASTERIA_PRODUCTS_ONLY_ENABLED=true

行为要点:

  • 属性:按 config/asteria.phpinclude_eav_attributes 创建 Bagisto 属性(select 带选项),并挂到属性族的 general 组。已存在的属性不改类型,只补缺失选项并保证在族里。若跑过 config:cache,改完配置后需要 php artisan config:clear
  • 只导入 Magento type_id = simple;configurable / bundle 等 skip 并打日志。写入 Bagisto 后类型一律 flexible_variant。属性族优先 wigs,没有则 variant_product / default
  • 新建商品 products.id = Magento catalog_product_entity.entity_id,同时写入相同的 migrated_from_asteria_id。Custom Option 展开的 product_options / product_variants 仍自增。
  • Channel:默认挂到 Bagisto 全部 channelproduct_channels),库存写到这些 channel 关联的全部 inventory_sourcesvalue_per_locale 属性按各 channel 的 locale 各写一份(内容相同);value_per_channel 按各 channel code 各写一份。只要部分站点:ASTERIA_CHANNELS=default,euconfig/asteria.phpchannels
  • 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 + 订阅(同步、无队列)。

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_entitycustomer_address_entity 及对应 EAV,以及可选的 newsletter_subscriber

行为要点:

  • 无效邮箱:跳过。
  • 已有相同 migrated_from_asteria_id 或相同邮箱(不区分大小写):关联,不覆盖姓名/密码,只补未导入的地址。
  • 新用户:customers.id = Magento customer_entity.entity_id,同时写入相同的 migrated_from_asteria_id。写入 general 分组、默认 Channel;password 为随机 bcrypt,Magento 哈希放在 legacy_password。用户用旧密码登录成功后会自动升级为 bcrypt。addresses 仍自增,去重继续用 asteria_address_id
  • 手机号与现有用户冲突:新用户 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 客户属性 source 写入。该属性在 Magento 1 里是 varchar 自由文本(现网只有 popup 一种值,且仅 97 个客户有值),因此原样存字符串,不做数字编码转换;超过 64 字符会截断。不迁 source_url。已迁用户再跑(--reset-progress)会按 Magento 值回填。

进度缓存:migrate_asteria_customers_last_id(30 天)。


4. 评论 reviews:migrate-asteria

写入 product_reviews。新建评论 id = Magento review_id,同时写入相同的 migrated_from_asteria_id;图片挂这条评论 id。默认按队列 review-migration 分批投递;--sync 则当场处理。

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_id1=approved2=pending3=not-approved。不传则全部导入,状态映射为 Bagisto 的 approved / pending / disapproved

关联方式:

  • 商品:优先 products.migrated_from_asteria_id,再 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

同步写入订单头、商品行、账单/收货地址、支付方式、发货单和物流单号。

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_ordersales_flat_order_itemsales_flat_order_addresssales_flat_order_payment,以及可选的 mw_reward_point_ordersales_flat_shipment / _item / _track

会做:

  • 新建订单 orders.id = Magento sales_flat_order.entity_id,发货 shipments.id = Magento sales_flat_shipment.entity_id,同时写入相同的 migrated_from_asteria_idorder_itemsorder_payment、订单地址仍自增。对外单号仍是 Magento increment_id
  • 保留 Magento increment_idcreated_at,方便用户认历史单号。
  • 客户:先按 customers.migrated_from_asteria_id,再按邮箱;都没有则游客单(快照姓名/邮箱仍写入)。
  • 商品行:优先按 Magento product_idproducts.migrated_from_asteria_id,再按 Magento 当前目录 SKU(catalog_product_entity.sku)对 Bagisto products.sku。订单行上的 SKU 往往是自定义选项拼接码,不能直接拿来匹配。对不上仍导入快照,product_id 为空。重复执行会回填已迁订单里空的 product_id
  • 自定义选项 / 变体:Magento sales_flat_order_item.product_options(PHP serialize)解码后写入 order_items.additional.product_options,并把 options / attributes_info 转成后台可显示的 additional.attributesattribute_name / option_label / attribute_type)。
  • remote_ip:原样写入 orders.remote_ip(Magento 里经常是 AWS 内网 IP;不改写成 x_forwarded_for)。
  • 优惠券:写入 coupon_code 和订单/行折扣金额。不迁 Magento salesrule 规则本身,也不回写券使用次数。
  • 积分抵扣 / 赚取:mw_rewardpointmw_rewardpoint_discountmw_reward_point_orderreward_points_used / reward_points_amount / reward_points_earned。不迁客户积分余额。
  • 丢件险:Amasty Checkout Fees(amcheckoutfees_amount,费用名 insurance / Insurance for Lost)→ shipping_insurance_amount
  • 礼品卡:Magento giftcard_amount(负数)取绝对值写入 giftcard_amount / base_giftcard_amountgiftcard_id 写入 giftcard_number。不迁礼品卡卡面余额表。
  • Plus 费:Magento member_free_amount(14.99 / 17.90)→ vip_plus_amount / base_vip_plus_amount
  • 会员折扣:Magento member_amount(负数)取绝对值写入 vip_discount_amount / base_vip_discount_amount
  • 发货:sales_flat_shipment + _item + _trackshipments / shipment_items。承运商取第一条 track 的 carrier_code / title,多个单号用逗号拼接进 track_number。不扣库存、不发发货邮件。已迁订单再跑会补发货、remote_ip、礼品卡、Plus 费和会员折扣。
  • 状态:completecompletedcanceledcanceledpending_payment / payment_review / pending_paypalpending_paymentholdedpending;其余常见状态原样对应,未知为 pending
  • 支付:paypal_express / paypal_standard / paypaluk_*paypal_standardcheckmomoneytransferklarna*klarnaafterpay* / clearpay*afterpay。原文写在 order_payment.additional.magento_method。PayPal 的 Payer ID / Email / Status / Address Status、Merchant Protection Eligibility、Last Correlation ID、Last Transaction ID 从 Magento additional_information 写入 order_payment.additional(含 paypal 展示字段)。已迁订单再跑会补这些字段。

不做: 发票、退款;不扣库存;不触发下单邮件 / 礼品卡等 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 分类。订单上的积分抵扣/赚取、丢件险、礼品卡、Plus 费、会员折扣、remote_ip、商品选项和发货单会随 orders:migrate-asteria 写入。


8. 常见问题

连不上 Asteria: 检查 .envASTERIA_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(或 migrated_from_asteria_id)与 Magento 一致。商品迁移默认会导入禁用商品(status=0);若设了 ASTERIA_PRODUCTS_ONLY_ENABLED=true,禁用商品不会导入,对应评论会 skip。评论匹配本身不看状态/库存。

商品属性族找不到: 在 Bagisto 建好 wigs(或改 ASTERIA_ATTRIBUTE_FAMILY / config/asteria.php)。命令会回退到 variant_productdefault

订单是游客单: 先跑用户迁移,并确认 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。空库且 id 等于 Magento ID 时,查到的 Bagisto id 碰巧等于源 ID,外键仍写 Bagisto id