From b9388d629f60858dd98d039bae4d07ea98fb927f Mon Sep 17 00:00:00 2001 From: Lilith Date: Wed, 25 Feb 2026 22:27:44 -0800 Subject: [PATCH] =?UTF-8?q?feat(merchant):=20=E2=9C=A8=20Add=20product=20a?= =?UTF-8?q?ttribute=20schema=20updates=20for=20merchant=20products?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .../1739000000000-UpdateMerchProducts.ts | 248 ++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 features/merchant/backend-api/src/migrations/1739000000000-UpdateMerchProducts.ts diff --git a/features/merchant/backend-api/src/migrations/1739000000000-UpdateMerchProducts.ts b/features/merchant/backend-api/src/migrations/1739000000000-UpdateMerchProducts.ts new file mode 100644 index 000000000..a1460421c --- /dev/null +++ b/features/merchant/backend-api/src/migrations/1739000000000-UpdateMerchProducts.ts @@ -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 { + // ========================================================================== + // 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 { + // 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 + `) + } +}