@infrab4a/connect-angular 5.8.3 → 5.8.4

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.
Files changed (301) hide show
  1. package/eslint.config.js +18 -0
  2. package/index.ts +1 -0
  3. package/karma.conf.js +32 -0
  4. package/ng-package.json +8 -0
  5. package/package.json +4 -24
  6. package/project.json +37 -0
  7. package/src/angular-connect.module.ts +270 -0
  8. package/src/angular-elastic-search.module.ts +23 -0
  9. package/src/angular-firebase-auth.module.ts +101 -0
  10. package/src/angular-firestore.module.ts +407 -0
  11. package/src/angular-hasura-graphql.module.ts +268 -0
  12. package/src/angular-vertex-search.module.ts +23 -0
  13. package/src/consts/backend-url.const.ts +1 -0
  14. package/src/consts/category-structure.ts +1 -0
  15. package/src/consts/default-shop.const.ts +1 -0
  16. package/src/consts/es-config.const.ts +1 -0
  17. package/src/consts/firebase-const.ts +5 -0
  18. package/src/consts/hasura-options.const.ts +1 -0
  19. package/src/consts/index.ts +8 -0
  20. package/src/consts/persistence.const.ts +1 -0
  21. package/src/consts/storage-base-url.const.ts +1 -0
  22. package/src/consts/vertex-config.const.ts +1 -0
  23. package/src/helpers/index.ts +1 -0
  24. package/src/helpers/mobile-operation-system-checker.helper.ts +10 -0
  25. package/src/index.ts +6 -0
  26. package/src/interfaces/catalog-strategies.interface.ts +36 -0
  27. package/src/interfaces/category-facades.interface.ts +7 -0
  28. package/src/interfaces/index.ts +2 -0
  29. package/src/persistence/cookie-data-persistence.ts +21 -0
  30. package/src/persistence/data-persistence.ts +7 -0
  31. package/src/persistence/index.ts +2 -0
  32. package/src/services/auth.service.ts +39 -0
  33. package/src/services/cart/cart-services.facade.ts +14 -0
  34. package/src/services/cart/index.ts +1 -0
  35. package/src/services/cart.service.ts +124 -0
  36. package/src/services/catalog/adapters/category-structure.adapter.ts +5 -0
  37. package/src/services/catalog/adapters/index.ts +3 -0
  38. package/src/services/catalog/adapters/new-category-structure.adapter.ts +42 -0
  39. package/src/services/catalog/adapters/old-category-structure.adapter.ts +17 -0
  40. package/src/services/catalog/catalog.service.ts +153 -0
  41. package/src/services/catalog/category.service.ts +56 -0
  42. package/src/services/catalog/context/catalog-search.context.ts +59 -0
  43. package/src/services/catalog/enums/index.ts +1 -0
  44. package/src/services/catalog/enums/product-sorts.enum.ts +9 -0
  45. package/src/services/catalog/facades/catalog-service.facade.ts +32 -0
  46. package/src/services/catalog/facades/catalog-strategies.facade.ts +12 -0
  47. package/src/services/catalog/facades/category-repository.facade.ts +10 -0
  48. package/src/services/catalog/facades/category-service.facade.ts +25 -0
  49. package/{services/catalog/facades/index.d.ts → src/services/catalog/facades/index.ts} +5 -5
  50. package/src/services/catalog/facades/product-catalog.facade.ts +13 -0
  51. package/src/services/catalog/helpers/brand-manager.helper.ts +69 -0
  52. package/src/services/catalog/helpers/catalog-filter.helper.ts +50 -0
  53. package/src/services/catalog/helpers/catalog-sort.helper.ts +54 -0
  54. package/src/services/catalog/helpers/index.ts +4 -0
  55. package/src/services/catalog/helpers/product-fields.helper.ts +39 -0
  56. package/src/services/catalog/index.ts +7 -0
  57. package/src/services/catalog/models/category-with-tree.model.ts +7 -0
  58. package/src/services/catalog/models/index.ts +1 -0
  59. package/src/services/catalog/services/catalog-helpers.service.ts +35 -0
  60. package/src/services/catalog/services/catalog-operations.facade.ts +24 -0
  61. package/src/services/catalog/services/catalog-repository.service.ts +20 -0
  62. package/{services/catalog/services/index.d.ts → src/services/catalog/services/index.ts} +4 -4
  63. package/src/services/catalog/services/product-management.facade.ts +20 -0
  64. package/src/services/catalog/strategies/category-search.strategy.ts +168 -0
  65. package/src/services/catalog/strategies/index.ts +3 -0
  66. package/src/services/catalog/strategies/profile-search.strategy.ts +51 -0
  67. package/src/services/catalog/strategies/term-search.strategy.ts +163 -0
  68. package/src/services/catalog/strategies/types/strategy-params.type.ts +59 -0
  69. package/src/services/catalog/types/fetch-products-options.type.ts +10 -0
  70. package/src/services/catalog/types/fetch-products-params.type.ts +27 -0
  71. package/src/services/catalog/types/fetch-products-response.type.ts +11 -0
  72. package/src/services/catalog/types/index.ts +5 -0
  73. package/src/services/catalog/types/method-params.type.ts +21 -0
  74. package/src/services/catalog/types/product-sort.type.ts +3 -0
  75. package/src/services/catalog/wishlist.service.ts +364 -0
  76. package/src/services/checkout/checkout-dependencies.facade.ts +13 -0
  77. package/src/services/checkout/checkout-repositories.facade.ts +10 -0
  78. package/{services/checkout/index.d.ts → src/services/checkout/index.ts} +2 -2
  79. package/src/services/checkout-subscription.service.ts +76 -0
  80. package/src/services/checkout.service.ts +213 -0
  81. package/src/services/coupon/coupon-repositories.facade.ts +11 -0
  82. package/{services/coupon/index.d.ts → src/services/coupon/index.ts} +1 -1
  83. package/src/services/coupon/types/coupon-params.type.ts +15 -0
  84. package/src/services/coupon.service.ts +347 -0
  85. package/src/services/errors/group-invalid-coupon.error.ts +9 -0
  86. package/src/services/errors/index.ts +2 -0
  87. package/src/services/errors/invalid-coupon.error.ts +7 -0
  88. package/src/services/helpers/index.ts +1 -0
  89. package/src/services/helpers/util.helper.ts +17 -0
  90. package/src/services/home-shop/home-shop-repositories.facade.ts +11 -0
  91. package/{services/home-shop/index.d.ts → src/services/home-shop/index.ts} +1 -1
  92. package/src/services/home-shop.service.ts +210 -0
  93. package/src/services/index.ts +12 -0
  94. package/src/services/order-product-review.service.ts +135 -0
  95. package/src/services/order-recurrence.service.ts +115 -0
  96. package/src/services/order.service.ts +23 -0
  97. package/src/services/shared/configuration.facade.ts +21 -0
  98. package/src/services/shared/index.ts +1 -0
  99. package/src/services/types/index.ts +4 -0
  100. package/src/services/types/pending-product-review.type.ts +12 -0
  101. package/src/services/types/product-review-create.type.ts +15 -0
  102. package/src/services/types/required-checkout-data.type.ts +3 -0
  103. package/src/services/types/required-checkout-subscription-data.type.ts +3 -0
  104. package/src/types/firebase-app-config.type.ts +1 -0
  105. package/src/types/index.ts +1 -0
  106. package/tsconfig.json +17 -0
  107. package/tsconfig.lib.json +13 -0
  108. package/tsconfig.lib.prod.json +13 -0
  109. package/tsconfig.spec.json +17 -0
  110. package/angular-connect.module.d.ts +0 -36
  111. package/angular-elastic-search.module.d.ts +0 -9
  112. package/angular-firebase-auth.module.d.ts +0 -11
  113. package/angular-firestore.module.d.ts +0 -17
  114. package/angular-hasura-graphql.module.d.ts +0 -14
  115. package/angular-vertex-search.module.d.ts +0 -9
  116. package/consts/backend-url.const.d.ts +0 -1
  117. package/consts/category-structure.d.ts +0 -1
  118. package/consts/default-shop.const.d.ts +0 -1
  119. package/consts/es-config.const.d.ts +0 -1
  120. package/consts/firebase-const.d.ts +0 -4
  121. package/consts/hasura-options.const.d.ts +0 -1
  122. package/consts/index.d.ts +0 -8
  123. package/consts/persistence.const.d.ts +0 -1
  124. package/consts/storage-base-url.const.d.ts +0 -1
  125. package/consts/vertex-config.const.d.ts +0 -1
  126. package/esm2020/angular-connect.module.mjs +0 -293
  127. package/esm2020/angular-elastic-search.module.mjs +0 -34
  128. package/esm2020/angular-firebase-auth.module.mjs +0 -141
  129. package/esm2020/angular-firestore.module.mjs +0 -597
  130. package/esm2020/angular-hasura-graphql.module.mjs +0 -421
  131. package/esm2020/angular-vertex-search.module.mjs +0 -34
  132. package/esm2020/consts/backend-url.const.mjs +0 -2
  133. package/esm2020/consts/category-structure.mjs +0 -2
  134. package/esm2020/consts/default-shop.const.mjs +0 -2
  135. package/esm2020/consts/es-config.const.mjs +0 -2
  136. package/esm2020/consts/firebase-const.mjs +0 -5
  137. package/esm2020/consts/hasura-options.const.mjs +0 -2
  138. package/esm2020/consts/index.mjs +0 -9
  139. package/esm2020/consts/persistence.const.mjs +0 -2
  140. package/esm2020/consts/storage-base-url.const.mjs +0 -2
  141. package/esm2020/consts/vertex-config.const.mjs +0 -2
  142. package/esm2020/helpers/index.mjs +0 -2
  143. package/esm2020/helpers/mobile-operation-system-checker.helper.mjs +0 -7
  144. package/esm2020/index.mjs +0 -7
  145. package/esm2020/infrab4a-connect-angular.mjs +0 -5
  146. package/esm2020/interfaces/catalog-strategies.interface.mjs +0 -2
  147. package/esm2020/interfaces/category-facades.interface.mjs +0 -2
  148. package/esm2020/interfaces/index.mjs +0 -3
  149. package/esm2020/persistence/cookie-data-persistence.mjs +0 -22
  150. package/esm2020/persistence/data-persistence.mjs +0 -2
  151. package/esm2020/persistence/index.mjs +0 -3
  152. package/esm2020/services/auth.service.mjs +0 -37
  153. package/esm2020/services/cart/cart-services.facade.mjs +0 -21
  154. package/esm2020/services/cart/index.mjs +0 -2
  155. package/esm2020/services/cart.service.mjs +0 -73
  156. package/esm2020/services/catalog/adapters/category-structure.adapter.mjs +0 -2
  157. package/esm2020/services/catalog/adapters/index.mjs +0 -4
  158. package/esm2020/services/catalog/adapters/new-category-structure.adapter.mjs +0 -43
  159. package/esm2020/services/catalog/adapters/old-category-structure.adapter.mjs +0 -23
  160. package/esm2020/services/catalog/catalog.service.mjs +0 -111
  161. package/esm2020/services/catalog/category.service.mjs +0 -42
  162. package/esm2020/services/catalog/context/catalog-search.context.mjs +0 -40
  163. package/esm2020/services/catalog/enums/index.mjs +0 -2
  164. package/esm2020/services/catalog/enums/product-sorts.enum.mjs +0 -11
  165. package/esm2020/services/catalog/facades/catalog-service.facade.mjs +0 -32
  166. package/esm2020/services/catalog/facades/catalog-strategies.facade.mjs +0 -17
  167. package/esm2020/services/catalog/facades/category-repository.facade.mjs +0 -20
  168. package/esm2020/services/catalog/facades/category-service.facade.mjs +0 -30
  169. package/esm2020/services/catalog/facades/index.mjs +0 -6
  170. package/esm2020/services/catalog/facades/product-catalog.facade.mjs +0 -21
  171. package/esm2020/services/catalog/helpers/brand-manager.helper.mjs +0 -62
  172. package/esm2020/services/catalog/helpers/catalog-filter.helper.mjs +0 -44
  173. package/esm2020/services/catalog/helpers/catalog-sort.helper.mjs +0 -52
  174. package/esm2020/services/catalog/helpers/index.mjs +0 -5
  175. package/esm2020/services/catalog/helpers/product-fields.helper.mjs +0 -43
  176. package/esm2020/services/catalog/index.mjs +0 -8
  177. package/esm2020/services/catalog/models/category-with-tree.model.mjs +0 -10
  178. package/esm2020/services/catalog/models/index.mjs +0 -2
  179. package/esm2020/services/catalog/services/catalog-helpers.service.mjs +0 -33
  180. package/esm2020/services/catalog/services/catalog-operations.facade.mjs +0 -26
  181. package/esm2020/services/catalog/services/catalog-repository.service.mjs +0 -25
  182. package/esm2020/services/catalog/services/index.mjs +0 -5
  183. package/esm2020/services/catalog/services/product-management.facade.mjs +0 -25
  184. package/esm2020/services/catalog/strategies/category-search.strategy.mjs +0 -133
  185. package/esm2020/services/catalog/strategies/index.mjs +0 -4
  186. package/esm2020/services/catalog/strategies/profile-search.strategy.mjs +0 -42
  187. package/esm2020/services/catalog/strategies/term-search.strategy.mjs +0 -126
  188. package/esm2020/services/catalog/strategies/types/strategy-params.type.mjs +0 -2
  189. package/esm2020/services/catalog/types/fetch-products-options.type.mjs +0 -2
  190. package/esm2020/services/catalog/types/fetch-products-params.type.mjs +0 -2
  191. package/esm2020/services/catalog/types/fetch-products-response.type.mjs +0 -2
  192. package/esm2020/services/catalog/types/index.mjs +0 -6
  193. package/esm2020/services/catalog/types/method-params.type.mjs +0 -2
  194. package/esm2020/services/catalog/types/product-sort.type.mjs +0 -2
  195. package/esm2020/services/catalog/wishlist.service.mjs +0 -258
  196. package/esm2020/services/checkout/checkout-dependencies.facade.mjs +0 -20
  197. package/esm2020/services/checkout/checkout-repositories.facade.mjs +0 -20
  198. package/esm2020/services/checkout/index.mjs +0 -3
  199. package/esm2020/services/checkout-subscription.service.mjs +0 -55
  200. package/esm2020/services/checkout.service.mjs +0 -120
  201. package/esm2020/services/coupon/coupon-repositories.facade.mjs +0 -24
  202. package/esm2020/services/coupon/index.mjs +0 -2
  203. package/esm2020/services/coupon/types/coupon-params.type.mjs +0 -2
  204. package/esm2020/services/coupon.service.mjs +0 -248
  205. package/esm2020/services/helpers/index.mjs +0 -2
  206. package/esm2020/services/helpers/util.helper.mjs +0 -18
  207. package/esm2020/services/home-shop/home-shop-repositories.facade.mjs +0 -24
  208. package/esm2020/services/home-shop/index.mjs +0 -2
  209. package/esm2020/services/home-shop.service.mjs +0 -119
  210. package/esm2020/services/index.mjs +0 -12
  211. package/esm2020/services/order-product-review.service.mjs +0 -126
  212. package/esm2020/services/order-recurrence.service.mjs +0 -83
  213. package/esm2020/services/order.service.mjs +0 -30
  214. package/esm2020/services/shared/configuration.facade.mjs +0 -29
  215. package/esm2020/services/shared/index.mjs +0 -2
  216. package/esm2020/services/types/index.mjs +0 -5
  217. package/esm2020/services/types/pending-product-review.type.mjs +0 -2
  218. package/esm2020/services/types/product-review-create.type.mjs +0 -2
  219. package/esm2020/services/types/required-checkout-data.type.mjs +0 -2
  220. package/esm2020/services/types/required-checkout-subscription-data.type.mjs +0 -2
  221. package/esm2020/types/firebase-app-config.type.mjs +0 -2
  222. package/esm2020/types/index.mjs +0 -2
  223. package/fesm2015/infrab4a-connect-angular.mjs +0 -3746
  224. package/fesm2015/infrab4a-connect-angular.mjs.map +0 -1
  225. package/fesm2020/infrab4a-connect-angular.mjs +0 -3648
  226. package/fesm2020/infrab4a-connect-angular.mjs.map +0 -1
  227. package/helpers/index.d.ts +0 -1
  228. package/helpers/mobile-operation-system-checker.helper.d.ts +0 -3
  229. package/index.d.ts +0 -6
  230. package/interfaces/catalog-strategies.interface.d.ts +0 -31
  231. package/interfaces/category-facades.interface.d.ts +0 -6
  232. package/interfaces/index.d.ts +0 -2
  233. package/persistence/cookie-data-persistence.d.ts +0 -10
  234. package/persistence/data-persistence.d.ts +0 -6
  235. package/persistence/index.d.ts +0 -2
  236. package/services/auth.service.d.ts +0 -18
  237. package/services/cart/cart-services.facade.d.ts +0 -12
  238. package/services/cart/index.d.ts +0 -1
  239. package/services/cart.service.d.ts +0 -26
  240. package/services/catalog/adapters/category-structure.adapter.d.ts +0 -4
  241. package/services/catalog/adapters/index.d.ts +0 -3
  242. package/services/catalog/adapters/new-category-structure.adapter.d.ts +0 -12
  243. package/services/catalog/adapters/old-category-structure.adapter.d.ts +0 -10
  244. package/services/catalog/catalog.service.d.ts +0 -24
  245. package/services/catalog/category.service.d.ts +0 -23
  246. package/services/catalog/context/catalog-search.context.d.ts +0 -14
  247. package/services/catalog/enums/index.d.ts +0 -1
  248. package/services/catalog/enums/product-sorts.enum.d.ts +0 -9
  249. package/services/catalog/facades/catalog-service.facade.d.ts +0 -15
  250. package/services/catalog/facades/catalog-strategies.facade.d.ts +0 -10
  251. package/services/catalog/facades/category-repository.facade.d.ts +0 -9
  252. package/services/catalog/facades/category-service.facade.d.ts +0 -15
  253. package/services/catalog/facades/product-catalog.facade.d.ts +0 -10
  254. package/services/catalog/helpers/brand-manager.helper.d.ts +0 -14
  255. package/services/catalog/helpers/catalog-filter.helper.d.ts +0 -8
  256. package/services/catalog/helpers/catalog-sort.helper.d.ts +0 -7
  257. package/services/catalog/helpers/index.d.ts +0 -4
  258. package/services/catalog/helpers/product-fields.helper.d.ts +0 -7
  259. package/services/catalog/index.d.ts +0 -7
  260. package/services/catalog/models/category-with-tree.model.d.ts +0 -4
  261. package/services/catalog/models/index.d.ts +0 -1
  262. package/services/catalog/services/catalog-helpers.service.d.ts +0 -17
  263. package/services/catalog/services/catalog-operations.facade.d.ts +0 -13
  264. package/services/catalog/services/catalog-repository.service.d.ts +0 -12
  265. package/services/catalog/services/product-management.facade.d.ts +0 -12
  266. package/services/catalog/strategies/category-search.strategy.d.ts +0 -19
  267. package/services/catalog/strategies/index.d.ts +0 -3
  268. package/services/catalog/strategies/profile-search.strategy.d.ts +0 -14
  269. package/services/catalog/strategies/term-search.strategy.d.ts +0 -20
  270. package/services/catalog/strategies/types/strategy-params.type.d.ts +0 -59
  271. package/services/catalog/types/fetch-products-options.type.d.ts +0 -8
  272. package/services/catalog/types/fetch-products-params.type.d.ts +0 -25
  273. package/services/catalog/types/fetch-products-response.type.d.ts +0 -19
  274. package/services/catalog/types/index.d.ts +0 -5
  275. package/services/catalog/types/method-params.type.d.ts +0 -17
  276. package/services/catalog/types/product-sort.type.d.ts +0 -2
  277. package/services/catalog/wishlist.service.d.ts +0 -60
  278. package/services/checkout/checkout-dependencies.facade.d.ts +0 -10
  279. package/services/checkout/checkout-repositories.facade.d.ts +0 -9
  280. package/services/checkout-subscription.service.d.ts +0 -19
  281. package/services/checkout.service.d.ts +0 -31
  282. package/services/coupon/coupon-repositories.facade.d.ts +0 -10
  283. package/services/coupon/types/coupon-params.type.d.ts +0 -13
  284. package/services/coupon.service.d.ts +0 -36
  285. package/services/helpers/index.d.ts +0 -1
  286. package/services/helpers/util.helper.d.ts +0 -3
  287. package/services/home-shop/home-shop-repositories.facade.d.ts +0 -10
  288. package/services/home-shop.service.d.ts +0 -26
  289. package/services/index.d.ts +0 -11
  290. package/services/order-product-review.service.d.ts +0 -18
  291. package/services/order-recurrence.service.d.ts +0 -37
  292. package/services/order.service.d.ts +0 -13
  293. package/services/shared/configuration.facade.d.ts +0 -12
  294. package/services/shared/index.d.ts +0 -1
  295. package/services/types/index.d.ts +0 -4
  296. package/services/types/pending-product-review.type.d.ts +0 -12
  297. package/services/types/product-review-create.type.d.ts +0 -14
  298. package/services/types/required-checkout-data.type.d.ts +0 -2
  299. package/services/types/required-checkout-subscription-data.type.d.ts +0 -2
  300. package/types/firebase-app-config.type.d.ts +0 -1
  301. package/types/index.d.ts +0 -1
