无法更新 Medusa JS 中的字段

问题描述 投票:0回答:1

我正在开发 Medusa JS,需要在“Cart”的核心模型中添加一个自定义字段,这意味着扩展一个实体。因此,按照指南 -> 扩展实体,我能够做所有事情。在使用 Store API 更新新创建的购物车字段的值时,我没有收到任何错误,这意味着验证也工作正常,但问题是字段没有在数据库中更新。

第 2 步(根据文档):扩展购物车模型

import { Column, Entity } from "typeorm";
import {
  // alias the core entity to not cause a naming conflict
  Cart as MedusaCart,
} from "@medusajs/medusa";

@Entity()
export class Cart extends MedusaCart {
  @Column()
  is_subscribed?: boolean;
}

第 3 步:创建 Typescript 声明文件

export declare module "@medusajs/medusa/dist/models/order" {
    declare interface Order {
        is_subscribed: boolean;
    }
}

扩展验证(使用更新购物车验证)

import { registerOverriddenValidators } from "@medusajs/medusa";
import { StorePostCartsCartReq as MedusaStorePostCartsCartReq } from "@medusajs/medusa/dist/api/routes/store/carts/update-cart";
import { IsBoolean, IsOptional } from "class-validator";

class StorePostCartsCartReq extends MedusaStorePostCartsCartReq {
  @IsOptional()
  @IsBoolean()
  is_subscribed?: boolean;
}

registerOverriddenValidators(StorePostCartsCartReq);

我需要更新自定义字段的值,以便我可以根据该值创建订阅者。只有当我能够使用更新存储 API 修改此属性的值时,我才能做到这一点。

node.js e-commerce medusajs
1个回答
0
投票

我相信您还必须扩展与购物车相关的存储库和服务(我假设您进行了迁移)。经过很长时间的摸索和研究节点模块后,我解决了这个问题。这是我在 Github 上的一个帖子中发布的解决方案:

经过长时间的尝试和研究节点模块后,我已经解决了这个问题。我将向您展示我的文件是什么样子。我想扩展嵌套在产品中的变体数组中的价格(MoneyAmount 实体)数组。因此,当我发布新产品时,应返回新的自定义属性并在数据库中更新。

延长金额:

import { Column, Entity } from "typeorm"
import {
  // alias the core entity to not cause a naming conflict
  MoneyAmount as MedusaMoneyAmount,
} from "@medusajs/medusa"

enum PurchaseType {
    OneTime = "one_time",
    Recurring = "recurring"
  }

enum AggregrateUsageType{
LastDuringPeriod="last_during_period",
LastEver="last_ever",
Max="max",
Sum="sum"
}

enum IntervalType{
    Day = "day",
    Week = "week",
    Month = "month",
    Year = "year"
  }

enum UsageTypeType{
  Metered="metered",
  Licensed="licensed"
}

@Entity()
export class MoneyAmount extends MedusaMoneyAmount {
  @Column({
    type:"enum",
    enum:PurchaseType,
    default: PurchaseType.OneTime, // Set a default value if needed
    nullable:true
  })
  type: PurchaseType
 
  @Column({
    type: "jsonb",
    nullable: true,
  })
  recurring: {
    aggregate_usage: null | AggregrateUsageType;
    interval: IntervalType;
    interval_count: number;
    trial_period_days: null | number;
    usage_type: UsageTypeType;
  };
}

迁移:

import { MigrationInterface, QueryRunner,TableColumn } from "typeorm";

export class MoneyAmountExtension1709761619941 implements MigrationInterface {

    public async up(queryRunner: QueryRunner): Promise<void> {  await queryRunner.addColumn(
        "money_amount", 
        new TableColumn({
            name: "type",
            type: "enum",
            enum: ["one_time", "recurring"], 
            default: "'one_time'", 
            isNullable:true,
        })
    )

    await queryRunner.addColumn(
        "money_amount",
        new TableColumn({
            name: "recurring",
            type: "jsonb",
            isNullable: true,
        })
    )
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.dropColumn("money_amount", "type");
        await queryRunner.dropColumn("money_amount", "recurring");
    }

}

允许返回自定义属性的加载器文件:

export default async function () {
    const imports = (await import(
      "@medusajs/medusa/dist/api/routes/store/products/index"
    )) as any
    imports.allowedStoreProductsFields = [
      ...imports.allowedStoreProductsFields,
      "variants__prices.type",
      "variants__prices.recurring"
    ]
    imports.defaultStoreProductsFields = [
      ...imports.defaultStoreProductsFields,
      "variants__prices.type",
      "variants__prices.recurring"
    ]
  }

