@infrab4a/connect 5.3.0-beta.31 → 5.3.0-beta.32
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/index.cjs.js +261 -65
- package/index.esm.js +255 -66
- package/package.json +1 -1
- package/src/domain/shop-settings/models/shop-configs.d.ts +3 -12
- package/src/domain/shop-settings/models/types/antifraud-config.type.d.ts +21 -0
- package/src/domain/shop-settings/models/types/index.d.ts +1 -0
- package/src/domain/shop-settings/models/types/limit-orders.type.d.ts +3 -2
- package/src/domain/shopping/helpers/antifraud-enabled.helper.d.ts +8 -0
- package/src/domain/shopping/helpers/antifraud-volume-limits.helper.d.ts +6 -0
- package/src/domain/shopping/helpers/index.d.ts +2 -0
- package/src/domain/shopping/index.d.ts +1 -0
- package/src/domain/shopping/models/campaign-hashtag-posts.d.ts +23 -0
- package/src/domain/shopping/models/campaign-hashtag.d.ts +12 -10
- package/src/domain/shopping/models/coupons/coupon.d.ts +1 -0
- package/src/domain/shopping/models/index.d.ts +1 -0
- package/src/domain/shopping/models/shipping-method.d.ts +1 -0
- package/src/domain/shopping/repositories/campaign-hashtag-posts.repository.d.ts +4 -0
- package/src/domain/shopping/repositories/index.d.ts +1 -0
- package/src/domain/shopping/services/antifraud-bankslip.service.d.ts +3 -1
- package/src/domain/shopping/services/antifraud-card.service.d.ts +6 -6
- package/src/domain/shopping/services/antifraud-glampoints.service.d.ts +4 -2
- package/src/domain/shopping/services/antifraud-pix.service.d.ts +4 -2
- package/src/domain/shopping/types/antifraud-card-validation.type.d.ts +40 -0
- package/src/domain/shopping/types/antifraud-volume-limits.type.d.ts +24 -0
- package/src/domain/shopping/types/index.d.ts +2 -0
- package/src/infra/firebase/firestore/repositories/shopping/campaign-hashtag-posts-firestore.repository.d.ts +8 -0
- package/src/infra/firebase/firestore/repositories/shopping/index.d.ts +1 -0
package/index.cjs.js
CHANGED
|
@@ -157,6 +157,123 @@ class PaymentProviderFactory {
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
const ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS = 60;
|
|
161
|
+
/**
|
|
162
|
+
* Lê `shopConfigs.antifraude.enabled`.
|
|
163
|
+
* - `false` explícito → antifraude desligado
|
|
164
|
+
* - ausente / erro / inválido → `true` (mantém comportamento histórico)
|
|
165
|
+
*/
|
|
166
|
+
async function isAntifraudEnabled(shopConfigsRepository) {
|
|
167
|
+
if (!shopConfigsRepository) {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
const result = await shopConfigsRepository.find({}, { cache: { enabled: true, ttl: ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS } });
|
|
172
|
+
const enabled = result?.data?.at(0)?.antifraude?.enabled;
|
|
173
|
+
if (typeof enabled === 'boolean') {
|
|
174
|
+
return enabled;
|
|
175
|
+
}
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
console.warn(JSON.stringify({
|
|
180
|
+
msg: 'antifraud_enabled_config_load_failed',
|
|
181
|
+
enabled: true,
|
|
182
|
+
error: error instanceof Error ? error.message : String(error),
|
|
183
|
+
}));
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Defaults de runtime (week.zip = Infinity). Usados só como fallback no checkout. */
|
|
189
|
+
const DEFAULT_ANTIFRAUD_VOLUME_LIMITS = {
|
|
190
|
+
enabled: true,
|
|
191
|
+
source: 'fallback',
|
|
192
|
+
day: {
|
|
193
|
+
subscriber: { cpf: 4, email: 4, phone: 4, card: 4, zip: 4 },
|
|
194
|
+
nonSubscriber: { cpf: 2, email: 2, phone: 2, card: 2, zip: 2 },
|
|
195
|
+
},
|
|
196
|
+
week: {
|
|
197
|
+
subscriber: { cpf: 12, email: 12, phone: 12, card: 12, zip: Infinity },
|
|
198
|
+
nonSubscriber: { cpf: 7, email: 7, phone: 7, card: 7, zip: Infinity },
|
|
199
|
+
},
|
|
200
|
+
blockedAttemptsDay: {
|
|
201
|
+
subscriber: 7,
|
|
202
|
+
nonSubscriber: 5,
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
function isPositiveInteger(value) {
|
|
206
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 1 && Number.isInteger(value);
|
|
207
|
+
}
|
|
208
|
+
function normalizeLimitOrders(raw, allowInfiniteZip) {
|
|
209
|
+
if (!raw)
|
|
210
|
+
return null;
|
|
211
|
+
const zip = allowInfiniteZip && (raw.zip === null || raw.zip === undefined || raw.zip === Infinity) ? Infinity : raw.zip;
|
|
212
|
+
const normalized = {
|
|
213
|
+
cpf: raw.cpf,
|
|
214
|
+
email: raw.email,
|
|
215
|
+
phone: raw.phone,
|
|
216
|
+
zip: zip,
|
|
217
|
+
card: raw.card,
|
|
218
|
+
};
|
|
219
|
+
for (const key of ['cpf', 'email', 'phone', 'zip', 'card']) {
|
|
220
|
+
if (key === 'zip' && normalized.zip === Infinity)
|
|
221
|
+
continue;
|
|
222
|
+
if (!isPositiveInteger(normalized[key]))
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
return normalized;
|
|
226
|
+
}
|
|
227
|
+
function cloneFallbackLimits() {
|
|
228
|
+
return {
|
|
229
|
+
...DEFAULT_ANTIFRAUD_VOLUME_LIMITS,
|
|
230
|
+
day: {
|
|
231
|
+
subscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.day.subscriber },
|
|
232
|
+
nonSubscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.day.nonSubscriber },
|
|
233
|
+
},
|
|
234
|
+
week: {
|
|
235
|
+
subscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.week.subscriber },
|
|
236
|
+
nonSubscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.week.nonSubscriber },
|
|
237
|
+
},
|
|
238
|
+
blockedAttemptsDay: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.blockedAttemptsDay },
|
|
239
|
+
source: 'fallback',
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/** Config inválida/ausente → fallback (comportamento histórico). */
|
|
243
|
+
function resolveAntifraudVolumeLimits(antifraude) {
|
|
244
|
+
if (!antifraude || typeof antifraude.enabled !== 'boolean') {
|
|
245
|
+
return cloneFallbackLimits();
|
|
246
|
+
}
|
|
247
|
+
const daySubscriber = normalizeLimitOrders(antifraude.day?.subscriber, false);
|
|
248
|
+
const dayNonSubscriber = normalizeLimitOrders(antifraude.day?.nonSubscriber, false);
|
|
249
|
+
const weekSubscriber = normalizeLimitOrders(antifraude.week?.subscriber, true);
|
|
250
|
+
const weekNonSubscriber = normalizeLimitOrders(antifraude.week?.nonSubscriber, true);
|
|
251
|
+
const blocked = antifraude.blockedAttemptsDay;
|
|
252
|
+
if (!daySubscriber ||
|
|
253
|
+
!dayNonSubscriber ||
|
|
254
|
+
!weekSubscriber ||
|
|
255
|
+
!weekNonSubscriber ||
|
|
256
|
+
!blocked ||
|
|
257
|
+
!isPositiveInteger(blocked.subscriber) ||
|
|
258
|
+
!isPositiveInteger(blocked.nonSubscriber)) {
|
|
259
|
+
// Kill-switch explícito prevalece mesmo com payload inválido.
|
|
260
|
+
if (antifraude.enabled === false) {
|
|
261
|
+
return { ...cloneFallbackLimits(), enabled: false, source: 'fallback' };
|
|
262
|
+
}
|
|
263
|
+
return cloneFallbackLimits();
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
enabled: antifraude.enabled,
|
|
267
|
+
source: 'config',
|
|
268
|
+
day: { subscriber: daySubscriber, nonSubscriber: dayNonSubscriber },
|
|
269
|
+
week: { subscriber: weekSubscriber, nonSubscriber: weekNonSubscriber },
|
|
270
|
+
blockedAttemptsDay: {
|
|
271
|
+
subscriber: blocked.subscriber,
|
|
272
|
+
nonSubscriber: blocked.nonSubscriber,
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
160
277
|
const registry = new Map();
|
|
161
278
|
function registerClass(name, classConstructor) {
|
|
162
279
|
registry.set(name, classConstructor);
|
|
@@ -1038,6 +1155,12 @@ class CampaignHashtag extends BaseModel {
|
|
|
1038
1155
|
}
|
|
1039
1156
|
}
|
|
1040
1157
|
|
|
1158
|
+
class CampaignHashtagPosts extends BaseModel {
|
|
1159
|
+
static get identifiersFields() {
|
|
1160
|
+
return ['id'];
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1041
1164
|
class BeautyProfile extends BaseModel {
|
|
1042
1165
|
toPlain() {
|
|
1043
1166
|
const plain = super.toPlain();
|
|
@@ -1906,12 +2029,23 @@ class StockOutError extends BusinessError {
|
|
|
1906
2029
|
}
|
|
1907
2030
|
}
|
|
1908
2031
|
|
|
2032
|
+
/* eslint-disable no-console */
|
|
1909
2033
|
class AntifraudBankSlipService {
|
|
1910
|
-
constructor(orderBlockedRepository) {
|
|
2034
|
+
constructor(orderBlockedRepository, shopConfigsRepository) {
|
|
1911
2035
|
this.orderBlockedRepository = orderBlockedRepository;
|
|
2036
|
+
this.shopConfigsRepository = shopConfigsRepository;
|
|
1912
2037
|
this.MAX_ORDER_VALUE = 5000;
|
|
1913
2038
|
}
|
|
1914
2039
|
async validate(checkout) {
|
|
2040
|
+
const enabled = await isAntifraudEnabled(this.shopConfigsRepository);
|
|
2041
|
+
if (!enabled) {
|
|
2042
|
+
console.info(JSON.stringify({
|
|
2043
|
+
msg: 'antifraud_bankslip_skipped',
|
|
2044
|
+
enabled: false,
|
|
2045
|
+
checkoutId: checkout.id,
|
|
2046
|
+
}));
|
|
2047
|
+
return true;
|
|
2048
|
+
}
|
|
1915
2049
|
if (checkout.totalPrice && checkout.totalPrice > this.MAX_ORDER_VALUE && !checkout.user?.isSubscriber) {
|
|
1916
2050
|
await this.orderBlockedRepository.createBlockedOrderOrPayment({
|
|
1917
2051
|
checkout,
|
|
@@ -1933,62 +2067,67 @@ class AntifraudBankSlipService {
|
|
|
1933
2067
|
}
|
|
1934
2068
|
}
|
|
1935
2069
|
|
|
2070
|
+
/* eslint-disable max-params */
|
|
1936
2071
|
class AntifraudCardService {
|
|
1937
|
-
constructor(orderRepository, orderBlockedRepository) {
|
|
2072
|
+
constructor(orderRepository, orderBlockedRepository, shopConfigsRepository) {
|
|
1938
2073
|
this.orderRepository = orderRepository;
|
|
1939
2074
|
this.orderBlockedRepository = orderBlockedRepository;
|
|
1940
|
-
this.
|
|
1941
|
-
this.LIMIT_ORDERS_WEEK = null;
|
|
2075
|
+
this.shopConfigsRepository = shopConfigsRepository;
|
|
1942
2076
|
}
|
|
1943
2077
|
async validate(checkout, card) {
|
|
1944
|
-
|
|
1945
|
-
await this.
|
|
1946
|
-
|
|
2078
|
+
// Limites locais por request — evita race em provider Nest singleton entre awaits.
|
|
2079
|
+
const resolved = await this.loadResolvedLimits();
|
|
2080
|
+
const isSubscriber = !!checkout.user?.isSubscriber;
|
|
2081
|
+
const dayLimits = isSubscriber ? resolved.day.subscriber : resolved.day.nonSubscriber;
|
|
2082
|
+
const weekLimits = isSubscriber ? resolved.week.subscriber : resolved.week.nonSubscriber;
|
|
2083
|
+
const blockedAttemptsDay = isSubscriber
|
|
2084
|
+
? resolved.blockedAttemptsDay.subscriber
|
|
2085
|
+
: resolved.blockedAttemptsDay.nonSubscriber;
|
|
2086
|
+
if (!resolved.enabled) {
|
|
2087
|
+
console.info(JSON.stringify({
|
|
2088
|
+
msg: 'antifraud_card_volume_skipped',
|
|
2089
|
+
source: resolved.source,
|
|
2090
|
+
enabled: false,
|
|
2091
|
+
checkoutId: checkout.id,
|
|
2092
|
+
isSubscriber,
|
|
2093
|
+
}));
|
|
2094
|
+
return true;
|
|
2095
|
+
}
|
|
2096
|
+
console.info(JSON.stringify({
|
|
2097
|
+
msg: 'antifraud_card_volume_limits',
|
|
2098
|
+
source: resolved.source,
|
|
2099
|
+
enabled: true,
|
|
2100
|
+
checkoutId: checkout.id,
|
|
2101
|
+
isSubscriber,
|
|
2102
|
+
blockedAttemptsDay,
|
|
2103
|
+
day: dayLimits,
|
|
2104
|
+
week: weekLimits,
|
|
2105
|
+
}));
|
|
2106
|
+
await this.validateBlockedOrderAttempts(checkout, card, blockedAttemptsDay);
|
|
2107
|
+
await this.validateDayAndWeekOrderLimits(checkout, card, dayLimits, weekLimits);
|
|
1947
2108
|
return true;
|
|
1948
2109
|
}
|
|
1949
|
-
|
|
1950
|
-
this.
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
};
|
|
1966
|
-
this.LIMIT_ORDERS_WEEK = {
|
|
1967
|
-
subscriber: {
|
|
1968
|
-
cpf: 12,
|
|
1969
|
-
email: 12,
|
|
1970
|
-
phone: 12,
|
|
1971
|
-
card: 12,
|
|
1972
|
-
zip: Infinity,
|
|
1973
|
-
},
|
|
1974
|
-
nonSubscriber: {
|
|
1975
|
-
cpf: 7,
|
|
1976
|
-
email: 7,
|
|
1977
|
-
phone: 7,
|
|
1978
|
-
card: 7,
|
|
1979
|
-
zip: Infinity,
|
|
1980
|
-
},
|
|
1981
|
-
};
|
|
1982
|
-
this.LIMIT_BLOCKED_ORDERS_DAY = isSubscriber ? 7 : 5;
|
|
1983
|
-
}
|
|
1984
|
-
getLimitsByUserType(type, isSubscriber) {
|
|
1985
|
-
const limits = type === 'day' ? this.LIMIT_ORDERS_DAY : this.LIMIT_ORDERS_WEEK;
|
|
1986
|
-
return isSubscriber ? limits['subscriber'] : limits['nonSubscriber'];
|
|
2110
|
+
async loadResolvedLimits() {
|
|
2111
|
+
if (!this.shopConfigsRepository) {
|
|
2112
|
+
return resolveAntifraudVolumeLimits(null);
|
|
2113
|
+
}
|
|
2114
|
+
try {
|
|
2115
|
+
const result = await this.shopConfigsRepository.find({}, { cache: { enabled: true, ttl: ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS } });
|
|
2116
|
+
return resolveAntifraudVolumeLimits(result?.data?.at(0)?.antifraude);
|
|
2117
|
+
}
|
|
2118
|
+
catch (error) {
|
|
2119
|
+
console.warn(JSON.stringify({
|
|
2120
|
+
msg: 'antifraud_card_volume_config_load_failed',
|
|
2121
|
+
source: 'fallback',
|
|
2122
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2123
|
+
}));
|
|
2124
|
+
return resolveAntifraudVolumeLimits(null);
|
|
2125
|
+
}
|
|
1987
2126
|
}
|
|
1988
|
-
async validateBlockedOrderAttempts(checkout, card) {
|
|
1989
|
-
const isValid = await this.verifyBlockedOrderAttempts(checkout, card);
|
|
2127
|
+
async validateBlockedOrderAttempts(checkout, card, blockedAttemptsDay) {
|
|
2128
|
+
const isValid = await this.verifyBlockedOrderAttempts(checkout, card, blockedAttemptsDay);
|
|
1990
2129
|
if (!isValid) {
|
|
1991
|
-
throw new FraudValidationError(`Cliente com mais de ${
|
|
2130
|
+
throw new FraudValidationError(`Cliente com mais de ${blockedAttemptsDay} compras negadas/bloqueadas no dia`, exports.ErrorsCode.fraudPreventionInternal, {
|
|
1992
2131
|
checkoutId: checkout.id,
|
|
1993
2132
|
userEmail: checkout.user.email,
|
|
1994
2133
|
info: {
|
|
@@ -1999,8 +2138,8 @@ class AntifraudCardService {
|
|
|
1999
2138
|
});
|
|
2000
2139
|
}
|
|
2001
2140
|
}
|
|
2002
|
-
async validateDayAndWeekOrderLimits(checkout, card) {
|
|
2003
|
-
const isValid = await this.verifyDayAndWeekOrders(checkout, card);
|
|
2141
|
+
async validateDayAndWeekOrderLimits(checkout, card, dayLimits, weekLimits) {
|
|
2142
|
+
const isValid = await this.verifyDayAndWeekOrders(checkout, card, dayLimits, weekLimits);
|
|
2004
2143
|
if (!isValid) {
|
|
2005
2144
|
throw new FraudValidationError('Cliente tentando comprar mais do que o permitido no dia/semana', exports.ErrorsCode.fraudPreventionInternal, {
|
|
2006
2145
|
checkoutId: checkout.id,
|
|
@@ -2013,15 +2152,15 @@ class AntifraudCardService {
|
|
|
2013
2152
|
});
|
|
2014
2153
|
}
|
|
2015
2154
|
}
|
|
2016
|
-
async verifyBlockedOrderAttempts(checkout, card) {
|
|
2155
|
+
async verifyBlockedOrderAttempts(checkout, card, blockedAttemptsDay) {
|
|
2017
2156
|
const dateRange = this.getTodayDateRange();
|
|
2018
2157
|
const blockedOrders = await this.getBlockedOrdersByMultipleCriteria(checkout, dateRange);
|
|
2019
2158
|
const totalBlockedAttempts = this.calculateUniqueBlockedAttempts(blockedOrders, checkout);
|
|
2020
|
-
if (totalBlockedAttempts >=
|
|
2159
|
+
if (totalBlockedAttempts >= blockedAttemptsDay) {
|
|
2021
2160
|
await this.createBlockedOrderRecord({
|
|
2022
2161
|
checkout,
|
|
2023
2162
|
card,
|
|
2024
|
-
reason: `More than ${
|
|
2163
|
+
reason: `More than ${blockedAttemptsDay} attempts have failed`,
|
|
2025
2164
|
key: 'Failed attempts',
|
|
2026
2165
|
period: 'day',
|
|
2027
2166
|
});
|
|
@@ -2123,12 +2262,12 @@ class AntifraudCardService {
|
|
|
2123
2262
|
card,
|
|
2124
2263
|
});
|
|
2125
2264
|
}
|
|
2126
|
-
async verifyDayAndWeekOrders(checkout, card) {
|
|
2265
|
+
async verifyDayAndWeekOrders(checkout, card, dayLimits, weekLimits) {
|
|
2127
2266
|
const validationParams = this.buildValidationParams(checkout, card);
|
|
2128
|
-
const isDayLimitValid = await this.validateDayOrderLimits(checkout, validationParams);
|
|
2267
|
+
const isDayLimitValid = await this.validateDayOrderLimits(checkout, validationParams, dayLimits);
|
|
2129
2268
|
if (!isDayLimitValid)
|
|
2130
2269
|
return false;
|
|
2131
|
-
const isWeekLimitValid = await this.validateWeekOrderLimits(checkout, validationParams);
|
|
2270
|
+
const isWeekLimitValid = await this.validateWeekOrderLimits(checkout, validationParams, weekLimits);
|
|
2132
2271
|
return isWeekLimitValid;
|
|
2133
2272
|
}
|
|
2134
2273
|
buildValidationParams(checkout, card) {
|
|
@@ -2140,9 +2279,8 @@ class AntifraudCardService {
|
|
|
2140
2279
|
card,
|
|
2141
2280
|
};
|
|
2142
2281
|
}
|
|
2143
|
-
async validateDayOrderLimits(checkout, params) {
|
|
2282
|
+
async validateDayOrderLimits(checkout, params, limits) {
|
|
2144
2283
|
const ordersPerDay = await this.validateOrdersByRange(params, this.getDateRange('day'));
|
|
2145
|
-
const limits = this.getLimitsByUserType('day', checkout.user.isSubscriber);
|
|
2146
2284
|
return this.checkOrderLimitsAndBlock({
|
|
2147
2285
|
checkout,
|
|
2148
2286
|
orderCounts: ordersPerDay,
|
|
@@ -2150,9 +2288,8 @@ class AntifraudCardService {
|
|
|
2150
2288
|
period: 'day',
|
|
2151
2289
|
});
|
|
2152
2290
|
}
|
|
2153
|
-
async validateWeekOrderLimits(checkout, params) {
|
|
2291
|
+
async validateWeekOrderLimits(checkout, params, limits) {
|
|
2154
2292
|
const ordersPerWeek = await this.validateOrdersByRange(params, this.getDateRange('week'));
|
|
2155
|
-
const limits = this.getLimitsByUserType('week', checkout.user.isSubscriber);
|
|
2156
2293
|
return this.checkOrderLimitsAndBlock({
|
|
2157
2294
|
checkout,
|
|
2158
2295
|
orderCounts: ordersPerWeek,
|
|
@@ -2229,15 +2366,35 @@ class AntifraudCardService {
|
|
|
2229
2366
|
}
|
|
2230
2367
|
|
|
2231
2368
|
class AntifraudGlampointsService {
|
|
2232
|
-
constructor() {
|
|
2233
|
-
|
|
2369
|
+
constructor(shopConfigsRepository) {
|
|
2370
|
+
this.shopConfigsRepository = shopConfigsRepository;
|
|
2371
|
+
}
|
|
2372
|
+
async validate(checkout) {
|
|
2373
|
+
const enabled = await isAntifraudEnabled(this.shopConfigsRepository);
|
|
2374
|
+
if (!enabled) {
|
|
2375
|
+
console.info(JSON.stringify({
|
|
2376
|
+
msg: 'antifraud_glampoints_skipped',
|
|
2377
|
+
enabled: false,
|
|
2378
|
+
checkoutId: checkout.id,
|
|
2379
|
+
}));
|
|
2380
|
+
}
|
|
2234
2381
|
return true;
|
|
2235
2382
|
}
|
|
2236
2383
|
}
|
|
2237
2384
|
|
|
2238
2385
|
class AntifraudPixService {
|
|
2239
|
-
constructor() {
|
|
2240
|
-
|
|
2386
|
+
constructor(shopConfigsRepository) {
|
|
2387
|
+
this.shopConfigsRepository = shopConfigsRepository;
|
|
2388
|
+
}
|
|
2389
|
+
async validate(checkout) {
|
|
2390
|
+
const enabled = await isAntifraudEnabled(this.shopConfigsRepository);
|
|
2391
|
+
if (!enabled) {
|
|
2392
|
+
console.info(JSON.stringify({
|
|
2393
|
+
msg: 'antifraud_pix_skipped',
|
|
2394
|
+
enabled: false,
|
|
2395
|
+
checkoutId: checkout.id,
|
|
2396
|
+
}));
|
|
2397
|
+
}
|
|
2241
2398
|
return true;
|
|
2242
2399
|
}
|
|
2243
2400
|
}
|
|
@@ -2591,6 +2748,26 @@ class ShopSettings extends BaseModel {
|
|
|
2591
2748
|
}
|
|
2592
2749
|
}
|
|
2593
2750
|
|
|
2751
|
+
/**
|
|
2752
|
+
* Defaults iguais ao hardcode histórico do checkout.
|
|
2753
|
+
* `week.*.zip = null` → Infinity no runtime do volume de cartão.
|
|
2754
|
+
*/
|
|
2755
|
+
const DEFAULT_SHOP_ANTIFRAUD_CONFIG = {
|
|
2756
|
+
enabled: true,
|
|
2757
|
+
day: {
|
|
2758
|
+
subscriber: { cpf: 4, email: 4, phone: 4, card: 4, zip: 4 },
|
|
2759
|
+
nonSubscriber: { cpf: 2, email: 2, phone: 2, card: 2, zip: 2 },
|
|
2760
|
+
},
|
|
2761
|
+
week: {
|
|
2762
|
+
subscriber: { cpf: 12, email: 12, phone: 12, card: 12, zip: null },
|
|
2763
|
+
nonSubscriber: { cpf: 7, email: 7, phone: 7, card: 7, zip: null },
|
|
2764
|
+
},
|
|
2765
|
+
blockedAttemptsDay: {
|
|
2766
|
+
subscriber: 7,
|
|
2767
|
+
nonSubscriber: 5,
|
|
2768
|
+
},
|
|
2769
|
+
};
|
|
2770
|
+
|
|
2594
2771
|
class AdyenBlockedOrderHelper {
|
|
2595
2772
|
static async handleUnauthorizedPayment(params) {
|
|
2596
2773
|
await params.orderBlockedRepository.createBlockedOrderOrPayment({
|
|
@@ -5474,7 +5651,7 @@ class CampaignHashtagFirestoreRepository extends withCrudFirestore(withHelpers(w
|
|
|
5474
5651
|
constructor({ firestore, interceptors, cache, }) {
|
|
5475
5652
|
super({
|
|
5476
5653
|
firestore,
|
|
5477
|
-
collectionName: '
|
|
5654
|
+
collectionName: 'CampaignsHashtags',
|
|
5478
5655
|
model: CampaignHashtag,
|
|
5479
5656
|
interceptors,
|
|
5480
5657
|
cache,
|
|
@@ -5482,6 +5659,18 @@ class CampaignHashtagFirestoreRepository extends withCrudFirestore(withHelpers(w
|
|
|
5482
5659
|
}
|
|
5483
5660
|
}
|
|
5484
5661
|
|
|
5662
|
+
class CampaignHashtagPostsFirestoreRepository extends withCrudFirestore(withHelpers(withFirestore(Base))) {
|
|
5663
|
+
constructor({ firestore, interceptors, cache, }) {
|
|
5664
|
+
super({
|
|
5665
|
+
firestore,
|
|
5666
|
+
collectionName: 'CampaignsHashtagsPosts',
|
|
5667
|
+
model: CampaignHashtagPosts,
|
|
5668
|
+
interceptors,
|
|
5669
|
+
cache,
|
|
5670
|
+
});
|
|
5671
|
+
}
|
|
5672
|
+
}
|
|
5673
|
+
|
|
5485
5674
|
class CheckoutFirestoreRepository extends withCrudFirestore(withHelpers(withFirestore(Base))) {
|
|
5486
5675
|
constructor({ firestore, interceptors, cache, }) {
|
|
5487
5676
|
super({
|
|
@@ -11715,6 +11904,7 @@ Object.defineProperty(exports, 'unset', {
|
|
|
11715
11904
|
enumerable: true,
|
|
11716
11905
|
get: function () { return lodash.unset; }
|
|
11717
11906
|
});
|
|
11907
|
+
exports.ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS = ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS;
|
|
11718
11908
|
exports.Address = Address;
|
|
11719
11909
|
exports.AdyenCardAxiosAdapter = AdyenCardAxiosAdapter;
|
|
11720
11910
|
exports.AdyenPaymentMethodFactory = AdyenPaymentMethodFactory;
|
|
@@ -11741,6 +11931,8 @@ exports.CampaignDashboard = CampaignDashboard;
|
|
|
11741
11931
|
exports.CampaignDashboardFirestoreRepository = CampaignDashboardFirestoreRepository;
|
|
11742
11932
|
exports.CampaignHashtag = CampaignHashtag;
|
|
11743
11933
|
exports.CampaignHashtagFirestoreRepository = CampaignHashtagFirestoreRepository;
|
|
11934
|
+
exports.CampaignHashtagPosts = CampaignHashtagPosts;
|
|
11935
|
+
exports.CampaignHashtagPostsFirestoreRepository = CampaignHashtagPostsFirestoreRepository;
|
|
11744
11936
|
exports.Category = Category;
|
|
11745
11937
|
exports.CategoryCollectionChildren = CategoryCollectionChildren;
|
|
11746
11938
|
exports.CategoryCollectionChildrenHasuraGraphQLRepository = CategoryCollectionChildrenHasuraGraphQLRepository;
|
|
@@ -11762,6 +11954,8 @@ exports.ConnectDocumentService = ConnectDocumentService;
|
|
|
11762
11954
|
exports.ConnectFirestoreService = ConnectFirestoreService;
|
|
11763
11955
|
exports.Coupon = Coupon;
|
|
11764
11956
|
exports.CouponFirestoreRepository = CouponFirestoreRepository;
|
|
11957
|
+
exports.DEFAULT_ANTIFRAUD_VOLUME_LIMITS = DEFAULT_ANTIFRAUD_VOLUME_LIMITS;
|
|
11958
|
+
exports.DEFAULT_SHOP_ANTIFRAUD_CONFIG = DEFAULT_SHOP_ANTIFRAUD_CONFIG;
|
|
11765
11959
|
exports.Debug = Debug;
|
|
11766
11960
|
exports.DebugDecoratorHelper = DebugDecoratorHelper;
|
|
11767
11961
|
exports.DebugHelper = DebugHelper;
|
|
@@ -11898,10 +12092,12 @@ exports.WishlistHasuraGraphQLRepository = WishlistHasuraGraphQLRepository;
|
|
|
11898
12092
|
exports.deserialize = deserialize;
|
|
11899
12093
|
exports.getClass = getClass;
|
|
11900
12094
|
exports.is = is;
|
|
12095
|
+
exports.isAntifraudEnabled = isAntifraudEnabled;
|
|
11901
12096
|
exports.isDebuggable = isDebuggable;
|
|
11902
12097
|
exports.isUUID = isUUID;
|
|
11903
12098
|
exports.parseDateTime = parseDateTime;
|
|
11904
12099
|
exports.registerClass = registerClass;
|
|
12100
|
+
exports.resolveAntifraudVolumeLimits = resolveAntifraudVolumeLimits;
|
|
11905
12101
|
exports.resolveCacheConfig = resolveCacheConfig;
|
|
11906
12102
|
exports.resolveClass = resolveClass;
|
|
11907
12103
|
exports.serialize = serialize;
|
package/index.esm.js
CHANGED
|
@@ -151,6 +151,123 @@ class PaymentProviderFactory {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
const ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS = 60;
|
|
155
|
+
/**
|
|
156
|
+
* Lê `shopConfigs.antifraude.enabled`.
|
|
157
|
+
* - `false` explícito → antifraude desligado
|
|
158
|
+
* - ausente / erro / inválido → `true` (mantém comportamento histórico)
|
|
159
|
+
*/
|
|
160
|
+
async function isAntifraudEnabled(shopConfigsRepository) {
|
|
161
|
+
if (!shopConfigsRepository) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
const result = await shopConfigsRepository.find({}, { cache: { enabled: true, ttl: ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS } });
|
|
166
|
+
const enabled = result?.data?.at(0)?.antifraude?.enabled;
|
|
167
|
+
if (typeof enabled === 'boolean') {
|
|
168
|
+
return enabled;
|
|
169
|
+
}
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
console.warn(JSON.stringify({
|
|
174
|
+
msg: 'antifraud_enabled_config_load_failed',
|
|
175
|
+
enabled: true,
|
|
176
|
+
error: error instanceof Error ? error.message : String(error),
|
|
177
|
+
}));
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Defaults de runtime (week.zip = Infinity). Usados só como fallback no checkout. */
|
|
183
|
+
const DEFAULT_ANTIFRAUD_VOLUME_LIMITS = {
|
|
184
|
+
enabled: true,
|
|
185
|
+
source: 'fallback',
|
|
186
|
+
day: {
|
|
187
|
+
subscriber: { cpf: 4, email: 4, phone: 4, card: 4, zip: 4 },
|
|
188
|
+
nonSubscriber: { cpf: 2, email: 2, phone: 2, card: 2, zip: 2 },
|
|
189
|
+
},
|
|
190
|
+
week: {
|
|
191
|
+
subscriber: { cpf: 12, email: 12, phone: 12, card: 12, zip: Infinity },
|
|
192
|
+
nonSubscriber: { cpf: 7, email: 7, phone: 7, card: 7, zip: Infinity },
|
|
193
|
+
},
|
|
194
|
+
blockedAttemptsDay: {
|
|
195
|
+
subscriber: 7,
|
|
196
|
+
nonSubscriber: 5,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
function isPositiveInteger(value) {
|
|
200
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 1 && Number.isInteger(value);
|
|
201
|
+
}
|
|
202
|
+
function normalizeLimitOrders(raw, allowInfiniteZip) {
|
|
203
|
+
if (!raw)
|
|
204
|
+
return null;
|
|
205
|
+
const zip = allowInfiniteZip && (raw.zip === null || raw.zip === undefined || raw.zip === Infinity) ? Infinity : raw.zip;
|
|
206
|
+
const normalized = {
|
|
207
|
+
cpf: raw.cpf,
|
|
208
|
+
email: raw.email,
|
|
209
|
+
phone: raw.phone,
|
|
210
|
+
zip: zip,
|
|
211
|
+
card: raw.card,
|
|
212
|
+
};
|
|
213
|
+
for (const key of ['cpf', 'email', 'phone', 'zip', 'card']) {
|
|
214
|
+
if (key === 'zip' && normalized.zip === Infinity)
|
|
215
|
+
continue;
|
|
216
|
+
if (!isPositiveInteger(normalized[key]))
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
return normalized;
|
|
220
|
+
}
|
|
221
|
+
function cloneFallbackLimits() {
|
|
222
|
+
return {
|
|
223
|
+
...DEFAULT_ANTIFRAUD_VOLUME_LIMITS,
|
|
224
|
+
day: {
|
|
225
|
+
subscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.day.subscriber },
|
|
226
|
+
nonSubscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.day.nonSubscriber },
|
|
227
|
+
},
|
|
228
|
+
week: {
|
|
229
|
+
subscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.week.subscriber },
|
|
230
|
+
nonSubscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.week.nonSubscriber },
|
|
231
|
+
},
|
|
232
|
+
blockedAttemptsDay: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.blockedAttemptsDay },
|
|
233
|
+
source: 'fallback',
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/** Config inválida/ausente → fallback (comportamento histórico). */
|
|
237
|
+
function resolveAntifraudVolumeLimits(antifraude) {
|
|
238
|
+
if (!antifraude || typeof antifraude.enabled !== 'boolean') {
|
|
239
|
+
return cloneFallbackLimits();
|
|
240
|
+
}
|
|
241
|
+
const daySubscriber = normalizeLimitOrders(antifraude.day?.subscriber, false);
|
|
242
|
+
const dayNonSubscriber = normalizeLimitOrders(antifraude.day?.nonSubscriber, false);
|
|
243
|
+
const weekSubscriber = normalizeLimitOrders(antifraude.week?.subscriber, true);
|
|
244
|
+
const weekNonSubscriber = normalizeLimitOrders(antifraude.week?.nonSubscriber, true);
|
|
245
|
+
const blocked = antifraude.blockedAttemptsDay;
|
|
246
|
+
if (!daySubscriber ||
|
|
247
|
+
!dayNonSubscriber ||
|
|
248
|
+
!weekSubscriber ||
|
|
249
|
+
!weekNonSubscriber ||
|
|
250
|
+
!blocked ||
|
|
251
|
+
!isPositiveInteger(blocked.subscriber) ||
|
|
252
|
+
!isPositiveInteger(blocked.nonSubscriber)) {
|
|
253
|
+
// Kill-switch explícito prevalece mesmo com payload inválido.
|
|
254
|
+
if (antifraude.enabled === false) {
|
|
255
|
+
return { ...cloneFallbackLimits(), enabled: false, source: 'fallback' };
|
|
256
|
+
}
|
|
257
|
+
return cloneFallbackLimits();
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
enabled: antifraude.enabled,
|
|
261
|
+
source: 'config',
|
|
262
|
+
day: { subscriber: daySubscriber, nonSubscriber: dayNonSubscriber },
|
|
263
|
+
week: { subscriber: weekSubscriber, nonSubscriber: weekNonSubscriber },
|
|
264
|
+
blockedAttemptsDay: {
|
|
265
|
+
subscriber: blocked.subscriber,
|
|
266
|
+
nonSubscriber: blocked.nonSubscriber,
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
154
271
|
const registry = new Map();
|
|
155
272
|
function registerClass(name, classConstructor) {
|
|
156
273
|
registry.set(name, classConstructor);
|
|
@@ -1032,6 +1149,12 @@ class CampaignHashtag extends BaseModel {
|
|
|
1032
1149
|
}
|
|
1033
1150
|
}
|
|
1034
1151
|
|
|
1152
|
+
class CampaignHashtagPosts extends BaseModel {
|
|
1153
|
+
static get identifiersFields() {
|
|
1154
|
+
return ['id'];
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1035
1158
|
class BeautyProfile extends BaseModel {
|
|
1036
1159
|
toPlain() {
|
|
1037
1160
|
const plain = super.toPlain();
|
|
@@ -1900,12 +2023,23 @@ class StockOutError extends BusinessError {
|
|
|
1900
2023
|
}
|
|
1901
2024
|
}
|
|
1902
2025
|
|
|
2026
|
+
/* eslint-disable no-console */
|
|
1903
2027
|
class AntifraudBankSlipService {
|
|
1904
|
-
constructor(orderBlockedRepository) {
|
|
2028
|
+
constructor(orderBlockedRepository, shopConfigsRepository) {
|
|
1905
2029
|
this.orderBlockedRepository = orderBlockedRepository;
|
|
2030
|
+
this.shopConfigsRepository = shopConfigsRepository;
|
|
1906
2031
|
this.MAX_ORDER_VALUE = 5000;
|
|
1907
2032
|
}
|
|
1908
2033
|
async validate(checkout) {
|
|
2034
|
+
const enabled = await isAntifraudEnabled(this.shopConfigsRepository);
|
|
2035
|
+
if (!enabled) {
|
|
2036
|
+
console.info(JSON.stringify({
|
|
2037
|
+
msg: 'antifraud_bankslip_skipped',
|
|
2038
|
+
enabled: false,
|
|
2039
|
+
checkoutId: checkout.id,
|
|
2040
|
+
}));
|
|
2041
|
+
return true;
|
|
2042
|
+
}
|
|
1909
2043
|
if (checkout.totalPrice && checkout.totalPrice > this.MAX_ORDER_VALUE && !checkout.user?.isSubscriber) {
|
|
1910
2044
|
await this.orderBlockedRepository.createBlockedOrderOrPayment({
|
|
1911
2045
|
checkout,
|
|
@@ -1927,62 +2061,67 @@ class AntifraudBankSlipService {
|
|
|
1927
2061
|
}
|
|
1928
2062
|
}
|
|
1929
2063
|
|
|
2064
|
+
/* eslint-disable max-params */
|
|
1930
2065
|
class AntifraudCardService {
|
|
1931
|
-
constructor(orderRepository, orderBlockedRepository) {
|
|
2066
|
+
constructor(orderRepository, orderBlockedRepository, shopConfigsRepository) {
|
|
1932
2067
|
this.orderRepository = orderRepository;
|
|
1933
2068
|
this.orderBlockedRepository = orderBlockedRepository;
|
|
1934
|
-
this.
|
|
1935
|
-
this.LIMIT_ORDERS_WEEK = null;
|
|
2069
|
+
this.shopConfigsRepository = shopConfigsRepository;
|
|
1936
2070
|
}
|
|
1937
2071
|
async validate(checkout, card) {
|
|
1938
|
-
|
|
1939
|
-
await this.
|
|
1940
|
-
|
|
2072
|
+
// Limites locais por request — evita race em provider Nest singleton entre awaits.
|
|
2073
|
+
const resolved = await this.loadResolvedLimits();
|
|
2074
|
+
const isSubscriber = !!checkout.user?.isSubscriber;
|
|
2075
|
+
const dayLimits = isSubscriber ? resolved.day.subscriber : resolved.day.nonSubscriber;
|
|
2076
|
+
const weekLimits = isSubscriber ? resolved.week.subscriber : resolved.week.nonSubscriber;
|
|
2077
|
+
const blockedAttemptsDay = isSubscriber
|
|
2078
|
+
? resolved.blockedAttemptsDay.subscriber
|
|
2079
|
+
: resolved.blockedAttemptsDay.nonSubscriber;
|
|
2080
|
+
if (!resolved.enabled) {
|
|
2081
|
+
console.info(JSON.stringify({
|
|
2082
|
+
msg: 'antifraud_card_volume_skipped',
|
|
2083
|
+
source: resolved.source,
|
|
2084
|
+
enabled: false,
|
|
2085
|
+
checkoutId: checkout.id,
|
|
2086
|
+
isSubscriber,
|
|
2087
|
+
}));
|
|
2088
|
+
return true;
|
|
2089
|
+
}
|
|
2090
|
+
console.info(JSON.stringify({
|
|
2091
|
+
msg: 'antifraud_card_volume_limits',
|
|
2092
|
+
source: resolved.source,
|
|
2093
|
+
enabled: true,
|
|
2094
|
+
checkoutId: checkout.id,
|
|
2095
|
+
isSubscriber,
|
|
2096
|
+
blockedAttemptsDay,
|
|
2097
|
+
day: dayLimits,
|
|
2098
|
+
week: weekLimits,
|
|
2099
|
+
}));
|
|
2100
|
+
await this.validateBlockedOrderAttempts(checkout, card, blockedAttemptsDay);
|
|
2101
|
+
await this.validateDayAndWeekOrderLimits(checkout, card, dayLimits, weekLimits);
|
|
1941
2102
|
return true;
|
|
1942
2103
|
}
|
|
1943
|
-
|
|
1944
|
-
this.
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
};
|
|
1960
|
-
this.LIMIT_ORDERS_WEEK = {
|
|
1961
|
-
subscriber: {
|
|
1962
|
-
cpf: 12,
|
|
1963
|
-
email: 12,
|
|
1964
|
-
phone: 12,
|
|
1965
|
-
card: 12,
|
|
1966
|
-
zip: Infinity,
|
|
1967
|
-
},
|
|
1968
|
-
nonSubscriber: {
|
|
1969
|
-
cpf: 7,
|
|
1970
|
-
email: 7,
|
|
1971
|
-
phone: 7,
|
|
1972
|
-
card: 7,
|
|
1973
|
-
zip: Infinity,
|
|
1974
|
-
},
|
|
1975
|
-
};
|
|
1976
|
-
this.LIMIT_BLOCKED_ORDERS_DAY = isSubscriber ? 7 : 5;
|
|
1977
|
-
}
|
|
1978
|
-
getLimitsByUserType(type, isSubscriber) {
|
|
1979
|
-
const limits = type === 'day' ? this.LIMIT_ORDERS_DAY : this.LIMIT_ORDERS_WEEK;
|
|
1980
|
-
return isSubscriber ? limits['subscriber'] : limits['nonSubscriber'];
|
|
2104
|
+
async loadResolvedLimits() {
|
|
2105
|
+
if (!this.shopConfigsRepository) {
|
|
2106
|
+
return resolveAntifraudVolumeLimits(null);
|
|
2107
|
+
}
|
|
2108
|
+
try {
|
|
2109
|
+
const result = await this.shopConfigsRepository.find({}, { cache: { enabled: true, ttl: ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS } });
|
|
2110
|
+
return resolveAntifraudVolumeLimits(result?.data?.at(0)?.antifraude);
|
|
2111
|
+
}
|
|
2112
|
+
catch (error) {
|
|
2113
|
+
console.warn(JSON.stringify({
|
|
2114
|
+
msg: 'antifraud_card_volume_config_load_failed',
|
|
2115
|
+
source: 'fallback',
|
|
2116
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2117
|
+
}));
|
|
2118
|
+
return resolveAntifraudVolumeLimits(null);
|
|
2119
|
+
}
|
|
1981
2120
|
}
|
|
1982
|
-
async validateBlockedOrderAttempts(checkout, card) {
|
|
1983
|
-
const isValid = await this.verifyBlockedOrderAttempts(checkout, card);
|
|
2121
|
+
async validateBlockedOrderAttempts(checkout, card, blockedAttemptsDay) {
|
|
2122
|
+
const isValid = await this.verifyBlockedOrderAttempts(checkout, card, blockedAttemptsDay);
|
|
1984
2123
|
if (!isValid) {
|
|
1985
|
-
throw new FraudValidationError(`Cliente com mais de ${
|
|
2124
|
+
throw new FraudValidationError(`Cliente com mais de ${blockedAttemptsDay} compras negadas/bloqueadas no dia`, ErrorsCode.fraudPreventionInternal, {
|
|
1986
2125
|
checkoutId: checkout.id,
|
|
1987
2126
|
userEmail: checkout.user.email,
|
|
1988
2127
|
info: {
|
|
@@ -1993,8 +2132,8 @@ class AntifraudCardService {
|
|
|
1993
2132
|
});
|
|
1994
2133
|
}
|
|
1995
2134
|
}
|
|
1996
|
-
async validateDayAndWeekOrderLimits(checkout, card) {
|
|
1997
|
-
const isValid = await this.verifyDayAndWeekOrders(checkout, card);
|
|
2135
|
+
async validateDayAndWeekOrderLimits(checkout, card, dayLimits, weekLimits) {
|
|
2136
|
+
const isValid = await this.verifyDayAndWeekOrders(checkout, card, dayLimits, weekLimits);
|
|
1998
2137
|
if (!isValid) {
|
|
1999
2138
|
throw new FraudValidationError('Cliente tentando comprar mais do que o permitido no dia/semana', ErrorsCode.fraudPreventionInternal, {
|
|
2000
2139
|
checkoutId: checkout.id,
|
|
@@ -2007,15 +2146,15 @@ class AntifraudCardService {
|
|
|
2007
2146
|
});
|
|
2008
2147
|
}
|
|
2009
2148
|
}
|
|
2010
|
-
async verifyBlockedOrderAttempts(checkout, card) {
|
|
2149
|
+
async verifyBlockedOrderAttempts(checkout, card, blockedAttemptsDay) {
|
|
2011
2150
|
const dateRange = this.getTodayDateRange();
|
|
2012
2151
|
const blockedOrders = await this.getBlockedOrdersByMultipleCriteria(checkout, dateRange);
|
|
2013
2152
|
const totalBlockedAttempts = this.calculateUniqueBlockedAttempts(blockedOrders, checkout);
|
|
2014
|
-
if (totalBlockedAttempts >=
|
|
2153
|
+
if (totalBlockedAttempts >= blockedAttemptsDay) {
|
|
2015
2154
|
await this.createBlockedOrderRecord({
|
|
2016
2155
|
checkout,
|
|
2017
2156
|
card,
|
|
2018
|
-
reason: `More than ${
|
|
2157
|
+
reason: `More than ${blockedAttemptsDay} attempts have failed`,
|
|
2019
2158
|
key: 'Failed attempts',
|
|
2020
2159
|
period: 'day',
|
|
2021
2160
|
});
|
|
@@ -2117,12 +2256,12 @@ class AntifraudCardService {
|
|
|
2117
2256
|
card,
|
|
2118
2257
|
});
|
|
2119
2258
|
}
|
|
2120
|
-
async verifyDayAndWeekOrders(checkout, card) {
|
|
2259
|
+
async verifyDayAndWeekOrders(checkout, card, dayLimits, weekLimits) {
|
|
2121
2260
|
const validationParams = this.buildValidationParams(checkout, card);
|
|
2122
|
-
const isDayLimitValid = await this.validateDayOrderLimits(checkout, validationParams);
|
|
2261
|
+
const isDayLimitValid = await this.validateDayOrderLimits(checkout, validationParams, dayLimits);
|
|
2123
2262
|
if (!isDayLimitValid)
|
|
2124
2263
|
return false;
|
|
2125
|
-
const isWeekLimitValid = await this.validateWeekOrderLimits(checkout, validationParams);
|
|
2264
|
+
const isWeekLimitValid = await this.validateWeekOrderLimits(checkout, validationParams, weekLimits);
|
|
2126
2265
|
return isWeekLimitValid;
|
|
2127
2266
|
}
|
|
2128
2267
|
buildValidationParams(checkout, card) {
|
|
@@ -2134,9 +2273,8 @@ class AntifraudCardService {
|
|
|
2134
2273
|
card,
|
|
2135
2274
|
};
|
|
2136
2275
|
}
|
|
2137
|
-
async validateDayOrderLimits(checkout, params) {
|
|
2276
|
+
async validateDayOrderLimits(checkout, params, limits) {
|
|
2138
2277
|
const ordersPerDay = await this.validateOrdersByRange(params, this.getDateRange('day'));
|
|
2139
|
-
const limits = this.getLimitsByUserType('day', checkout.user.isSubscriber);
|
|
2140
2278
|
return this.checkOrderLimitsAndBlock({
|
|
2141
2279
|
checkout,
|
|
2142
2280
|
orderCounts: ordersPerDay,
|
|
@@ -2144,9 +2282,8 @@ class AntifraudCardService {
|
|
|
2144
2282
|
period: 'day',
|
|
2145
2283
|
});
|
|
2146
2284
|
}
|
|
2147
|
-
async validateWeekOrderLimits(checkout, params) {
|
|
2285
|
+
async validateWeekOrderLimits(checkout, params, limits) {
|
|
2148
2286
|
const ordersPerWeek = await this.validateOrdersByRange(params, this.getDateRange('week'));
|
|
2149
|
-
const limits = this.getLimitsByUserType('week', checkout.user.isSubscriber);
|
|
2150
2287
|
return this.checkOrderLimitsAndBlock({
|
|
2151
2288
|
checkout,
|
|
2152
2289
|
orderCounts: ordersPerWeek,
|
|
@@ -2223,15 +2360,35 @@ class AntifraudCardService {
|
|
|
2223
2360
|
}
|
|
2224
2361
|
|
|
2225
2362
|
class AntifraudGlampointsService {
|
|
2226
|
-
constructor() {
|
|
2227
|
-
|
|
2363
|
+
constructor(shopConfigsRepository) {
|
|
2364
|
+
this.shopConfigsRepository = shopConfigsRepository;
|
|
2365
|
+
}
|
|
2366
|
+
async validate(checkout) {
|
|
2367
|
+
const enabled = await isAntifraudEnabled(this.shopConfigsRepository);
|
|
2368
|
+
if (!enabled) {
|
|
2369
|
+
console.info(JSON.stringify({
|
|
2370
|
+
msg: 'antifraud_glampoints_skipped',
|
|
2371
|
+
enabled: false,
|
|
2372
|
+
checkoutId: checkout.id,
|
|
2373
|
+
}));
|
|
2374
|
+
}
|
|
2228
2375
|
return true;
|
|
2229
2376
|
}
|
|
2230
2377
|
}
|
|
2231
2378
|
|
|
2232
2379
|
class AntifraudPixService {
|
|
2233
|
-
constructor() {
|
|
2234
|
-
|
|
2380
|
+
constructor(shopConfigsRepository) {
|
|
2381
|
+
this.shopConfigsRepository = shopConfigsRepository;
|
|
2382
|
+
}
|
|
2383
|
+
async validate(checkout) {
|
|
2384
|
+
const enabled = await isAntifraudEnabled(this.shopConfigsRepository);
|
|
2385
|
+
if (!enabled) {
|
|
2386
|
+
console.info(JSON.stringify({
|
|
2387
|
+
msg: 'antifraud_pix_skipped',
|
|
2388
|
+
enabled: false,
|
|
2389
|
+
checkoutId: checkout.id,
|
|
2390
|
+
}));
|
|
2391
|
+
}
|
|
2235
2392
|
return true;
|
|
2236
2393
|
}
|
|
2237
2394
|
}
|
|
@@ -2585,6 +2742,26 @@ class ShopSettings extends BaseModel {
|
|
|
2585
2742
|
}
|
|
2586
2743
|
}
|
|
2587
2744
|
|
|
2745
|
+
/**
|
|
2746
|
+
* Defaults iguais ao hardcode histórico do checkout.
|
|
2747
|
+
* `week.*.zip = null` → Infinity no runtime do volume de cartão.
|
|
2748
|
+
*/
|
|
2749
|
+
const DEFAULT_SHOP_ANTIFRAUD_CONFIG = {
|
|
2750
|
+
enabled: true,
|
|
2751
|
+
day: {
|
|
2752
|
+
subscriber: { cpf: 4, email: 4, phone: 4, card: 4, zip: 4 },
|
|
2753
|
+
nonSubscriber: { cpf: 2, email: 2, phone: 2, card: 2, zip: 2 },
|
|
2754
|
+
},
|
|
2755
|
+
week: {
|
|
2756
|
+
subscriber: { cpf: 12, email: 12, phone: 12, card: 12, zip: null },
|
|
2757
|
+
nonSubscriber: { cpf: 7, email: 7, phone: 7, card: 7, zip: null },
|
|
2758
|
+
},
|
|
2759
|
+
blockedAttemptsDay: {
|
|
2760
|
+
subscriber: 7,
|
|
2761
|
+
nonSubscriber: 5,
|
|
2762
|
+
},
|
|
2763
|
+
};
|
|
2764
|
+
|
|
2588
2765
|
class AdyenBlockedOrderHelper {
|
|
2589
2766
|
static async handleUnauthorizedPayment(params) {
|
|
2590
2767
|
await params.orderBlockedRepository.createBlockedOrderOrPayment({
|
|
@@ -5468,7 +5645,7 @@ class CampaignHashtagFirestoreRepository extends withCrudFirestore(withHelpers(w
|
|
|
5468
5645
|
constructor({ firestore, interceptors, cache, }) {
|
|
5469
5646
|
super({
|
|
5470
5647
|
firestore,
|
|
5471
|
-
collectionName: '
|
|
5648
|
+
collectionName: 'CampaignsHashtags',
|
|
5472
5649
|
model: CampaignHashtag,
|
|
5473
5650
|
interceptors,
|
|
5474
5651
|
cache,
|
|
@@ -5476,6 +5653,18 @@ class CampaignHashtagFirestoreRepository extends withCrudFirestore(withHelpers(w
|
|
|
5476
5653
|
}
|
|
5477
5654
|
}
|
|
5478
5655
|
|
|
5656
|
+
class CampaignHashtagPostsFirestoreRepository extends withCrudFirestore(withHelpers(withFirestore(Base))) {
|
|
5657
|
+
constructor({ firestore, interceptors, cache, }) {
|
|
5658
|
+
super({
|
|
5659
|
+
firestore,
|
|
5660
|
+
collectionName: 'CampaignsHashtagsPosts',
|
|
5661
|
+
model: CampaignHashtagPosts,
|
|
5662
|
+
interceptors,
|
|
5663
|
+
cache,
|
|
5664
|
+
});
|
|
5665
|
+
}
|
|
5666
|
+
}
|
|
5667
|
+
|
|
5479
5668
|
class CheckoutFirestoreRepository extends withCrudFirestore(withHelpers(withFirestore(Base))) {
|
|
5480
5669
|
constructor({ firestore, interceptors, cache, }) {
|
|
5481
5670
|
super({
|
|
@@ -11581,4 +11770,4 @@ class ProductsVertexSearch {
|
|
|
11581
11770
|
}
|
|
11582
11771
|
}
|
|
11583
11772
|
|
|
11584
|
-
export { AccessoryImportances, Address, AdyenCardAxiosAdapter, AdyenPaymentMethodFactory, AntifraudBankSlipService, AntifraudCardService, AntifraudGlampointsService, AntifraudPixService, AntifraudProviderFactory, AntifraudProviders, Area, Authentication, AuthenticationFirebaseAuthService, AxiosAdapter, Base, BaseModel, BeardProblems, BeardSizes, BeautyProductImportances, BeautyProfile, BeautyQuestionsHelper, BillingStatus, BodyProblems, BodyShapes, BodyTattoos, BrandCategory, BrandCategoryFirestoreRepository, BrandEquityOptions, BusinessError, BusinessUnitEnum, Buy2Win, Buy2WinFirestoreRepository, Campaign, CampaignBanner, CampaignDashboard, CampaignDashboardFirestoreRepository, CampaignHashtag, CampaignHashtagFirestoreRepository, Category, CategoryCollectionChildren, CategoryCollectionChildrenHasuraGraphQLRepository, CategoryFilter, CategoryFilterHasuraGraphQLRepository, CategoryFirestoreRepository, CategoryHasuraGraphQL, CategoryHasuraGraphQLRepository, CategoryProduct, CategoryProductHasuraGraphQLRepository, Checkout, CheckoutFirestoreRepository, CheckoutSubscription, CheckoutSubscriptionFirestoreRepository, CheckoutTypes, ClassNameHelper, ConnectBaseDocumentSnapshot, ConnectCollectionService, ConnectDocumentService, ConnectFirestoreService, Coupon, CouponCategories, CouponCategory, CouponChannels, CouponFirestoreRepository, CouponOldCategories, CouponSubtypes, CouponTypes, Debug, DebugDecoratorHelper, DebugHelper, DebugNamespaces, DuplicatedResultsError, Edition, EditionStatus, ErrorsCode, Exclusivities, FaceSkinOilinesses, FaceSkinProblems, FaceSkinTones, FamilyIncomes, Filter, FilterHasuraGraphQLRepository, FilterOption, FilterOptionHasuraGraphQLRepository, FilterType, FirebaseFileUploaderService, FragranceImportances, FraudValidationError, GenderDestination, GlampointsPaymentMethodFactory, GlampointsPaymentService, Group, GroupFirestoreRepository, HairColors, HairProblems, HairStrands, HairTypes, Home, HomeFirestoreRepository, InvalidArgumentError, InvalidCheckoutError, KitProduct, KitProductHasuraGraphQL, Lead, LeadFirestoreRepository, LegacyOrderFirestoreRepository, LineItem, Log, LogDocument, LogFirestoreRepository, Logger, MercadoPagoBankSlipAxiosAdapter, MercadoPagoCardAxiosAdapter, MercadoPagoErrorHelper, MercadoPagoPaymentMethodFactory, MercadoPagoPixAxiosAdapter, MercadoPagoRequestHelper, MercadoPagoResponseHelper, MercadoPagoStatusDetailEnum, MercadoPagoStatusEnum, NotFoundError, ObsEmitter, OfficePosition, Order, OrderBlocked, OrderBlockedFirestoreRepository, OrderBlockedType, OrderFirestoreRepository, OrderPaymentStatus, OrderStatus, PagarMeV5OrderStatus, PagarMeV5PaymentStatus, PagarmeBankSlipAxiosAdapter, PagarmeCardAxiosAdapter, PagarmePaymentMethodFactory, PagarmePaymentStatus, PagarmePixAxiosAdapter, PagarmeV5BankSlipAxiosAdapter, PagarmeV5BaseAxiosAdapter, PagarmeV5CardAxiosAdapter, PagarmeV5PixAxiosAdapter, Payment, PaymentError, PaymentFirestoreRepository, PaymentMethods, PaymentProviderFactory, PaymentProviders, PaymentTransaction, PaymentType, PersonTypes, Plans, Product, ProductCatalogHasuraGraphQL, ProductCatalogHasuraGraphQLRepository, ProductErrors, ProductErrorsHasuraGraphQL, ProductErrorsHasuraGraphQLRepository, ProductFirestoreRepository, ProductGroup, ProductGroupHasuraGraphQLRepository, ProductHasuraGraphQL, ProductHasuraGraphQLRepository, ProductLabelEnum, ProductPriceLog, ProductPriceLogHasuraGraphQLRepository, ProductReview, ProductReviewHasuraGraphQLRepository, ProductSpents, ProductStockEntry, ProductStockEntryHasuraGraphQL, ProductStockEntryHasuraGraphQLRepository, ProductStockNotification, ProductStockNotificationHasuraGraphQLRepository, ProductVariantFirestoreRepository, ProductsIndex, ProductsVertexSearch, QuestionsFilters, RecoveryPassword, ReflectHelper, Register, RegisterFirebaseAuthService, RequiredArgumentError, RestCacheAdapter, RoundProductPricesHelper, Sequence, SequenceFirestoreRepository, ShippingMethod, ShopConfigs, ShopConfigsFirestoreRepository, ShopMenu, ShopMenuFirestoreRepository, ShopPageName, ShopSettings, ShopSettingsFirestoreRepository, ShoppingRecurrence, ShoppingRecurrenceCycle, ShoppingRecurrenceEdition, ShoppingRecurrenceEditionFirestoreRepository, ShoppingRecurrenceEditionStatus, ShoppingRecurrenceErrorLog, ShoppingRecurrenceErrorLogFirestoreRepository, ShoppingRecurrenceFirestoreRepository, ShoppingRecurrenceStatus, Shops, SignInMethods, SignOut, Status, StockLimitError, StockOutError, Subscription, SubscriptionEditionFirestoreRepository, SubscriptionFirestoreRepository, SubscriptionMaterialization, SubscriptionMaterializationFirestoreRepository, SubscriptionPayment, SubscriptionPaymentFirestoreRepository, SubscriptionPlan, SubscriptionPlanFirestoreRepository, SubscriptionProductFirestoreRepository, SubscriptionSummary, SubscriptionSummaryFirestoreRepository, Trace, TransactionPaymentMethods, UnauthorizedError, UpdateOptionActions, UpdateUserImage, User, UserAddress, UserAddressFirestoreRepository, UserAlreadyRegisteredError, UserBeautyProfileFirestoreRepository, UserFirestoreRepository, UserPaymentMethod, UserPaymentMethodFirestoreRepository, UserType, Variant, VariantHasuraGraphQL, VariantHasuraGraphQLRepository, VertexAxiosAdapter, WeakPasswordError, Where, Wishlist, WishlistHasuraGraphQLRepository, WishlistLogType, deserialize, getClass, is, isDebuggable, isUUID, parseDateTime, registerClass, resolveCacheConfig, resolveClass, serialize, toCents, withCreateFirestore, withCreateHasuraGraphQL, withCrudFirestore, withCrudHasuraGraphQL, withDeleteFirestore, withDeleteHasuraGraphQL, withFindFirestore, withFindHasuraGraphQL, withFirestore, withGetFirestore, withGetHasuraGraphQL, withHasuraGraphQL, withHelpers, withSubCollection, withUpdateFirestore, withUpdateHasuraGraphQL };
|
|
11773
|
+
export { ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS, AccessoryImportances, Address, AdyenCardAxiosAdapter, AdyenPaymentMethodFactory, AntifraudBankSlipService, AntifraudCardService, AntifraudGlampointsService, AntifraudPixService, AntifraudProviderFactory, AntifraudProviders, Area, Authentication, AuthenticationFirebaseAuthService, AxiosAdapter, Base, BaseModel, BeardProblems, BeardSizes, BeautyProductImportances, BeautyProfile, BeautyQuestionsHelper, BillingStatus, BodyProblems, BodyShapes, BodyTattoos, BrandCategory, BrandCategoryFirestoreRepository, BrandEquityOptions, BusinessError, BusinessUnitEnum, Buy2Win, Buy2WinFirestoreRepository, Campaign, CampaignBanner, CampaignDashboard, CampaignDashboardFirestoreRepository, CampaignHashtag, CampaignHashtagFirestoreRepository, CampaignHashtagPosts, CampaignHashtagPostsFirestoreRepository, Category, CategoryCollectionChildren, CategoryCollectionChildrenHasuraGraphQLRepository, CategoryFilter, CategoryFilterHasuraGraphQLRepository, CategoryFirestoreRepository, CategoryHasuraGraphQL, CategoryHasuraGraphQLRepository, CategoryProduct, CategoryProductHasuraGraphQLRepository, Checkout, CheckoutFirestoreRepository, CheckoutSubscription, CheckoutSubscriptionFirestoreRepository, CheckoutTypes, ClassNameHelper, ConnectBaseDocumentSnapshot, ConnectCollectionService, ConnectDocumentService, ConnectFirestoreService, Coupon, CouponCategories, CouponCategory, CouponChannels, CouponFirestoreRepository, CouponOldCategories, CouponSubtypes, CouponTypes, DEFAULT_ANTIFRAUD_VOLUME_LIMITS, DEFAULT_SHOP_ANTIFRAUD_CONFIG, Debug, DebugDecoratorHelper, DebugHelper, DebugNamespaces, DuplicatedResultsError, Edition, EditionStatus, ErrorsCode, Exclusivities, FaceSkinOilinesses, FaceSkinProblems, FaceSkinTones, FamilyIncomes, Filter, FilterHasuraGraphQLRepository, FilterOption, FilterOptionHasuraGraphQLRepository, FilterType, FirebaseFileUploaderService, FragranceImportances, FraudValidationError, GenderDestination, GlampointsPaymentMethodFactory, GlampointsPaymentService, Group, GroupFirestoreRepository, HairColors, HairProblems, HairStrands, HairTypes, Home, HomeFirestoreRepository, InvalidArgumentError, InvalidCheckoutError, KitProduct, KitProductHasuraGraphQL, Lead, LeadFirestoreRepository, LegacyOrderFirestoreRepository, LineItem, Log, LogDocument, LogFirestoreRepository, Logger, MercadoPagoBankSlipAxiosAdapter, MercadoPagoCardAxiosAdapter, MercadoPagoErrorHelper, MercadoPagoPaymentMethodFactory, MercadoPagoPixAxiosAdapter, MercadoPagoRequestHelper, MercadoPagoResponseHelper, MercadoPagoStatusDetailEnum, MercadoPagoStatusEnum, NotFoundError, ObsEmitter, OfficePosition, Order, OrderBlocked, OrderBlockedFirestoreRepository, OrderBlockedType, OrderFirestoreRepository, OrderPaymentStatus, OrderStatus, PagarMeV5OrderStatus, PagarMeV5PaymentStatus, PagarmeBankSlipAxiosAdapter, PagarmeCardAxiosAdapter, PagarmePaymentMethodFactory, PagarmePaymentStatus, PagarmePixAxiosAdapter, PagarmeV5BankSlipAxiosAdapter, PagarmeV5BaseAxiosAdapter, PagarmeV5CardAxiosAdapter, PagarmeV5PixAxiosAdapter, Payment, PaymentError, PaymentFirestoreRepository, PaymentMethods, PaymentProviderFactory, PaymentProviders, PaymentTransaction, PaymentType, PersonTypes, Plans, Product, ProductCatalogHasuraGraphQL, ProductCatalogHasuraGraphQLRepository, ProductErrors, ProductErrorsHasuraGraphQL, ProductErrorsHasuraGraphQLRepository, ProductFirestoreRepository, ProductGroup, ProductGroupHasuraGraphQLRepository, ProductHasuraGraphQL, ProductHasuraGraphQLRepository, ProductLabelEnum, ProductPriceLog, ProductPriceLogHasuraGraphQLRepository, ProductReview, ProductReviewHasuraGraphQLRepository, ProductSpents, ProductStockEntry, ProductStockEntryHasuraGraphQL, ProductStockEntryHasuraGraphQLRepository, ProductStockNotification, ProductStockNotificationHasuraGraphQLRepository, ProductVariantFirestoreRepository, ProductsIndex, ProductsVertexSearch, QuestionsFilters, RecoveryPassword, ReflectHelper, Register, RegisterFirebaseAuthService, RequiredArgumentError, RestCacheAdapter, RoundProductPricesHelper, Sequence, SequenceFirestoreRepository, ShippingMethod, ShopConfigs, ShopConfigsFirestoreRepository, ShopMenu, ShopMenuFirestoreRepository, ShopPageName, ShopSettings, ShopSettingsFirestoreRepository, ShoppingRecurrence, ShoppingRecurrenceCycle, ShoppingRecurrenceEdition, ShoppingRecurrenceEditionFirestoreRepository, ShoppingRecurrenceEditionStatus, ShoppingRecurrenceErrorLog, ShoppingRecurrenceErrorLogFirestoreRepository, ShoppingRecurrenceFirestoreRepository, ShoppingRecurrenceStatus, Shops, SignInMethods, SignOut, Status, StockLimitError, StockOutError, Subscription, SubscriptionEditionFirestoreRepository, SubscriptionFirestoreRepository, SubscriptionMaterialization, SubscriptionMaterializationFirestoreRepository, SubscriptionPayment, SubscriptionPaymentFirestoreRepository, SubscriptionPlan, SubscriptionPlanFirestoreRepository, SubscriptionProductFirestoreRepository, SubscriptionSummary, SubscriptionSummaryFirestoreRepository, Trace, TransactionPaymentMethods, UnauthorizedError, UpdateOptionActions, UpdateUserImage, User, UserAddress, UserAddressFirestoreRepository, UserAlreadyRegisteredError, UserBeautyProfileFirestoreRepository, UserFirestoreRepository, UserPaymentMethod, UserPaymentMethodFirestoreRepository, UserType, Variant, VariantHasuraGraphQL, VariantHasuraGraphQLRepository, VertexAxiosAdapter, WeakPasswordError, Where, Wishlist, WishlistHasuraGraphQLRepository, WishlistLogType, deserialize, getClass, is, isAntifraudEnabled, isDebuggable, isUUID, parseDateTime, registerClass, resolveAntifraudVolumeLimits, resolveCacheConfig, resolveClass, serialize, toCents, withCreateFirestore, withCreateHasuraGraphQL, withCrudFirestore, withCrudHasuraGraphQL, withDeleteFirestore, withDeleteHasuraGraphQL, withFindFirestore, withFindHasuraGraphQL, withFirestore, withGetFirestore, withGetHasuraGraphQL, withHasuraGraphQL, withHelpers, withSubCollection, withUpdateFirestore, withUpdateHasuraGraphQL };
|
package/package.json
CHANGED
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
import { BaseModel, GenericIdentifier } from '../../generic/model';
|
|
2
|
-
import {
|
|
2
|
+
import { ShopAntifraudConfig, ShopErrorMessages, ShopSameDayNotAvailable } from './types';
|
|
3
3
|
export declare class ShopConfigs extends BaseModel<ShopConfigs> {
|
|
4
|
+
id: string;
|
|
4
5
|
errors?: ShopErrorMessages[];
|
|
5
|
-
antifraude?:
|
|
6
|
-
enabled: boolean;
|
|
7
|
-
week: {
|
|
8
|
-
subscriber: LimitOrders;
|
|
9
|
-
nonSubscriber: LimitOrders;
|
|
10
|
-
};
|
|
11
|
-
day: {
|
|
12
|
-
subscriber: LimitOrders;
|
|
13
|
-
nonSubscriber: LimitOrders;
|
|
14
|
-
};
|
|
15
|
-
};
|
|
6
|
+
antifraude?: ShopAntifraudConfig;
|
|
16
7
|
sameDayNotAvaliable?: ShopSameDayNotAvailable;
|
|
17
8
|
static get identifiersFields(): GenericIdentifier[];
|
|
18
9
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { LimitOrders } from './limit-orders.type';
|
|
2
|
+
export type AntifraudBlockedAttemptsDay = {
|
|
3
|
+
subscriber: number;
|
|
4
|
+
nonSubscriber: number;
|
|
5
|
+
};
|
|
6
|
+
export type AntifraudPeriodLimits = {
|
|
7
|
+
subscriber: LimitOrders;
|
|
8
|
+
nonSubscriber: LimitOrders;
|
|
9
|
+
};
|
|
10
|
+
/** Shape persistido em Firestore `shopConfigs.antifraude`. */
|
|
11
|
+
export type ShopAntifraudConfig = {
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
day: AntifraudPeriodLimits;
|
|
14
|
+
week: AntifraudPeriodLimits;
|
|
15
|
+
blockedAttemptsDay: AntifraudBlockedAttemptsDay;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Defaults iguais ao hardcode histórico do checkout.
|
|
19
|
+
* `week.*.zip = null` → Infinity no runtime do volume de cartão.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DEFAULT_SHOP_ANTIFRAUD_CONFIG: ShopAntifraudConfig;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ShopConfigsRepository } from '../../shop-settings';
|
|
2
|
+
export declare const ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS = 60;
|
|
3
|
+
/**
|
|
4
|
+
* Lê `shopConfigs.antifraude.enabled`.
|
|
5
|
+
* - `false` explícito → antifraude desligado
|
|
6
|
+
* - ausente / erro / inválido → `true` (mantém comportamento histórico)
|
|
7
|
+
*/
|
|
8
|
+
export declare function isAntifraudEnabled(shopConfigsRepository?: ShopConfigsRepository): Promise<boolean>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ShopAntifraudConfig } from '../../shop-settings/models/types';
|
|
2
|
+
import { ResolvedAntifraudVolumeLimits } from '../types/antifraud-volume-limits.type';
|
|
3
|
+
/** Defaults de runtime (week.zip = Infinity). Usados só como fallback no checkout. */
|
|
4
|
+
export declare const DEFAULT_ANTIFRAUD_VOLUME_LIMITS: ResolvedAntifraudVolumeLimits;
|
|
5
|
+
/** Config inválida/ausente → fallback (comportamento histórico). */
|
|
6
|
+
export declare function resolveAntifraudVolumeLimits(antifraude: ShopAntifraudConfig | undefined | null): ResolvedAntifraudVolumeLimits;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BaseModel, GenericIdentifier } from '../../generic';
|
|
2
|
+
export declare class CampaignHashtagPosts extends BaseModel<CampaignHashtagPosts> {
|
|
3
|
+
id: string;
|
|
4
|
+
campaignId: string;
|
|
5
|
+
postUrl: string;
|
|
6
|
+
status: string;
|
|
7
|
+
approved: boolean;
|
|
8
|
+
rating: number;
|
|
9
|
+
personId: number;
|
|
10
|
+
personAccount: string;
|
|
11
|
+
postAnalysis: string;
|
|
12
|
+
postEvaluationDate?: Date;
|
|
13
|
+
consent?: boolean;
|
|
14
|
+
consentDate?: Date;
|
|
15
|
+
metadata: {
|
|
16
|
+
IPAddress: string;
|
|
17
|
+
UserAgent: string;
|
|
18
|
+
Platform: string;
|
|
19
|
+
};
|
|
20
|
+
createdAt?: Date;
|
|
21
|
+
updatedAt?: Date;
|
|
22
|
+
static get identifiersFields(): GenericIdentifier[];
|
|
23
|
+
}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { BaseModel, GenericIdentifier } from '../../generic';
|
|
2
2
|
export declare class CampaignHashtag extends BaseModel<CampaignHashtag> {
|
|
3
3
|
id: string;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
campaignReferCode?: string;
|
|
12
|
-
campaignDescription?: string;
|
|
4
|
+
active: boolean;
|
|
5
|
+
title: string;
|
|
6
|
+
hashtagCode: string;
|
|
7
|
+
image?: string;
|
|
8
|
+
minimumGlampoints: number;
|
|
9
|
+
maximumGlampoints: number;
|
|
10
|
+
description?: string;
|
|
13
11
|
startDate?: Date;
|
|
14
12
|
endDate?: Date;
|
|
15
|
-
|
|
13
|
+
steps?: string[];
|
|
16
14
|
rules?: string[];
|
|
15
|
+
postsToShowInHome?: number;
|
|
16
|
+
topPosts?: string[];
|
|
17
|
+
createdAt?: Date;
|
|
18
|
+
updatedAt?: Date;
|
|
17
19
|
static get identifiersFields(): GenericIdentifier[];
|
|
18
20
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './buy-2-win.repository';
|
|
2
2
|
export * from './campaign-dashboard.repository';
|
|
3
3
|
export * from './campaign-hashtag.repository';
|
|
4
|
+
export * from './campaign-hashtag-posts.repository';
|
|
4
5
|
export * from './checkout.repository';
|
|
5
6
|
export * from './coupon.repository';
|
|
6
7
|
export * from './legacy-order.repository';
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { ShopConfigsRepository } from '../../shop-settings';
|
|
1
2
|
import { AntifraudProvider } from '../interfaces';
|
|
2
3
|
import { Checkout } from '../models';
|
|
3
4
|
import { OrderBlockedRepository } from '../repositories';
|
|
4
5
|
export declare class AntifraudBankSlipService implements AntifraudProvider {
|
|
5
6
|
private orderBlockedRepository;
|
|
7
|
+
private readonly shopConfigsRepository?;
|
|
6
8
|
private MAX_ORDER_VALUE;
|
|
7
|
-
constructor(orderBlockedRepository: OrderBlockedRepository);
|
|
9
|
+
constructor(orderBlockedRepository: OrderBlockedRepository, shopConfigsRepository?: ShopConfigsRepository);
|
|
8
10
|
validate(checkout: Checkout): Promise<Boolean>;
|
|
9
11
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
+
import { ShopConfigsRepository } from '../../shop-settings';
|
|
2
|
+
import { DEFAULT_ANTIFRAUD_VOLUME_LIMITS, resolveAntifraudVolumeLimits } from '../helpers';
|
|
1
3
|
import { AntifraudProvider } from '../interfaces';
|
|
2
4
|
import { Checkout } from '../models';
|
|
3
5
|
import { OrderBlockedRepository, OrderRepository } from '../repositories';
|
|
4
6
|
import { PaymentCardInfo } from '../types';
|
|
7
|
+
export { DEFAULT_ANTIFRAUD_VOLUME_LIMITS, resolveAntifraudVolumeLimits };
|
|
5
8
|
export declare class AntifraudCardService implements AntifraudProvider {
|
|
6
9
|
private readonly orderRepository;
|
|
7
10
|
private readonly orderBlockedRepository;
|
|
8
|
-
private
|
|
9
|
-
|
|
10
|
-
private LIMIT_BLOCKED_ORDERS_DAY;
|
|
11
|
-
constructor(orderRepository: OrderRepository, orderBlockedRepository: OrderBlockedRepository);
|
|
11
|
+
private readonly shopConfigsRepository?;
|
|
12
|
+
constructor(orderRepository: OrderRepository, orderBlockedRepository: OrderBlockedRepository, shopConfigsRepository?: ShopConfigsRepository);
|
|
12
13
|
validate(checkout: Checkout, card: PaymentCardInfo): Promise<Boolean>;
|
|
13
|
-
private
|
|
14
|
-
private getLimitsByUserType;
|
|
14
|
+
private loadResolvedLimits;
|
|
15
15
|
private validateBlockedOrderAttempts;
|
|
16
16
|
private validateDayAndWeekOrderLimits;
|
|
17
17
|
private verifyBlockedOrderAttempts;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { ShopConfigsRepository } from '../../shop-settings';
|
|
1
2
|
import { AntifraudProvider } from '../interfaces';
|
|
2
3
|
import { Checkout } from '../models';
|
|
3
4
|
export declare class AntifraudGlampointsService implements AntifraudProvider {
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
private readonly shopConfigsRepository?;
|
|
6
|
+
constructor(shopConfigsRepository?: ShopConfigsRepository);
|
|
7
|
+
validate(checkout: Checkout): Promise<Boolean>;
|
|
6
8
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { ShopConfigsRepository } from '../../shop-settings';
|
|
1
2
|
import { AntifraudProvider } from '../interfaces';
|
|
2
3
|
import { Checkout } from '../models';
|
|
3
4
|
export declare class AntifraudPixService implements AntifraudProvider {
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
private readonly shopConfigsRepository?;
|
|
6
|
+
constructor(shopConfigsRepository?: ShopConfigsRepository);
|
|
7
|
+
validate(checkout: Checkout): Promise<boolean>;
|
|
6
8
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Checkout } from '../models';
|
|
2
|
+
import { PaymentCardInfo } from './payment-card-info.type';
|
|
3
|
+
import { AntifraudRuntimeLimitOrders } from './antifraud-volume-limits.type';
|
|
4
|
+
export type AntifraudValidationParams = {
|
|
5
|
+
cpf: string;
|
|
6
|
+
email: string;
|
|
7
|
+
phone: string;
|
|
8
|
+
zip: string;
|
|
9
|
+
card: PaymentCardInfo;
|
|
10
|
+
};
|
|
11
|
+
export type AntifraudDateRange = {
|
|
12
|
+
firstDate: number;
|
|
13
|
+
lastDate: number;
|
|
14
|
+
};
|
|
15
|
+
export type AntifraudOrderCounts = {
|
|
16
|
+
cpf: number;
|
|
17
|
+
email: number;
|
|
18
|
+
phone: number;
|
|
19
|
+
zip: number;
|
|
20
|
+
card?: number;
|
|
21
|
+
};
|
|
22
|
+
export type AntifraudBlockedOrderRecordParams = {
|
|
23
|
+
checkout: Checkout;
|
|
24
|
+
card: PaymentCardInfo | null;
|
|
25
|
+
reason: string;
|
|
26
|
+
key: string;
|
|
27
|
+
period: string;
|
|
28
|
+
};
|
|
29
|
+
export type AntifraudOrderLimitCheckParams = {
|
|
30
|
+
checkout: Checkout;
|
|
31
|
+
orderCounts: AntifraudOrderCounts;
|
|
32
|
+
limit: AntifraudRuntimeLimitOrders;
|
|
33
|
+
period: string;
|
|
34
|
+
};
|
|
35
|
+
export type AntifraudOrderFieldQueryParams = {
|
|
36
|
+
property: string;
|
|
37
|
+
field: string;
|
|
38
|
+
value: unknown;
|
|
39
|
+
range: AntifraudDateRange;
|
|
40
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Limites resolvidos em runtime (zip semanal pode ser Infinity). */
|
|
2
|
+
export type AntifraudRuntimeLimitOrders = {
|
|
3
|
+
cpf: number;
|
|
4
|
+
email: number;
|
|
5
|
+
phone: number;
|
|
6
|
+
zip: number;
|
|
7
|
+
card: number;
|
|
8
|
+
};
|
|
9
|
+
export type ResolvedAntifraudVolumeLimits = {
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
source: 'config' | 'fallback';
|
|
12
|
+
day: {
|
|
13
|
+
subscriber: AntifraudRuntimeLimitOrders;
|
|
14
|
+
nonSubscriber: AntifraudRuntimeLimitOrders;
|
|
15
|
+
};
|
|
16
|
+
week: {
|
|
17
|
+
subscriber: AntifraudRuntimeLimitOrders;
|
|
18
|
+
nonSubscriber: AntifraudRuntimeLimitOrders;
|
|
19
|
+
};
|
|
20
|
+
blockedAttemptsDay: {
|
|
21
|
+
subscriber: number;
|
|
22
|
+
nonSubscriber: number;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from './adyen-card.type';
|
|
2
2
|
export * from './adyen-credentials.type';
|
|
3
|
+
export * from './antifraud-card-validation.type';
|
|
3
4
|
export * from './antifraud-provider.type';
|
|
5
|
+
export * from './antifraud-volume-limits.type';
|
|
4
6
|
export * from './card-info.type';
|
|
5
7
|
export * from './checkout-paylod-request.type';
|
|
6
8
|
export * from './checkout-response.type';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CampaignHashtagPosts } from '../../../../../domain/shopping/models/campaign-hashtag-posts';
|
|
2
|
+
import { CampaignHashtagPostsRepository } from '../../../../../domain/shopping/repositories/campaign-hashtag-posts.repository';
|
|
3
|
+
import { FirestoreConstructorParams } from '../../mixins';
|
|
4
|
+
declare const CampaignHashtagPostsFirestoreRepository_base: import("../../../../../utils").MixinCtor<import("../..").FirestoreRepository<CampaignHashtagPosts> & import("../../../../..").CrudRepository<CampaignHashtagPosts, import("../../../../..").CrudParams<CampaignHashtagPosts>> & import("../..").FirestoreHelpers, [FirestoreConstructorParams<CampaignHashtagPosts>, ...any[]]>;
|
|
5
|
+
export declare class CampaignHashtagPostsFirestoreRepository extends CampaignHashtagPostsFirestoreRepository_base implements CampaignHashtagPostsRepository {
|
|
6
|
+
constructor({ firestore, interceptors, cache, }: Pick<FirestoreConstructorParams<CampaignHashtagPosts>, 'firestore' | 'interceptors' | 'cache'>);
|
|
7
|
+
}
|
|
8
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './buy-2-win-firestore.repository';
|
|
2
2
|
export * from './campaign-dashboard-firestore.repository';
|
|
3
3
|
export * from './campaign-hashtag-firestore.repository';
|
|
4
|
+
export * from './campaign-hashtag-posts-firestore.repository';
|
|
4
5
|
export * from './checkout-firestore.repository';
|
|
5
6
|
export * from './checkout-subscription-firestore.repository';
|
|
6
7
|
export * from './coupon-firestore.repository';
|