@google-cloud/nodejs-common 1.5.8-beta → 1.6.0
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/package.json +1 -1
- package/src/apis/dfa_reporting.js +22 -0
- package/src/apis/google_ads.js +59 -18
package/package.json
CHANGED
|
@@ -284,6 +284,10 @@ class DfaReporting {
|
|
|
284
284
|
* Runs a report and return the file Id. As an asynchronized process, the
|
|
285
285
|
* returned file Id will be a placeholder until the status changes to
|
|
286
286
|
* 'REPORT_AVAILABLE' in the response of `getFile`.
|
|
287
|
+
* Campaign Manager reports use a fixed timezone(America/Los Angeles) when it
|
|
288
|
+
* has a relative date range, e.g. YESTERDAY. To solve this, if there are
|
|
289
|
+
* `startDate` and `endDate` available in the given `config`, they will be
|
|
290
|
+
* used to update the report before the report is started to run.
|
|
287
291
|
* @see https://developers.google.com/doubleclick-advertisers/rest/v4/reports/run
|
|
288
292
|
*
|
|
289
293
|
* @param {{
|
|
@@ -296,6 +300,24 @@ class DfaReporting {
|
|
|
296
300
|
async runReport(config) {
|
|
297
301
|
const profileId = await this.getProfileForOperation_(config);
|
|
298
302
|
const dfareporting = await this.getApiClient_();
|
|
303
|
+
const { startDate, endDate } = config;
|
|
304
|
+
if (startDate && endDate) {
|
|
305
|
+
const { data: report } = await dfareporting.reports.get({
|
|
306
|
+
profileId,
|
|
307
|
+
reportId: config.reportId,
|
|
308
|
+
});
|
|
309
|
+
report.criteria.dateRange = { startDate, endDate };
|
|
310
|
+
const updated = await dfareporting.reports.update({
|
|
311
|
+
profileId,
|
|
312
|
+
reportId: config.reportId,
|
|
313
|
+
requestBody: report
|
|
314
|
+
});
|
|
315
|
+
if (updated.status >= 400) {
|
|
316
|
+
this.logger.error(
|
|
317
|
+
'Failed to update data range of CM360 report', config.reportId);
|
|
318
|
+
this.logger.error('Report to be updated', report);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
299
321
|
const response = await dfareporting.reports.run({
|
|
300
322
|
profileId,
|
|
301
323
|
reportId: config.reportId,
|
package/src/apis/google_ads.js
CHANGED
|
@@ -21,9 +21,12 @@ const {protos: {google: {ads: {googleads}}}} = require('google-ads-node');
|
|
|
21
21
|
const googleAdsLib = googleads[Object.keys(googleads)[0]];
|
|
22
22
|
const {
|
|
23
23
|
common: {
|
|
24
|
+
CustomerMatchUserListMetadata,
|
|
25
|
+
StoreSalesMetadata,
|
|
26
|
+
TransactionAttribute,
|
|
27
|
+
UserAttribute,
|
|
24
28
|
UserData,
|
|
25
29
|
UserIdentifier,
|
|
26
|
-
CustomerMatchUserListMetadata,
|
|
27
30
|
},
|
|
28
31
|
resources: {
|
|
29
32
|
GoogleAdsField,
|
|
@@ -31,24 +34,25 @@ const {
|
|
|
31
34
|
UserList,
|
|
32
35
|
},
|
|
33
36
|
services: {
|
|
34
|
-
CreateOfflineUserDataJobRequest,
|
|
35
37
|
AddOfflineUserDataJobOperationsRequest,
|
|
38
|
+
CreateOfflineUserDataJobRequest,
|
|
36
39
|
RunOfflineUserDataJobRequest,
|
|
40
|
+
SearchGoogleAdsFieldsRequest,
|
|
37
41
|
UploadCallConversionsRequest,
|
|
38
|
-
UploadClickConversionsRequest,
|
|
39
42
|
UploadCallConversionsResponse,
|
|
43
|
+
UploadClickConversionsRequest,
|
|
40
44
|
UploadClickConversionsResponse,
|
|
41
45
|
UploadConversionAdjustmentsRequest,
|
|
42
46
|
UploadConversionAdjustmentsResponse,
|
|
43
47
|
UploadUserDataRequest,
|
|
44
48
|
UploadUserDataResponse,
|
|
45
49
|
UserDataOperation,
|
|
46
|
-
SearchGoogleAdsFieldsRequest,
|
|
47
50
|
},
|
|
48
51
|
errors: {
|
|
49
52
|
GoogleAdsFailure,
|
|
50
53
|
},
|
|
51
54
|
enums: {
|
|
55
|
+
OfflineUserDataJobFailureReasonEnum: { OfflineUserDataJobFailureReason },
|
|
52
56
|
OfflineUserDataJobTypeEnum: { OfflineUserDataJobType },
|
|
53
57
|
OfflineUserDataJobStatusEnum: { OfflineUserDataJobStatus },
|
|
54
58
|
UserListMembershipStatusEnum: { UserListMembershipStatus },
|
|
@@ -107,6 +111,16 @@ const IDENTIFIERS = [
|
|
|
107
111
|
'address_info',
|
|
108
112
|
];
|
|
109
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Additional attributes in user data for store sales data or customer match.
|
|
116
|
+
* @see https://developers.google.com/google-ads/api/reference/rpc/latest/UserData
|
|
117
|
+
* @type {Array<string>}
|
|
118
|
+
*/
|
|
119
|
+
const USERDATA_ADDITIONAL_ATTRIBUTES = [
|
|
120
|
+
'transaction_attribute',
|
|
121
|
+
'user_attribute',
|
|
122
|
+
];
|
|
123
|
+
|
|
110
124
|
/**
|
|
111
125
|
* Maximum number of user identifiers in single UserData.
|
|
112
126
|
* @see https://ads-developers.googleblog.com/2021/10/userdata-enforcement-in-google-ads-api.html
|
|
@@ -181,11 +195,17 @@ let CustomerMatchConfig;
|
|
|
181
195
|
* Configuration for offline user data job, includes:
|
|
182
196
|
* customer_id, login_customer_id, list_id, operation and type.
|
|
183
197
|
* 'operation' should be one of the two: 'create' or 'remove',
|
|
184
|
-
* 'type' is OfflineUserDataJobType, it can be 'CUSTOMER_MATCH_USER_LIST'
|
|
185
|
-
* 'STORE_SALES_UPLOAD_FIRST_PARTY'.
|
|
198
|
+
* 'type' is OfflineUserDataJobType, it can be 'CUSTOMER_MATCH_USER_LIST',
|
|
199
|
+
* 'CUSTOMER_MATCH_WITH_ATTRIBUTES' or 'STORE_SALES_UPLOAD_FIRST_PARTY'.
|
|
186
200
|
* For job type 'CUSTOMER_MATCH_USER_LIST', if `list_id` is not present,
|
|
187
201
|
* 'list_name' and 'upload_key_type' need to be there so they can be used to
|
|
188
202
|
* create a customer match user list.
|
|
203
|
+
* For job type 'CUSTOMER_MATCH_WITH_ATTRIBUTES', 'user_attribute' can be used
|
|
204
|
+
* to store shared additional user attributes.
|
|
205
|
+
* For job type 'STORE_SALES_UPLOAD_FIRST_PARTY', `store_sales_metadata` is
|
|
206
|
+
* required to offer StoreSalesMetadata. Besides that, for the store sales data,
|
|
207
|
+
* common data (e.g. `currency_code`, `conversion_action`) in
|
|
208
|
+
* `transaction_attribute` can be put here as well.
|
|
189
209
|
* @see https://developers.google.com/google-ads/api/reference/rpc/latest/OfflineUserDataJob
|
|
190
210
|
* @typedef {{
|
|
191
211
|
* customer_id: (string|number),
|
|
@@ -195,7 +215,9 @@ let CustomerMatchConfig;
|
|
|
195
215
|
* upload_key_type: ('CONTACT_INFO'|'CRM_ID'|'MOBILE_ADVERTISING_ID'|undefined),
|
|
196
216
|
* operation: ('create'|'remove'),
|
|
197
217
|
* type: !OfflineUserDataJobType,
|
|
198
|
-
*
|
|
218
|
+
* store_sales_metadata: (undefined|StoreSalesMetadata),
|
|
219
|
+
* transaction_attribute: (undefined|TransactionAttribute),
|
|
220
|
+
* user_attribute: (undefined|UserAttribute),
|
|
199
221
|
* }}
|
|
200
222
|
*/
|
|
201
223
|
let OfflineUserDataJobConfig;
|
|
@@ -804,10 +826,16 @@ class GoogleAds {
|
|
|
804
826
|
* @see https://developers.google.com/google-ads/api/reference/rpc/latest/UserDataOperation
|
|
805
827
|
* @param {string} operationType either 'create' or 'remove'
|
|
806
828
|
* @param {Array<CustomerMatchRecord>} customerMatchRecords userIds
|
|
829
|
+
* @param {{
|
|
830
|
+
* transaction_attribute: TransactionAttribute|undefined,
|
|
831
|
+
* user_attribute: UserAttribute,
|
|
832
|
+
* }} additionalAttributes Additional attributes for 'UserData', includes
|
|
833
|
+
* 'transaction_attribute' or 'user_attribute'.
|
|
807
834
|
* @return {Array<UserDataOperation>}
|
|
808
835
|
* @private
|
|
809
836
|
*/
|
|
810
|
-
buildOperationsList_(operationType, customerMatchRecords
|
|
837
|
+
buildOperationsList_(operationType, customerMatchRecords,
|
|
838
|
+
additionalAttributes = {}) {
|
|
811
839
|
return customerMatchRecords.map((customerMatchRecord) => {
|
|
812
840
|
const userIdentifiers = [];
|
|
813
841
|
IDENTIFIERS.forEach((idType) => {
|
|
@@ -822,17 +850,24 @@ class GoogleAds {
|
|
|
822
850
|
}
|
|
823
851
|
}
|
|
824
852
|
});
|
|
825
|
-
|
|
853
|
+
const userData = {};
|
|
826
854
|
if (userIdentifiers.length <= MAX_IDENTIFIERS_PER_USER) {
|
|
827
|
-
userData =
|
|
855
|
+
userData.user_identifiers = userIdentifiers;
|
|
828
856
|
} else {
|
|
829
857
|
this.logger.warn(
|
|
830
858
|
`Too many user identifiers, will only send ${MAX_IDENTIFIERS_PER_USER}:`,
|
|
831
859
|
JSON.stringify(customerMatchRecord));
|
|
832
|
-
userData
|
|
833
|
-
|
|
860
|
+
userData.user_identifiers =
|
|
861
|
+
userIdentifiers.slice(0, MAX_IDENTIFIERS_PER_USER);
|
|
834
862
|
}
|
|
835
|
-
|
|
863
|
+
USERDATA_ADDITIONAL_ATTRIBUTES.forEach((attribute) => {
|
|
864
|
+
if (additionalAttributes[attribute] || customerMatchRecord[attribute]) {
|
|
865
|
+
userData[attribute] = lodash.merge(
|
|
866
|
+
{}, additionalAttributes[attribute], customerMatchRecord[attribute]);
|
|
867
|
+
}
|
|
868
|
+
})
|
|
869
|
+
return UserDataOperation.create(
|
|
870
|
+
{ [operationType]: UserData.create(userData) });
|
|
836
871
|
});
|
|
837
872
|
}
|
|
838
873
|
|
|
@@ -887,7 +922,12 @@ class GoogleAds {
|
|
|
887
922
|
if (jobs.length === 0) {
|
|
888
923
|
throw new Error(`Can't find the OfflineUserDataJob: ${resourceName}`);
|
|
889
924
|
}
|
|
890
|
-
|
|
925
|
+
const { failure_reason: failure, status } = jobs[0].offline_user_data_job;
|
|
926
|
+
if (failure > 0) {
|
|
927
|
+
this.logger.warn(`Offline UserData Job [${resourceName}] failed: `,
|
|
928
|
+
OfflineUserDataJobFailureReason[failure])
|
|
929
|
+
}
|
|
930
|
+
return OfflineUserDataJobStatus[status];
|
|
891
931
|
}
|
|
892
932
|
|
|
893
933
|
/**
|
|
@@ -912,9 +952,10 @@ class GoogleAds {
|
|
|
912
952
|
job.customer_match_user_list_metadata = metadata;
|
|
913
953
|
// https://developers.google.com/google-ads/api/rest/reference/rest/latest/customers.offlineUserDataJobs?hl=en#StoreSalesMetadata
|
|
914
954
|
} else if (type.startsWith('STORE_SALES')) {
|
|
915
|
-
//
|
|
916
|
-
if (config.
|
|
917
|
-
job.store_sales_metadata = config.
|
|
955
|
+
// Support previous property 'StoreSalesMetadata' for compatibility.
|
|
956
|
+
if (config.store_sales_metadata || config.StoreSalesMetadata) {
|
|
957
|
+
job.store_sales_metadata = config.store_sales_metadata
|
|
958
|
+
|| config.StoreSalesMetadata;
|
|
918
959
|
}
|
|
919
960
|
} else {
|
|
920
961
|
throw new Error(`UNSUPPORTED OfflineUserDataJobType: ${type}.`);
|
|
@@ -945,7 +986,7 @@ class GoogleAds {
|
|
|
945
986
|
const operation = config.operation;
|
|
946
987
|
const customer = await this.getGoogleAdsApiCustomer_(
|
|
947
988
|
loginCustomerId, customerId);
|
|
948
|
-
const operationsList = this.buildOperationsList_(operation, records);
|
|
989
|
+
const operationsList = this.buildOperationsList_(operation, records, config);
|
|
949
990
|
const request = AddOfflineUserDataJobOperationsRequest.create({
|
|
950
991
|
resource_name: jobResourceName,
|
|
951
992
|
operations: operationsList,
|