扩展 MoneyAmount 的存储库(请注意,它实际上与 DOCS 不同,因为遵循文档显示的方式会导致错误。请参阅我遵循的此线程 https://github.com/medusajs/medusa/issues/6139 ):

import { MoneyAmount } from "@medusajs/medusa";
import { dataSource } from "@medusajs/medusa/dist/loaders/database";
import { MoneyAmountRepository as MedusaMoneyAmountRepository } from "@medusajs/medusa/dist/repositories/money-amount";

export const MoneyAmountRepository:any = dataSource
  .getRepository(MoneyAmount)
  // .extend({
  //  ...Object.assign(MedusaMoneyAmountRepository, {
  //     target: MoneyAmount
  //   }),
  // });
// this causes "moneyAmountRepo.deleteVariantPricesNotIn is not a function\nCannot read properties of undefined (reading 'length')" but is in DOCS

  .extend(
    Object.assign(MedusaMoneyAmountRepository, {
       target: MoneyAmount
     }),
   );

export default MoneyAmountRepository;

重写验证器:

import { registerOverriddenValidators } from "@medusajs/medusa"
import {AdminPostProductsReq as MedusaAdminPostProductsReq} from "@medusajs/medusa/dist/api/routes/admin/products/create-product"
import{AdminPostProductsProductVariantsReq as MedusaAdminPostProductsProductVariantsReq} from "@medusajs/medusa/dist/api/routes/admin/products/create-variant"
import{ ProductVariantPricesCreateReq as MedusaProductVariantPricesCreateReq }from "@medusajs/medusa/dist/types/product-variant"
import { IsString,ValidateNested,IsArray,IsEnum,IsObject,IsOptional } from "class-validator"
import {Type} from "class-transformer"

class AdminPostProductsReq extends MedusaAdminPostProductsReq {
@Type(() => AdminPostProductsProductVariantsReq)
@ValidateNested({ each: true })
@IsArray()
variants: AdminPostProductsProductVariantsReq[];
}

class AdminPostProductsProductVariantsReq extends MedusaAdminPostProductsProductVariantsReq {
 @Type(() => ProductVariantPricesCreateReq)
 @ValidateNested({ each: true })
 @IsArray()
 prices: ProductVariantPricesCreateReq[];
}

enum PurchaseType {
 OneTime = "one_time",
 Recurring = "recurring"
}

enum AggregrateUsageType{
 LastDuringPeriod="last_during_period",
 LastEver="last_ever",
 Max="max",
 Sum="sum"
 }
 
 enum IntervalType{
     Day = "day",
     Week = "week",
     Month = "month",
     Year = "year"
   }
 
 enum UsageTypeType{
   Metered="metered",
   Licensed="licensed"
 }

class ProductVariantPricesCreateReq extends MedusaProductVariantPricesCreateReq{
@IsOptional()
 @IsEnum(PurchaseType)
 type:PurchaseType

 @IsOptional()
 @IsObject()
 recurring:{
  aggregate_usage: null | AggregrateUsageType;
  interval: IntervalType;
  interval_count: number;
  trial_period_days: null | number;
  usage_type: UsageTypeType;
 }
}

registerOverriddenValidators(AdminPostProductsReq)
// registerOverriddenValidators(AdminPostProductsProductVariantsReq)
// post request goes through without overriding AdminPostProductsProductVariantsReq

// registerOverriddenValidators(ProductVariantPricesCreateReq) 
// post request goes through without overriding ProductVariantPricesCreateReq)

扩展产品变体服务(创建产品需要产品变体服务):


import { ProductVariantService as MedusaProductVariantService } from "@medusajs/medusa";
import { Lifetime } from "awilix";
import MoneyAmountRepository from "src/repositories/money-amount";
import { CreateProductVariantInput as MedusaCreateProductVariantInput } from "@medusajs/medusa/dist/types/product-variant";
import { ProductVariantPrice as MedusaProductVariantPrice } from "@medusajs/medusa/dist/types/product-variant";
import ProductVariantRepository from "@medusajs/medusa/dist/repositories/product-variant";

type ProductVariantPrice={
  type?:string,
  recurring?:object
} & MedusaProductVariantPrice

type CreateProductVariantInput={
  prices:ProductVariantPrice[]
} & MedusaCreateProductVariantInput[]

class ProductVariantService extends MedusaProductVariantService {
  static LIFE_TIME = Lifetime.SCOPED;
  protected readonly moneyAmountRepository_: typeof MoneyAmountRepository;
  protected readonly productVariantRepository_: typeof ProductVariantRepository;

  constructor(container, options) {
    // @ts-expect-error prefer-rest-params
    super(...arguments);
    this.moneyAmountRepository_ = container.moneyAmountRepository;
    this.productVariantRepository_ =container.productVariantRepository
  }

  async create(productOrProductId, variants: CreateProductVariantInput): Promise<any> {

    const variantsWithExtras = variants.map(variant => {

      const pricesWithExtras = variant.prices.map((price:ProductVariantPrice) => ({
        ...price,
        type: price.type || null,
        recurring: price.recurring || null
      }));
      // console.log(pricesWithExtras)

      return {
        ...variant,
        prices: pricesWithExtras
      };
    });

    // variantsWithExtras.forEach(variant => console.log(variant));

    const createdVariants:any = await super.create(productOrProductId, variantsWithExtras);

    this.updateVariantPrices(variantsWithExtras.map(function (v:any) { 
      console.log(`this is v:`,v)
      console.log(`this is createdvariantsid`,createdVariants[0].id)
      console.log(`this is v.prices:`,v.prices)
      return ({
      variantId: createdVariants[0].id,
      prices: v.prices,
  });
}))

    return createdVariants;
  }
}

export default ProductVariantService;

我还想指出的是,我在 Github 代码空间上工作时试图让它工作,我的文件看起来与我长期以来向您展示的文件完全相同,并且它不会将自定义属性值输入到数据库中已在 POST 正文中提供,而只是将其保留为默认值。在我用完他们允许我的所有时间后,我必须将我在代码空间中所做的更改导出到新分支,并将 GitHub 存储库克隆到 VS code 并在那里工作。我运行 npm i 两次,因为第一次由于某种原因失败,然后我没有在发布请求正文中使用region_id,而是将其切换为货币代码(由于某种原因,POST 正文中的region_id 在发送请求时导致错误)。然后令我惊讶的是它起作用了。

© www.soinside.com 2019 - 2024. All rights reserved.