@deenruv/merchant-plugin 1.0.17-dev.17 → 1.0.17-dev.20
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/README.md +14 -0
- package/dist/plugin-server/api/platform-integration-admin-resolver.d.ts +20 -1
- package/dist/plugin-server/api/platform-integration-admin-resolver.js +44 -19
- package/dist/plugin-server/entities/merchant-sync-item.entity.d.ts +14 -0
- package/dist/plugin-server/entities/merchant-sync-item.entity.js +56 -0
- package/dist/plugin-server/entities/merchant-sync-run.entity.d.ts +19 -0
- package/dist/plugin-server/entities/merchant-sync-run.entity.js +72 -0
- package/dist/plugin-server/extensions/api-extensions.js +53 -2
- package/dist/plugin-server/index.js +10 -1
- package/dist/plugin-server/services/google-merchant-api.d.ts +48 -6
- package/dist/plugin-server/services/google-merchant-api.js +247 -32
- package/dist/plugin-server/services/google-platform-integration.service.d.ts +8 -7
- package/dist/plugin-server/services/google-platform-integration.service.js +79 -6
- package/dist/plugin-server/services/merchant-sync-history.service.d.ts +25 -0
- package/dist/plugin-server/services/merchant-sync-history.service.js +97 -0
- package/dist/plugin-server/services/platform-integration.service.d.ts +6 -2
- package/dist/plugin-server/services/platform-integration.service.js +53 -29
- package/dist/plugin-server/services/subscriber.service.d.ts +32 -4
- package/dist/plugin-server/services/subscriber.service.js +141 -23
- package/dist/plugin-server/ui/graphql/mutations.ts +7 -0
- package/dist/plugin-server/ui/graphql/queries.ts +99 -0
- package/dist/plugin-server/ui/pages/GooglePage.tsx +158 -16
- package/dist/plugin-ui/graphql/mutations.d.ts +5 -0
- package/dist/plugin-ui/graphql/mutations.js +6 -0
- package/dist/plugin-ui/graphql/queries.d.ts +53 -2
- package/dist/plugin-ui/graphql/queries.js +49 -0
- package/dist/plugin-ui/pages/GooglePage.js +51 -13
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -41,11 +41,22 @@ Google settings page requires:
|
|
|
41
41
|
- `credentials` — Google OAuth credential JSON for a service account or an
|
|
42
42
|
authorized user. Store and distribute this value as a secret.
|
|
43
43
|
- `brand` — the brand applied to exported product attributes.
|
|
44
|
+
- `contentLanguage` — two-letter product language code (defaults to `pl`).
|
|
45
|
+
- `feedLabel` — Merchant Center feed label (defaults to `PL`).
|
|
46
|
+
|
|
47
|
+
`publicBaseUrl` is supplied by the export strategy. It must produce absolute,
|
|
48
|
+
publicly reachable `http` or `https` product and image URLs. The example server
|
|
49
|
+
reads it from `PUBLIC_URL`, then `HOST_URL`, and only falls back to localhost in
|
|
50
|
+
local development.
|
|
44
51
|
|
|
45
52
|
Product inputs are written only to the configured data source. Merchant API
|
|
46
53
|
processing is asynchronous, so a processed product might not be readable for
|
|
47
54
|
several minutes after a successful write.
|
|
48
55
|
|
|
56
|
+
After upgrading an existing installation, generate and run a database migration
|
|
57
|
+
for the new `merchant_sync_run` and `merchant_sync_item` history tables before
|
|
58
|
+
starting workers.
|
|
59
|
+
|
|
49
60
|
#### Deployment prerequisites (documentation only)
|
|
50
61
|
|
|
51
62
|
An operator must complete the following outside this plugin and outside the
|
|
@@ -67,6 +78,9 @@ data sources, change Merchant Center configuration, or provision credentials:
|
|
|
67
78
|
- Google Merchant Center integration via Merchant API Products v1
|
|
68
79
|
- Facebook Commerce integration via Facebook Business SDK
|
|
69
80
|
- Per-platform settings storage and management
|
|
81
|
+
- Live account and data-source connection diagnostics
|
|
82
|
+
- Persistent synchronization run and per-product error history
|
|
83
|
+
- Retried, queued, idempotent Google product updates
|
|
70
84
|
- Bulk product sync to merchant platforms
|
|
71
85
|
- Orphan item cleanup for removed products
|
|
72
86
|
- `communicateID` custom field on ProductVariant for platform communication tracking
|
|
@@ -14,13 +14,32 @@ export declare class PlatformIntegrationAdminResolver {
|
|
|
14
14
|
getMerchantPlatformInfo(ctx: RequestContext, args: {
|
|
15
15
|
platform: string;
|
|
16
16
|
}): Promise<{
|
|
17
|
+
isValidConnection: boolean;
|
|
18
|
+
checkedAt: string;
|
|
19
|
+
connectionStatus: import("../services/google-merchant-api.js").GoogleMerchantConnectionStatus;
|
|
20
|
+
dataSourceVerified: boolean;
|
|
21
|
+
disapprovedProductsCount: number;
|
|
22
|
+
issues: import("../services/google-merchant-api.js").GoogleMerchantProductIssue[];
|
|
23
|
+
issuesCount: number;
|
|
24
|
+
lastError?: Omit<import("../services/google-merchant-api.js").NormalizedGoogleMerchantError, "status"> | undefined;
|
|
25
|
+
latencyMs: number;
|
|
26
|
+
productsCount: number;
|
|
27
|
+
}[] | {
|
|
17
28
|
productsCount: number;
|
|
18
29
|
isValidConnection: boolean;
|
|
19
30
|
}[]>;
|
|
31
|
+
sendAllProductsToMerchantPlatform(ctx: RequestContext, args: {
|
|
32
|
+
platform: string;
|
|
33
|
+
}): Promise<boolean>;
|
|
34
|
+
getMerchantSyncHistory(ctx: RequestContext, args: {
|
|
35
|
+
platform: string;
|
|
36
|
+
take?: number;
|
|
37
|
+
}): Promise<import("../entities/merchant-sync-run.entity.js").MerchantSyncRun[]>;
|
|
20
38
|
saveMerchantPlatformSettings(ctx: RequestContext, args: {
|
|
21
39
|
input: MerchantPlatformSettingsEntity;
|
|
22
|
-
}): Promise<MerchantPlatformSettingsEntity
|
|
40
|
+
}): Promise<MerchantPlatformSettingsEntity>;
|
|
23
41
|
removeOrphanItems(ctx: RequestContext, args: {
|
|
24
42
|
platform: string;
|
|
25
43
|
}): Promise<boolean>;
|
|
44
|
+
private redactCredentials;
|
|
26
45
|
}
|
|
@@ -26,28 +26,17 @@ let PlatformIntegrationAdminResolver = class PlatformIntegrationAdminResolver {
|
|
|
26
26
|
this.facebookPlatformIntegrationService = facebookPlatformIntegrationService;
|
|
27
27
|
this.platformIntegrationService = platformIntegrationService;
|
|
28
28
|
}
|
|
29
|
-
getMerchantPlatformSettings(ctx, args) {
|
|
30
|
-
|
|
29
|
+
async getMerchantPlatformSettings(ctx, args) {
|
|
30
|
+
const settings = await this.platformIntegrationService.getBaseSettings(ctx, args.platform);
|
|
31
|
+
return settings ? this.redactCredentials(settings) : null;
|
|
31
32
|
}
|
|
32
33
|
async getMerchantPlatformInfo(ctx, args) {
|
|
33
34
|
var _a;
|
|
34
35
|
const settings = await this.platformIntegrationService.getBaseSettings(ctx, args.platform);
|
|
35
36
|
if (args.platform === "google") {
|
|
36
|
-
|
|
37
|
-
if (settings) {
|
|
38
|
-
try {
|
|
39
|
-
this.googlePlatformIntegrationService.validateGoogleSettings(settings);
|
|
40
|
-
isValidConnection = true;
|
|
41
|
-
}
|
|
42
|
-
catch (_b) {
|
|
43
|
-
isValidConnection = false;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
37
|
+
const diagnostic = await this.googlePlatformIntegrationService.getConnectionDiagnostic(ctx);
|
|
46
38
|
return [
|
|
47
|
-
{
|
|
48
|
-
productsCount: 0,
|
|
49
|
-
isValidConnection,
|
|
50
|
-
},
|
|
39
|
+
Object.assign(Object.assign({}, diagnostic), { isValidConnection: diagnostic.connectionStatus === "CONNECTED" }),
|
|
51
40
|
];
|
|
52
41
|
}
|
|
53
42
|
if (args.platform === "facebook") {
|
|
@@ -60,20 +49,40 @@ let PlatformIntegrationAdminResolver = class PlatformIntegrationAdminResolver {
|
|
|
60
49
|
}
|
|
61
50
|
return [{ productsCount: 0, isValidConnection: false }];
|
|
62
51
|
}
|
|
52
|
+
async sendAllProductsToMerchantPlatform(ctx, args) {
|
|
53
|
+
return this.platformIntegrationService.enqueueFullSync(ctx, args.platform);
|
|
54
|
+
}
|
|
55
|
+
async getMerchantSyncHistory(ctx, args) {
|
|
56
|
+
return this.platformIntegrationService.getSyncHistory(ctx, args.platform, args.take);
|
|
57
|
+
}
|
|
63
58
|
async saveMerchantPlatformSettings(ctx, args) {
|
|
59
|
+
var _a, _b;
|
|
60
|
+
let entries = args.input.entries;
|
|
61
|
+
if (args.input.platform === "google" &&
|
|
62
|
+
((_a = entries.find((entry) => entry.key === "credentials")) === null || _a === void 0 ? void 0 : _a.value) === "") {
|
|
63
|
+
const existing = await this.platformIntegrationService.getBaseSettings(ctx, "google");
|
|
64
|
+
const existingCredentials = (_b = existing === null || existing === void 0 ? void 0 : existing.entries.find((entry) => entry.key === "credentials")) === null || _b === void 0 ? void 0 : _b.value;
|
|
65
|
+
if (existingCredentials) {
|
|
66
|
+
entries = entries.map((entry) => entry.key === "credentials"
|
|
67
|
+
? Object.assign(Object.assign({}, entry), { value: existingCredentials }) : entry);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
64
70
|
const settingsEntity = new platform_integration_settings_entity_js_1.MerchantPlatformSettingsEntity({
|
|
65
71
|
platform: args.input.platform,
|
|
66
|
-
entries:
|
|
72
|
+
entries: entries.map((entry) => new platform_integration_setting_entity_js_1.MerchantPlatformSetting(entry)),
|
|
67
73
|
});
|
|
68
74
|
if (settingsEntity.platform === "google") {
|
|
69
75
|
this.googlePlatformIntegrationService.validateGoogleSettings(settingsEntity);
|
|
70
76
|
}
|
|
71
77
|
const settings = await this.platformIntegrationService.savePlatformIntegrationSettings(ctx, settingsEntity);
|
|
72
|
-
return settings;
|
|
78
|
+
return settings ? this.redactCredentials(settings) : settings;
|
|
73
79
|
}
|
|
74
80
|
async removeOrphanItems(ctx, args) {
|
|
75
81
|
return this.platformIntegrationService.removeOrphanItems(ctx, args.platform);
|
|
76
82
|
}
|
|
83
|
+
redactCredentials(settings) {
|
|
84
|
+
return Object.assign(Object.assign({}, settings), { entries: settings.entries.map((entry) => entry.key === "credentials" ? Object.assign(Object.assign({}, entry), { value: "" }) : entry) });
|
|
85
|
+
}
|
|
77
86
|
};
|
|
78
87
|
exports.PlatformIntegrationAdminResolver = PlatformIntegrationAdminResolver;
|
|
79
88
|
__decorate([
|
|
@@ -82,7 +91,7 @@ __decorate([
|
|
|
82
91
|
__param(1, (0, graphql_1.Args)()),
|
|
83
92
|
__metadata("design:type", Function),
|
|
84
93
|
__metadata("design:paramtypes", [core_1.RequestContext, Object]),
|
|
85
|
-
__metadata("design:returntype",
|
|
94
|
+
__metadata("design:returntype", Promise)
|
|
86
95
|
], PlatformIntegrationAdminResolver.prototype, "getMerchantPlatformSettings", null);
|
|
87
96
|
__decorate([
|
|
88
97
|
(0, graphql_1.Query)(),
|
|
@@ -92,6 +101,22 @@ __decorate([
|
|
|
92
101
|
__metadata("design:paramtypes", [core_1.RequestContext, Object]),
|
|
93
102
|
__metadata("design:returntype", Promise)
|
|
94
103
|
], PlatformIntegrationAdminResolver.prototype, "getMerchantPlatformInfo", null);
|
|
104
|
+
__decorate([
|
|
105
|
+
(0, graphql_1.Mutation)(),
|
|
106
|
+
__param(0, (0, core_1.Ctx)()),
|
|
107
|
+
__param(1, (0, graphql_1.Args)()),
|
|
108
|
+
__metadata("design:type", Function),
|
|
109
|
+
__metadata("design:paramtypes", [core_1.RequestContext, Object]),
|
|
110
|
+
__metadata("design:returntype", Promise)
|
|
111
|
+
], PlatformIntegrationAdminResolver.prototype, "sendAllProductsToMerchantPlatform", null);
|
|
112
|
+
__decorate([
|
|
113
|
+
(0, graphql_1.Query)(),
|
|
114
|
+
__param(0, (0, core_1.Ctx)()),
|
|
115
|
+
__param(1, (0, graphql_1.Args)()),
|
|
116
|
+
__metadata("design:type", Function),
|
|
117
|
+
__metadata("design:paramtypes", [core_1.RequestContext, Object]),
|
|
118
|
+
__metadata("design:returntype", Promise)
|
|
119
|
+
], PlatformIntegrationAdminResolver.prototype, "getMerchantSyncHistory", null);
|
|
95
120
|
__decorate([
|
|
96
121
|
(0, graphql_1.Mutation)(),
|
|
97
122
|
__param(0, (0, core_1.Ctx)()),
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DeepPartial } from "@deenruv/common/lib/shared-types.js";
|
|
2
|
+
import { DeenruvEntity } from "@deenruv/core";
|
|
3
|
+
import type { Relation } from "typeorm";
|
|
4
|
+
import { MerchantSyncRun } from "./merchant-sync-run.entity.js";
|
|
5
|
+
export declare class MerchantSyncItem extends DeenruvEntity {
|
|
6
|
+
constructor(input?: DeepPartial<MerchantSyncItem>);
|
|
7
|
+
offerId: string;
|
|
8
|
+
operation: string;
|
|
9
|
+
status: string;
|
|
10
|
+
errorCode: string | null;
|
|
11
|
+
errorMessage: string | null;
|
|
12
|
+
attempts: number;
|
|
13
|
+
run: Relation<MerchantSyncRun>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MerchantSyncItem = void 0;
|
|
13
|
+
const core_1 = require("@deenruv/core");
|
|
14
|
+
const typeorm_1 = require("typeorm");
|
|
15
|
+
const merchant_sync_run_entity_js_1 = require("./merchant-sync-run.entity.js");
|
|
16
|
+
let MerchantSyncItem = class MerchantSyncItem extends core_1.DeenruvEntity {
|
|
17
|
+
constructor(input) {
|
|
18
|
+
super(input);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
exports.MerchantSyncItem = MerchantSyncItem;
|
|
22
|
+
__decorate([
|
|
23
|
+
(0, typeorm_1.Column)({ type: "varchar" }),
|
|
24
|
+
__metadata("design:type", String)
|
|
25
|
+
], MerchantSyncItem.prototype, "offerId", void 0);
|
|
26
|
+
__decorate([
|
|
27
|
+
(0, typeorm_1.Column)({ type: "varchar" }),
|
|
28
|
+
__metadata("design:type", String)
|
|
29
|
+
], MerchantSyncItem.prototype, "operation", void 0);
|
|
30
|
+
__decorate([
|
|
31
|
+
(0, typeorm_1.Column)({ type: "varchar" }),
|
|
32
|
+
__metadata("design:type", String)
|
|
33
|
+
], MerchantSyncItem.prototype, "status", void 0);
|
|
34
|
+
__decorate([
|
|
35
|
+
(0, typeorm_1.Column)({ nullable: true, type: "varchar" }),
|
|
36
|
+
__metadata("design:type", Object)
|
|
37
|
+
], MerchantSyncItem.prototype, "errorCode", void 0);
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, typeorm_1.Column)({ type: "text", nullable: true }),
|
|
40
|
+
__metadata("design:type", Object)
|
|
41
|
+
], MerchantSyncItem.prototype, "errorMessage", void 0);
|
|
42
|
+
__decorate([
|
|
43
|
+
(0, typeorm_1.Column)({ default: 1, type: "int" }),
|
|
44
|
+
__metadata("design:type", Number)
|
|
45
|
+
], MerchantSyncItem.prototype, "attempts", void 0);
|
|
46
|
+
__decorate([
|
|
47
|
+
(0, typeorm_1.ManyToOne)(() => merchant_sync_run_entity_js_1.MerchantSyncRun, (run) => run.items, {
|
|
48
|
+
onDelete: "CASCADE",
|
|
49
|
+
}),
|
|
50
|
+
__metadata("design:type", Object)
|
|
51
|
+
], MerchantSyncItem.prototype, "run", void 0);
|
|
52
|
+
exports.MerchantSyncItem = MerchantSyncItem = __decorate([
|
|
53
|
+
(0, typeorm_1.Entity)(),
|
|
54
|
+
(0, typeorm_1.Index)(["offerId", "createdAt"]),
|
|
55
|
+
__metadata("design:paramtypes", [Object])
|
|
56
|
+
], MerchantSyncItem);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DeepPartial } from "@deenruv/common/lib/shared-types.js";
|
|
2
|
+
import { DeenruvEntity } from "@deenruv/core";
|
|
3
|
+
import type { Relation } from "typeorm";
|
|
4
|
+
import { MerchantSyncItem } from "./merchant-sync-item.entity.js";
|
|
5
|
+
export type MerchantSyncRunStatus = "PENDING" | "RUNNING" | "SUCCESS" | "PARTIAL" | "FAILED";
|
|
6
|
+
export declare class MerchantSyncRun extends DeenruvEntity {
|
|
7
|
+
constructor(input?: DeepPartial<MerchantSyncRun>);
|
|
8
|
+
platform: string;
|
|
9
|
+
trigger: string;
|
|
10
|
+
status: MerchantSyncRunStatus;
|
|
11
|
+
jobId: string | null;
|
|
12
|
+
total: number;
|
|
13
|
+
succeeded: number;
|
|
14
|
+
failed: number;
|
|
15
|
+
errorSummary: string | null;
|
|
16
|
+
startedAt: Date | null;
|
|
17
|
+
finishedAt: Date | null;
|
|
18
|
+
items: Relation<MerchantSyncItem[]>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MerchantSyncRun = void 0;
|
|
13
|
+
const core_1 = require("@deenruv/core");
|
|
14
|
+
const typeorm_1 = require("typeorm");
|
|
15
|
+
const merchant_sync_item_entity_js_1 = require("./merchant-sync-item.entity.js");
|
|
16
|
+
let MerchantSyncRun = class MerchantSyncRun extends core_1.DeenruvEntity {
|
|
17
|
+
constructor(input) {
|
|
18
|
+
super(input);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
exports.MerchantSyncRun = MerchantSyncRun;
|
|
22
|
+
__decorate([
|
|
23
|
+
(0, typeorm_1.Column)({ type: "varchar" }),
|
|
24
|
+
__metadata("design:type", String)
|
|
25
|
+
], MerchantSyncRun.prototype, "platform", void 0);
|
|
26
|
+
__decorate([
|
|
27
|
+
(0, typeorm_1.Column)({ type: "varchar" }),
|
|
28
|
+
__metadata("design:type", String)
|
|
29
|
+
], MerchantSyncRun.prototype, "trigger", void 0);
|
|
30
|
+
__decorate([
|
|
31
|
+
(0, typeorm_1.Column)({ default: "PENDING", type: "varchar" }),
|
|
32
|
+
__metadata("design:type", String)
|
|
33
|
+
], MerchantSyncRun.prototype, "status", void 0);
|
|
34
|
+
__decorate([
|
|
35
|
+
(0, typeorm_1.Column)({ nullable: true, type: "varchar" }),
|
|
36
|
+
__metadata("design:type", Object)
|
|
37
|
+
], MerchantSyncRun.prototype, "jobId", void 0);
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, typeorm_1.Column)({ default: 0, type: "int" }),
|
|
40
|
+
__metadata("design:type", Number)
|
|
41
|
+
], MerchantSyncRun.prototype, "total", void 0);
|
|
42
|
+
__decorate([
|
|
43
|
+
(0, typeorm_1.Column)({ default: 0, type: "int" }),
|
|
44
|
+
__metadata("design:type", Number)
|
|
45
|
+
], MerchantSyncRun.prototype, "succeeded", void 0);
|
|
46
|
+
__decorate([
|
|
47
|
+
(0, typeorm_1.Column)({ default: 0, type: "int" }),
|
|
48
|
+
__metadata("design:type", Number)
|
|
49
|
+
], MerchantSyncRun.prototype, "failed", void 0);
|
|
50
|
+
__decorate([
|
|
51
|
+
(0, typeorm_1.Column)({ type: "text", nullable: true }),
|
|
52
|
+
__metadata("design:type", Object)
|
|
53
|
+
], MerchantSyncRun.prototype, "errorSummary", void 0);
|
|
54
|
+
__decorate([
|
|
55
|
+
(0, typeorm_1.Column)({ type: "timestamp", nullable: true }),
|
|
56
|
+
__metadata("design:type", Object)
|
|
57
|
+
], MerchantSyncRun.prototype, "startedAt", void 0);
|
|
58
|
+
__decorate([
|
|
59
|
+
(0, typeorm_1.Column)({ type: "timestamp", nullable: true }),
|
|
60
|
+
__metadata("design:type", Object)
|
|
61
|
+
], MerchantSyncRun.prototype, "finishedAt", void 0);
|
|
62
|
+
__decorate([
|
|
63
|
+
(0, typeorm_1.OneToMany)(() => merchant_sync_item_entity_js_1.MerchantSyncItem, (item) => item.run, {
|
|
64
|
+
cascade: true,
|
|
65
|
+
}),
|
|
66
|
+
__metadata("design:type", Object)
|
|
67
|
+
], MerchantSyncRun.prototype, "items", void 0);
|
|
68
|
+
exports.MerchantSyncRun = MerchantSyncRun = __decorate([
|
|
69
|
+
(0, typeorm_1.Entity)(),
|
|
70
|
+
(0, typeorm_1.Index)(["platform", "createdAt"]),
|
|
71
|
+
__metadata("design:paramtypes", [Object])
|
|
72
|
+
], MerchantSyncRun);
|
|
@@ -11,12 +11,59 @@ const base = (0, graphql_tag_1.gql) `
|
|
|
11
11
|
type MerchantPlatformSettingsEntity implements Node {
|
|
12
12
|
id: ID!
|
|
13
13
|
platform: String!
|
|
14
|
-
entries: [MerchantPlatformSetting!]
|
|
14
|
+
entries: [MerchantPlatformSetting!]!
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
type MerchantPlatformInfo {
|
|
18
18
|
isValidConnection: Boolean!
|
|
19
19
|
productsCount: Int!
|
|
20
|
+
connectionStatus: String
|
|
21
|
+
dataSourceVerified: Boolean
|
|
22
|
+
checkedAt: DateTime
|
|
23
|
+
latencyMs: Int
|
|
24
|
+
disapprovedProductsCount: Int
|
|
25
|
+
issuesCount: Int
|
|
26
|
+
lastError: MerchantPlatformError
|
|
27
|
+
issues: [MerchantProductIssue!]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type MerchantPlatformError {
|
|
31
|
+
code: String!
|
|
32
|
+
message: String!
|
|
33
|
+
retryable: Boolean!
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type MerchantProductIssue {
|
|
37
|
+
offerId: String!
|
|
38
|
+
code: String!
|
|
39
|
+
description: String!
|
|
40
|
+
severity: String!
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type MerchantSyncItem {
|
|
44
|
+
id: ID!
|
|
45
|
+
offerId: String!
|
|
46
|
+
operation: String!
|
|
47
|
+
status: String!
|
|
48
|
+
errorCode: String
|
|
49
|
+
errorMessage: String
|
|
50
|
+
attempts: Int!
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type MerchantSyncRun {
|
|
54
|
+
id: ID!
|
|
55
|
+
createdAt: DateTime!
|
|
56
|
+
platform: String!
|
|
57
|
+
trigger: String!
|
|
58
|
+
status: String!
|
|
59
|
+
jobId: String
|
|
60
|
+
total: Int!
|
|
61
|
+
succeeded: Int!
|
|
62
|
+
failed: Int!
|
|
63
|
+
errorSummary: String
|
|
64
|
+
startedAt: DateTime
|
|
65
|
+
finishedAt: DateTime
|
|
66
|
+
items: [MerchantSyncItem!]!
|
|
20
67
|
}
|
|
21
68
|
`;
|
|
22
69
|
exports.adminApiExtensions = (0, graphql_tag_1.gql) `
|
|
@@ -29,7 +76,7 @@ exports.adminApiExtensions = (0, graphql_tag_1.gql) `
|
|
|
29
76
|
|
|
30
77
|
input SaveMerchantPlatformSettingInput {
|
|
31
78
|
platform: String!
|
|
32
|
-
entries: [MerchantPlatformSettingInput!]
|
|
79
|
+
entries: [MerchantPlatformSettingInput!]!
|
|
33
80
|
}
|
|
34
81
|
|
|
35
82
|
extend type Mutation {
|
|
@@ -45,5 +92,9 @@ exports.adminApiExtensions = (0, graphql_tag_1.gql) `
|
|
|
45
92
|
platform: String!
|
|
46
93
|
): MerchantPlatformSettingsEntity
|
|
47
94
|
getMerchantPlatformInfo(platform: String!): [MerchantPlatformInfo!]
|
|
95
|
+
getMerchantSyncHistory(
|
|
96
|
+
platform: String!
|
|
97
|
+
take: Int
|
|
98
|
+
): [MerchantSyncRun!]!
|
|
48
99
|
}
|
|
49
100
|
`;
|
|
@@ -16,10 +16,13 @@ const platform_integration_admin_resolver_js_1 = require("./api/platform-integra
|
|
|
16
16
|
const constants_js_1 = require("./constants.js");
|
|
17
17
|
const platform_integration_setting_entity_js_1 = require("./entities/platform-integration-setting.entity.js");
|
|
18
18
|
const platform_integration_settings_entity_js_1 = require("./entities/platform-integration-settings.entity.js");
|
|
19
|
+
const merchant_sync_item_entity_js_1 = require("./entities/merchant-sync-item.entity.js");
|
|
20
|
+
const merchant_sync_run_entity_js_1 = require("./entities/merchant-sync-run.entity.js");
|
|
19
21
|
const api_extensions_js_1 = require("./extensions/api-extensions.js");
|
|
20
22
|
const facebook_platform_integration_service_js_1 = require("./services/facebook-platform-integration.service.js");
|
|
21
23
|
const google_platform_integration_service_js_1 = require("./services/google-platform-integration.service.js");
|
|
22
24
|
const merchant_strategy_service_js_1 = require("./services/merchant-strategy.service.js");
|
|
25
|
+
const merchant_sync_history_service_js_1 = require("./services/merchant-sync-history.service.js");
|
|
23
26
|
const platform_integration_service_js_1 = require("./services/platform-integration.service.js");
|
|
24
27
|
const subscriber_service_js_1 = require("./services/subscriber.service.js");
|
|
25
28
|
let MerchantPlugin = class MerchantPlugin {
|
|
@@ -56,7 +59,12 @@ exports.MerchantPlugin = MerchantPlugin = __decorate([
|
|
|
56
59
|
(0, core_1.DeenruvPlugin)({
|
|
57
60
|
compatibility: "^2.0.0",
|
|
58
61
|
imports: [core_1.PluginCommonModule],
|
|
59
|
-
entities: [
|
|
62
|
+
entities: [
|
|
63
|
+
platform_integration_setting_entity_js_1.MerchantPlatformSetting,
|
|
64
|
+
platform_integration_settings_entity_js_1.MerchantPlatformSettingsEntity,
|
|
65
|
+
merchant_sync_run_entity_js_1.MerchantSyncRun,
|
|
66
|
+
merchant_sync_item_entity_js_1.MerchantSyncItem,
|
|
67
|
+
],
|
|
60
68
|
shopApiExtensions: {},
|
|
61
69
|
adminApiExtensions: {
|
|
62
70
|
schema: api_extensions_js_1.adminApiExtensions,
|
|
@@ -68,6 +76,7 @@ exports.MerchantPlugin = MerchantPlugin = __decorate([
|
|
|
68
76
|
useFactory: () => MerchantPlugin.options,
|
|
69
77
|
},
|
|
70
78
|
merchant_strategy_service_js_1.MerchantStrategyService,
|
|
79
|
+
merchant_sync_history_service_js_1.MerchantSyncHistoryService,
|
|
71
80
|
platform_integration_service_js_1.PlatformIntegrationService,
|
|
72
81
|
google_platform_integration_service_js_1.GooglePlatformIntegrationService,
|
|
73
82
|
facebook_platform_integration_service_js_1.FacebookPlatformIntegrationService,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { v1 } from "@google-shopping/products";
|
|
2
|
+
import { v1 as dataSourcesV1 } from "@google-shopping/datasources";
|
|
2
3
|
import type { protos } from "@google-shopping/products";
|
|
3
4
|
import type { GoogleProcessedProduct, GoogleProduct, GoogleProductInput, RemoteProduct } from "../types.js";
|
|
4
5
|
export declare const GOOGLE_CONTENT_LANGUAGE = "pl";
|
|
@@ -12,8 +13,11 @@ export type GoogleMerchantSettings = {
|
|
|
12
13
|
brand: string;
|
|
13
14
|
credentials: GoogleMerchantCredentials;
|
|
14
15
|
dataSource: string;
|
|
16
|
+
contentLanguage: string;
|
|
17
|
+
feedLabel: string;
|
|
15
18
|
};
|
|
16
19
|
export type GoogleMerchantClients = {
|
|
20
|
+
dataSources: dataSourcesV1.DataSourcesServiceClient;
|
|
17
21
|
productInputs: v1.ProductInputsServiceClient;
|
|
18
22
|
products: v1.ProductsServiceClient;
|
|
19
23
|
};
|
|
@@ -35,10 +39,12 @@ export type GoogleWriteOperation = {
|
|
|
35
39
|
request: DeleteProductInputRequest;
|
|
36
40
|
};
|
|
37
41
|
export type MerchantOperationResult<T> = {
|
|
42
|
+
attempts: number;
|
|
38
43
|
index: number;
|
|
39
44
|
item: T;
|
|
40
45
|
status: "success";
|
|
41
46
|
} | {
|
|
47
|
+
attempts: number;
|
|
42
48
|
error: unknown;
|
|
43
49
|
index: number;
|
|
44
50
|
item: T;
|
|
@@ -59,26 +65,62 @@ export interface GoogleProductInputsWriter {
|
|
|
59
65
|
export interface GoogleProductsReader {
|
|
60
66
|
listProductsAsync(request: ListProductsRequest): AsyncIterable<GoogleProcessedProduct>;
|
|
61
67
|
}
|
|
68
|
+
export interface GoogleDataSourcesReader {
|
|
69
|
+
getDataSource(request: {
|
|
70
|
+
name: string;
|
|
71
|
+
}): Promise<unknown>;
|
|
72
|
+
}
|
|
73
|
+
export type GoogleMerchantRetryOptions = {
|
|
74
|
+
delay?: (attempt: number) => Promise<void>;
|
|
75
|
+
maxAttempts?: number;
|
|
76
|
+
};
|
|
77
|
+
export type GoogleMerchantConnectionStatus = "CONNECTED" | "NOT_CONFIGURED" | "INVALID_CONFIGURATION" | "DATA_SOURCE_NOT_FOUND" | "AUTHENTICATION_FAILED" | "PERMISSION_DENIED" | "UNAVAILABLE" | "ERROR";
|
|
78
|
+
export type GoogleMerchantProductIssue = {
|
|
79
|
+
code: string;
|
|
80
|
+
description: string;
|
|
81
|
+
offerId: string;
|
|
82
|
+
severity: string;
|
|
83
|
+
};
|
|
84
|
+
export type GoogleMerchantConnectionDiagnostic = {
|
|
85
|
+
checkedAt: string;
|
|
86
|
+
connectionStatus: GoogleMerchantConnectionStatus;
|
|
87
|
+
dataSourceVerified: boolean;
|
|
88
|
+
disapprovedProductsCount: number;
|
|
89
|
+
issues: GoogleMerchantProductIssue[];
|
|
90
|
+
issuesCount: number;
|
|
91
|
+
lastError?: Omit<NormalizedGoogleMerchantError, "status">;
|
|
92
|
+
latencyMs: number;
|
|
93
|
+
productsCount: number;
|
|
94
|
+
};
|
|
95
|
+
export type NormalizedGoogleMerchantError = {
|
|
96
|
+
code: string;
|
|
97
|
+
message: string;
|
|
98
|
+
retryable: boolean;
|
|
99
|
+
status: GoogleMerchantConnectionStatus;
|
|
100
|
+
};
|
|
62
101
|
type SettingEntry = {
|
|
63
102
|
key: string;
|
|
64
103
|
value: string;
|
|
65
104
|
};
|
|
105
|
+
export declare function normalizeGoogleMerchantError(error: unknown): NormalizedGoogleMerchantError;
|
|
66
106
|
export declare function parseGoogleCredentials(rawCredentials: string): GoogleMerchantCredentials;
|
|
67
107
|
export declare function normalizeMerchantId(rawMerchantId: string): string;
|
|
68
108
|
export declare function normalizeDataSource(rawDataSource: string, merchantId: string): string;
|
|
69
109
|
export declare function parseGoogleMerchantSettings(entries: readonly SettingEntry[]): GoogleMerchantSettings;
|
|
70
110
|
export declare function createGoogleMerchantClients(credentials: GoogleMerchantCredentials): GoogleMerchantClients;
|
|
71
|
-
export declare function buildGoogleProductIdentifier(offerId: string): string;
|
|
72
|
-
export declare function buildGoogleProductName(accountId: string, offerId: string): string;
|
|
73
|
-
export declare function buildGoogleProductInputName(accountId: string, offerId: string): string;
|
|
74
|
-
export declare function toGoogleProductInput(product: GoogleProduct, brand: string): GoogleProductInput;
|
|
111
|
+
export declare function buildGoogleProductIdentifier(offerId: string, contentLanguage?: string, feedLabel?: string): string;
|
|
112
|
+
export declare function buildGoogleProductName(accountId: string, offerId: string, contentLanguage?: string, feedLabel?: string): string;
|
|
113
|
+
export declare function buildGoogleProductInputName(accountId: string, offerId: string, contentLanguage?: string, feedLabel?: string): string;
|
|
114
|
+
export declare function toGoogleProductInput(product: GoogleProduct, brand: string, contentLanguage?: string, feedLabel?: string): GoogleProductInput;
|
|
115
|
+
export declare function validateGoogleProductUrls(product: GoogleProduct): void;
|
|
75
116
|
export declare function buildGoogleUpdateMask(productInput: GoogleProductInput): protos.google.protobuf.IFieldMask;
|
|
76
117
|
export declare function createGoogleInsertOperation(product: GoogleProduct, settings: GoogleMerchantSettings): GoogleWriteOperation;
|
|
77
118
|
export declare function createGoogleUpdateOperation(product: GoogleProduct, settings: GoogleMerchantSettings): GoogleWriteOperation;
|
|
78
119
|
export declare function createGoogleDeleteOperation(communicateID: string, settings: GoogleMerchantSettings): GoogleWriteOperation;
|
|
79
|
-
export declare function runBoundedMerchantOperations<T>(items: readonly T[], operation: (item: T, index: number) => Promise<void>, concurrency?: number): Promise<Array<MerchantOperationResult<T>>>;
|
|
80
|
-
export declare function executeGoogleWriteOperations(client: GoogleProductInputsWriter, operations: readonly GoogleWriteOperation[], concurrency?: number): Promise<Array<MerchantOperationResult<GoogleWriteOperation>>>;
|
|
120
|
+
export declare function runBoundedMerchantOperations<T>(items: readonly T[], operation: (item: T, index: number) => Promise<number | void>, concurrency?: number): Promise<Array<MerchantOperationResult<T>>>;
|
|
121
|
+
export declare function executeGoogleWriteOperations(client: GoogleProductInputsWriter, operations: readonly GoogleWriteOperation[], concurrency?: number, retryOptions?: GoogleMerchantRetryOptions): Promise<Array<MerchantOperationResult<GoogleWriteOperation>>>;
|
|
81
122
|
export declare function summarizeMerchantOperations<T>(results: Array<MerchantOperationResult<T>>): MerchantOperationSummary<T>;
|
|
82
123
|
export declare function collectGoogleProductsForDataSource(client: GoogleProductsReader, accountId: string, dataSource: string): Promise<RemoteProduct[]>;
|
|
124
|
+
export declare function diagnoseGoogleMerchantConnection(client: GoogleProductsReader, settings: Pick<GoogleMerchantSettings, "accountId" | "dataSource">, dataSourcesClient?: GoogleDataSourcesReader): Promise<GoogleMerchantConnectionDiagnostic>;
|
|
83
125
|
export declare function selectRemoteOrphanProducts(remoteProducts: readonly RemoteProduct[], localProducts: readonly Pick<GoogleProduct, "communicateID">[]): RemoteProduct[];
|
|
84
126
|
export {};
|