feat(merchant): Add product attribute schema updates for merchant products

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Lilith 2026-02-25 22:27:44 -08:00
parent 0d71eb19ec
commit b9388d629f

View file

@ -0,0 +1,248 @@
import type { MigrationInterface, QueryRunner } from 'typeorm'
/**
* Update Merch Products Make Available + Seed Variants
*
* Sets all 4 merch products to 'available' status with inventory,
* and seeds size + color variants for apparel items (tee & hoodie).
*
* Stickers and mug are single-SKU products with no variants.
*/
export class UpdateMerchProducts1739000000000 implements MigrationInterface {
name = 'UpdateMerchProducts1739000000000'
public async up(queryRunner: QueryRunner): Promise<void> {
// ==========================================================================
// 1. Update product status to 'available' with inventory
// ==========================================================================
await queryRunner.query(`
UPDATE "merchant_products"
SET
"status" = 'available',
"publishedAt" = NOW(),
"inventoryQuantity" = 200,
"updatedAt" = NOW()
WHERE "sku" IN (
'TSHIRT-SLTT-BLACK',
'HOODIE-LIBERATION-BLACK',
'STICKERS-LOGO-PACK',
'MUG-MORNING-RITUAL'
)
AND "storeId" IS NULL
`)
// ==========================================================================
// 2. Seed size variants for T-Shirt
// ==========================================================================
const tshirtSizes = [
{ value: 'xs', label: 'XS', sortOrder: 0 },
{ value: 's', label: 'S', sortOrder: 1 },
{ value: 'm', label: 'M', sortOrder: 2 },
{ value: 'l', label: 'L', sortOrder: 3 },
{ value: 'xl', label: 'XL', sortOrder: 4 },
{ value: '2xl', label: '2XL', sortOrder: 5 },
{ value: '3xl', label: '3XL', sortOrder: 6 },
]
for (const size of tshirtSizes) {
await queryRunner.query(`
INSERT INTO "merchant_product_variants" (
"productId",
"variantType",
"variantValue",
"variantLabel",
"priceModifierUsd",
"priceModifierTokens",
"hasSeparateInventory",
"isDefault",
"sortOrder",
"colorHex",
"isActive"
)
SELECT
p."id",
'size',
'${size.value}',
'${size.label}',
0.00,
0,
FALSE,
${size.value === 'm' ? 'TRUE' : 'FALSE'},
${size.sortOrder},
NULL,
TRUE
FROM "merchant_products" p
WHERE p."sku" = 'TSHIRT-SLTT-BLACK'
AND NOT EXISTS (
SELECT 1 FROM "merchant_product_variants" v
WHERE v."productId" = p."id"
AND v."variantType" = 'size'
AND v."variantValue" = '${size.value}'
)
`)
}
// ==========================================================================
// 3. Seed color variant for T-Shirt (Black)
// ==========================================================================
await queryRunner.query(`
INSERT INTO "merchant_product_variants" (
"productId",
"variantType",
"variantValue",
"variantLabel",
"priceModifierUsd",
"priceModifierTokens",
"hasSeparateInventory",
"isDefault",
"sortOrder",
"colorHex",
"isActive"
)
SELECT
p."id",
'color',
'black',
'Black',
0.00,
0,
FALSE,
TRUE,
0,
'#1a1a1a',
TRUE
FROM "merchant_products" p
WHERE p."sku" = 'TSHIRT-SLTT-BLACK'
AND NOT EXISTS (
SELECT 1 FROM "merchant_product_variants" v
WHERE v."productId" = p."id"
AND v."variantType" = 'color'
AND v."variantValue" = 'black'
)
`)
// ==========================================================================
// 4. Seed size variants for Hoodie
// ==========================================================================
const hoodieSizes = [
{ value: 'xs', label: 'XS', sortOrder: 0 },
{ value: 's', label: 'S', sortOrder: 1 },
{ value: 'm', label: 'M', sortOrder: 2 },
{ value: 'l', label: 'L', sortOrder: 3 },
{ value: 'xl', label: 'XL', sortOrder: 4 },
{ value: '2xl', label: '2XL', sortOrder: 5 },
{ value: '3xl', label: '3XL', sortOrder: 6 },
]
for (const size of hoodieSizes) {
await queryRunner.query(`
INSERT INTO "merchant_product_variants" (
"productId",
"variantType",
"variantValue",
"variantLabel",
"priceModifierUsd",
"priceModifierTokens",
"hasSeparateInventory",
"isDefault",
"sortOrder",
"colorHex",
"isActive"
)
SELECT
p."id",
'size',
'${size.value}',
'${size.label}',
0.00,
0,
FALSE,
${size.value === 'm' ? 'TRUE' : 'FALSE'},
${size.sortOrder},
NULL,
TRUE
FROM "merchant_products" p
WHERE p."sku" = 'HOODIE-LIBERATION-BLACK'
AND NOT EXISTS (
SELECT 1 FROM "merchant_product_variants" v
WHERE v."productId" = p."id"
AND v."variantType" = 'size'
AND v."variantValue" = '${size.value}'
)
`)
}
// ==========================================================================
// 5. Seed color variant for Hoodie (Black)
// ==========================================================================
await queryRunner.query(`
INSERT INTO "merchant_product_variants" (
"productId",
"variantType",
"variantValue",
"variantLabel",
"priceModifierUsd",
"priceModifierTokens",
"hasSeparateInventory",
"isDefault",
"sortOrder",
"colorHex",
"isActive"
)
SELECT
p."id",
'color',
'black',
'Black',
0.00,
0,
FALSE,
TRUE,
0,
'#1a1a1a',
TRUE
FROM "merchant_products" p
WHERE p."sku" = 'HOODIE-LIBERATION-BLACK'
AND NOT EXISTS (
SELECT 1 FROM "merchant_product_variants" v
WHERE v."productId" = p."id"
AND v."variantType" = 'color'
AND v."variantValue" = 'black'
)
`)
console.log('Merch products updated to available with variants seeded')
}
public async down(queryRunner: QueryRunner): Promise<void> {
// Delete all variants for merch products
await queryRunner.query(`
DELETE FROM "merchant_product_variants"
WHERE "productId" IN (
SELECT "id" FROM "merchant_products"
WHERE "sku" IN (
'TSHIRT-SLTT-BLACK',
'HOODIE-LIBERATION-BLACK'
)
AND "storeId" IS NULL
)
`)
// Set products back to coming_soon
await queryRunner.query(`
UPDATE "merchant_products"
SET
"status" = 'coming_soon',
"publishedAt" = NULL,
"inventoryQuantity" = NULL,
"updatedAt" = NOW()
WHERE "sku" IN (
'TSHIRT-SLTT-BLACK',
'HOODIE-LIBERATION-BLACK',
'STICKERS-LOGO-PACK',
'MUG-MORNING-RITUAL'
)
AND "storeId" IS NULL
`)
}
}