@bprotsyk/aso-core 2.1.142 → 2.1.180

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/lib/app/app.d.ts CHANGED
@@ -1,5 +1,13 @@
1
1
  import { AppType } from "./app-type";
2
2
  import mongoose, { Document } from "mongoose";
3
+ export interface IAppsflyerPostback {
4
+ campaign_id: number;
5
+ id: number;
6
+ method: "GET" | "POST";
7
+ statuses: string[];
8
+ url: string;
9
+ notes?: string;
10
+ }
3
11
  export interface IApp extends Document {
4
12
  id: number;
5
13
  enabled: boolean;
@@ -34,6 +42,7 @@ export interface IApp extends Document {
34
42
  ech?: boolean;
35
43
  imageFormat: EImageFormat;
36
44
  policyPath: string;
45
+ postbacks?: IAppsflyerPostback[];
37
46
  }
38
47
  export declare enum EImageFormat {
39
48
  PNG = "png",
@@ -211,6 +220,28 @@ export declare const AppSchema: mongoose.Schema<any, mongoose.Model<any, any, an
211
220
  integrationVersion: IntegrationVersion;
212
221
  removeInfo: any;
213
222
  policyPath: string;
223
+ postbacks: mongoose.Types.DocumentArray<{
224
+ id: number;
225
+ campaign_id: number;
226
+ method: "GET" | "POST";
227
+ statuses: string[];
228
+ url: string;
229
+ notes?: string | null | undefined;
230
+ }, mongoose.Types.Subdocument<mongoose.mongo.BSON.ObjectId, any, {
231
+ id: number;
232
+ campaign_id: number;
233
+ method: "GET" | "POST";
234
+ statuses: string[];
235
+ url: string;
236
+ notes?: string | null | undefined;
237
+ }> & {
238
+ id: number;
239
+ campaign_id: number;
240
+ method: "GET" | "POST";
241
+ statuses: string[];
242
+ url: string;
243
+ notes?: string | null | undefined;
244
+ }>;
214
245
  name?: string | null | undefined;
215
246
  pushesEnabled?: boolean | null | undefined;
216
247
  publicationHistory?: any;
@@ -255,6 +286,28 @@ export declare const AppSchema: mongoose.Schema<any, mongoose.Model<any, any, an
255
286
  integrationVersion: IntegrationVersion;
256
287
  removeInfo: any;
257
288
  policyPath: string;
289
+ postbacks: mongoose.Types.DocumentArray<{
290
+ id: number;
291
+ campaign_id: number;
292
+ method: "GET" | "POST";
293
+ statuses: string[];
294
+ url: string;
295
+ notes?: string | null | undefined;
296
+ }, mongoose.Types.Subdocument<mongoose.mongo.BSON.ObjectId, any, {
297
+ id: number;
298
+ campaign_id: number;
299
+ method: "GET" | "POST";
300
+ statuses: string[];
301
+ url: string;
302
+ notes?: string | null | undefined;
303
+ }> & {
304
+ id: number;
305
+ campaign_id: number;
306
+ method: "GET" | "POST";
307
+ statuses: string[];
308
+ url: string;
309
+ notes?: string | null | undefined;
310
+ }>;
258
311
  name?: string | null | undefined;
259
312
  pushesEnabled?: boolean | null | undefined;
260
313
  publicationHistory?: any;
@@ -299,6 +352,28 @@ export declare const AppSchema: mongoose.Schema<any, mongoose.Model<any, any, an
299
352
  integrationVersion: IntegrationVersion;
300
353
  removeInfo: any;
301
354
  policyPath: string;
355
+ postbacks: mongoose.Types.DocumentArray<{
356
+ id: number;
357
+ campaign_id: number;
358
+ method: "GET" | "POST";
359
+ statuses: string[];
360
+ url: string;
361
+ notes?: string | null | undefined;
362
+ }, mongoose.Types.Subdocument<mongoose.mongo.BSON.ObjectId, any, {
363
+ id: number;
364
+ campaign_id: number;
365
+ method: "GET" | "POST";
366
+ statuses: string[];
367
+ url: string;
368
+ notes?: string | null | undefined;
369
+ }> & {
370
+ id: number;
371
+ campaign_id: number;
372
+ method: "GET" | "POST";
373
+ statuses: string[];
374
+ url: string;
375
+ notes?: string | null | undefined;
376
+ }>;
302
377
  name?: string | null | undefined;
303
378
  pushesEnabled?: boolean | null | undefined;
304
379
  publicationHistory?: any;
package/lib/app/app.js CHANGED
@@ -215,5 +215,32 @@ exports.AppSchema = new mongoose_1.Schema({
215
215
  policyPath: {
216
216
  type: String,
217
217
  default: "none"
218
- }
218
+ },
219
+ postbacks: [{
220
+ campaign_id: {
221
+ type: Number,
222
+ required: true
223
+ },
224
+ id: {
225
+ type: Number,
226
+ required: true
227
+ },
228
+ method: {
229
+ type: String,
230
+ enum: ["GET", "POST"],
231
+ required: true
232
+ },
233
+ statuses: [{
234
+ type: String,
235
+ required: true
236
+ }],
237
+ url: {
238
+ type: String,
239
+ required: true
240
+ },
241
+ notes: {
242
+ type: String,
243
+ required: false
244
+ }
245
+ }]
219
246
  });
package/lib/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { IPush } from "./general/push";
2
2
  export { IOffer, IPartner, IOfferType } from "./offers/offer";
3
3
  export { IOffersSection, OffersSectionSchema, DefaultSectionId } from "./offers/section";
4
4
  export { IAppOffersSection, ISectionsList, SectionsListSchema, IOfferState } from "./offers/list";
5
- export { IAdjustEventIds, IntegrationVersion, IApp, AppSchema, PlugType, IAppKeitaroData, IExternalParams, IPlatformParams, EPlatform, AppStatus, IPublicationHistory, IRemovalInfo, EDirectType } from "./app/app";
5
+ export { IAdjustEventIds, IntegrationVersion, IApp, AppSchema, PlugType, IAppKeitaroData, IExternalParams, IPlatformParams, EPlatform, AppStatus, IPublicationHistory, IRemovalInfo, EDirectType, IAppsflyerPostback } from "./app/app";
6
6
  export { IAppListItem } from "./app/app-list-item";
7
7
  export { AppType } from "./app/app-type";
8
8
  export { AlternativeLayoutType, AlternativeSourceType, AlternativeLogicType, AlternativeNetworkTool, AlternativeStorageType, AlternativeNavigation, AlternativeOnBackPressed, AlternativeOnActivityResult, IAppIntegration as IFlashIntegration } from "./app/app-integration";
@@ -0,0 +1,52 @@
1
+ import { KeitaroClicksInterval } from './keitaro-clicks';
2
+ export declare enum KeitaroOperator {
3
+ EQUALS = "EQUALS",
4
+ NOT_EQUAL = "NOT_EQUAL",
5
+ EQUALS_OR_GREATER_THAN = "EQUALS_OR_GREATER_THAN",
6
+ EQUALS_OR_LESS_THAN = "EQUALS_OR_LESS_THAN",
7
+ GREATER_THAN = "GREATER_THAN",
8
+ LESS_THAN = "LESS_THAN",
9
+ MATCH_REGEXP = "MATCH_REGEXP",
10
+ NOT_MATCH_REGEXP = "NOT_MATCH_REGEXP",
11
+ BEGINS_WITH = "BEGINS_WITH",
12
+ ENDS_WITH = "ENDS_WITH",
13
+ CONTAINS = "CONTAINS",
14
+ NOT_CONTAIN = "NOT_CONTAIN",
15
+ IN_LIST = "IN_LIST",
16
+ NOT_IN_LIST = "NOT_IN_LIST",
17
+ BETWEEN = "BETWEEN",
18
+ IS_SET = "IS_SET",
19
+ IS_NOT_SET = "IS_NOT_SET",
20
+ IS_TRUE = "IS_TRUE",
21
+ IS_FALSE = "IS_FALSE",
22
+ HAS_LABEL = "HAS_LABEL",
23
+ NOT_HAS_LABEL = "NOT_HAS_LABEL"
24
+ }
25
+ export interface IKeitaroConversionRangeRequest {
26
+ from?: string;
27
+ to?: string;
28
+ timezone?: string;
29
+ interval?: KeitaroClicksInterval;
30
+ }
31
+ export interface IKeitaroConversionFilterRequest {
32
+ name: string;
33
+ operator: KeitaroOperator;
34
+ expression?: string | number | Array<string | number>;
35
+ }
36
+ export interface IKeitaroConversionSortRequest {
37
+ name: string;
38
+ order: 'ASC' | 'DESC';
39
+ }
40
+ export interface IKeitaroConversionsRequest {
41
+ range: IKeitaroConversionRangeRequest;
42
+ limit?: number;
43
+ offset?: number;
44
+ columns?: string[];
45
+ filters?: IKeitaroConversionFilterRequest[];
46
+ sort?: IKeitaroConversionSortRequest[];
47
+ }
48
+ export interface IKeitaroConversionsResponse {
49
+ rows: any[];
50
+ total: number;
51
+ meta: string[];
52
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KeitaroOperator = void 0;
4
+ var KeitaroOperator;
5
+ (function (KeitaroOperator) {
6
+ KeitaroOperator["EQUALS"] = "EQUALS";
7
+ KeitaroOperator["NOT_EQUAL"] = "NOT_EQUAL";
8
+ KeitaroOperator["EQUALS_OR_GREATER_THAN"] = "EQUALS_OR_GREATER_THAN";
9
+ KeitaroOperator["EQUALS_OR_LESS_THAN"] = "EQUALS_OR_LESS_THAN";
10
+ KeitaroOperator["GREATER_THAN"] = "GREATER_THAN";
11
+ KeitaroOperator["LESS_THAN"] = "LESS_THAN";
12
+ KeitaroOperator["MATCH_REGEXP"] = "MATCH_REGEXP";
13
+ KeitaroOperator["NOT_MATCH_REGEXP"] = "NOT_MATCH_REGEXP";
14
+ KeitaroOperator["BEGINS_WITH"] = "BEGINS_WITH";
15
+ KeitaroOperator["ENDS_WITH"] = "ENDS_WITH";
16
+ KeitaroOperator["CONTAINS"] = "CONTAINS";
17
+ KeitaroOperator["NOT_CONTAIN"] = "NOT_CONTAIN";
18
+ KeitaroOperator["IN_LIST"] = "IN_LIST";
19
+ KeitaroOperator["NOT_IN_LIST"] = "NOT_IN_LIST";
20
+ KeitaroOperator["BETWEEN"] = "BETWEEN";
21
+ KeitaroOperator["IS_SET"] = "IS_SET";
22
+ KeitaroOperator["IS_NOT_SET"] = "IS_NOT_SET";
23
+ KeitaroOperator["IS_TRUE"] = "IS_TRUE";
24
+ KeitaroOperator["IS_FALSE"] = "IS_FALSE";
25
+ KeitaroOperator["HAS_LABEL"] = "HAS_LABEL";
26
+ KeitaroOperator["NOT_HAS_LABEL"] = "NOT_HAS_LABEL";
27
+ })(KeitaroOperator = exports.KeitaroOperator || (exports.KeitaroOperator = {}));
@@ -0,0 +1,2 @@
1
+ import { ConversionComparison } from '../utils/comparing';
2
+ export declare function displayComparisonResults(comparison: ConversionComparison): void;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.displayComparisonResults = void 0;
4
+ function displayComparisonResults(comparison) {
5
+ const isValidStatus = (status) => ['sale', 'rebill'].includes(status);
6
+ let wpTotalSum = comparison.wpConversions
7
+ .reduce((sum, conv) => sum + conv.sum, 0);
8
+ let keitaroTotalSum = comparison.keitaroConversions
9
+ .filter(conv => isValidStatus(conv.status))
10
+ .reduce((sum, conv) => sum + (parseFloat(conv.revenue) || 0), 0);
11
+ // Get all Keitaro rejected conversions
12
+ const allKeitaroRejected = [
13
+ ...comparison.rejected.keitaro,
14
+ ...comparison.matches
15
+ .filter(match => match.keitaro.status === 'rejected')
16
+ .map(match => match.keitaro)
17
+ ];
18
+ // Group mismatches by project/offer
19
+ const wpMismatchesByProject = new Map();
20
+ const keitaroMismatchesByOffer = new Map();
21
+ const rejectedByOffer = new Map();
22
+ comparison.mismatches.onlyInWP.forEach(conv => {
23
+ if (!wpMismatchesByProject.has(conv.project)) {
24
+ wpMismatchesByProject.set(conv.project, { count: 0, sum: 0, conversions: [] });
25
+ }
26
+ const projectStats = wpMismatchesByProject.get(conv.project);
27
+ projectStats.count++;
28
+ projectStats.sum += conv.sum;
29
+ projectStats.conversions.push(conv);
30
+ });
31
+ // Include all conversions in mismatches, including rejected ones
32
+ [...comparison.mismatches.onlyInKeitaro, ...allKeitaroRejected].forEach(conv => {
33
+ if (!keitaroMismatchesByOffer.has(conv.offer)) {
34
+ keitaroMismatchesByOffer.set(conv.offer, { count: 0, sum: 0, conversions: [] });
35
+ }
36
+ const offerStats = keitaroMismatchesByOffer.get(conv.offer);
37
+ offerStats.count++;
38
+ offerStats.sum += parseFloat(conv.revenue) || 0;
39
+ offerStats.conversions.push(conv);
40
+ });
41
+ // Group rejected conversions by offer
42
+ allKeitaroRejected.forEach(conv => {
43
+ if (!rejectedByOffer.has(conv.offer)) {
44
+ rejectedByOffer.set(conv.offer, { count: 0, sum: 0, conversions: [] });
45
+ }
46
+ const offerStats = rejectedByOffer.get(conv.offer);
47
+ offerStats.count++;
48
+ offerStats.sum += parseFloat(conv.revenue) || 0;
49
+ offerStats.conversions.push(conv);
50
+ });
51
+ console.log('\n\x1b[1mЗагальна статистика:\x1b[0m');
52
+ console.log(`Всього конверсій у WP: ${comparison.wpConversions.length} (Сума: \x1b[33m$${wpTotalSum.toFixed(2)}\x1b[0m)`);
53
+ console.log(`Всього конверсій у Keitaro: ${comparison.keitaroConversions.filter(conv => isValidStatus(conv.status)).length} (Сума: \x1b[33m$${keitaroTotalSum.toFixed(2)}\x1b[0m)`);
54
+ console.log(`Співпадінь: ${comparison.matches.length}`);
55
+ console.log(`Відхилених конверсій: ${allKeitaroRejected.length}`);
56
+ const totalDiff = Math.abs(wpTotalSum - keitaroTotalSum);
57
+ console.log(`\x1b[1mЗагальна різниця:\x1b[0m \x1b[33m$${totalDiff.toFixed(2)}\x1b[0m`);
58
+ // Always show rejected conversions first if there are any
59
+ if (allKeitaroRejected.length > 0) {
60
+ const rejectedTotal = allKeitaroRejected.reduce((sum, conv) => sum + (parseFloat(conv.revenue) || 0), 0);
61
+ console.log('\n\x1b[1mВідхилені конверсії в Keitaro за офферами:\x1b[0m');
62
+ console.log(`Загальна кількість: ${allKeitaroRejected.length}`);
63
+ console.log(`Загальна сума: \x1b[33m$${rejectedTotal.toFixed(2)}\x1b[0m`);
64
+ for (const [offer, stats] of rejectedByOffer.entries()) {
65
+ console.log(`\n\x1b[33m${offer}:\x1b[0m`);
66
+ console.log(`Кількість: ${stats.count}, Сума: $${stats.sum.toFixed(2)}`);
67
+ stats.conversions.forEach(conv => {
68
+ const matchMark = comparison.matches.some(match => match.keitaro.sub_id === conv.sub_id) ? '[matched] ' : '';
69
+ console.log(` ${matchMark}${conv.sub_id} | ${conv.sale_datetime.split(' ')[0]} | $${conv.revenue}`);
70
+ });
71
+ }
72
+ }
73
+ console.log('\n\x1b[1mВідсутні в Keitaro за проектами:\x1b[0m');
74
+ for (const [project, stats] of wpMismatchesByProject) {
75
+ console.log(`\n\x1b[31m${project}:\x1b[0m`);
76
+ console.log(`Кількість: ${stats.count}, Сума: $${stats.sum.toFixed(2)}`);
77
+ stats.conversions.forEach(conv => {
78
+ console.log(` ${conv.clickId} | ${conv.regDate.toISOString().split('T')[0]} | $${conv.sum}`);
79
+ });
80
+ }
81
+ console.log('\n\x1b[1mВідсутні в WP за офферами:\x1b[0m');
82
+ for (const [offer, stats] of keitaroMismatchesByOffer) {
83
+ console.log(`\n\x1b[32m${offer}:\x1b[0m`);
84
+ console.log(`Кількість: ${stats.count}, Сума: $${stats.sum.toFixed(2)}`);
85
+ stats.conversions.forEach(conv => {
86
+ const statusMark = conv.status === 'rejected' ? '(rejected) ' : '';
87
+ const matchMark = comparison.matches.some(match => match.keitaro.sub_id === conv.sub_id) ? '[matched] ' : '';
88
+ console.log(` ${statusMark}${matchMark}${conv.sub_id} | ${conv.sale_datetime.split(' ')[0]} | $${conv.revenue}`);
89
+ });
90
+ }
91
+ let mismatchWPSum = comparison.mismatches.onlyInWP
92
+ .reduce((sum, conv) => sum + conv.sum, 0);
93
+ let mismatchKeitaroSum = [...comparison.mismatches.onlyInKeitaro, ...allKeitaroRejected]
94
+ .reduce((sum, conv) => sum + (parseFloat(conv.revenue) || 0), 0);
95
+ console.log('\n\x1b[1mПідсумок розбіжностей:\x1b[0m');
96
+ console.log(`Сума відсутніх в Keitaro: \x1b[31m$${mismatchWPSum.toFixed(2)}\x1b[0m`);
97
+ console.log(`Сума відсутніх в WP: \x1b[32m$${mismatchKeitaroSum.toFixed(2)}\x1b[0m`);
98
+ console.log(`Різниця у відсутніх конверсіях: \x1b[33m$${Math.abs(mismatchWPSum - mismatchKeitaroSum).toFixed(2)}\x1b[0m`);
99
+ // Debug information
100
+ const matchingRejected = comparison.matches.filter(match => match.keitaro.status === 'rejected').length;
101
+ console.log('\n\x1b[1mДебаг інформація:\x1b[0m');
102
+ console.log(`Кількість конверсій відсутніх в WP: ${comparison.mismatches.onlyInKeitaro.length + comparison.rejected.keitaro.length + matchingRejected}`);
103
+ console.log(`З них:`);
104
+ console.log(`- Активних: ${comparison.mismatches.onlyInKeitaro.length}`);
105
+ console.log(`- Відхилених (унікальних): ${comparison.rejected.keitaro.length}`);
106
+ console.log(`- Відхилених (що є в WP): ${matchingRejected}`);
107
+ }
108
+ exports.displayComparisonResults = displayComparisonResults;
@@ -0,0 +1,2 @@
1
+ import { ConversionComparison } from './utils/comparing';
2
+ export declare function displayComparisonResults(comparison: ConversionComparison): void;
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.displayComparisonResults = void 0;
27
+ const keitaro_service_1 = require("./network/keitaro/keitaro-service");
28
+ const keitaro_conversions_1 = require("./keitaro/keitaro-conversions");
29
+ const path = __importStar(require("path"));
30
+ const comparing_1 = require("./utils/comparing");
31
+ function displayComparisonResults(comparison) {
32
+ const isValidStatus = (status) => ['sale', 'rebill'].includes(status);
33
+ // Считаем общие суммы
34
+ let wpTotalSum = comparison.wpConversions
35
+ .reduce((sum, conv) => sum + conv.sum, 0);
36
+ let keitaroTotalSum = comparison.keitaroConversions
37
+ .filter((conv) => isValidStatus(conv.status))
38
+ .reduce((sum, conv) => sum + (parseFloat(conv.revenue) || 0), 0);
39
+ // Находим разницу
40
+ const totalDiff = keitaroTotalSum - wpTotalSum;
41
+ console.log('\n\x1b[1mЗагальна статистика:\x1b[0m');
42
+ console.log(`WP сума: $${wpTotalSum.toFixed(2)}`);
43
+ console.log(`Keitaro сума: $${keitaroTotalSum.toFixed(2)}`);
44
+ console.log(`Різниця: $${totalDiff.toFixed(2)}`);
45
+ // Получаем конверсии, которые есть в Keitaro, но нет в WP
46
+ const extraKeitaroConversions = comparison.mismatches.onlyInKeitaro
47
+ .filter(conv => isValidStatus(conv.status))
48
+ .sort((a, b) => (parseFloat(b.revenue) || 0) - (parseFloat(a.revenue) || 0));
49
+ // Группируем по офферам для удобства
50
+ const byOffer = new Map();
51
+ extraKeitaroConversions.forEach(conv => {
52
+ const offer = conv.offer || 'Unknown Offer';
53
+ if (!byOffer.has(offer)) {
54
+ byOffer.set(offer, { count: 0, sum: 0, conversions: [] });
55
+ }
56
+ const stats = byOffer.get(offer);
57
+ const revenue = parseFloat(conv.revenue) || 0;
58
+ stats.count++;
59
+ stats.sum += revenue;
60
+ stats.conversions.push(conv);
61
+ });
62
+ console.log('\n\x1b[1mКонверсії, які є в Keitaro, але відсутні в WP:\x1b[0m');
63
+ let totalExtraSum = 0;
64
+ for (const [offer, stats] of byOffer) {
65
+ console.log(`\n\x1b[33m${offer}:\x1b[0m`);
66
+ console.log(`Кількість: ${stats.count}, Сума: $${stats.sum.toFixed(2)}`);
67
+ stats.conversions.forEach(conv => {
68
+ if (conv.sub_id && conv.revenue) {
69
+ console.log(` ${conv.sub_id} | ${conv.revenue}`);
70
+ totalExtraSum += parseFloat(conv.revenue) || 0;
71
+ }
72
+ });
73
+ }
74
+ console.log('\n\x1b[1mПідсумок:\x1b[0m');
75
+ console.log(`Загальна сума "зайвих" конверсій: \x1b[33m$${totalExtraSum.toFixed(2)}\x1b[0m`);
76
+ console.log('Це конверсії, які потрібно видалити з Keitaro, щоб суми співпадали з WP');
77
+ }
78
+ exports.displayComparisonResults = displayComparisonResults;
79
+ // Self-executing function to fetch and compare conversions
80
+ (async () => {
81
+ const request = {
82
+ range: {
83
+ from: '2025-01-01',
84
+ to: '2025-01-31',
85
+ timezone: 'Europe/Kyiv'
86
+ },
87
+ filters: [
88
+ {
89
+ name: 'status',
90
+ operator: keitaro_conversions_1.KeitaroOperator.IN_LIST,
91
+ expression: ['sale', 'rejected']
92
+ },
93
+ {
94
+ name: 'affiliate_network_id',
95
+ operator: keitaro_conversions_1.KeitaroOperator.EQUALS,
96
+ expression: 2
97
+ }
98
+ ],
99
+ columns: [
100
+ 'sign', 'version', 'campaign', 'campaign_group', 'landing_group', 'offer_group',
101
+ 'landing', 'offer', 'affiliate_network', 'ts', 'stream', 'source',
102
+ 'x_requested_with', 'referrer', 'search_engine', 'keyword', 'click_id',
103
+ 'sub_id', 'visitor_code', 'campaign_id', 'campaign_group_id', 'offer_group_id',
104
+ 'landing_group_id', 'landing_id', 'offer_id', 'affiliate_network_id', 'ts_id',
105
+ 'stream_id', 'ad_campaign_id', 'external_id', 'creative_id',
106
+ 'sub_id_1', 'sub_id_2', 'sub_id_3', 'sub_id_4', 'sub_id_5',
107
+ 'sub_id_6', 'sub_id_7', 'sub_id_8', 'sub_id_9', 'sub_id_10',
108
+ 'sub_id_11', 'sub_id_12', 'sub_id_13', 'sub_id_14', 'sub_id_15',
109
+ 'sub_id_16', 'sub_id_17', 'sub_id_18', 'sub_id_19', 'sub_id_20',
110
+ 'sub_id_21', 'sub_id_22', 'sub_id_23', 'sub_id_24', 'sub_id_25',
111
+ 'sub_id_26', 'sub_id_27', 'sub_id_28', 'sub_id_29', 'sub_id_30',
112
+ 'connection_type', 'operator', 'isp', 'country_code', 'country_flag',
113
+ 'country', 'region', 'region_code', 'city', 'language', 'device_type',
114
+ 'user_agent', 'os_icon', 'os', 'os_version', 'browser', 'browser_version',
115
+ 'device_model', 'browser_icon', 'ip', 'ip_mask1', 'ip_mask2', 'ipv4only',
116
+ 'ipv6only', 'cost', 'postback_datetime', 'sale_datetime', 'click_datetime',
117
+ 'sale_period', 'status', 'previous_status', 'original_status',
118
+ 'previous_conversion_id', 'params', 'conversion_id', 'tid',
119
+ 'profitability', 'revenue', 'profit'
120
+ ],
121
+ sort: [{
122
+ name: 'sale_datetime',
123
+ order: 'DESC'
124
+ }]
125
+ };
126
+ try {
127
+ const conversions = await keitaro_service_1.KeitaroService.getConversions(request);
128
+ const wpFilePath = path.join(process.cwd(), 'src', 'utils', 'wp-january.csv');
129
+ const comparison = await (0, comparing_1.compareConversions)(wpFilePath, conversions);
130
+ // Use our improved display function
131
+ displayComparisonResults(comparison);
132
+ }
133
+ catch (error) {
134
+ console.error('Error fetching conversions:', error);
135
+ }
136
+ })();
@@ -0,0 +1,31 @@
1
+ export interface WPConversion {
2
+ status: string;
3
+ regDate: Date;
4
+ qualDate: Date;
5
+ approveOrRejectDate: Date;
6
+ project: string;
7
+ offerName: string;
8
+ sum: number;
9
+ currency: string;
10
+ geo: string;
11
+ subId?: string;
12
+ clickId: string;
13
+ }
14
+ export interface ConversionComparison {
15
+ wpConversions: WPConversion[];
16
+ keitaroConversions: any[];
17
+ matches: {
18
+ wp: WPConversion;
19
+ keitaro: any;
20
+ }[];
21
+ mismatches: {
22
+ onlyInWP: WPConversion[];
23
+ onlyInKeitaro: any[];
24
+ };
25
+ rejected: {
26
+ wp: WPConversion[];
27
+ keitaro: any[];
28
+ };
29
+ }
30
+ export declare function parseWPConversions(filePath: string): Promise<WPConversion[]>;
31
+ export declare function compareConversions(wpFilePath: string, keitaroConversions: any[]): Promise<ConversionComparison>;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.compareConversions = exports.parseWPConversions = void 0;
27
+ const sync_1 = require("csv-parse/sync");
28
+ const fs = __importStar(require("fs"));
29
+ function parseDate(dateStr) {
30
+ const [month, day, year] = dateStr.split('/').map(num => parseInt(num));
31
+ return new Date(2000 + year, month - 1, day);
32
+ }
33
+ async function parseWPConversions(filePath) {
34
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
35
+ const records = (0, sync_1.parse)(fileContent, {
36
+ delimiter: ';',
37
+ columns: true,
38
+ skip_empty_lines: true
39
+ });
40
+ return records.map((record) => ({
41
+ status: record.Status,
42
+ regDate: parseDate(record.RegDate),
43
+ qualDate: parseDate(record.QualDate),
44
+ approveOrRejectDate: parseDate(record.Approve_or_Reject_Date),
45
+ project: record.Project,
46
+ offerName: record.Offer_Name,
47
+ sum: parseFloat(record.Sum),
48
+ currency: record.Currency,
49
+ geo: record.Geo,
50
+ subId: record.Sub_ID || undefined,
51
+ clickId: record.Click_ID
52
+ }));
53
+ }
54
+ exports.parseWPConversions = parseWPConversions;
55
+ async function compareConversions(wpFilePath, keitaroConversions) {
56
+ const wpConversions = await parseWPConversions(wpFilePath);
57
+ const matches = [];
58
+ const onlyInWP = [];
59
+ const onlyInKeitaro = [];
60
+ const rejectedWP = [];
61
+ const rejectedKeitaro = [];
62
+ // Create a map of Keitaro conversions by their sub_id to match with WP's Click_ID
63
+ const keitaroMap = new Map(keitaroConversions.map(conv => [conv.sub_id, conv]));
64
+ // First, find matches and conversions only in WP
65
+ for (const wpConv of wpConversions) {
66
+ // Skip rejected conversions
67
+ if (wpConv.status === 'Удержан') {
68
+ rejectedWP.push(wpConv);
69
+ continue;
70
+ }
71
+ const keitaroMatch = keitaroMap.get(wpConv.clickId);
72
+ if (keitaroMatch) {
73
+ matches.push({ wp: wpConv, keitaro: keitaroMatch });
74
+ keitaroMap.delete(wpConv.clickId);
75
+ }
76
+ else {
77
+ onlyInWP.push(wpConv);
78
+ }
79
+ }
80
+ // Remaining conversions in keitaroMap are only in Keitaro
81
+ // We need to check their status before adding them to onlyInKeitaro
82
+ for (const [_, conv] of keitaroMap) {
83
+ if (conv.status === 'rejected') {
84
+ rejectedKeitaro.push(conv);
85
+ }
86
+ else {
87
+ onlyInKeitaro.push(conv);
88
+ }
89
+ }
90
+ return {
91
+ wpConversions: wpConversions.filter(conv => conv.status !== 'Удержан'),
92
+ keitaroConversions: keitaroConversions.filter(conv => conv.status !== 'rejected'),
93
+ matches,
94
+ mismatches: {
95
+ onlyInWP,
96
+ onlyInKeitaro
97
+ },
98
+ rejected: {
99
+ wp: rejectedWP,
100
+ keitaro: rejectedKeitaro
101
+ }
102
+ };
103
+ }
104
+ exports.compareConversions = compareConversions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bprotsyk/aso-core",
3
- "version": "2.1.142",
3
+ "version": "2.1.180",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "scripts": {
package/src/app/app.ts CHANGED
@@ -4,6 +4,15 @@ import mongoose, { Document, Model, model, PipelineStage, Schema, UpdateQuery, U
4
4
  import { AlternativeFullscreen } from "app/app-integration";
5
5
  const util = require("util")
6
6
 
7
+ export interface IAppsflyerPostback {
8
+ campaign_id: number
9
+ id: number
10
+ method: "GET" | "POST"
11
+ statuses: string[]
12
+ url: string
13
+ notes?: string
14
+ }
15
+
7
16
  export interface IApp extends Document {
8
17
  id: number
9
18
  enabled: boolean,
@@ -42,6 +51,7 @@ export interface IApp extends Document {
42
51
  ech?: boolean,
43
52
  imageFormat: EImageFormat
44
53
  policyPath: string
54
+ postbacks?: IAppsflyerPostback[]
45
55
  }
46
56
 
47
57
  export enum EImageFormat {
@@ -390,7 +400,34 @@ export const AppSchema = new Schema({
390
400
  policyPath: {
391
401
  type: String,
392
402
  default: "none"
393
- }
403
+ },
404
+ postbacks: [{
405
+ campaign_id: {
406
+ type: Number,
407
+ required: true
408
+ },
409
+ id: {
410
+ type: Number,
411
+ required: true
412
+ },
413
+ method: {
414
+ type: String,
415
+ enum: ["GET", "POST"],
416
+ required: true
417
+ },
418
+ statuses: [{
419
+ type: String,
420
+ required: true
421
+ }],
422
+ url: {
423
+ type: String,
424
+ required: true
425
+ },
426
+ notes: {
427
+ type: String,
428
+ required: false
429
+ }
430
+ }]
394
431
  })
395
432
 
396
433
 
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@ export { IOffer, IPartner, IOfferType } from "./offers/offer"
4
4
  export { IOffersSection, OffersSectionSchema, DefaultSectionId } from "./offers/section"
5
5
  export { IAppOffersSection, ISectionsList, SectionsListSchema, IOfferState } from "./offers/list"
6
6
 
7
- export { IAdjustEventIds, IntegrationVersion, IApp, AppSchema, PlugType, IAppKeitaroData, IExternalParams, IPlatformParams, EPlatform, AppStatus, IPublicationHistory, IRemovalInfo, EDirectType } from "./app/app"
7
+ export { IAdjustEventIds, IntegrationVersion, IApp, AppSchema, PlugType, IAppKeitaroData, IExternalParams, IPlatformParams, EPlatform, AppStatus, IPublicationHistory, IRemovalInfo, EDirectType, IAppsflyerPostback } from "./app/app"
8
8
  export { IAppListItem } from "./app/app-list-item"
9
9
  export { AppType } from "./app/app-type"
10
10
  export { AlternativeLayoutType, AlternativeSourceType, AlternativeLogicType, AlternativeNetworkTool, AlternativeStorageType, AlternativeNavigation, AlternativeOnBackPressed, AlternativeOnActivityResult, IAppIntegration as IFlashIntegration } from "./app/app-integration"
@@ -1,212 +0,0 @@
1
- apple
2
- banana
3
- cherry
4
- dragon
5
- eagle
6
- forest
7
- garden
8
- hammer
9
- island
10
- jungle
11
- kitten
12
- lemon
13
- mountain
14
- ocean
15
- pencil
16
- queen
17
- river
18
- sunset
19
- tiger
20
- umbrella
21
- village
22
- window
23
- xylophone
24
- yellow
25
- zebra
26
- adventure
27
- beautiful
28
- creative
29
- delicious
30
- excellent
31
- fantastic
32
- gorgeous
33
- handsome
34
- incredible
35
- joyful
36
- knowledge
37
- luminous
38
- magnificent
39
- natural
40
- outstanding
41
- perfect
42
- quality
43
- radiant
44
- spectacular
45
- tremendous
46
- ultimate
47
- valuable
48
- wonderful
49
- amazing
50
- brilliant
51
- charming
52
- delightful
53
- elegant
54
- fascinating
55
- graceful
56
- harmonious
57
- inspiring
58
- jubilant
59
- kindhearted
60
- loving
61
- mysterious
62
- nurturing
63
- optimistic
64
- peaceful
65
- quintessential
66
- radiant
67
- serene
68
- tranquil
69
- uplifting
70
- vibrant
71
- whimsical
72
- abundant
73
- blessed
74
- cheerful
75
- dazzling
76
- energetic
77
- friendly
78
- generous
79
- hopeful
80
- imaginative
81
- jovial
82
- knowledgeable
83
- lively
84
- majestic
85
- noble
86
- outstanding
87
- passionate
88
- quintessential
89
- remarkable
90
- splendid
91
- treasured
92
- unique
93
- valuable
94
- warmhearted
95
- authentic
96
- benevolent
97
- charismatic
98
- determined
99
- enthusiastic
100
- faithful
101
- gracious
102
- humble
103
- inspiring
104
- joyful
105
- kind
106
- loyal
107
- magnificent
108
- nurturing
109
- optimistic
110
- patient
111
- quintessential
112
- resilient
113
- sincere
114
- trustworthy
115
- understanding
116
- virtuous
117
- wise
118
- zealous
119
- abundant
120
- blessed
121
- cheerful
122
- dazzling
123
- energetic
124
- friendly
125
- generous
126
- hopeful
127
- imaginative
128
- jovial
129
- knowledgeable
130
- lively
131
- majestic
132
- noble
133
- outstanding
134
- passionate
135
- quintessential
136
- remarkable
137
- splendid
138
- treasured
139
- unique
140
- valuable
141
- warmhearted
142
- authentic
143
- benevolent
144
- charismatic
145
- determined
146
- enthusiastic
147
- faithful
148
- gracious
149
- humble
150
- inspiring
151
- joyful
152
- kind
153
- loyal
154
- magnificent
155
- nurturing
156
- optimistic
157
- patient
158
- quintessential
159
- resilient
160
- sincere
161
- trustworthy
162
- understanding
163
- virtuous
164
- wise
165
- zealous
166
- abundant
167
- blessed
168
- cheerful
169
- dazzling
170
- energetic
171
- friendly
172
- generous
173
- hopeful
174
- imaginative
175
- jovial
176
- knowledgeable
177
- lively
178
- majestic
179
- noble
180
- outstanding
181
- passionate
182
- quintessential
183
- remarkable
184
- splendid
185
- treasured
186
- unique
187
- valuable
188
- warmhearted
189
- authentic
190
- benevolent
191
- charismatic
192
- determined
193
- enthusiastic
194
- faithful
195
- gracious
196
- humble
197
- inspiring
198
- joyful
199
- kind
200
- loyal
201
- magnificent
202
- nurturing
203
- optimistic
204
- patient
205
- quintessential
206
- resilient
207
- sincere
208
- trustworthy
209
- understanding
210
- virtuous
211
- wise
212
- zealous