@porulle/plugin-channel-connector 0.50.0 → 0.50.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/service.js +35 -7
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/service.ts +41 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@porulle/plugin-channel-connector",
|
|
3
|
-
"version": "0.50.
|
|
3
|
+
"version": "0.50.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -19,15 +19,15 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@hono/zod-openapi": "^1.2.2",
|
|
21
21
|
"hono": "^4.12.5",
|
|
22
|
-
"@porulle/core": "0.50.
|
|
22
|
+
"@porulle/core": "0.50.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^24.5.2",
|
|
26
26
|
"eslint": "^9.39.1",
|
|
27
27
|
"typescript": "5.9.2",
|
|
28
28
|
"vitest": "^3.2.4",
|
|
29
|
-
"@porulle/
|
|
30
|
-
"@porulle/
|
|
29
|
+
"@porulle/eslint-config": "0.1.0",
|
|
30
|
+
"@porulle/typescript-config": "0.1.0"
|
|
31
31
|
},
|
|
32
32
|
"publishConfig": {
|
|
33
33
|
"access": "public"
|
package/src/service.ts
CHANGED
|
@@ -40,6 +40,8 @@ import {
|
|
|
40
40
|
customerAddresses,
|
|
41
41
|
customers,
|
|
42
42
|
entityMedia,
|
|
43
|
+
entityBrands,
|
|
44
|
+
entityCategories,
|
|
43
45
|
entityTags,
|
|
44
46
|
inventoryLevels,
|
|
45
47
|
mediaAssets,
|
|
@@ -1633,6 +1635,22 @@ export class ChannelConnectorService {
|
|
|
1633
1635
|
existingOptionValues.set(row.variantId, list);
|
|
1634
1636
|
}
|
|
1635
1637
|
}
|
|
1638
|
+
// The product's plain base prices, read once. `setBasePrice` upserts and fires its hook even at
|
|
1639
|
+
// the same amount, so an unchanged price is skipped here — and a price that IS written is what
|
|
1640
|
+
// makes the variant "changed", which is what `converged` counts.
|
|
1641
|
+
const storedPrices = item.variants.some((variant) => (variant.prices ?? []).length > 0)
|
|
1642
|
+
? await this.db.select({ variantId: prices.variantId, currency: prices.currency, amount: prices.amount, compareAtAmount: prices.compareAtAmount })
|
|
1643
|
+
.from(prices)
|
|
1644
|
+
.where(and(
|
|
1645
|
+
eq(prices.organizationId, orgId),
|
|
1646
|
+
eq(prices.entityId, entityId),
|
|
1647
|
+
isNull(prices.customerGroupId),
|
|
1648
|
+
isNull(prices.minQuantity),
|
|
1649
|
+
isNull(prices.maxQuantity),
|
|
1650
|
+
isNull(prices.validFrom),
|
|
1651
|
+
isNull(prices.validUntil),
|
|
1652
|
+
))
|
|
1653
|
+
: [];
|
|
1636
1654
|
for (const sourceVariant of item.variants) {
|
|
1637
1655
|
const fullSourceVariant = fullItem.variants.find((variant) => variant.externalId === sourceVariant.externalId) ?? sourceVariant;
|
|
1638
1656
|
let mapping = mappings.find((row) => row.externalId === sourceVariant.externalId);
|
|
@@ -1738,6 +1756,9 @@ export class ChannelConnectorService {
|
|
|
1738
1756
|
}
|
|
1739
1757
|
}
|
|
1740
1758
|
for (const price of sourceVariant.prices ?? []) {
|
|
1759
|
+
const currency = price.currency.trim().toUpperCase();
|
|
1760
|
+
const stored = storedPrices.find((row) => row.variantId === variantId && row.currency === currency);
|
|
1761
|
+
if (stored && stored.amount === price.amount && stored.compareAtAmount === (price.compareAtAmount ?? null)) continue;
|
|
1741
1762
|
const priced = await this.pricing.setBasePrice({
|
|
1742
1763
|
entityId,
|
|
1743
1764
|
variantId,
|
|
@@ -1746,6 +1767,7 @@ export class ChannelConnectorService {
|
|
|
1746
1767
|
compareAtAmount: price.compareAtAmount ?? null,
|
|
1747
1768
|
}, actor);
|
|
1748
1769
|
if (!priced.ok) return PluginErr(priced.error.message);
|
|
1770
|
+
changed = true;
|
|
1749
1771
|
}
|
|
1750
1772
|
// Was UNCONDITIONAL: one UPDATE per variant on every import, including a re-sync where the
|
|
1751
1773
|
// variant is byte-identical. `mapping.syncHash` is already in hand from the select above, so
|
|
@@ -1812,8 +1834,15 @@ export class ChannelConnectorService {
|
|
|
1812
1834
|
item: ChannelCatalogItem,
|
|
1813
1835
|
actor: Actor,
|
|
1814
1836
|
warnings: string[],
|
|
1815
|
-
): Promise<PluginResult<
|
|
1837
|
+
): Promise<PluginResult<{ changed: boolean }>> {
|
|
1816
1838
|
const taxonomy = await this.taxonomyFor(orgId);
|
|
1839
|
+
// The links this entity already has, read only for the classes the item names. A link already
|
|
1840
|
+
// there is not re-written, and a link that is added is what reports the taxonomy as changed.
|
|
1841
|
+
const linkedCategories = new Set((item.categories ?? []).length === 0 ? [] : (await this.db
|
|
1842
|
+
.select({ id: entityCategories.categoryId }).from(entityCategories).where(eq(entityCategories.entityId, entityId))).map((row) => row.id));
|
|
1843
|
+
const linkedBrands = new Set(!item.brand ? [] : (await this.db
|
|
1844
|
+
.select({ id: entityBrands.brandId }).from(entityBrands).where(eq(entityBrands.entityId, entityId))).map((row) => row.id));
|
|
1845
|
+
let changed = false;
|
|
1817
1846
|
const categoryRows = taxonomy.categories;
|
|
1818
1847
|
for (const slug of new Set(item.categories ?? [])) {
|
|
1819
1848
|
let category = categoryRows.find((row) => row.slug === slug);
|
|
@@ -1829,8 +1858,10 @@ export class ChannelConnectorService {
|
|
|
1829
1858
|
category = createdCategory;
|
|
1830
1859
|
categoryRows.push(category);
|
|
1831
1860
|
}
|
|
1861
|
+
if (linkedCategories.has(category.id)) continue;
|
|
1832
1862
|
const linked = await this.catalog.addToCategory(entityId, category.id, actor);
|
|
1833
1863
|
if (!linked.ok) return PluginErr(linked.error.message);
|
|
1864
|
+
changed = true;
|
|
1834
1865
|
}
|
|
1835
1866
|
|
|
1836
1867
|
const brandRows = taxonomy.brands;
|
|
@@ -1844,8 +1875,11 @@ export class ChannelConnectorService {
|
|
|
1844
1875
|
brand = createdBrand;
|
|
1845
1876
|
brandRows.push(brand);
|
|
1846
1877
|
}
|
|
1847
|
-
|
|
1848
|
-
|
|
1878
|
+
if (!linkedBrands.has(brand.id)) {
|
|
1879
|
+
const linked = await this.catalog.addToBrand(entityId, brand.id, actor);
|
|
1880
|
+
if (!linked.ok) return PluginErr(linked.error.message);
|
|
1881
|
+
changed = true;
|
|
1882
|
+
}
|
|
1849
1883
|
}
|
|
1850
1884
|
|
|
1851
1885
|
const tagRows = taxonomy.tags;
|
|
@@ -1860,9 +1894,10 @@ export class ChannelConnectorService {
|
|
|
1860
1894
|
if (!tag) return PluginErr(`Tag "${slug}" was not persisted.`);
|
|
1861
1895
|
tagRows.push(tag);
|
|
1862
1896
|
}
|
|
1863
|
-
await this.db.insert(entityTags).values({ entityId, tagId: tag.id }).onConflictDoNothing();
|
|
1897
|
+
const added = await this.db.insert(entityTags).values({ entityId, tagId: tag.id }).onConflictDoNothing().returning({ tagId: entityTags.tagId });
|
|
1898
|
+
if (added.length > 0) changed = true;
|
|
1864
1899
|
}
|
|
1865
|
-
return Ok(
|
|
1900
|
+
return Ok({ changed });
|
|
1866
1901
|
}
|
|
1867
1902
|
|
|
1868
1903
|
private async applyMedia(
|
|
@@ -3822,7 +3857,7 @@ export class ChannelConnectorService {
|
|
|
3822
3857
|
mediaImported += media.value.imported;
|
|
3823
3858
|
variantsGivenOptionValues += variantIds.value.repaired;
|
|
3824
3859
|
skipped.push(...media.value.skipped.map((fieldPath) => ({ entityId, fieldPath })));
|
|
3825
|
-
entityTouched = entityTouched || optionAxes.value.changed || variantIds.value.changed || media.value.changed || attributes.value.changed;
|
|
3860
|
+
entityTouched = entityTouched || optionAxes.value.changed || variantIds.value.changed || taxonomy.value.changed || media.value.changed || attributes.value.changed;
|
|
3826
3861
|
if (entityTouched) entitiesTouched += 1;
|
|
3827
3862
|
// Counted from what was written, not from the stored hash: a hash that moved while the
|
|
3828
3863
|
// product did not (a blanked map row, a change in how an item serialises) is not drift.
|