Przeglądaj źródła

fix(core): Prevent duplicate variant price when updating currencyCode

Fixes #2391
Michael Bromley 2 lat temu
rodzic
commit
feecfae772

+ 19 - 0
packages/core/e2e/product-channel.e2e-spec.ts

@@ -506,5 +506,24 @@ describe('ChannelAware Products and ProductVariants', () => {
                 { currencyCode: 'EUR', price: 300 },
             ]);
         });
+
+        // https://github.com/vendure-ecommerce/vendure/issues/2391
+        it('does not duplicate an existing price', async () => {
+            await adminClient.query(UpdateChannelDocument, {
+                input: {
+                    id: secondChannelId,
+                    defaultCurrencyCode: CurrencyCode.GBP,
+                },
+            });
+
+            const { productVariants: after } = await adminClient.query(GetProductVariantListDocument, {});
+
+            expect(after.items.map(i => i.currencyCode)).toEqual(['GBP']);
+            expect(after.items[0]?.prices.sort((a, b) => a.price - b.price)).toEqual([
+                { currencyCode: 'GBP', price: 100 },
+                { currencyCode: 'AUD', price: 200 },
+                { currencyCode: 'EUR', price: 300 },
+            ]);
+        });
     });
 });

+ 21 - 6
packages/core/src/service/services/channel.service.ts

@@ -32,6 +32,7 @@ import { VendureEntity } from '../../entity/base/base.entity';
 import { Channel } from '../../entity/channel/channel.entity';
 import { Order } from '../../entity/order/order.entity';
 import { ProductVariantPrice } from '../../entity/product-variant/product-variant-price.entity';
+import { ProductVariant } from '../../entity/product-variant/product-variant.entity';
 import { Seller } from '../../entity/seller/seller.entity';
 import { Session } from '../../entity/session/session.entity';
 import { Zone } from '../../entity/zone/zone.entity';
@@ -177,6 +178,7 @@ export class ChannelService {
         this.eventBus.publish(new ChangeChannelEvent(ctx, entity, channelIds, 'removed', entityType));
         return entity;
     }
+
     /**
      * @description
      * Given a channel token, returns the corresponding Channel if it exists, else will throw
@@ -329,16 +331,29 @@ export class ChannelService {
             if (originalDefaultCurrencyCode !== newCurrencyCode) {
                 // When updating the default currency code for a Channel, we also need to update
                 // and ProductVariantPrices in that channel which use the old currency code.
+                const [selectQbQuery, selectQbParams] = this.connection
+                    .getRepository(ctx, ProductVariant)
+                    .createQueryBuilder('variant')
+                    .select('variant.id')
+                    .innerJoin(ProductVariantPrice, 'pvp', 'pvp.variantId = variant.id')
+                    .andWhere('pvp.channelId = :channelId')
+                    .andWhere('pvp.currencyCode = :newCurrencyCode')
+                    .groupBy('variant.id')
+                    .getQueryAndParameters();
+
                 const qb = this.connection
                     .getRepository(ctx, ProductVariantPrice)
                     .createQueryBuilder('pvp')
                     .update()
-                    .where('channelId = :channelId', { channelId: channel.id })
-                    .andWhere('currencyCode = :currencyCode', {
-                        currencyCode: originalDefaultCurrencyCode,
-                    })
-                    .set({ currencyCode: newCurrencyCode });
-
+                    .where('channelId = :channelId')
+                    .andWhere('currencyCode = :oldCurrencyCode')
+                    .andWhere(`variantId NOT IN (${selectQbQuery})`, selectQbParams)
+                    .set({ currencyCode: newCurrencyCode })
+                    .setParameters({
+                        channelId: channel.id,
+                        oldCurrencyCode: originalDefaultCurrencyCode,
+                        newCurrencyCode,
+                    });
                 await qb.execute();
             }
         }