@@ -0,0 +1,15 @@
1
+ import { Checkout, CheckoutTypes, Coupon } from '@infrab4a/connect'
2
+
3
+ export type CheckCouponParams = {
4
+ nickname: string
5
+ checkoutType: CheckoutTypes
6
+ checkout: Partial<Checkout>
7
+ plan: string
8
+ }
9
+
10
+ export type CouponRulesValidationParams = {
11
+ coupon: Coupon
12
+ checkoutType: CheckoutTypes
13
+ checkout: Partial<Checkout>
14
+ plan: string
15
+ }
@@ -0,0 +1,347 @@
1
+ import { Injectable } from '@angular/core'
2
+ import {
3
+ Category,
4
+ Checkout,
5
+ CheckoutSubscription,
6
+ CheckoutTypes,
7
+ Coupon,
8
+ CouponTypes,
9
+ Exclusivities,
10
+ LineItem,
11
+ Order,
12
+ OrderStatus,
13
+ Shops,
14
+ User,
15
+ Where,
16
+ } from '@infrab4a/connect'
17
+ import { from, Observable, of } from 'rxjs'
18
+ import { concatMap, map } from 'rxjs/operators'
19
+
20
+ import { CouponRepositoriesFacade } from './coupon'
21
+ import { CheckCouponParams, CouponRulesValidationParams } from './coupon/types/coupon-params.type'
22
+ import { ConfigurationFacade } from './shared'
23
+
24
+ @Injectable({
25
+ providedIn: 'root',
26
+ })
27
+ export class CouponService {
28
+ constructor(
29
+ private readonly repositoriesFacade: CouponRepositoriesFacade,
30
+ private readonly configurationFacade: ConfigurationFacade,
31
+ ) {}
32
+
33
+ checkCoupon(params: CheckCouponParams): Observable<Coupon> {
34
+ const { nickname, checkoutType, checkout, plan } = params
35
+
36
+ return from(
37
+ this.repositoriesFacade.couponRepository
38
+ .find({
39
+ filters: {
40
+ nickname: { operator: Where.EQUALS, value: nickname },
41
+ active: { operator: Where.EQUALS, value: true },
42
+ },
43
+ })
44
+ .then((result) => result.data[0]),
45
+ ).pipe(
46
+ concatMap((coupon) => this.couponValidation(coupon, checkoutType)),
47
+ concatMap((couponValid: Coupon) =>
48
+ this.couponRulesValidation({ coupon: couponValid, checkoutType, checkout, plan }),
49
+ ),
50
+ map((couponValidated: Coupon) => couponValidated as Coupon),
51
+ )
52
+ }
53
+
54
+ private async couponValidation(coupon: Coupon, checkoutType: CheckoutTypes) {
55
+ if (!coupon) throw 'Cupom inválido.'
56
+
57
+ if (coupon?.beginAt && coupon?.beginAt.getTime() > new Date().getTime()) throw 'Cupom inválido.'
58
+
59
+ if (coupon?.expiresIn && (coupon?.expiresIn as Date).getTime() < new Date().getTime()) throw 'Cupom expirado.'
60
+
61
+ const isInShop =
62
+ coupon.shopAvailability === Shops.ALL || coupon.shopAvailability === this.configurationFacade.defaultShop
63
+
64
+ if (!isInShop) throw 'Cupom inválido para loja.'
65
+
66
+ const isCheckoutType = coupon.checkoutType === CheckoutTypes.ALL || coupon.checkoutType === checkoutType
67
+
68
+ if (!isCheckoutType) throw 'Cupom inválido. Erro de checkout.'
69
+
70
+ return coupon
71
+ }
72
+
73
+ private async couponRulesValidation(params: CouponRulesValidationParams) {
74
+ const { coupon, checkoutType, checkout, plan } = params
75
+
76
+ if (checkoutType == CheckoutTypes.SUBSCRIPTION) {
77
+ return this.validateSubscriptionCoupon(coupon, plan)
78
+ }
79
+
80
+ return this.validateEcommerceCoupon(coupon, checkoutType, checkout)
81
+ }
82
+
83
+ private validateSubscriptionCoupon(coupon: Coupon, plan: string): Coupon {
84
+ if (coupon.plan && coupon.plan.toUpperCase() !== plan.toUpperCase()) {
85
+ throw 'Cupom inválido para sua assinatura.'
86
+ }
87
+
88
+ return coupon
89
+ }
90
+
91
+ private async validateEcommerceCoupon(
92
+ coupon: Coupon,
93
+ checkoutType: CheckoutTypes,
94
+ checkout: Partial<Checkout>,
95
+ ): Promise<Coupon> {
96
+ this.validateUserEligibility(coupon, checkout?.user)
97
+ await this.validateUsageLimits(coupon, checkoutType, checkout)
98
+ await this.validateProductEligibility(coupon, checkout)
99
+
100
+ return coupon
101
+ }
102
+
103
+ private validateUserEligibility(coupon: Coupon, user: User): void {
104
+ const validUser = this.coupomUserValidation(coupon, user)
105
+
106
+ if (!validUser) throw 'Usuário não elegível.'
107
+ }
108
+
109
+ private async validateUsageLimits(
110
+ coupon: Coupon,
111
+ checkoutType: CheckoutTypes,
112
+ checkout: Partial<Checkout>,
113
+ ): Promise<void> {
114
+ const couponUseLimits = this.getCouponUseLimits(coupon, checkoutType, checkout.user)
115
+
116
+ if (couponUseLimits.firstOrder) {
117
+ await this.validateFirstOrderLimit(checkout.user.email)
118
+ }
119
+
120
+ if (!couponUseLimits.unlimited || couponUseLimits.limitedPerUser) {
121
+ await this.validateCouponUsageLimits(coupon, couponUseLimits, checkout.user.email)
122
+ }
123
+ }
124
+
125
+ private async validateFirstOrderLimit(userEmail: string): Promise<void> {
126
+ const ordersUser = await this.getOrdersFromUser(userEmail.toLocaleLowerCase())
127
+
128
+ if (ordersUser.length >= 1) throw 'Limite de uso atingido'
129
+ }
130
+
131
+ private async validateCouponUsageLimits(coupon: Coupon, couponUseLimits: any, userEmail: string): Promise<void> {
132
+ const ordersCoupon = await this.getOrdersWithCoupon(coupon)
133
+
134
+ if (!couponUseLimits.unlimited && couponUseLimits.total && ordersCoupon.length >= couponUseLimits.total) {
135
+ throw 'Limite de uso atingido.'
136
+ }
137
+
138
+ if (couponUseLimits.limitedPerUser) {
139
+ const ordersWithUser = this.countOrdersWithUser(ordersCoupon, userEmail)
140
+
141
+ if (ordersWithUser > 0) throw 'Limite de uso por usuário atingido.'
142
+ }
143
+ }
144
+
145
+ private async validateProductEligibility(coupon: Coupon, checkout: Partial<Checkout>): Promise<void> {
146
+ const hasProductCategories = await this.hasProductCategories(coupon, checkout)
147
+
148
+ if (!hasProductCategories) throw 'Seu carrinho não possui produtos elegíveis para desconto.'
149
+
150
+ const hasMinSubTotal = await this.hasMinSubTotal(coupon, checkout)
151
+
152
+ if (!hasMinSubTotal) {
153
+ this.throwMinSubTotalError(coupon)
154
+ }
155
+ }
156
+
157
+ private throwMinSubTotalError(coupon: Coupon): void {
158
+ const formattedValue = Intl.NumberFormat('pt-BR', {
159
+ style: 'currency',
160
+ currency: 'BRL',
161
+ }).format(coupon.minSubTotalValue)
162
+
163
+ if (coupon.productsCategories?.length) {
164
+ throw `Valor mínimo de ${formattedValue} não atingido na(s) categoria(s) elegíveis para o desconto.`
165
+ }
166
+
167
+ throw `Valor mínimo de ${formattedValue} não atingido.`
168
+ }
169
+
170
+ public calcDiscountSubscription(coupon: Coupon, checkout: Partial<CheckoutSubscription>): Observable<number> {
171
+ let discount = 0
172
+
173
+ if (coupon.discount.subscription.type == CouponTypes.ABSOLUTE) discount = coupon.discount.subscription.value
174
+ else discount = checkout.subscriptionPlan.recurrencePrice * (coupon.discount.subscription.value / 100)
175
+
176
+ return of(discount)
177
+ }
178
+
179
+ private async hasMinSubTotal(coupon: Coupon, checkout: Partial<Checkout>): Promise<boolean> {
180
+ if (!coupon.minSubTotalValue) return true
181
+
182
+ const lineItensDiscount = await this.getLineItensEligebleForDiscount(coupon.productsCategories, checkout)
183
+ const subTotal = this.calcCheckoutSubtotal(lineItensDiscount, checkout.user)
184
+
185
+ if (coupon.minSubTotalValue <= subTotal) return true
186
+
187
+ return false
188
+ }
189
+
190
+ private async hasProductCategories(coupon: Coupon, checkout: Partial<Checkout>): Promise<boolean> {
191
+ if (!coupon.productsCategories?.length) {
192
+ return true
193
+ }
194
+
195
+ const couponCategories = await this.getCouponCategoriesId(coupon.productsCategories)
196
+ const hasCategories = checkout.lineItems?.filter((item) => {
197
+ if (item.isGift) return false
198
+
199
+ if (!item.categories?.length) return true
200
+
201
+ return item.categories.some((c) => couponCategories.some((cat) => cat == c))
202
+ })
203
+
204
+ return hasCategories?.length ? true : false
205
+ }
206
+
207
+ private coupomUserValidation(coupon: Coupon, user: User) {
208
+ if (!user || coupon.exclusivityType.includes(Exclusivities.ALL_USERS)) return true
209
+
210
+ const userTypes: Exclusivities[] = []
211
+
212
+ if (
213
+ coupon.exclusivityType.includes(Exclusivities.COLLABORATORS) &&
214
+ this.emailIsFromCollaborator(user.email.toLocaleLowerCase())
215
+ )
216
+ userTypes.push(Exclusivities.COLLABORATORS)
217
+
218
+ if (
219
+ coupon.exclusivityType.includes(Exclusivities.SPECIFIC_USER) &&
220
+ coupon.userExclusiveEmail.includes(user.email.toLocaleLowerCase())
221
+ )
222
+ userTypes.push(Exclusivities.SPECIFIC_USER)
223
+
224
+ if (
225
+ coupon.exclusivityType.includes(Exclusivities.ACTIVE_SUBSCRIBER) &&
226
+ user.isSubscriber &&
227
+ user.subscriptionPlan != ''
228
+ )
229
+ userTypes.push(Exclusivities.ACTIVE_SUBSCRIBER)
230
+
231
+ if (
232
+ user.isSubscriber &&
233
+ user.subscriptionPlan == '' &&
234
+ coupon.exclusivityType.includes(Exclusivities.INACTIVE_SUBSCRIBER)
235
+ )
236
+ userTypes.push(Exclusivities.INACTIVE_SUBSCRIBER)
237
+
238
+ if (coupon.exclusivityType.includes(Exclusivities.NON_SUBSCRIBER) && !user.isSubscriber)
239
+ userTypes.push(Exclusivities.NON_SUBSCRIBER)
240
+
241
+ return coupon.exclusivityType.some((r) => userTypes.includes(r))
242
+ }
243
+
244
+ private async getCouponCategoriesId(productsCategories: string[]): Promise<Array<String>> {
245
+ const couponCategories: Array<String> = []
246
+
247
+ for (let index = 0; index < productsCategories.length; index++) {
248
+ const category: Category & { firestoreId?: string } = await this.repositoriesFacade.categoryRepository.get({
249
+ id: productsCategories[index],
250
+ })
251
+
252
+ if (category) {
253
+ const children = await this.repositoriesFacade.categoryRepository.getChildren(
254
+ parseInt(productsCategories[index]),
255
+ )
256
+
257
+ couponCategories.push(category.id, ...children.map((c) => c.id.toString()))
258
+ }
259
+ }
260
+
261
+ return [...new Set(couponCategories)]
262
+ }
263
+
264
+ private emailIsFromCollaborator = (userEmail: string): boolean => !!userEmail?.match(/@b4a.com.br/g)
265
+
266
+ private async getLineItensEligebleForDiscount(
267
+ productsCategories: string[],
268
+ checkout: Partial<Checkout>,
269
+ ): Promise<LineItem[]> {
270
+ let lineItensDiscount = []
271
+ const couponCategories = await this.getCouponCategoriesId(productsCategories)
272
+
273
+ if (productsCategories?.length) {
274
+ lineItensDiscount = checkout.lineItems?.filter((item) => {
275
+ if (item.isGift) return false
276
+
277
+ if (item.categories?.length) {
278
+ return item.categories.some((c) => couponCategories.some((cat) => cat == c))
279
+ }
280
+
281
+ return true
282
+ })
283
+ } else {
284
+ lineItensDiscount = checkout.lineItems.filter((item) => !item.isGift)
285
+ }
286
+
287
+ return lineItensDiscount
288
+ }
289
+
290
+ private calcCheckoutSubtotal(lineItens: LineItem[], user: User): number {
291
+ return (
292
+ lineItens
293
+ ?.filter((item) => !item.isGift)
294
+ .reduce(
295
+ (acc, curr) =>
296
+ user?.isSubscriber && curr.price?.subscriberPrice
297
+ ? acc + curr.price?.subscriberPrice * curr.quantity
298
+ : acc + curr.pricePaid * curr.quantity,
299
+ 0,
300
+ ) || 0
301
+ )
302
+ }
303
+
304
+ private async getOrdersWithCoupon(coupon: Coupon): Promise<Order[]> {
305
+ return await this.repositoriesFacade.orderRepository
306
+ .find({
307
+ filters: {
308
+ coupon: { id: coupon.id },
309
+ status: { operator: Where.NOTEQUALS, value: OrderStatus.CANCELADO },
310
+ },
311
+ })
312
+ .then((result) => result.data)
313
+ }
314
+
315
+ private async getOrdersFromUser(email: string) {
316
+ return await this.repositoriesFacade.orderRepository
317
+ .find({
318
+ filters: {
319
+ user: { email: { operator: Where.EQUALS, value: email } },
320
+ status: { operator: Where.NOTEQUALS, value: OrderStatus.CANCELADO },
321
+ },
322
+ })
323
+ .then((result) => result.data)
324
+ }
325
+
326
+ private countOrdersWithUser(orders: Order[], email: string): number {
327
+ return orders.filter((o) => o.user.email == email).length
328
+ }
329
+
330
+ private getCouponUseLimits(coupon: Coupon, checkoutType: CheckoutTypes, user: User) {
331
+ let couponUseLimits: { unlimited?: boolean; total?: number; limitedPerUser?: boolean; firstOrder?: boolean }
332
+
333
+ if (checkoutType == CheckoutTypes.ECOMMERCE || checkoutType == CheckoutTypes.ALL) {
334
+ if (
335
+ coupon.exclusivityType.length === 1 &&
336
+ (coupon.exclusivityType.at(0) === Exclusivities.SPECIFIC_USER ||
337
+ coupon.exclusivityType.at(0) === Exclusivities.COLLABORATORS)
338
+ )
339
+ couponUseLimits = coupon.useLimits.non_subscriber
340
+ else couponUseLimits = user?.isSubscriber ? coupon.useLimits.subscriber : coupon.useLimits.non_subscriber
341
+ } else {
342
+ couponUseLimits = coupon.useLimits.subscription
343
+ }
344
+
345
+ return couponUseLimits
346
+ }
347
+ }
@@ -0,0 +1,9 @@
1
+ import { CustomError } from 'ts-custom-error'
2
+
3
+ import { InvalidCouponError } from './invalid-coupon.error'
4
+
5
+ export class GroupInvalidCouponError extends CustomError {
6
+ constructor(readonly errors: InvalidCouponError[]) {
7
+ super('Many coupon errors throw')
8
+ }
9
+ }
@@ -0,0 +1,2 @@
1
+ export * from './group-invalid-coupon.error'
2
+ export * from './invalid-coupon.error'
@@ -0,0 +1,7 @@
1
+ import { CustomError } from 'ts-custom-error'
2
+
3
+ export class InvalidCouponError extends CustomError {
4
+ constructor(message: string) {
5
+ super(message)
6
+ }
7
+ }
@@ -0,0 +1 @@
1
+ export * from './util.helper'
@@ -0,0 +1,17 @@
1
+ export class UtilHelper {
2
+ static createSlug(name: string): string {
3
+ return name
4
+ .toLowerCase()
5
+ .replace(/\s+/g, '-')
6
+ .replace(/[ãàáäâ]/g, 'a')
7
+ .replace(/[ẽèéëê]/g, 'e')
8
+ .replace(/[ìíïî]/g, 'i')
9
+ .replace(/[õòóöô]/g, 'o')
10
+ .replace(/[ùúüû]/g, 'u')
11
+ .replace(/[ñ]/g, 'n')
12
+ .replace(/[ç]/g, 'c')
13
+ .replace(/[&]/g, 'and')
14
+ .replace(/[^\w-]+/g, '')
15
+ .replace(/--+/g, '-')
16
+ }
17
+ }
@@ -0,0 +1,11 @@
1
+ import { Inject, Injectable } from '@angular/core'
2
+ import { CategoryRepository, HomeRepository, ProductRepository } from '@infrab4a/connect'
3
+
4
+ @Injectable()
5
+ export class HomeShopRepositoriesFacade {
6
+ constructor(
7
+ @Inject('CategoryRepository') public readonly categoryRepository: CategoryRepository,
8
+ @Inject('HomeRepository') public readonly homeRepository: HomeRepository,
9
+ @Inject('ProductRepository') public readonly productRepository: ProductRepository,
10
+ ) {}
11
+ }
@@ -1 +1 @@
1
- export { HomeShopRepositoriesFacade } from './home-shop-repositories.facade';
1
+ export { HomeShopRepositoriesFacade } from './home-shop-repositories.facade'
@@ -0,0 +1,210 @@
1
+ import { Injectable } from '@angular/core'
2
+ import {
3
+ add,
4
+ Banner,
5
+ Category,
6
+ Home,
7
+ HomeCategoryGroup,
8
+ HomeData,
9
+ pick,
10
+ Product,
11
+ RequiredArgumentError,
12
+ ShippingThresholds,
13
+ Shops,
14
+ Where,
15
+ } from '@infrab4a/connect'
16
+ import { forkJoin, from, Observable, of, throwError } from 'rxjs'
17
+ import { concatMap, map, tap } from 'rxjs/operators'
18
+
19
+ import { HomeShopRepositoriesFacade } from './home-shop'
20
+ import { ConfigurationFacade } from './shared'
21
+
22
+ type HomeConfigurationId = 'glamshop' | 'mens_market'
23
+ type BannerType = 'brand' | 'buyToWin' | 'block' | 'blog'
24
+
25
+ @Injectable()
26
+ export class HomeShopService {
27
+ private homeConfiguration: Home
28
+
29
+ private get homeId(): HomeConfigurationId {
30
+ if (this.configurationFacade.defaultShop === Shops.GLAMSHOP) return 'glamshop'
31
+
32
+ if (this.configurationFacade.defaultShop === Shops.MENSMARKET) return 'mens_market'
33
+
34
+ return null
35
+ }
36
+
37
+ constructor(
38
+ private readonly repositoriesFacade: HomeShopRepositoriesFacade,
39
+ private readonly configurationFacade: ConfigurationFacade,
40
+ ) {}
41
+
42
+ getHomeData(): Observable<Home> {
43
+ return this.getHomeConfiguration().pipe(
44
+ map((home) => (home?.data?.expiresAt > new Date() ? home : null)),
45
+ concatMap((home) =>
46
+ home
47
+ ? of(home)
48
+ : forkJoin([
49
+ this.getDiscoverProducts(this.gender),
50
+ this.getFeaturedProducts(this.gender),
51
+ this.getVerticalProducts(this.gender),
52
+ ]).pipe(
53
+ map(([discoverProducts, featuredProducts, verticalProducts]) => ({
54
+ discoverProducts,
55
+ featuredProducts,
56
+ verticalProducts,
57
+ })),
58
+ concatMap((data) => this.saveHomeData(data)),
59
+ ),
60
+ ),
61
+ )
62
+ }
63
+
64
+ getBanners(type: BannerType): Observable<Banner[]> {
65
+ return this.getHomeConfiguration().pipe(
66
+ map((home) => {
67
+ if (type === 'brand') return home.brandsCarousel
68
+
69
+ if (type === 'buyToWin') return [home.buyToWinBanner]
70
+
71
+ if (type === 'block') return home.blockBanners
72
+
73
+ if (type === 'blog') return [home.blogBanner]
74
+
75
+ return []
76
+ }),
77
+ )
78
+ }
79
+
80
+ getMinValueForFreeShipping(): Observable<number> {
81
+ return this.getHomeConfiguration().pipe(map((home) => home.minValueForFreeShipping))
82
+ }
83
+
84
+ /**
85
+ * Retorna os thresholds de frete grátis estruturados configurados no documento
86
+ * Home (`shippingThresholds`). Quando o documento ainda não possui essa
87
+ * estrutura, retorna um default conservador equivalente à regra legada
88
+ * (edition: 50, avulsoSp: 99, avulsoOutro: null) para que consumidores não
89
+ * quebrem durante a migração.
90
+ */
91
+ getShippingThresholds(): Observable<ShippingThresholds> {
92
+ const conservativeDefault: ShippingThresholds = { edition: 50, avulsoSp: 99, avulsoOutro: null }
93
+
94
+ return this.getHomeConfiguration().pipe(map((home) => home.shippingThresholds ?? conservativeDefault))
95
+ }
96
+
97
+ private getDiscoverProducts(_gender?: string): Observable<{ category: Category; products: Product[] }[]> {
98
+ return this.getHomeConfiguration().pipe(
99
+ concatMap((home) =>
100
+ from(
101
+ this.repositoriesFacade.categoryRepository.getCategoriesForHome({
102
+ categoryIds: home.discoverCategories,
103
+ shop: this.configurationFacade.defaultShop,
104
+ }),
105
+ ).pipe(map((groups) => groups.map(this.buildCategoryGroupWithRequiredData))),
106
+ ),
107
+ )
108
+ }
109
+
110
+ private getFeaturedProducts(_gender?: string): Observable<{ category: Category; products: Product[] }[]> {
111
+ return this.getHomeConfiguration().pipe(
112
+ concatMap((home) =>
113
+ from(
114
+ this.repositoriesFacade.categoryRepository.getCategoriesForHome({
115
+ categoryIds: home.featuredCategories,
116
+ shop: this.configurationFacade.defaultShop,
117
+ }),
118
+ ).pipe(map((groups) => groups.map(this.buildCategoryGroupWithRequiredData))),
119
+ ),
120
+ )
121
+ }
122
+
123
+ private getVerticalProducts(gender?: string): Observable<{ category: Category; products: Product[] }[]> {
124
+ return this.getHomeConfiguration().pipe(
125
+ concatMap((home) =>
126
+ forkJoin(
127
+ home.verticalCarousels.filter(Boolean).map((id) =>
128
+ from(this.repositoriesFacade.categoryRepository.get({ id })).pipe(
129
+ concatMap((category) =>
130
+ from(
131
+ this.repositoriesFacade.productRepository.find({
132
+ filters: {
133
+ categories: { operator: Where.IN, value: [category.id] },
134
+ ...(gender ? { tags: { operator: Where.IN, value: [gender] } } : {}),
135
+ },
136
+ limits: { limit: 12 },
137
+ }),
138
+ ).pipe(map((products) => ({ category, products }))),
139
+ ),
140
+ map(({ category, products }) => ({ category, products: products.data })),
141
+ map(this.buildCategoryGroupWithRequiredData),
142
+ ),
143
+ ),
144
+ ),
145
+ ),
146
+ )
147
+ }
148
+
149
+ private getHomeConfiguration(): Observable<Home> {
150
+ return of(this.homeConfiguration).pipe(
151
+ concatMap((home) =>
152
+ home
153
+ ? of(home)
154
+ : !this.homeId
155
+ ? throwError(() => new RequiredArgumentError(['homeId']))
156
+ : from(this.repositoriesFacade.homeRepository.get({ id: this.homeId })).pipe(
157
+ tap((homeLoaded) => (this.homeConfiguration = homeLoaded)),
158
+ ),
159
+ ),
160
+ )
161
+ }
162
+
163
+ private saveHomeData(homeData: HomeData): Observable<Home> {
164
+ const data = {
165
+ createdAt: new Date(),
166
+ expiresAt: add(new Date(), { hours: 1 }),
167
+ data: homeData,
168
+ }
169
+
170
+ return from(
171
+ this.repositoriesFacade.homeRepository.update({
172
+ id: this.homeId,
173
+ data,
174
+ }),
175
+ ).pipe(
176
+ tap(() => (this.homeConfiguration.data = data)),
177
+ map(() => this.homeConfiguration),
178
+ )
179
+ }
180
+
181
+ private buildCategoryGroupWithRequiredData = (group: HomeCategoryGroup): HomeCategoryGroup => ({
182
+ category: Category.toInstance(pick(group?.category?.toPlain() || {}, ['id', 'name', 'slug', 'conditions'])),
183
+ products:
184
+ group?.products?.map((product) =>
185
+ Product.toInstance(
186
+ pick(product?.toPlain() || {}, [
187
+ 'id',
188
+ 'price',
189
+ 'reviews',
190
+ 'hasVariants',
191
+ 'slug',
192
+ 'sku',
193
+ 'stock',
194
+ 'costPrice',
195
+ 'images',
196
+ 'miniatures',
197
+ 'name',
198
+ 'weight',
199
+ 'rate',
200
+ 'type',
201
+ 'brand',
202
+ ]),
203
+ ),
204
+ ) || [],
205
+ })
206
+
207
+ private get gender() {
208
+ return this.homeId === 'mens_market' ? 'masculino' : undefined
209
+ }
210
+ }
@@ -0,0 +1,12 @@
1
+ export * from './auth.service'
2
+ export * from './cart.service'
3
+ export * from './catalog'
4
+ export * from './checkout-subscription.service'
5
+ export * from './checkout.service'
6
+ export * from './coupon.service'
7
+ export * from './helpers'
8
+ export * from './home-shop.service'
9
+ export * from './order-product-review.service'
10
+ export * from './order-recurrence.service'
11
+ export * from './order.service'
12
+